From 8e39efd840b8d4eae5ab398b43e20ffaff0010cc Mon Sep 17 00:00:00 2001 From: David Matlack Date: Tue, 10 May 2022 15:40:34 -0700 Subject: [PATCH 0001/1436] KVM: VMX: Print VM-instruction error when it may be helpful Include the value of the "VM-instruction error" field from the current VMCS (if any) in the error message for VMCLEAR and VMPTRLD, since each of these instructions may result in more than one VM-instruction error. Previously, this field was only reported for VMWRITE errors. Signed-off-by: David Matlack [Rebased and refactored code; dropped the error number for INVVPID and INVEPT; reworded commit message.] Signed-off-by: Jim Mattson Message-Id: <20220510224035.1792952-1-jmattson@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index f5aeade623d6..673ba5ca0beb 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -392,12 +392,14 @@ noinline void vmwrite_error(unsigned long field, unsigned long value) noinline void vmclear_error(struct vmcs *vmcs, u64 phys_addr) { - vmx_insn_failed("kvm: vmclear failed: %p/%llx\n", vmcs, phys_addr); + vmx_insn_failed("kvm: vmclear failed: %p/%llx err=%u\n", + vmcs, phys_addr, vmcs_read32(VM_INSTRUCTION_ERROR)); } noinline void vmptrld_error(struct vmcs *vmcs, u64 phys_addr) { - vmx_insn_failed("kvm: vmptrld failed: %p/%llx\n", vmcs, phys_addr); + vmx_insn_failed("kvm: vmptrld failed: %p/%llx err=%u\n", + vmcs, phys_addr, vmcs_read32(VM_INSTRUCTION_ERROR)); } noinline void invvpid_error(unsigned long ext, u16 vpid, gva_t gva) From cc07e60b0811eeeca769fb342aa6e13da5977657 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Tue, 10 May 2022 15:40:35 -0700 Subject: [PATCH 0002/1436] KVM: VMX: Print VM-instruction error as unsigned Change the printf format character from 'd' to 'u' for the VM-instruction error in vmwrite_error(). Fixes: 6aa8b732ca01 ("[PATCH] kvm: userspace interface") Reported-by: Sean Christopherson Signed-off-by: Jim Mattson Message-Id: <20220510224035.1792952-2-jmattson@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 673ba5ca0beb..e0d3bea73b28 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -386,7 +386,7 @@ asmlinkage void vmread_error(unsigned long field, bool fault) noinline void vmwrite_error(unsigned long field, unsigned long value) { - vmx_insn_failed("kvm: vmwrite failed: field=%lx val=%lx err=%d\n", + vmx_insn_failed("kvm: vmwrite failed: field=%lx val=%lx err=%u\n", field, value, vmcs_read32(VM_INSTRUCTION_ERROR)); } From 0471a7bd1bca2a47a5f378f2222c5cf39ce94152 Mon Sep 17 00:00:00 2001 From: Lev Kujawski Date: Sat, 21 May 2022 08:15:11 +0000 Subject: [PATCH 0003/1436] KVM: set_msr_mce: Permit guests to ignore single-bit ECC errors Certain guest operating systems (e.g., UNIXWARE) clear bit 0 of MC1_CTL to ignore single-bit ECC data errors. Single-bit ECC data errors are always correctable and thus are safe to ignore because they are informational in nature rather than signaling a loss of data integrity. Prior to this patch, these guests would crash upon writing MC1_CTL, with resultant error messages like the following: error: kvm run failed Operation not permitted EAX=fffffffe EBX=fffffffe ECX=00000404 EDX=ffffffff ESI=ffffffff EDI=00000001 EBP=fffdaba4 ESP=fffdab20 EIP=c01333a5 EFL=00000246 [---Z-P-] CPL=0 II=0 A20=1 SMM=0 HLT=0 ES =0108 00000000 ffffffff 00c09300 DPL=0 DS [-WA] CS =0100 00000000 ffffffff 00c09b00 DPL=0 CS32 [-RA] SS =0108 00000000 ffffffff 00c09300 DPL=0 DS [-WA] DS =0108 00000000 ffffffff 00c09300 DPL=0 DS [-WA] FS =0000 00000000 ffffffff 00c00000 GS =0000 00000000 ffffffff 00c00000 LDT=0118 c1026390 00000047 00008200 DPL=0 LDT TR =0110 ffff5af0 00000067 00008b00 DPL=0 TSS32-busy GDT= ffff5020 000002cf IDT= ffff52f0 000007ff CR0=8001003b CR2=00000000 CR3=0100a000 CR4=00000230 DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 DR6=ffff0ff0 DR7=00000400 EFER=0000000000000000 Code=08 89 01 89 51 04 c3 8b 4c 24 08 8b 01 8b 51 04 8b 4c 24 04 <0f> 30 c3 f7 05 a4 6d ff ff 10 00 00 00 74 03 0f 31 c3 33 c0 33 d2 c3 8d 74 26 00 0f 31 c3 Signed-off-by: Lev Kujawski Message-Id: <20220521081511.187388-1-lkujaw@member.fsf.org> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b81ef4f497f4..b5aeed18b9f5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3234,10 +3234,13 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) /* only 0 or all 1s can be written to IA32_MCi_CTL * some Linux kernels though clear bit 10 in bank 4 to * workaround a BIOS/GART TBL issue on AMD K8s, ignore - * this to avoid an uncatched #GP in the guest + * this to avoid an uncatched #GP in the guest. + * + * UNIXWARE clears bit 0 of MC1_CTL to ignore + * correctable, single-bit ECC data errors. */ if ((offset & 0x3) == 0 && - data != 0 && (data | (1 << 10)) != ~(u64)0) + data != 0 && (data | (1 << 10) | 1) != ~(u64)0) return -1; /* MCi_STATUS */ From 345b0fd6fe5f66dfe841bad0b39dd11a5672df68 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 21:00:20 +0000 Subject: [PATCH 0004/1436] KVM: Drop unused @gpa param from gfn=>pfn cache's __release_gpc() helper Drop the @pga param from __release_gpc() and rename the helper to make it more obvious that the cache itself is not being released. The helper will be reused by a future commit to release a pfn+khva combination that is _never_ associated with the cache, at which point the current name would go from slightly misleading to blatantly wrong. No functional change intended. Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Message-Id: <20220429210025.3293691-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/pfncache.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index dd84676615f1..e05a6a1b8eff 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -95,7 +95,7 @@ bool kvm_gfn_to_pfn_cache_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, } EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_check); -static void __release_gpc(struct kvm *kvm, kvm_pfn_t pfn, void *khva, gpa_t gpa) +static void gpc_release_pfn_and_khva(struct kvm *kvm, kvm_pfn_t pfn, void *khva) { /* Unmap the old page if it was mapped before, and release it */ if (!is_error_noslot_pfn(pfn)) { @@ -146,7 +146,6 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, unsigned long page_offset = gpa & ~PAGE_MASK; kvm_pfn_t old_pfn, new_pfn; unsigned long old_uhva; - gpa_t old_gpa; void *old_khva; bool old_valid; int ret = 0; @@ -160,7 +159,6 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, write_lock_irq(&gpc->lock); - old_gpa = gpc->gpa; old_pfn = gpc->pfn; old_khva = gpc->khva - offset_in_page(gpc->khva); old_uhva = gpc->uhva; @@ -244,7 +242,7 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, out: write_unlock_irq(&gpc->lock); - __release_gpc(kvm, old_pfn, old_khva, old_gpa); + gpc_release_pfn_and_khva(kvm, old_pfn, old_khva); return ret; } @@ -254,14 +252,12 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) { void *old_khva; kvm_pfn_t old_pfn; - gpa_t old_gpa; write_lock_irq(&gpc->lock); gpc->valid = false; old_khva = gpc->khva - offset_in_page(gpc->khva); - old_gpa = gpc->gpa; old_pfn = gpc->pfn; /* @@ -273,7 +269,7 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) write_unlock_irq(&gpc->lock); - __release_gpc(kvm, old_pfn, old_khva, old_gpa); + gpc_release_pfn_and_khva(kvm, old_pfn, old_khva); } EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_unmap); From 3dddf65b4f4c451c345d34ae85bdf1791a746e49 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 21:00:21 +0000 Subject: [PATCH 0005/1436] KVM: Put the extra pfn reference when reusing a pfn in the gpc cache Put the struct page reference to pfn acquired by hva_to_pfn() when the old and new pfns for a gfn=>pfn cache match. The cache already has a reference via the old/current pfn, and will only put one reference when the cache is done with the pfn. Fixes: 982ed0de4753 ("KVM: Reinstate gfn_to_pfn_cache with invalidation support") Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Message-Id: <20220429210025.3293691-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/pfncache.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index e05a6a1b8eff..40cbe90d52e0 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -206,6 +206,14 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, if (gpc->usage & KVM_HOST_USES_PFN) { if (new_pfn == old_pfn) { + /* + * Reuse the existing pfn and khva, but put the + * reference acquired hva_to_pfn_retry(); the + * cache still holds a reference to the pfn + * from the previous refresh. + */ + gpc_release_pfn_and_khva(kvm, new_pfn, NULL); + new_khva = old_khva; old_pfn = KVM_PFN_ERR_FAULT; old_khva = NULL; From 3ba2c95ea180740b16281fa43a3ee5f47279c0ed Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 21:00:22 +0000 Subject: [PATCH 0006/1436] KVM: Do not incorporate page offset into gfn=>pfn cache user address Don't adjust the userspace address in the gfn=>pfn cache by the page offset from the gpa. KVM should never use the user address directly, and all KVM operations that translate a user address to something else require the user address to be page aligned. Ignoring the offset will allow the cache to reuse a gfn=>hva translation in the unlikely event that the page offset of the gpa changes, but the gfn does not. And more importantly, not having to (un)adjust the user address will simplify a future bug fix. Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Message-Id: <20220429210025.3293691-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/pfncache.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 40cbe90d52e0..05cb0bcbf662 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -179,8 +179,6 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, ret = -EFAULT; goto out; } - - gpc->uhva += page_offset; } /* From 93984f19e7bce4c18084a6ef3dacafb155b806ed Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 21:00:23 +0000 Subject: [PATCH 0007/1436] KVM: Fully serialize gfn=>pfn cache refresh via mutex Protect gfn=>pfn cache refresh with a mutex to fully serialize refreshes. The refresh logic doesn't protect against - concurrent unmaps, or refreshes with different GPAs (which may or may not happen in practice, for example if a cache is only used under vcpu->mutex; but it's allowed in the code) - a false negative on the memslot generation. If the first refresh sees a stale memslot generation, it will refresh the hva and generation before moving on to the hva=>pfn translation. If it then drops gpc->lock, a different user of the cache can come along, acquire gpc->lock, see that the memslot generation is fresh, and skip the hva=>pfn update due to the userspace address also matching (because it too was updated). The refresh path can already sleep during hva=>pfn resolution, so wrap the refresh with a mutex to ensure that any given refresh runs to completion before other callers can start their refresh. Cc: stable@vger.kernel.org Cc: Lai Jiangshan Signed-off-by: Sean Christopherson Message-Id: <20220429210025.3293691-7-seanjc@google.com> Signed-off-by: Paolo Bonzini --- include/linux/kvm_types.h | 2 ++ virt/kvm/pfncache.c | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index ac1ebb37a0ff..f328a01db4fe 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h @@ -19,6 +19,7 @@ struct kvm_memslots; enum kvm_mr_change; #include +#include #include #include @@ -69,6 +70,7 @@ struct gfn_to_pfn_cache { struct kvm_vcpu *vcpu; struct list_head list; rwlock_t lock; + struct mutex refresh_lock; void *khva; kvm_pfn_t pfn; enum pfn_cache_usage usage; diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index 05cb0bcbf662..f610d3945b69 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -157,6 +157,13 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, if (page_offset + len > PAGE_SIZE) return -EINVAL; + /* + * If another task is refreshing the cache, wait for it to complete. + * There is no guarantee that concurrent refreshes will see the same + * gpa, memslots generation, etc..., so they must be fully serialized. + */ + mutex_lock(&gpc->refresh_lock); + write_lock_irq(&gpc->lock); old_pfn = gpc->pfn; @@ -248,6 +255,8 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, out: write_unlock_irq(&gpc->lock); + mutex_unlock(&gpc->refresh_lock); + gpc_release_pfn_and_khva(kvm, old_pfn, old_khva); return ret; @@ -259,6 +268,7 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) void *old_khva; kvm_pfn_t old_pfn; + mutex_lock(&gpc->refresh_lock); write_lock_irq(&gpc->lock); gpc->valid = false; @@ -274,6 +284,7 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) gpc->pfn = KVM_PFN_ERR_FAULT; write_unlock_irq(&gpc->lock); + mutex_unlock(&gpc->refresh_lock); gpc_release_pfn_and_khva(kvm, old_pfn, old_khva); } @@ -288,6 +299,7 @@ int kvm_gfn_to_pfn_cache_init(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, if (!gpc->active) { rwlock_init(&gpc->lock); + mutex_init(&gpc->refresh_lock); gpc->khva = NULL; gpc->pfn = KVM_PFN_ERR_FAULT; From 58cd407ca4c6278cf9f9d09a2e663bf645b0c982 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 21:00:24 +0000 Subject: [PATCH 0008/1436] KVM: Fix multiple races in gfn=>pfn cache refresh Rework the gfn=>pfn cache (gpc) refresh logic to address multiple races between the cache itself, and between the cache and mmu_notifier events. The existing refresh code attempts to guard against races with the mmu_notifier by speculatively marking the cache valid, and then marking it invalid if a mmu_notifier invalidation occurs. That handles the case where an invalidation occurs between dropping and re-acquiring gpc->lock, but it doesn't handle the scenario where the cache is refreshed after the cache was invalidated by the notifier, but before the notifier elevates mmu_notifier_count. The gpc refresh can't use the "retry" helper as its invalidation occurs _before_ mmu_notifier_count is elevated and before mmu_notifier_range_start is set/updated. CPU0 CPU1 ---- ---- gfn_to_pfn_cache_invalidate_start() | -> gpc->valid = false; kvm_gfn_to_pfn_cache_refresh() | |-> gpc->valid = true; hva_to_pfn_retry() | -> acquire kvm->mmu_lock kvm->mmu_notifier_count == 0 mmu_seq == kvm->mmu_notifier_seq drop kvm->mmu_lock return pfn 'X' acquire kvm->mmu_lock kvm_inc_notifier_count() drop kvm->mmu_lock() kernel frees pfn 'X' kvm_gfn_to_pfn_cache_check() | |-> gpc->valid == true caller accesses freed pfn 'X' Key off of mn_active_invalidate_count to detect that a pfncache refresh needs to wait for an in-progress mmu_notifier invalidation. While mn_active_invalidate_count is not guaranteed to be stable, it is guaranteed to be elevated prior to an invalidation acquiring gpc->lock, so either the refresh will see an active invalidation and wait, or the invalidation will run after the refresh completes. Speculatively marking the cache valid is itself flawed, as a concurrent kvm_gfn_to_pfn_cache_check() would see a valid cache with stale pfn/khva values. The KVM Xen use case explicitly allows/wants multiple users; even though the caches are allocated per vCPU, __kvm_xen_has_interrupt() can read a different vCPU (or vCPUs). Address this race by invalidating the cache prior to dropping gpc->lock (this is made possible by fixing the above mmu_notifier race). Complicating all of this is the fact that both the hva=>pfn resolution and mapping of the kernel address can sleep, i.e. must be done outside of gpc->lock. Fix the above races in one fell swoop, trying to fix each individual race is largely pointless and essentially impossible to test, e.g. closing one hole just shifts the focus to the other hole. Fixes: 982ed0de4753 ("KVM: Reinstate gfn_to_pfn_cache with invalidation support") Cc: stable@vger.kernel.org Cc: David Woodhouse Cc: Mingwei Zhang Signed-off-by: Sean Christopherson Message-Id: <20220429210025.3293691-8-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/kvm_main.c | 9 +++ virt/kvm/pfncache.c | 193 ++++++++++++++++++++++++++++---------------- 2 files changed, 131 insertions(+), 71 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 342043b30125..a65a2369f788 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -724,6 +724,15 @@ static int kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn, kvm->mn_active_invalidate_count++; spin_unlock(&kvm->mn_invalidate_lock); + /* + * Invalidate pfn caches _before_ invalidating the secondary MMUs, i.e. + * before acquiring mmu_lock, to avoid holding mmu_lock while acquiring + * each cache's lock. There are relatively few caches in existence at + * any given time, and the caches themselves can check for hva overlap, + * i.e. don't need to rely on memslot overlap checks for performance. + * Because this runs without holding mmu_lock, the pfn caches must use + * mn_active_invalidate_count (see above) instead of mmu_notifier_count. + */ gfn_to_pfn_cache_invalidate_start(kvm, range->start, range->end, hva_range.may_block); diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index f610d3945b69..b0b678367376 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -112,31 +112,122 @@ static void gpc_release_pfn_and_khva(struct kvm *kvm, kvm_pfn_t pfn, void *khva) } } -static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, unsigned long uhva) +static inline bool mmu_notifier_retry_cache(struct kvm *kvm, unsigned long mmu_seq) { + /* + * mn_active_invalidate_count acts for all intents and purposes + * like mmu_notifier_count here; but the latter cannot be used + * here because the invalidation of caches in the mmu_notifier + * event occurs _before_ mmu_notifier_count is elevated. + * + * Note, it does not matter that mn_active_invalidate_count + * is not protected by gpc->lock. It is guaranteed to + * be elevated before the mmu_notifier acquires gpc->lock, and + * isn't dropped until after mmu_notifier_seq is updated. + */ + if (kvm->mn_active_invalidate_count) + return true; + + /* + * Ensure mn_active_invalidate_count is read before + * mmu_notifier_seq. This pairs with the smp_wmb() in + * mmu_notifier_invalidate_range_end() to guarantee either the + * old (non-zero) value of mn_active_invalidate_count or the + * new (incremented) value of mmu_notifier_seq is observed. + */ + smp_rmb(); + return kvm->mmu_notifier_seq != mmu_seq; +} + +static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) +{ + /* Note, the new page offset may be different than the old! */ + void *old_khva = gpc->khva - offset_in_page(gpc->khva); + kvm_pfn_t new_pfn = KVM_PFN_ERR_FAULT; + void *new_khva = NULL; unsigned long mmu_seq; - kvm_pfn_t new_pfn; - int retry; + + lockdep_assert_held(&gpc->refresh_lock); + + lockdep_assert_held_write(&gpc->lock); + + /* + * Invalidate the cache prior to dropping gpc->lock, the gpa=>uhva + * assets have already been updated and so a concurrent check() from a + * different task may not fail the gpa/uhva/generation checks. + */ + gpc->valid = false; do { mmu_seq = kvm->mmu_notifier_seq; smp_rmb(); + write_unlock_irq(&gpc->lock); + + /* + * If the previous iteration "failed" due to an mmu_notifier + * event, release the pfn and unmap the kernel virtual address + * from the previous attempt. Unmapping might sleep, so this + * needs to be done after dropping the lock. Opportunistically + * check for resched while the lock isn't held. + */ + if (new_pfn != KVM_PFN_ERR_FAULT) { + /* + * Keep the mapping if the previous iteration reused + * the existing mapping and didn't create a new one. + */ + if (new_khva == old_khva) + new_khva = NULL; + + gpc_release_pfn_and_khva(kvm, new_pfn, new_khva); + + cond_resched(); + } + /* We always request a writeable mapping */ - new_pfn = hva_to_pfn(uhva, false, NULL, true, NULL); + new_pfn = hva_to_pfn(gpc->uhva, false, NULL, true, NULL); if (is_error_noslot_pfn(new_pfn)) - break; + goto out_error; - KVM_MMU_READ_LOCK(kvm); - retry = mmu_notifier_retry_hva(kvm, mmu_seq, uhva); - KVM_MMU_READ_UNLOCK(kvm); - if (!retry) - break; + /* + * Obtain a new kernel mapping if KVM itself will access the + * pfn. Note, kmap() and memremap() can both sleep, so this + * too must be done outside of gpc->lock! + */ + if (gpc->usage & KVM_HOST_USES_PFN) { + if (new_pfn == gpc->pfn) { + new_khva = old_khva; + } else if (pfn_valid(new_pfn)) { + new_khva = kmap(pfn_to_page(new_pfn)); +#ifdef CONFIG_HAS_IOMEM + } else { + new_khva = memremap(pfn_to_hpa(new_pfn), PAGE_SIZE, MEMREMAP_WB); +#endif + } + if (!new_khva) { + kvm_release_pfn_clean(new_pfn); + goto out_error; + } + } - cond_resched(); - } while (1); + write_lock_irq(&gpc->lock); - return new_pfn; + /* + * Other tasks must wait for _this_ refresh to complete before + * attempting to refresh. + */ + WARN_ON_ONCE(gpc->valid); + } while (mmu_notifier_retry_cache(kvm, mmu_seq)); + + gpc->valid = true; + gpc->pfn = new_pfn; + gpc->khva = new_khva + (gpc->gpa & ~PAGE_MASK); + return 0; + +out_error: + write_lock_irq(&gpc->lock); + + return -EFAULT; } int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, @@ -147,7 +238,6 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, kvm_pfn_t old_pfn, new_pfn; unsigned long old_uhva; void *old_khva; - bool old_valid; int ret = 0; /* @@ -169,7 +259,6 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, old_pfn = gpc->pfn; old_khva = gpc->khva - offset_in_page(gpc->khva); old_uhva = gpc->uhva; - old_valid = gpc->valid; /* If the userspace HVA is invalid, refresh that first */ if (gpc->gpa != gpa || gpc->generation != slots->generation || @@ -182,7 +271,6 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, gpc->uhva = gfn_to_hva_memslot(gpc->memslot, gfn); if (kvm_is_error_hva(gpc->uhva)) { - gpc->pfn = KVM_PFN_ERR_FAULT; ret = -EFAULT; goto out; } @@ -192,60 +280,8 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, * If the userspace HVA changed or the PFN was already invalid, * drop the lock and do the HVA to PFN lookup again. */ - if (!old_valid || old_uhva != gpc->uhva) { - unsigned long uhva = gpc->uhva; - void *new_khva = NULL; - - /* Placeholders for "hva is valid but not yet mapped" */ - gpc->pfn = KVM_PFN_ERR_FAULT; - gpc->khva = NULL; - gpc->valid = true; - - write_unlock_irq(&gpc->lock); - - new_pfn = hva_to_pfn_retry(kvm, uhva); - if (is_error_noslot_pfn(new_pfn)) { - ret = -EFAULT; - goto map_done; - } - - if (gpc->usage & KVM_HOST_USES_PFN) { - if (new_pfn == old_pfn) { - /* - * Reuse the existing pfn and khva, but put the - * reference acquired hva_to_pfn_retry(); the - * cache still holds a reference to the pfn - * from the previous refresh. - */ - gpc_release_pfn_and_khva(kvm, new_pfn, NULL); - - new_khva = old_khva; - old_pfn = KVM_PFN_ERR_FAULT; - old_khva = NULL; - } else if (pfn_valid(new_pfn)) { - new_khva = kmap(pfn_to_page(new_pfn)); -#ifdef CONFIG_HAS_IOMEM - } else { - new_khva = memremap(pfn_to_hpa(new_pfn), PAGE_SIZE, MEMREMAP_WB); -#endif - } - if (new_khva) - new_khva += page_offset; - else - ret = -EFAULT; - } - - map_done: - write_lock_irq(&gpc->lock); - if (ret) { - gpc->valid = false; - gpc->pfn = KVM_PFN_ERR_FAULT; - gpc->khva = NULL; - } else { - /* At this point, gpc->valid may already have been cleared */ - gpc->pfn = new_pfn; - gpc->khva = new_khva; - } + if (!gpc->valid || old_uhva != gpc->uhva) { + ret = hva_to_pfn_retry(kvm, gpc); } else { /* If the HVA→PFN mapping was already valid, don't unmap it. */ old_pfn = KVM_PFN_ERR_FAULT; @@ -253,11 +289,26 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, } out: + /* + * Invalidate the cache and purge the pfn/khva if the refresh failed. + * Some/all of the uhva, gpa, and memslot generation info may still be + * valid, leave it as is. + */ + if (ret) { + gpc->valid = false; + gpc->pfn = KVM_PFN_ERR_FAULT; + gpc->khva = NULL; + } + + /* Snapshot the new pfn before dropping the lock! */ + new_pfn = gpc->pfn; + write_unlock_irq(&gpc->lock); mutex_unlock(&gpc->refresh_lock); - gpc_release_pfn_and_khva(kvm, old_pfn, old_khva); + if (old_pfn != new_pfn) + gpc_release_pfn_and_khva(kvm, old_pfn, old_khva); return ret; } From 85165781c5d900d97052be1d2723f6929d56768d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 21:00:25 +0000 Subject: [PATCH 0009/1436] KVM: Do not pin pages tracked by gfn=>pfn caches Put the reference to any struct page mapped/tracked by a gfn=>pfn cache upon inserting the pfn into its associated cache, as opposed to putting the reference only when the cache is done using the pfn. In other words, don't pin pages while they're in the cache. One of the major roles of the gfn=>pfn cache is to play nicely with invalidation events, i.e. it exists in large part so that KVM doesn't rely on pinning pages. Signed-off-by: Sean Christopherson Message-Id: <20220429210025.3293691-9-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/pfncache.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/virt/kvm/pfncache.c b/virt/kvm/pfncache.c index b0b678367376..ab519f72f2cd 100644 --- a/virt/kvm/pfncache.c +++ b/virt/kvm/pfncache.c @@ -95,20 +95,16 @@ bool kvm_gfn_to_pfn_cache_check(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, } EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_check); -static void gpc_release_pfn_and_khva(struct kvm *kvm, kvm_pfn_t pfn, void *khva) +static void gpc_unmap_khva(struct kvm *kvm, kvm_pfn_t pfn, void *khva) { - /* Unmap the old page if it was mapped before, and release it */ - if (!is_error_noslot_pfn(pfn)) { - if (khva) { - if (pfn_valid(pfn)) - kunmap(pfn_to_page(pfn)); + /* Unmap the old pfn/page if it was mapped before. */ + if (!is_error_noslot_pfn(pfn) && khva) { + if (pfn_valid(pfn)) + kunmap(pfn_to_page(pfn)); #ifdef CONFIG_HAS_IOMEM - else - memunmap(khva); + else + memunmap(khva); #endif - } - - kvm_release_pfn(pfn, false); } } @@ -176,10 +172,10 @@ static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) * Keep the mapping if the previous iteration reused * the existing mapping and didn't create a new one. */ - if (new_khva == old_khva) - new_khva = NULL; + if (new_khva != old_khva) + gpc_unmap_khva(kvm, new_pfn, new_khva); - gpc_release_pfn_and_khva(kvm, new_pfn, new_khva); + kvm_release_pfn_clean(new_pfn); cond_resched(); } @@ -222,6 +218,14 @@ static kvm_pfn_t hva_to_pfn_retry(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) gpc->valid = true; gpc->pfn = new_pfn; gpc->khva = new_khva + (gpc->gpa & ~PAGE_MASK); + + /* + * Put the reference to the _new_ pfn. The pfn is now tracked by the + * cache and can be safely migrated, swapped, etc... as the cache will + * invalidate any mappings in response to relevant mmu_notifier events. + */ + kvm_release_pfn_clean(new_pfn); + return 0; out_error: @@ -308,7 +312,7 @@ int kvm_gfn_to_pfn_cache_refresh(struct kvm *kvm, struct gfn_to_pfn_cache *gpc, mutex_unlock(&gpc->refresh_lock); if (old_pfn != new_pfn) - gpc_release_pfn_and_khva(kvm, old_pfn, old_khva); + gpc_unmap_khva(kvm, old_pfn, old_khva); return ret; } @@ -337,7 +341,7 @@ void kvm_gfn_to_pfn_cache_unmap(struct kvm *kvm, struct gfn_to_pfn_cache *gpc) write_unlock_irq(&gpc->lock); mutex_unlock(&gpc->refresh_lock); - gpc_release_pfn_and_khva(kvm, old_pfn, old_khva); + gpc_unmap_khva(kvm, old_pfn, old_khva); } EXPORT_SYMBOL_GPL(kvm_gfn_to_pfn_cache_unmap); From 7ccced33a0ba39b0103ae1dfbf7f1dffdc0a1bc2 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Fri, 13 May 2022 14:51:56 -0700 Subject: [PATCH 0010/1436] HID: wacom: Only report rotation for art pen The generic routine, wacom_wac_pen_event, turns rotation value 90 degree anti-clockwise before posting the events. This non-zero event trggers a non-zero ABS_Z event for non art pen tools. However, HID_DG_TWIST is only supported by art pen. [jkosina@suse.cz: fix build: add missing brace] Cc: stable@vger.kernel.org Signed-off-by: Ping Cheng Reviewed-by: Jason Gerecke -- Hi Jiri, This is kind of a version 2 of the last one I posted two days ago. I updated the logic so it has less changed lines: 29 vs 158! Hopefully, the logic is easier to follow now. Please ignore the last one. Thank you! Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 9470c2b0b529..866b484b82de 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -638,9 +638,26 @@ static int wacom_intuos_id_mangle(int tool_id) return (tool_id & ~0xFFF) << 4 | (tool_id & 0xFFF); } +static bool wacom_is_art_pen(int tool_id) +{ + bool is_art_pen = false; + + switch (tool_id) { + case 0x885: /* Intuos3 Marker Pen */ + case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */ + case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */ + is_art_pen = true; + break; + } + return is_art_pen; +} + static int wacom_intuos_get_tool_type(int tool_id) { - int tool_type; + int tool_type = BTN_TOOL_PEN; + + if (wacom_is_art_pen(tool_id)) + return tool_type; switch (tool_id) { case 0x812: /* Inking pen */ @@ -655,12 +672,9 @@ static int wacom_intuos_get_tool_type(int tool_id) case 0x852: case 0x823: /* Intuos3 Grip Pen */ case 0x813: /* Intuos3 Classic Pen */ - case 0x885: /* Intuos3 Marker Pen */ case 0x802: /* Intuos4/5 13HD/24HD General Pen */ - case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */ case 0x8e2: /* IntuosHT2 pen */ case 0x022: - case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */ case 0x10842: /* MobileStudio Pro Pro Pen slim */ case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */ case 0x16802: /* Cintiq 13HD Pro Pen */ @@ -718,10 +732,6 @@ static int wacom_intuos_get_tool_type(int tool_id) case 0x10902: /* Intuos4/5 13HD/24HD Airbrush */ tool_type = BTN_TOOL_AIRBRUSH; break; - - default: /* Unknown tool */ - tool_type = BTN_TOOL_PEN; - break; } return tool_type; } @@ -2336,6 +2346,9 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field } return; case HID_DG_TWIST: + /* don't modify the value if the pen doesn't support the feature */ + if (!wacom_is_art_pen(wacom_wac->id[0])) return; + /* * Userspace expects pen twist to have its zero point when * the buttons/finger is on the tablet's left. HID values From d6b675687a4ab4dba684716d97c8c6f81bf10905 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Fri, 13 May 2022 14:52:37 -0700 Subject: [PATCH 0011/1436] HID: wacom: Don't register pad_input for touch switch Touch switch state is received through WACOM_PAD_FIELD. However, it is reported by touch_input. Don't register pad_input if no other pad events require the interface. Cc: stable@vger.kernel.org Signed-off-by: Ping Cheng Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 2 +- drivers/hid/wacom_wac.c | 43 ++++++++++++++++++++++++----------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 620fe74f5676..98384b911288 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -2121,7 +2121,7 @@ static int wacom_register_inputs(struct wacom *wacom) error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac); if (error) { - /* no pad in use on this interface */ + /* no pad events using this interface */ input_free_device(pad_input_dev); wacom_wac->pad_input = NULL; pad_input_dev = NULL; diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 866b484b82de..f8cc4bb3e3a7 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2019,7 +2019,6 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev, wacom_wac->has_mute_touch_switch = true; usage->type = EV_SW; usage->code = SW_MUTE_DEVICE; - features->device_type |= WACOM_DEVICETYPE_PAD; break; case WACOM_HID_WD_TOUCHSTRIP: wacom_map_usage(input, usage, field, EV_ABS, ABS_RX, 0); @@ -2099,6 +2098,30 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field wacom_wac->hid_data.inrange_state |= value; } + /* Process touch switch state first since it is reported through touch interface, + * which is indepentent of pad interface. In the case when there are no other pad + * events, the pad interface will not even be created. + */ + if ((equivalent_usage == WACOM_HID_WD_MUTE_DEVICE) || + (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)) { + if (wacom_wac->shared->touch_input) { + bool *is_touch_on = &wacom_wac->shared->is_touch_on; + + if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value) + *is_touch_on = !(*is_touch_on); + else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF) + *is_touch_on = value; + + input_report_switch(wacom_wac->shared->touch_input, + SW_MUTE_DEVICE, !(*is_touch_on)); + input_sync(wacom_wac->shared->touch_input); + } + return; + } + + if (!input) + return; + switch (equivalent_usage) { case WACOM_HID_WD_TOUCHRING: /* @@ -2134,22 +2157,6 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field input_event(input, usage->type, usage->code, 0); break; - case WACOM_HID_WD_MUTE_DEVICE: - case WACOM_HID_WD_TOUCHONOFF: - if (wacom_wac->shared->touch_input) { - bool *is_touch_on = &wacom_wac->shared->is_touch_on; - - if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value) - *is_touch_on = !(*is_touch_on); - else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF) - *is_touch_on = value; - - input_report_switch(wacom_wac->shared->touch_input, - SW_MUTE_DEVICE, !(*is_touch_on)); - input_sync(wacom_wac->shared->touch_input); - } - break; - case WACOM_HID_WD_MODE_CHANGE: if (wacom_wac->is_direct_mode != value) { wacom_wac->is_direct_mode = value; @@ -2835,7 +2842,7 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field, /* usage tests must precede field tests */ if (WACOM_BATTERY_USAGE(usage)) wacom_wac_battery_event(hdev, field, usage, value); - else if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input) + else if (WACOM_PAD_FIELD(field)) wacom_wac_pad_event(hdev, field, usage, value); else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input) wacom_wac_pen_event(hdev, field, usage, value); From e51d8d3ea3d773334d2c047c8d1623dba66f592a Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 12 May 2022 13:18:48 -0500 Subject: [PATCH 0012/1436] HID: amd_sfh: Don't show client init failed as error when discovery fails When sensor discovery fails, this means that the system doesn't have any sensors connected and a user should only be notified at most one time. A message is already displayed at WARN level of "failed to discover, sensors not enabled". It's pointless to show that the client init failed at ERR level for the same condition. Check the return code and don't display this message in those conditions. Fixes: b5d7f43e97da ("HID: amd_sfh: Add support for sensor discovery") Reported-by: David Chang Signed-off-by: Mario Limonciello Acked-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index dadc491bbf6b..1441787a154a 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -327,7 +327,8 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i rc = amd_sfh_hid_client_init(privdata); if (rc) { amd_sfh_clear_intr(privdata); - dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n"); + if (rc != -EOPNOTSUPP) + dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n"); return rc; } From ac640db3a0260541058e95e4acd249cc166cb0eb Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:19 +0000 Subject: [PATCH 0013/1436] s390/uv: Add SE hdr query information We have information about the supported se header version and pcf bits so let's expose it via the sysfs files. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Reviewed-by: Steffen Eiden Link: https://lore.kernel.org/r/20220517163629.3443-2-frankja@linux.ibm.com Message-Id: <20220517163629.3443-2-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/boot/uv.c | 2 ++ arch/s390/include/asm/uv.h | 7 ++++++- arch/s390/kernel/uv.c | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/arch/s390/boot/uv.c b/arch/s390/boot/uv.c index e6be155ab2e5..b100b57cf15d 100644 --- a/arch/s390/boot/uv.c +++ b/arch/s390/boot/uv.c @@ -41,6 +41,8 @@ void uv_query_info(void) uv_info.max_num_sec_conf = uvcb.max_num_sec_conf; uv_info.max_guest_cpu_id = uvcb.max_guest_cpu_id; uv_info.uv_feature_indications = uvcb.uv_feature_indications; + uv_info.supp_se_hdr_ver = uvcb.supp_se_hdr_versions; + uv_info.supp_se_hdr_pcf = uvcb.supp_se_hdr_pcf; } #ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index cfea7b77a5b8..46498b8c587b 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -110,7 +110,10 @@ struct uv_cb_qui { u8 reserved88[158 - 136]; /* 0x0088 */ u16 max_guest_cpu_id; /* 0x009e */ u64 uv_feature_indications; /* 0x00a0 */ - u8 reserveda8[200 - 168]; /* 0x00a8 */ + u64 reserveda8; /* 0x00a8 */ + u64 supp_se_hdr_versions; /* 0x00b0 */ + u64 supp_se_hdr_pcf; /* 0x00b8 */ + u64 reservedc0; /* 0x00c0 */ } __packed __aligned(8); /* Initialize Ultravisor */ @@ -307,6 +310,8 @@ struct uv_info { unsigned int max_num_sec_conf; unsigned short max_guest_cpu_id; unsigned long uv_feature_indications; + unsigned long supp_se_hdr_ver; + unsigned long supp_se_hdr_pcf; }; extern struct uv_info uv_info; diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index a5425075dd25..852840384e75 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -392,6 +392,24 @@ static ssize_t uv_query_facilities(struct kobject *kobj, static struct kobj_attribute uv_query_facilities_attr = __ATTR(facilities, 0444, uv_query_facilities, NULL); +static ssize_t uv_query_supp_se_hdr_ver(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%lx\n", uv_info.supp_se_hdr_ver); +} + +static struct kobj_attribute uv_query_supp_se_hdr_ver_attr = + __ATTR(supp_se_hdr_ver, 0444, uv_query_supp_se_hdr_ver, NULL); + +static ssize_t uv_query_supp_se_hdr_pcf(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%lx\n", uv_info.supp_se_hdr_pcf); +} + +static struct kobj_attribute uv_query_supp_se_hdr_pcf_attr = + __ATTR(supp_se_hdr_pcf, 0444, uv_query_supp_se_hdr_pcf, NULL); + static ssize_t uv_query_feature_indications(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -437,6 +455,8 @@ static struct attribute *uv_query_attrs[] = { &uv_query_max_guest_cpus_attr.attr, &uv_query_max_guest_vms_attr.attr, &uv_query_max_guest_addr_attr.attr, + &uv_query_supp_se_hdr_ver_attr.attr, + &uv_query_supp_se_hdr_pcf_attr.attr, NULL, }; From 38c218259d4c4a8c232c2b16a5598568b814d2df Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:20 +0000 Subject: [PATCH 0014/1436] s390/uv: Add dump fields to query The new dump feature requires us to know how much memory is needed for the "dump storage state" and "dump finalize" ultravisor call. These values are reported via the UV query call. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Reviewed-by: Steffen Eiden Link: https://lore.kernel.org/r/20220517163629.3443-3-frankja@linux.ibm.com Message-Id: <20220517163629.3443-3-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/boot/uv.c | 2 ++ arch/s390/include/asm/uv.h | 5 +++++ arch/s390/kernel/uv.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/arch/s390/boot/uv.c b/arch/s390/boot/uv.c index b100b57cf15d..67c737c1e580 100644 --- a/arch/s390/boot/uv.c +++ b/arch/s390/boot/uv.c @@ -43,6 +43,8 @@ void uv_query_info(void) uv_info.uv_feature_indications = uvcb.uv_feature_indications; uv_info.supp_se_hdr_ver = uvcb.supp_se_hdr_versions; uv_info.supp_se_hdr_pcf = uvcb.supp_se_hdr_pcf; + uv_info.conf_dump_storage_state_len = uvcb.conf_dump_storage_state_len; + uv_info.conf_dump_finalize_len = uvcb.conf_dump_finalize_len; } #ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index 46498b8c587b..e8257a293dd1 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -114,6 +114,9 @@ struct uv_cb_qui { u64 supp_se_hdr_versions; /* 0x00b0 */ u64 supp_se_hdr_pcf; /* 0x00b8 */ u64 reservedc0; /* 0x00c0 */ + u64 conf_dump_storage_state_len; /* 0x00c8 */ + u64 conf_dump_finalize_len; /* 0x00d0 */ + u8 reservedd8[256 - 216]; /* 0x00d8 */ } __packed __aligned(8); /* Initialize Ultravisor */ @@ -312,6 +315,8 @@ struct uv_info { unsigned long uv_feature_indications; unsigned long supp_se_hdr_ver; unsigned long supp_se_hdr_pcf; + unsigned long conf_dump_storage_state_len; + unsigned long conf_dump_finalize_len; }; extern struct uv_info uv_info; diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index 852840384e75..84fe33b6af4d 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -410,6 +410,36 @@ static ssize_t uv_query_supp_se_hdr_pcf(struct kobject *kobj, static struct kobj_attribute uv_query_supp_se_hdr_pcf_attr = __ATTR(supp_se_hdr_pcf, 0444, uv_query_supp_se_hdr_pcf, NULL); +static ssize_t uv_query_dump_cpu_len(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return scnprintf(page, PAGE_SIZE, "%lx\n", + uv_info.guest_cpu_stor_len); +} + +static struct kobj_attribute uv_query_dump_cpu_len_attr = + __ATTR(uv_query_dump_cpu_len, 0444, uv_query_dump_cpu_len, NULL); + +static ssize_t uv_query_dump_storage_state_len(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return scnprintf(page, PAGE_SIZE, "%lx\n", + uv_info.conf_dump_storage_state_len); +} + +static struct kobj_attribute uv_query_dump_storage_state_len_attr = + __ATTR(dump_storage_state_len, 0444, uv_query_dump_storage_state_len, NULL); + +static ssize_t uv_query_dump_finalize_len(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return scnprintf(page, PAGE_SIZE, "%lx\n", + uv_info.conf_dump_finalize_len); +} + +static struct kobj_attribute uv_query_dump_finalize_len_attr = + __ATTR(dump_finalize_len, 0444, uv_query_dump_finalize_len, NULL); + static ssize_t uv_query_feature_indications(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -457,6 +487,9 @@ static struct attribute *uv_query_attrs[] = { &uv_query_max_guest_addr_attr.attr, &uv_query_supp_se_hdr_ver_attr.attr, &uv_query_supp_se_hdr_pcf_attr.attr, + &uv_query_dump_storage_state_len_attr.attr, + &uv_query_dump_finalize_len_attr.attr, + &uv_query_dump_cpu_len_attr.attr, NULL, }; From 35d02493dba1ae6386fac07072908717affc3ff8 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:21 +0000 Subject: [PATCH 0015/1436] KVM: s390: pv: Add query interface Some of the query information is already available via sysfs but having a IOCTL makes the information easier to retrieve. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Reviewed-by: Steffen Eiden Link: https://lore.kernel.org/r/20220517163629.3443-4-frankja@linux.ibm.com Message-Id: <20220517163629.3443-4-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 76 ++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 25 +++++++++++++ 2 files changed, 101 insertions(+) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 76ad6408cb2c..5859f243d287 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2224,6 +2224,42 @@ static int kvm_s390_cpus_to_pv(struct kvm *kvm, u16 *rc, u16 *rrc) return r; } +/* + * Here we provide user space with a direct interface to query UV + * related data like UV maxima and available features as well as + * feature specific data. + * + * To facilitate future extension of the data structures we'll try to + * write data up to the maximum requested length. + */ +static ssize_t kvm_s390_handle_pv_info(struct kvm_s390_pv_info *info) +{ + ssize_t len_min; + + switch (info->header.id) { + case KVM_PV_INFO_VM: { + len_min = sizeof(info->header) + sizeof(info->vm); + + if (info->header.len_max < len_min) + return -EINVAL; + + memcpy(info->vm.inst_calls_list, + uv_info.inst_calls_list, + sizeof(uv_info.inst_calls_list)); + + /* It's max cpuid not max cpus, so it's off by one */ + info->vm.max_cpus = uv_info.max_guest_cpu_id + 1; + info->vm.max_guests = uv_info.max_num_sec_conf; + info->vm.max_guest_addr = uv_info.max_sec_stor_addr; + info->vm.feature_indication = uv_info.uv_feature_indications; + + return len_min; + } + default: + return -EINVAL; + } +} + static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) { int r = 0; @@ -2360,6 +2396,46 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) cmd->rc, cmd->rrc); break; } + case KVM_PV_INFO: { + struct kvm_s390_pv_info info = {}; + ssize_t data_len; + + /* + * No need to check the VM protection here. + * + * Maybe user space wants to query some of the data + * when the VM is still unprotected. If we see the + * need to fence a new data command we can still + * return an error in the info handler. + */ + + r = -EFAULT; + if (copy_from_user(&info, argp, sizeof(info.header))) + break; + + r = -EINVAL; + if (info.header.len_max < sizeof(info.header)) + break; + + data_len = kvm_s390_handle_pv_info(&info); + if (data_len < 0) { + r = data_len; + break; + } + /* + * If a data command struct is extended (multiple + * times) this can be used to determine how much of it + * is valid. + */ + info.header.len_written = data_len; + + r = -EFAULT; + if (copy_to_user(argp, &info, data_len)) + break; + + r = 0; + break; + } default: r = -ENOTTY; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 5088bd9f1922..5a5f66026dd3 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1660,6 +1660,30 @@ struct kvm_s390_pv_unp { __u64 tweak; }; +enum pv_cmd_info_id { + KVM_PV_INFO_VM, +}; + +struct kvm_s390_pv_info_vm { + __u64 inst_calls_list[4]; + __u64 max_cpus; + __u64 max_guests; + __u64 max_guest_addr; + __u64 feature_indication; +}; + +struct kvm_s390_pv_info_header { + __u32 id; + __u32 len_max; + __u32 len_written; + __u32 reserved; +}; + +struct kvm_s390_pv_info { + struct kvm_s390_pv_info_header header; + struct kvm_s390_pv_info_vm vm; +}; + enum pv_cmd_id { KVM_PV_ENABLE, KVM_PV_DISABLE, @@ -1668,6 +1692,7 @@ enum pv_cmd_id { KVM_PV_VERIFY, KVM_PV_PREP_RESET, KVM_PV_UNSHARE_ALL, + KVM_PV_INFO, }; struct kvm_pv_cmd { From 06eb3388e703d95de0dfeea657b2640fdda720db Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:22 +0000 Subject: [PATCH 0016/1436] KVM: s390: pv: Add dump support definitions Let's add the constants and structure definitions needed for the dump support. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Reviewed-by: Steffen Eiden Link: https://lore.kernel.org/r/20220517163629.3443-5-frankja@linux.ibm.com Message-Id: <20220517163629.3443-5-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/uv.h | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index e8257a293dd1..3e597bb634bd 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -50,6 +50,10 @@ #define UVC_CMD_SET_UNSHARE_ALL 0x0340 #define UVC_CMD_PIN_PAGE_SHARED 0x0341 #define UVC_CMD_UNPIN_PAGE_SHARED 0x0342 +#define UVC_CMD_DUMP_INIT 0x0400 +#define UVC_CMD_DUMP_CONF_STOR_STATE 0x0401 +#define UVC_CMD_DUMP_CPU 0x0402 +#define UVC_CMD_DUMP_COMPLETE 0x0403 #define UVC_CMD_SET_SHARED_ACCESS 0x1000 #define UVC_CMD_REMOVE_SHARED_ACCESS 0x1001 #define UVC_CMD_RETR_ATTEST 0x1020 @@ -77,6 +81,10 @@ enum uv_cmds_inst { BIT_UVC_CMD_UNSHARE_ALL = 20, BIT_UVC_CMD_PIN_PAGE_SHARED = 21, BIT_UVC_CMD_UNPIN_PAGE_SHARED = 22, + BIT_UVC_CMD_DUMP_INIT = 24, + BIT_UVC_CMD_DUMP_CONFIG_STOR_STATE = 25, + BIT_UVC_CMD_DUMP_CPU = 26, + BIT_UVC_CMD_DUMP_COMPLETE = 27, BIT_UVC_CMD_RETR_ATTEST = 28, }; @@ -246,6 +254,31 @@ struct uv_cb_attest { u64 reserved168[4]; /* 0x0168 */ } __packed __aligned(8); +struct uv_cb_dump_cpu { + struct uv_cb_header header; + u64 reserved08[2]; + u64 cpu_handle; + u64 dump_area_origin; + u64 reserved28[5]; +} __packed __aligned(8); + +struct uv_cb_dump_stor_state { + struct uv_cb_header header; + u64 reserved08[2]; + u64 config_handle; + u64 dump_area_origin; + u64 gaddr; + u64 reserved28[4]; +} __packed __aligned(8); + +struct uv_cb_dump_complete { + struct uv_cb_header header; + u64 reserved08[2]; + u64 config_handle; + u64 dump_area_origin; + u64 reserved30[5]; +} __packed __aligned(8); + static inline int __uv_call(unsigned long r1, unsigned long r2) { int cc; From fe9a93e07ba4f29def2f8a4318b63e0c70a5c6c2 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:23 +0000 Subject: [PATCH 0017/1436] KVM: s390: pv: Add query dump information The dump API requires userspace to provide buffers into which we will store data. The dump information added in this patch tells userspace how big those buffers need to be. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Reviewed-by: Steffen Eiden Link: https://lore.kernel.org/r/20220517163629.3443-6-frankja@linux.ibm.com Message-Id: <20220517163629.3443-6-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 11 +++++++++++ include/uapi/linux/kvm.h | 12 +++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 5859f243d287..de54f14e081e 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2255,6 +2255,17 @@ static ssize_t kvm_s390_handle_pv_info(struct kvm_s390_pv_info *info) return len_min; } + case KVM_PV_INFO_DUMP: { + len_min = sizeof(info->header) + sizeof(info->dump); + + if (info->header.len_max < len_min) + return -EINVAL; + + info->dump.dump_cpu_buffer_len = uv_info.guest_cpu_stor_len; + info->dump.dump_config_mem_buffer_per_1m = uv_info.conf_dump_storage_state_len; + info->dump.dump_config_finalize_len = uv_info.conf_dump_finalize_len; + return len_min; + } default: return -EINVAL; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 5a5f66026dd3..065a05ec06b6 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1662,6 +1662,13 @@ struct kvm_s390_pv_unp { enum pv_cmd_info_id { KVM_PV_INFO_VM, + KVM_PV_INFO_DUMP, +}; + +struct kvm_s390_pv_info_dump { + __u64 dump_cpu_buffer_len; + __u64 dump_config_mem_buffer_per_1m; + __u64 dump_config_finalize_len; }; struct kvm_s390_pv_info_vm { @@ -1681,7 +1688,10 @@ struct kvm_s390_pv_info_header { struct kvm_s390_pv_info { struct kvm_s390_pv_info_header header; - struct kvm_s390_pv_info_vm vm; + union { + struct kvm_s390_pv_info_dump dump; + struct kvm_s390_pv_info_vm vm; + }; }; enum pv_cmd_id { From 0460eb35b443f73f8a8e3be1ea87bd690a852e20 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:24 +0000 Subject: [PATCH 0018/1436] KVM: s390: Add configuration dump functionality Sometimes dumping inside of a VM fails, is unavailable or doesn't yield the required data. For these occasions we dump the VM from the outside, writing memory and cpu data to a file. Up to now PV guests only supported dumping from the inside of the guest through dumpers like KDUMP. A PV guest can be dumped from the hypervisor but the data will be stale and / or encrypted. To get the actual state of the PV VM we need the help of the Ultravisor who safeguards the VM state. New UV calls have been added to initialize the dump, dump storage state data, dump cpu data and complete the dump process. We expose these calls in this patch via a new UV ioctl command. The sensitive parts of the dump data are encrypted, the dump key is derived from the Customer Communication Key (CCK). This ensures that only the owner of the VM who has the CCK can decrypt the dump data. The memory is dumped / read via a normal export call and a re-import after the dump initialization is not needed (no re-encryption with a dump key). Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Link: https://lore.kernel.org/r/20220517163629.3443-7-frankja@linux.ibm.com Message-Id: <20220517163629.3443-7-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 1 + arch/s390/kvm/kvm-s390.c | 93 ++++++++++++++++ arch/s390/kvm/kvm-s390.h | 4 + arch/s390/kvm/pv.c | 182 +++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 15 +++ 5 files changed, 295 insertions(+) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 766028d54a3e..a0fbe4820e0a 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -923,6 +923,7 @@ struct kvm_s390_pv { u64 guest_len; unsigned long stor_base; void *stor_var; + bool dumping; }; struct kvm_arch{ diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index de54f14e081e..1d00aead6bc5 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2271,6 +2271,68 @@ static ssize_t kvm_s390_handle_pv_info(struct kvm_s390_pv_info *info) } } +static int kvm_s390_pv_dmp(struct kvm *kvm, struct kvm_pv_cmd *cmd, + struct kvm_s390_pv_dmp dmp) +{ + int r = -EINVAL; + void __user *result_buff = (void __user *)dmp.buff_addr; + + switch (dmp.subcmd) { + case KVM_PV_DUMP_INIT: { + if (kvm->arch.pv.dumping) + break; + + /* + * Block SIE entry as concurrent dump UVCs could lead + * to validities. + */ + kvm_s390_vcpu_block_all(kvm); + + r = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm), + UVC_CMD_DUMP_INIT, &cmd->rc, &cmd->rrc); + KVM_UV_EVENT(kvm, 3, "PROTVIRT DUMP INIT: rc %x rrc %x", + cmd->rc, cmd->rrc); + if (!r) { + kvm->arch.pv.dumping = true; + } else { + kvm_s390_vcpu_unblock_all(kvm); + r = -EINVAL; + } + break; + } + case KVM_PV_DUMP_CONFIG_STOR_STATE: { + if (!kvm->arch.pv.dumping) + break; + + /* + * gaddr is an output parameter since we might stop + * early. As dmp will be copied back in our caller, we + * don't need to do it ourselves. + */ + r = kvm_s390_pv_dump_stor_state(kvm, result_buff, &dmp.gaddr, dmp.buff_len, + &cmd->rc, &cmd->rrc); + break; + } + case KVM_PV_DUMP_COMPLETE: { + if (!kvm->arch.pv.dumping) + break; + + r = -EINVAL; + if (dmp.buff_len < uv_info.conf_dump_finalize_len) + break; + + r = kvm_s390_pv_dump_complete(kvm, result_buff, + &cmd->rc, &cmd->rrc); + break; + } + default: + r = -ENOTTY; + break; + } + + return r; +} + static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) { int r = 0; @@ -2447,6 +2509,28 @@ static int kvm_s390_handle_pv(struct kvm *kvm, struct kvm_pv_cmd *cmd) r = 0; break; } + case KVM_PV_DUMP: { + struct kvm_s390_pv_dmp dmp; + + r = -EINVAL; + if (!kvm_s390_pv_is_protected(kvm)) + break; + + r = -EFAULT; + if (copy_from_user(&dmp, argp, sizeof(dmp))) + break; + + r = kvm_s390_pv_dmp(kvm, cmd, dmp); + if (r) + break; + + if (copy_to_user(argp, &dmp, sizeof(dmp))) { + r = -EFAULT; + break; + } + + break; + } default: r = -ENOTTY; } @@ -4564,6 +4648,15 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) struct kvm_run *kvm_run = vcpu->run; int rc; + /* + * Running a VM while dumping always has the potential to + * produce inconsistent dump data. But for PV vcpus a SIE + * entry while dumping could also lead to a fatal validity + * intercept which we absolutely want to avoid. + */ + if (vcpu->kvm->arch.pv.dumping) + return -EINVAL; + if (kvm_run->immediate_exit) return -EINTR; diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 497d52a83c78..2c11eb5ba3ef 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -250,6 +250,10 @@ int kvm_s390_pv_set_sec_parms(struct kvm *kvm, void *hdr, u64 length, u16 *rc, int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size, unsigned long tweak, u16 *rc, u16 *rrc); int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state); +int kvm_s390_pv_dump_stor_state(struct kvm *kvm, void __user *buff_user, + u64 *gaddr, u64 buff_user_len, u16 *rc, u16 *rrc); +int kvm_s390_pv_dump_complete(struct kvm *kvm, void __user *buff_user, + u16 *rc, u16 *rrc); static inline u64 kvm_s390_pv_get_handle(struct kvm *kvm) { diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index cc7c9599f43e..e9912113879c 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -7,6 +7,7 @@ */ #include #include +#include #include #include #include @@ -298,3 +299,184 @@ int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state) return -EINVAL; return 0; } + +/* Size of the cache for the storage state dump data. 1MB for now */ +#define DUMP_BUFF_LEN HPAGE_SIZE + +/** + * kvm_s390_pv_dump_stor_state + * + * @kvm: pointer to the guest's KVM struct + * @buff_user: Userspace pointer where we will write the results to + * @gaddr: Starting absolute guest address for which the storage state + * is requested. + * @buff_user_len: Length of the buff_user buffer + * @rc: Pointer to where the uvcb return code is stored + * @rrc: Pointer to where the uvcb return reason code is stored + * + * Stores buff_len bytes of tweak component values to buff_user + * starting with the 1MB block specified by the absolute guest address + * (gaddr). The gaddr pointer will be updated with the last address + * for which data was written when returning to userspace. buff_user + * might be written to even if an error rc is returned. For instance + * if we encounter a fault after writing the first page of data. + * + * Context: kvm->lock needs to be held + * + * Return: + * 0 on success + * -ENOMEM if allocating the cache fails + * -EINVAL if gaddr is not aligned to 1MB + * -EINVAL if buff_user_len is not aligned to uv_info.conf_dump_storage_state_len + * -EINVAL if the UV call fails, rc and rrc will be set in this case + * -EFAULT if copying the result to buff_user failed + */ +int kvm_s390_pv_dump_stor_state(struct kvm *kvm, void __user *buff_user, + u64 *gaddr, u64 buff_user_len, u16 *rc, u16 *rrc) +{ + struct uv_cb_dump_stor_state uvcb = { + .header.cmd = UVC_CMD_DUMP_CONF_STOR_STATE, + .header.len = sizeof(uvcb), + .config_handle = kvm->arch.pv.handle, + .gaddr = *gaddr, + .dump_area_origin = 0, + }; + const u64 increment_len = uv_info.conf_dump_storage_state_len; + size_t buff_kvm_size; + size_t size_done = 0; + u8 *buff_kvm = NULL; + int cc, ret; + + ret = -EINVAL; + /* UV call processes 1MB guest storage chunks at a time */ + if (!IS_ALIGNED(*gaddr, HPAGE_SIZE)) + goto out; + + /* + * We provide the storage state for 1MB chunks of guest + * storage. The buffer will need to be aligned to + * conf_dump_storage_state_len so we don't end on a partial + * chunk. + */ + if (!buff_user_len || + !IS_ALIGNED(buff_user_len, increment_len)) + goto out; + + /* + * Allocate a buffer from which we will later copy to the user + * process. We don't want userspace to dictate our buffer size + * so we limit it to DUMP_BUFF_LEN. + */ + ret = -ENOMEM; + buff_kvm_size = min_t(u64, buff_user_len, DUMP_BUFF_LEN); + buff_kvm = vzalloc(buff_kvm_size); + if (!buff_kvm) + goto out; + + ret = 0; + uvcb.dump_area_origin = (u64)buff_kvm; + /* We will loop until the user buffer is filled or an error occurs */ + do { + /* Get 1MB worth of guest storage state data */ + cc = uv_call_sched(0, (u64)&uvcb); + + /* All or nothing */ + if (cc) { + ret = -EINVAL; + break; + } + + size_done += increment_len; + uvcb.dump_area_origin += increment_len; + buff_user_len -= increment_len; + uvcb.gaddr += HPAGE_SIZE; + + /* KVM Buffer full, time to copy to the process */ + if (!buff_user_len || size_done == DUMP_BUFF_LEN) { + if (copy_to_user(buff_user, buff_kvm, size_done)) { + ret = -EFAULT; + break; + } + + buff_user += size_done; + size_done = 0; + uvcb.dump_area_origin = (u64)buff_kvm; + } + } while (buff_user_len); + + /* Report back where we ended dumping */ + *gaddr = uvcb.gaddr; + + /* Lets only log errors, we don't want to spam */ +out: + if (ret) + KVM_UV_EVENT(kvm, 3, + "PROTVIRT DUMP STORAGE STATE: addr %llx ret %d, uvcb rc %x rrc %x", + uvcb.gaddr, ret, uvcb.header.rc, uvcb.header.rrc); + *rc = uvcb.header.rc; + *rrc = uvcb.header.rrc; + vfree(buff_kvm); + + return ret; +} + +/** + * kvm_s390_pv_dump_complete + * + * @kvm: pointer to the guest's KVM struct + * @buff_user: Userspace pointer where we will write the results to + * @rc: Pointer to where the uvcb return code is stored + * @rrc: Pointer to where the uvcb return reason code is stored + * + * Completes the dumping operation and writes the completion data to + * user space. + * + * Context: kvm->lock needs to be held + * + * Return: + * 0 on success + * -ENOMEM if allocating the completion buffer fails + * -EINVAL if the UV call fails, rc and rrc will be set in this case + * -EFAULT if copying the result to buff_user failed + */ +int kvm_s390_pv_dump_complete(struct kvm *kvm, void __user *buff_user, + u16 *rc, u16 *rrc) +{ + struct uv_cb_dump_complete complete = { + .header.len = sizeof(complete), + .header.cmd = UVC_CMD_DUMP_COMPLETE, + .config_handle = kvm_s390_pv_get_handle(kvm), + }; + u64 *compl_data; + int ret; + + /* Allocate dump area */ + compl_data = vzalloc(uv_info.conf_dump_finalize_len); + if (!compl_data) + return -ENOMEM; + complete.dump_area_origin = (u64)compl_data; + + ret = uv_call_sched(0, (u64)&complete); + *rc = complete.header.rc; + *rrc = complete.header.rrc; + KVM_UV_EVENT(kvm, 3, "PROTVIRT DUMP COMPLETE: rc %x rrc %x", + complete.header.rc, complete.header.rrc); + + if (!ret) { + /* + * kvm_s390_pv_dealloc_vm() will also (mem)set + * this to false on a reboot or other destroy + * operation for this vm. + */ + kvm->arch.pv.dumping = false; + kvm_s390_vcpu_unblock_all(kvm); + ret = copy_to_user(buff_user, compl_data, uv_info.conf_dump_finalize_len); + if (ret) + ret = -EFAULT; + } + vfree(compl_data); + /* If the UVC returned an error, translate it to -EINVAL */ + if (ret > 0) + ret = -EINVAL; + return ret; +} diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 065a05ec06b6..673be2061c6c 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1660,6 +1660,20 @@ struct kvm_s390_pv_unp { __u64 tweak; }; +enum pv_cmd_dmp_id { + KVM_PV_DUMP_INIT, + KVM_PV_DUMP_CONFIG_STOR_STATE, + KVM_PV_DUMP_COMPLETE, +}; + +struct kvm_s390_pv_dmp { + __u64 subcmd; + __u64 buff_addr; + __u64 buff_len; + __u64 gaddr; /* For dump storage state */ + __u64 reserved[4]; +}; + enum pv_cmd_info_id { KVM_PV_INFO_VM, KVM_PV_INFO_DUMP, @@ -1703,6 +1717,7 @@ enum pv_cmd_id { KVM_PV_PREP_RESET, KVM_PV_UNSHARE_ALL, KVM_PV_INFO, + KVM_PV_DUMP, }; struct kvm_pv_cmd { From 8aba09588d2af37c6cc1a781b87d1d91ebf389ae Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:25 +0000 Subject: [PATCH 0019/1436] KVM: s390: Add CPU dump functionality The previous patch introduced the per-VM dump functions now let's focus on dumping the VCPU state via the newly introduced KVM_S390_PV_CPU_COMMAND ioctl which mirrors the VM UV ioctl and can be extended with new commands later. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Link: https://lore.kernel.org/r/20220517163629.3443-8-frankja@linux.ibm.com Message-Id: <20220517163629.3443-8-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 69 ++++++++++++++++++++++++++++++++++++++++ arch/s390/kvm/kvm-s390.h | 1 + arch/s390/kvm/pv.c | 16 ++++++++++ include/uapi/linux/kvm.h | 4 +++ 4 files changed, 90 insertions(+) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 1d00aead6bc5..37be2a33edb5 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -5096,6 +5096,48 @@ long kvm_arch_vcpu_async_ioctl(struct file *filp, return -ENOIOCTLCMD; } +static int kvm_s390_handle_pv_vcpu_dump(struct kvm_vcpu *vcpu, + struct kvm_pv_cmd *cmd) +{ + struct kvm_s390_pv_dmp dmp; + void *data; + int ret; + + /* Dump initialization is a prerequisite */ + if (!vcpu->kvm->arch.pv.dumping) + return -EINVAL; + + if (copy_from_user(&dmp, (__u8 __user *)cmd->data, sizeof(dmp))) + return -EFAULT; + + /* We only handle this subcmd right now */ + if (dmp.subcmd != KVM_PV_DUMP_CPU) + return -EINVAL; + + /* CPU dump length is the same as create cpu storage donation. */ + if (dmp.buff_len != uv_info.guest_cpu_stor_len) + return -EINVAL; + + data = kvzalloc(uv_info.guest_cpu_stor_len, GFP_KERNEL); + if (!data) + return -ENOMEM; + + ret = kvm_s390_pv_dump_cpu(vcpu, data, &cmd->rc, &cmd->rrc); + + VCPU_EVENT(vcpu, 3, "PROTVIRT DUMP CPU %d rc %x rrc %x", + vcpu->vcpu_id, cmd->rc, cmd->rrc); + + if (ret) + ret = -EINVAL; + + /* On success copy over the dump data */ + if (!ret && copy_to_user((__u8 __user *)dmp.buff_addr, data, uv_info.guest_cpu_stor_len)) + ret = -EFAULT; + + kvfree(data); + return ret; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -5260,6 +5302,33 @@ long kvm_arch_vcpu_ioctl(struct file *filp, irq_state.len); break; } + case KVM_S390_PV_CPU_COMMAND: { + struct kvm_pv_cmd cmd; + + r = -EINVAL; + if (!is_prot_virt_host()) + break; + + r = -EFAULT; + if (copy_from_user(&cmd, argp, sizeof(cmd))) + break; + + r = -EINVAL; + if (cmd.flags) + break; + + /* We only handle this cmd right now */ + if (cmd.cmd != KVM_PV_DUMP) + break; + + r = kvm_s390_handle_pv_vcpu_dump(vcpu, &cmd); + + /* Always copy over UV rc / rrc data */ + if (copy_to_user((__u8 __user *)argp, &cmd.rc, + sizeof(cmd.rc) + sizeof(cmd.rrc))) + r = -EFAULT; + break; + } default: r = -ENOTTY; } diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 2c11eb5ba3ef..dd01d989816f 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -250,6 +250,7 @@ int kvm_s390_pv_set_sec_parms(struct kvm *kvm, void *hdr, u64 length, u16 *rc, int kvm_s390_pv_unpack(struct kvm *kvm, unsigned long addr, unsigned long size, unsigned long tweak, u16 *rc, u16 *rrc); int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state); +int kvm_s390_pv_dump_cpu(struct kvm_vcpu *vcpu, void *buff, u16 *rc, u16 *rrc); int kvm_s390_pv_dump_stor_state(struct kvm *kvm, void __user *buff_user, u64 *gaddr, u64 buff_user_len, u16 *rc, u16 *rrc); int kvm_s390_pv_dump_complete(struct kvm *kvm, void __user *buff_user, diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index e9912113879c..b4a499b10b67 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -300,6 +300,22 @@ int kvm_s390_pv_set_cpu_state(struct kvm_vcpu *vcpu, u8 state) return 0; } +int kvm_s390_pv_dump_cpu(struct kvm_vcpu *vcpu, void *buff, u16 *rc, u16 *rrc) +{ + struct uv_cb_dump_cpu uvcb = { + .header.cmd = UVC_CMD_DUMP_CPU, + .header.len = sizeof(uvcb), + .cpu_handle = vcpu->arch.pv.handle, + .dump_area_origin = (u64)buff, + }; + int cc; + + cc = uv_call_sched(0, (u64)&uvcb); + *rc = uvcb.header.rc; + *rrc = uvcb.header.rrc; + return cc; +} + /* Size of the cache for the storage state dump data. 1MB for now */ #define DUMP_BUFF_LEN HPAGE_SIZE diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 673be2061c6c..af5d254f8061 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1664,6 +1664,7 @@ enum pv_cmd_dmp_id { KVM_PV_DUMP_INIT, KVM_PV_DUMP_CONFIG_STOR_STATE, KVM_PV_DUMP_COMPLETE, + KVM_PV_DUMP_CPU, }; struct kvm_s390_pv_dmp { @@ -2168,4 +2169,7 @@ struct kvm_stats_desc { /* Available with KVM_CAP_XSAVE2 */ #define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) +/* Available with KVM_CAP_S390_PROTECTED_DUMP */ +#define KVM_S390_PV_CPU_COMMAND _IOWR(KVMIO, 0xd0, struct kvm_pv_cmd) + #endif /* __LINUX_KVM_H */ From e9bf3acb23f0a6e18438c35944d6cb618d16cf05 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:26 +0000 Subject: [PATCH 0020/1436] KVM: s390: Add KVM_CAP_S390_PROTECTED_DUMP The capability indicates dump support for protected VMs. Signed-off-by: Janosch Frank Reviewed-by: Claudio Imbrenda Link: https://lore.kernel.org/r/20220517163629.3443-9-frankja@linux.ibm.com Message-Id: <20220517163629.3443-9-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- arch/s390/kvm/kvm-s390.c | 20 ++++++++++++++++++++ include/uapi/linux/kvm.h | 1 + 2 files changed, 21 insertions(+) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 37be2a33edb5..d1a32eb3cf5d 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -606,6 +606,26 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_S390_PROTECTED: r = is_prot_virt_host(); break; + case KVM_CAP_S390_PROTECTED_DUMP: { + u64 pv_cmds_dump[] = { + BIT_UVC_CMD_DUMP_INIT, + BIT_UVC_CMD_DUMP_CONFIG_STOR_STATE, + BIT_UVC_CMD_DUMP_CPU, + BIT_UVC_CMD_DUMP_COMPLETE, + }; + int i; + + r = is_prot_virt_host(); + + for (i = 0; i < ARRAY_SIZE(pv_cmds_dump); i++) { + if (!test_bit_inv(pv_cmds_dump[i], + (unsigned long *)&uv_info.inst_calls_list)) { + r = 0; + break; + } + } + break; + } default: r = 0; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index af5d254f8061..c4a32910b88a 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1157,6 +1157,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_VM_TSC_CONTROL 214 #define KVM_CAP_SYSTEM_EVENT_DATA 215 #define KVM_CAP_ARM_SYSTEM_SUSPEND 216 +#define KVM_CAP_S390_PROTECTED_DUMP 217 #ifdef KVM_CAP_IRQ_ROUTING From 660a28653d839b70949087d2662e140cc511b363 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:27 +0000 Subject: [PATCH 0021/1436] Documentation: virt: Protected virtual machine dumps Let's add a documentation file which describes the dump process. Since we only copy the UV dump data from the UV to userspace we'll not go into detail here and let the party which processes the data describe its structure. Signed-off-by: Janosch Frank Acked-by: Claudio Imbrenda Link: https://lore.kernel.org/r/20220517163629.3443-10-frankja@linux.ibm.com Message-Id: <20220517163629.3443-10-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- Documentation/virt/kvm/s390/index.rst | 1 + Documentation/virt/kvm/s390/s390-pv-dump.rst | 64 ++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 Documentation/virt/kvm/s390/s390-pv-dump.rst diff --git a/Documentation/virt/kvm/s390/index.rst b/Documentation/virt/kvm/s390/index.rst index 605f488f0cc5..44ec9ab14b59 100644 --- a/Documentation/virt/kvm/s390/index.rst +++ b/Documentation/virt/kvm/s390/index.rst @@ -10,3 +10,4 @@ KVM for s390 systems s390-diag s390-pv s390-pv-boot + s390-pv-dump diff --git a/Documentation/virt/kvm/s390/s390-pv-dump.rst b/Documentation/virt/kvm/s390/s390-pv-dump.rst new file mode 100644 index 000000000000..e542f06048f3 --- /dev/null +++ b/Documentation/virt/kvm/s390/s390-pv-dump.rst @@ -0,0 +1,64 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=========================================== +s390 (IBM Z) Protected Virtualization dumps +=========================================== + +Summary +------- + +Dumping a VM is an essential tool for debugging problems inside +it. This is especially true when a protected VM runs into trouble as +there's no way to access its memory and registers from the outside +while it's running. + +However when dumping a protected VM we need to maintain its +confidentiality until the dump is in the hands of the VM owner who +should be the only one capable of analysing it. + +The confidentiality of the VM dump is ensured by the Ultravisor who +provides an interface to KVM over which encrypted CPU and memory data +can be requested. The encryption is based on the Customer +Communication Key which is the key that's used to encrypt VM data in a +way that the customer is able to decrypt. + + +Dump process +------------ + +A dump is done in 3 steps: + +**Initiation** + +This step initializes the dump process, generates cryptographic seeds +and extracts dump keys with which the VM dump data will be encrypted. + +**Data gathering** + +Currently there are two types of data that can be gathered from a VM: +the memory and the vcpu state. + +The vcpu state contains all the important registers, general, floating +point, vector, control and tod/timers of a vcpu. The vcpu dump can +contain incomplete data if a vcpu is dumped while an instruction is +emulated with help of the hypervisor. This is indicated by a flag bit +in the dump data. For the same reason it is very important to not only +write out the encrypted vcpu state, but also the unencrypted state +from the hypervisor. + +The memory state is further divided into the encrypted memory and its +metadata comprised of the encryption tweaks and status flags. The +encrypted memory can simply be read once it has been exported. The +time of the export does not matter as no re-encryption is +needed. Memory that has been swapped out and hence was exported can be +read from the swap and written to the dump target without need for any +special actions. + +The tweaks / status flags for the exported pages need to be requested +from the Ultravisor. + +**Finalization** + +The finalization step will provide the data needed to be able to +decrypt the vcpu and memory data and end the dump process. When this +step completes successfully a new dump initiation can be started. From 437cfd714db9c1d28878a6e2555e9a730f3490c8 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:28 +0000 Subject: [PATCH 0022/1436] Documentation/virt/kvm/api.rst: Add protvirt dump/info api descriptions Time to add the dump API changes to the api documentation file. Also some minor cleanup. Signed-off-by: Janosch Frank Acked-by: Claudio Imbrenda Link: https://lore.kernel.org/r/20220517163629.3443-11-frankja@linux.ibm.com Message-Id: <20220517163629.3443-11-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- Documentation/virt/kvm/api.rst | 154 ++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 28b547a9d96a..47d3064f5b79 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -5127,7 +5127,7 @@ into ESA mode. This reset is a superset of the initial reset. __u32 reserved[3]; }; -cmd values: +**cmd values:** KVM_PV_ENABLE Allocate memory and register the VM with the Ultravisor, thereby @@ -5143,7 +5143,6 @@ KVM_PV_ENABLE ===== ============================= KVM_PV_DISABLE - Deregister the VM from the Ultravisor and reclaim the memory that had been donated to the Ultravisor, making it usable by the kernel again. All registered VCPUs are converted back to non-protected @@ -5160,6 +5159,117 @@ KVM_PV_VM_VERIFY Verify the integrity of the unpacked image. Only if this succeeds, KVM is allowed to start protected VCPUs. +KVM_PV_INFO + :Capability: KVM_CAP_S390_PROTECTED_DUMP + + Presents an API that provides Ultravisor related data to userspace + via subcommands. len_max is the size of the user space buffer, + len_written is KVM's indication of how much bytes of that buffer + were actually written to. len_written can be used to determine the + valid fields if more response fields are added in the future. + + :: + + enum pv_cmd_info_id { + KVM_PV_INFO_VM, + KVM_PV_INFO_DUMP, + }; + + struct kvm_s390_pv_info_header { + __u32 id; + __u32 len_max; + __u32 len_written; + __u32 reserved; + }; + + struct kvm_s390_pv_info { + struct kvm_s390_pv_info_header header; + struct kvm_s390_pv_info_dump dump; + struct kvm_s390_pv_info_vm vm; + }; + +**subcommands:** + + KVM_PV_INFO_VM + This subcommand provides basic Ultravisor information for PV + hosts. These values are likely also exported as files in the sysfs + firmware UV query interface but they are more easily available to + programs in this API. + + The installed calls and feature_indication members provide the + installed UV calls and the UV's other feature indications. + + The max_* members provide information about the maximum number of PV + vcpus, PV guests and PV guest memory size. + + :: + + struct kvm_s390_pv_info_vm { + __u64 inst_calls_list[4]; + __u64 max_cpus; + __u64 max_guests; + __u64 max_guest_addr; + __u64 feature_indication; + }; + + + KVM_PV_INFO_DUMP + This subcommand provides information related to dumping PV guests. + + :: + + struct kvm_s390_pv_info_dump { + __u64 dump_cpu_buffer_len; + __u64 dump_config_mem_buffer_per_1m; + __u64 dump_config_finalize_len; + }; + +KVM_PV_DUMP + :Capability: KVM_CAP_S390_PROTECTED_DUMP + + Presents an API that provides calls which facilitate dumping a + protected VM. + + :: + + struct kvm_s390_pv_dmp { + __u64 subcmd; + __u64 buff_addr; + __u64 buff_len; + __u64 gaddr; /* For dump storage state */ + }; + + **subcommands:** + + KVM_PV_DUMP_INIT + Initializes the dump process of a protected VM. If this call does + not succeed all other subcommands will fail with -EINVAL. This + subcommand will return -EINVAL if a dump process has not yet been + completed. + + Not all PV vms can be dumped, the owner needs to set `dump + allowed` PCF bit 34 in the SE header to allow dumping. + + KVM_PV_DUMP_CONFIG_STOR_STATE + Stores `buff_len` bytes of tweak component values starting with + the 1MB block specified by the absolute guest address + (`gaddr`). `buff_len` needs to be `conf_dump_storage_state_len` + aligned and at least >= the `conf_dump_storage_state_len` value + provided by the dump uv_info data. buff_user might be written to + even if an error rc is returned. For instance if we encounter a + fault after writing the first page of data. + + KVM_PV_DUMP_COMPLETE + If the subcommand succeeds it completes the dump process and lets + KVM_PV_DUMP_INIT be called again. + + On success `conf_dump_finalize_len` bytes of completion data will be + stored to the `buff_addr`. The completion data contains a key + derivation seed, IV, tweak nonce and encryption keys as well as an + authentication tag all of which are needed to decrypt the dump at a + later time. + + 4.126 KVM_X86_SET_MSR_FILTER ---------------------------- @@ -5802,6 +5912,32 @@ of CPUID leaf 0xD on the host. This ioctl injects an event channel interrupt directly to the guest vCPU. +4.136 KVM_S390_PV_CPU_COMMAND +----------------------------- + +:Capability: KVM_CAP_S390_PROTECTED_DUMP +:Architectures: s390 +:Type: vcpu ioctl +:Parameters: none +:Returns: 0 on success, < 0 on error + +This ioctl closely mirrors `KVM_S390_PV_COMMAND` but handles requests +for vcpus. It re-uses the kvm_s390_pv_dmp struct and hence also shares +the command ids. + +**command:** + +KVM_PV_DUMP + Presents an API that provides calls which facilitate dumping a vcpu + of a protected VM. + +**subcommand:** + +KVM_PV_DUMP_CPU + Provides encrypted dump data like register values. + The length of the returned data is provided by uv_info.guest_cpu_stor_len. + + 5. The kvm_run structure ======================== @@ -7954,6 +8090,20 @@ should adjust CPUID leaf 0xA to reflect that the PMU is disabled. When enabled, KVM will exit to userspace with KVM_EXIT_SYSTEM_EVENT of type KVM_SYSTEM_EVENT_SUSPEND to process the guest suspend request. +8.37 KVM_CAP_S390_PROTECTED_DUMP +-------------------------------- + +:Capability: KVM_CAP_S390_PROTECTED_DUMP +:Architectures: s390 +:Type: vm + +This capability indicates that KVM and the Ultravisor support dumping +PV guests. The `KVM_PV_DUMP` command is available for the +`KVM_S390_PV_COMMAND` ioctl and the `KVM_PV_INFO` command provides +dump related UV data. Also the vcpu ioctl `KVM_S390_PV_CPU_COMMAND` is +available and supports the `KVM_PV_DUMP_CPU` subcommand. + + 9. Known KVM API problems ========================= From b0f46280d3fcd59a65cfae9742fa5172362af893 Mon Sep 17 00:00:00 2001 From: Janosch Frank Date: Tue, 17 May 2022 16:36:29 +0000 Subject: [PATCH 0023/1436] Documentation/virt/kvm/api.rst: Explain rc/rrc delivery Let's explain in which situations the rc/rrc will set in struct kvm_pv_cmd so it's clear that the struct members should be set to 0. rc/rrc are independent of the IOCTL return code. Signed-off-by: Janosch Frank Acked-by: Claudio Imbrenda Link: https://lore.kernel.org/r/20220517163629.3443-12-frankja@linux.ibm.com Message-Id: <20220517163629.3443-12-frankja@linux.ibm.com> Signed-off-by: Christian Borntraeger --- Documentation/virt/kvm/api.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 47d3064f5b79..0dd6d23c32ee 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -5127,6 +5127,14 @@ into ESA mode. This reset is a superset of the initial reset. __u32 reserved[3]; }; +**Ultravisor return codes** +The Ultravisor return (reason) codes are provided by the kernel if a +Ultravisor call has been executed to achieve the results expected by +the command. Therefore they are independent of the IOCTL return +code. If KVM changes `rc`, its value will always be greater than 0 +hence setting it to 0 before issuing a PV command is advised to be +able to detect a change of `rc`. + **cmd values:** KVM_PV_ENABLE From 97da92c0ff92f33a7c33533e5fdd3e870f01cc6a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 31 May 2022 12:15:51 +0200 Subject: [PATCH 0024/1436] KVM: s390: selftests: Use TAP interface in the memop test The memop test currently does not have any output (unless one of the TEST_ASSERT statement fails), so it's hard to say for a user whether a certain new sub-test has been included in the binary or not. Let's make this a little bit more user-friendly and include some TAP output via the kselftests.h interface. Reviewed-by: Janosch Frank Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20220531101554.36844-2-thuth@redhat.com Signed-off-by: Christian Borntraeger --- tools/testing/selftests/kvm/s390x/memop.c | 97 ++++++++++++++++++----- 1 file changed, 78 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c index 49f26f544127..e704c6fa5758 100644 --- a/tools/testing/selftests/kvm/s390x/memop.c +++ b/tools/testing/selftests/kvm/s390x/memop.c @@ -14,6 +14,7 @@ #include "test_util.h" #include "kvm_util.h" +#include "kselftest.h" enum mop_target { LOGICAL, @@ -691,34 +692,92 @@ static void test_errors(void) kvm_vm_free(t.kvm_vm); } +struct testdef { + const char *name; + void (*test)(void); + int extension; +} testlist[] = { + { + .name = "simple copy", + .test = test_copy, + }, + { + .name = "generic error checks", + .test = test_errors, + }, + { + .name = "copy with storage keys", + .test = test_copy_key, + .extension = 1, + }, + { + .name = "copy with key storage protection override", + .test = test_copy_key_storage_prot_override, + .extension = 1, + }, + { + .name = "copy with key fetch protection", + .test = test_copy_key_fetch_prot, + .extension = 1, + }, + { + .name = "copy with key fetch protection override", + .test = test_copy_key_fetch_prot_override, + .extension = 1, + }, + { + .name = "error checks with key", + .test = test_errors_key, + .extension = 1, + }, + { + .name = "termination", + .test = test_termination, + .extension = 1, + }, + { + .name = "error checks with key storage protection override", + .test = test_errors_key_storage_prot_override, + .extension = 1, + }, + { + .name = "error checks without key fetch prot override", + .test = test_errors_key_fetch_prot_override_not_enabled, + .extension = 1, + }, + { + .name = "error checks with key fetch prot override", + .test = test_errors_key_fetch_prot_override_enabled, + .extension = 1, + }, +}; + int main(int argc, char *argv[]) { - int memop_cap, extension_cap; + int memop_cap, extension_cap, idx; setbuf(stdout, NULL); /* Tell stdout not to buffer its content */ + ksft_print_header(); + memop_cap = kvm_check_cap(KVM_CAP_S390_MEM_OP); extension_cap = kvm_check_cap(KVM_CAP_S390_MEM_OP_EXTENSION); if (!memop_cap) { - print_skip("CAP_S390_MEM_OP not supported"); - exit(KSFT_SKIP); + ksft_exit_skip("CAP_S390_MEM_OP not supported.\n"); } - test_copy(); - if (extension_cap > 0) { - test_copy_key(); - test_copy_key_storage_prot_override(); - test_copy_key_fetch_prot(); - test_copy_key_fetch_prot_override(); - test_errors_key(); - test_termination(); - test_errors_key_storage_prot_override(); - test_errors_key_fetch_prot_override_not_enabled(); - test_errors_key_fetch_prot_override_enabled(); - } else { - print_skip("storage key memop extension not supported"); - } - test_errors(); + ksft_set_plan(ARRAY_SIZE(testlist)); - return 0; + for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) { + if (testlist[idx].extension >= extension_cap) { + testlist[idx].test(); + ksft_test_result_pass("%s\n", testlist[idx].name); + } else { + ksft_test_result_skip("%s - extension level %d not supported\n", + testlist[idx].name, + testlist[idx].extension); + } + } + + ksft_finished(); /* Print results and exit() accordingly */ } From 17e48d8a1ef0ab070b11e7368e14ac45c335de57 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 31 May 2022 12:15:52 +0200 Subject: [PATCH 0025/1436] KVM: s390: selftests: Use TAP interface in the sync_regs test The sync_regs test currently does not have any output (unless one of the TEST_ASSERT statement fails), so it's hard to say for a user whether a certain new sub-test has been included in the binary or not. Let's make this a little bit more user-friendly and include some TAP output via the kselftests.h interface. To be able to distinguish the different sub-tests more easily, we also break up the huge main() function here in more fine grained parts. Acked-by: Janosch Frank Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20220531101554.36844-3-thuth@redhat.com Signed-off-by: Christian Borntraeger --- .../selftests/kvm/s390x/sync_regs_test.c | 87 ++++++++++++++----- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/tools/testing/selftests/kvm/s390x/sync_regs_test.c b/tools/testing/selftests/kvm/s390x/sync_regs_test.c index caf7b8859a94..9510739e226d 100644 --- a/tools/testing/selftests/kvm/s390x/sync_regs_test.c +++ b/tools/testing/selftests/kvm/s390x/sync_regs_test.c @@ -21,6 +21,7 @@ #include "test_util.h" #include "kvm_util.h" #include "diag318_test_handler.h" +#include "kselftest.h" #define VCPU_ID 5 @@ -74,27 +75,9 @@ static void compare_sregs(struct kvm_sregs *left, struct kvm_sync_regs *right) #define TEST_SYNC_FIELDS (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS|KVM_SYNC_DIAG318) #define INVALID_SYNC_FIELD 0x80000000 -int main(int argc, char *argv[]) +void test_read_invalid(struct kvm_vm *vm, struct kvm_run *run) { - struct kvm_vm *vm; - struct kvm_run *run; - struct kvm_regs regs; - struct kvm_sregs sregs; - int rv, cap; - - /* Tell stdout not to buffer its content */ - setbuf(stdout, NULL); - - cap = kvm_check_cap(KVM_CAP_SYNC_REGS); - if (!cap) { - print_skip("CAP_SYNC_REGS not supported"); - exit(KSFT_SKIP); - } - - /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); - - run = vcpu_state(vm, VCPU_ID); + int rv; /* Request reading invalid register set from VCPU. */ run->kvm_valid_regs = INVALID_SYNC_FIELD; @@ -110,6 +93,11 @@ int main(int argc, char *argv[]) "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", rv); vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0; +} + +void test_set_invalid(struct kvm_vm *vm, struct kvm_run *run) +{ + int rv; /* Request setting invalid register set into VCPU. */ run->kvm_dirty_regs = INVALID_SYNC_FIELD; @@ -125,6 +113,13 @@ int main(int argc, char *argv[]) "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", rv); vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0; +} + +void test_req_and_verify_all_valid_regs(struct kvm_vm *vm, struct kvm_run *run) +{ + struct kvm_sregs sregs; + struct kvm_regs regs; + int rv; /* Request and verify all valid register sets. */ run->kvm_valid_regs = TEST_SYNC_FIELDS; @@ -146,6 +141,13 @@ int main(int argc, char *argv[]) vcpu_sregs_get(vm, VCPU_ID, &sregs); compare_sregs(&sregs, &run->s.regs); +} + +void test_set_and_verify_various_reg_values(struct kvm_vm *vm, struct kvm_run *run) +{ + struct kvm_sregs sregs; + struct kvm_regs regs; + int rv; /* Set and verify various register values */ run->s.regs.gprs[11] = 0xBAD1DEA; @@ -180,6 +182,11 @@ int main(int argc, char *argv[]) vcpu_sregs_get(vm, VCPU_ID, &sregs); compare_sregs(&sregs, &run->s.regs); +} + +void test_clear_kvm_dirty_regs_bits(struct kvm_vm *vm, struct kvm_run *run) +{ + int rv; /* Clear kvm_dirty_regs bits, verify new s.regs values are * overwritten with existing guest values. @@ -200,8 +207,46 @@ int main(int argc, char *argv[]) TEST_ASSERT(run->s.regs.diag318 != 0x4B1D, "diag318 sync regs value incorrect 0x%llx.", run->s.regs.diag318); +} + +struct testdef { + const char *name; + void (*test)(struct kvm_vm *vm, struct kvm_run *run); +} testlist[] = { + { "read invalid", test_read_invalid }, + { "set invalid", test_set_invalid }, + { "request+verify all valid regs", test_req_and_verify_all_valid_regs }, + { "set+verify various regs", test_set_and_verify_various_reg_values }, + { "clear kvm_dirty_regs bits", test_clear_kvm_dirty_regs_bits }, +}; + +int main(int argc, char *argv[]) +{ + static struct kvm_run *run; + static struct kvm_vm *vm; + int idx; + + /* Tell stdout not to buffer its content */ + setbuf(stdout, NULL); + + ksft_print_header(); + + if (!kvm_check_cap(KVM_CAP_SYNC_REGS)) + ksft_exit_skip("CAP_SYNC_REGS not supported"); + + ksft_set_plan(ARRAY_SIZE(testlist)); + + /* Create VM */ + vm = vm_create_default(VCPU_ID, 0, guest_code); + + run = vcpu_state(vm, VCPU_ID); + + for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) { + testlist[idx].test(vm, run); + ksft_test_result_pass("%s\n", testlist[idx].name); + } kvm_vm_free(vm); - return 0; + ksft_finished(); /* Print results and exit() accordingly */ } From 0c073227df5055714a545cbe536e3bd9ea39c74b Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 31 May 2022 12:15:53 +0200 Subject: [PATCH 0026/1436] KVM: s390: selftests: Use TAP interface in the tprot test The tprot test currently does not have any output (unless one of the TEST_ASSERT statement fails), so it's hard to say for a user whether a certain new sub-test has been included in the binary or not. Let's make this a little bit more user-friendly and include some TAP output via the kselftests.h interface. Reviewed-by: Janosch Frank Reviewed-by: Janis Schoetterl-Glausch Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20220531101554.36844-4-thuth@redhat.com Signed-off-by: Christian Borntraeger --- tools/testing/selftests/kvm/s390x/tprot.c | 29 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/s390x/tprot.c b/tools/testing/selftests/kvm/s390x/tprot.c index c097b9db495e..14d74a9e7b3d 100644 --- a/tools/testing/selftests/kvm/s390x/tprot.c +++ b/tools/testing/selftests/kvm/s390x/tprot.c @@ -8,6 +8,7 @@ #include #include "test_util.h" #include "kvm_util.h" +#include "kselftest.h" #define PAGE_SHIFT 12 #define PAGE_SIZE (1 << PAGE_SHIFT) @@ -63,12 +64,12 @@ static enum permission test_protection(void *addr, uint8_t key) } enum stage { - STAGE_END, STAGE_INIT_SIMPLE, TEST_SIMPLE, STAGE_INIT_FETCH_PROT_OVERRIDE, TEST_FETCH_PROT_OVERRIDE, TEST_STORAGE_PROT_OVERRIDE, + STAGE_END /* must be the last entry (it's the amount of tests) */ }; struct test { @@ -182,7 +183,7 @@ static void guest_code(void) GUEST_SYNC(perform_next_stage(&i, mapped_0)); } -#define HOST_SYNC(vmp, stage) \ +#define HOST_SYNC_NO_TAP(vmp, stage) \ ({ \ struct kvm_vm *__vm = (vmp); \ struct ucall uc; \ @@ -198,12 +199,21 @@ static void guest_code(void) ASSERT_EQ(uc.args[1], __stage); \ }) +#define HOST_SYNC(vmp, stage) \ +({ \ + HOST_SYNC_NO_TAP(vmp, stage); \ + ksft_test_result_pass("" #stage "\n"); \ +}) + int main(int argc, char *argv[]) { struct kvm_vm *vm; struct kvm_run *run; vm_vaddr_t guest_0_page; + ksft_print_header(); + ksft_set_plan(STAGE_END); + vm = vm_create_default(VCPU_ID, 0, guest_code); run = vcpu_state(vm, VCPU_ID); @@ -212,9 +222,14 @@ int main(int argc, char *argv[]) HOST_SYNC(vm, TEST_SIMPLE); guest_0_page = vm_vaddr_alloc(vm, PAGE_SIZE, 0); - if (guest_0_page != 0) - print_skip("Did not allocate page at 0 for fetch protection override tests"); - HOST_SYNC(vm, STAGE_INIT_FETCH_PROT_OVERRIDE); + if (guest_0_page != 0) { + /* Use NO_TAP so we don't get a PASS print */ + HOST_SYNC_NO_TAP(vm, STAGE_INIT_FETCH_PROT_OVERRIDE); + ksft_test_result_skip("STAGE_INIT_FETCH_PROT_OVERRIDE - " + "Did not allocate page at 0\n"); + } else { + HOST_SYNC(vm, STAGE_INIT_FETCH_PROT_OVERRIDE); + } if (guest_0_page == 0) mprotect(addr_gva2hva(vm, (vm_vaddr_t)0), PAGE_SIZE, PROT_READ); run->s.regs.crs[0] |= CR0_FETCH_PROTECTION_OVERRIDE; @@ -224,4 +239,8 @@ int main(int argc, char *argv[]) run->s.regs.crs[0] |= CR0_STORAGE_PROTECTION_OVERRIDE; run->kvm_dirty_regs = KVM_SYNC_CRS; HOST_SYNC(vm, TEST_STORAGE_PROT_OVERRIDE); + + kvm_vm_free(vm); + + ksft_finished(); /* Print results and exit() accordingly */ } From b1edf7f159a6d532757b004a70f31a6425d5043f Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 31 May 2022 12:15:54 +0200 Subject: [PATCH 0027/1436] KVM: s390: selftests: Use TAP interface in the reset test Let's standardize the s390x KVM selftest output to the TAP output generated via the kselftests.h interface. Reviewed-by: Janosch Frank Signed-off-by: Thomas Huth Link: https://lore.kernel.org/r/20220531101554.36844-5-thuth@redhat.com Signed-off-by: Christian Borntraeger --- tools/testing/selftests/kvm/s390x/resets.c | 38 +++++++++++++++++----- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/s390x/resets.c b/tools/testing/selftests/kvm/s390x/resets.c index b143db6d8693..889449a22e7a 100644 --- a/tools/testing/selftests/kvm/s390x/resets.c +++ b/tools/testing/selftests/kvm/s390x/resets.c @@ -12,6 +12,7 @@ #include "test_util.h" #include "kvm_util.h" +#include "kselftest.h" #define VCPU_ID 3 #define LOCAL_IRQS 32 @@ -202,7 +203,7 @@ static void inject_irq(int cpu_id) static void test_normal(void) { - pr_info("Testing normal reset\n"); + ksft_print_msg("Testing normal reset\n"); /* Create VM */ vm = vm_create_default(VCPU_ID, 0, guest_code_initial); run = vcpu_state(vm, VCPU_ID); @@ -225,7 +226,7 @@ static void test_normal(void) static void test_initial(void) { - pr_info("Testing initial reset\n"); + ksft_print_msg("Testing initial reset\n"); vm = vm_create_default(VCPU_ID, 0, guest_code_initial); run = vcpu_state(vm, VCPU_ID); sync_regs = &run->s.regs; @@ -247,7 +248,7 @@ static void test_initial(void) static void test_clear(void) { - pr_info("Testing clear reset\n"); + ksft_print_msg("Testing clear reset\n"); vm = vm_create_default(VCPU_ID, 0, guest_code_initial); run = vcpu_state(vm, VCPU_ID); sync_regs = &run->s.regs; @@ -266,14 +267,35 @@ static void test_clear(void) kvm_vm_free(vm); } +struct testdef { + const char *name; + void (*test)(void); + bool needs_cap; +} testlist[] = { + { "initial", test_initial, false }, + { "normal", test_normal, true }, + { "clear", test_clear, true }, +}; + int main(int argc, char *argv[]) { + bool has_s390_vcpu_resets = kvm_check_cap(KVM_CAP_S390_VCPU_RESETS); + int idx; + setbuf(stdout, NULL); /* Tell stdout not to buffer its content */ - test_initial(); - if (kvm_check_cap(KVM_CAP_S390_VCPU_RESETS)) { - test_normal(); - test_clear(); + ksft_print_header(); + ksft_set_plan(ARRAY_SIZE(testlist)); + + for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) { + if (!testlist[idx].needs_cap || has_s390_vcpu_resets) { + testlist[idx].test(); + ksft_test_result_pass("%s\n", testlist[idx].name); + } else { + ksft_test_result_skip("%s - no VCPU_RESETS capability\n", + testlist[idx].name); + } } - return 0; + + ksft_finished(); /* Print results and exit() accordingly */ } From db681eaf7145158fb49eddbdb548692e8bfe7fab Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 18 May 2022 17:18:11 +0800 Subject: [PATCH 0028/1436] platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_prepare_tx() cros_ec_prepare_tx() is used to fill the protocol headers according to the requested protocol version. Add Kunit tests cros_ec_prepare_tx() for each version. Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220518091814.2028579-2-tzungbi@kernel.org --- drivers/platform/chrome/Kconfig | 9 + drivers/platform/chrome/Makefile | 3 + drivers/platform/chrome/cros_ec_proto_test.c | 173 +++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 drivers/platform/chrome/cros_ec_proto_test.c diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 717299cbccac..4b3d2427e8dd 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -267,4 +267,13 @@ config CHROMEOS_PRIVACY_SCREEN source "drivers/platform/chrome/wilco_ec/Kconfig" +# Kunit test cases +config CROS_EC_PROTO_KUNIT_TEST + tristate "Kunit tests for ChromeOS EC protocol" if !KUNIT_ALL_TESTS + depends on KUNIT && CROS_EC + default KUNIT_ALL_TESTS + select CROS_EC_PROTO + help + Kunit tests for the ChromeOS Embedded Controller protocol. + endif # CHROMEOS_PLATFORMS diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 52f5a2dde8b8..3c380066c6b6 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -30,3 +30,6 @@ obj-$(CONFIG_CROS_USBPD_LOGGER) += cros_usbpd_logger.o obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o obj-$(CONFIG_WILCO_EC) += wilco_ec/ + +# Kunit test cases +obj-$(CONFIG_CROS_EC_PROTO_KUNIT_TEST) += cros_ec_proto_test.o diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c new file mode 100644 index 000000000000..61abb18ac00b --- /dev/null +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Kunit tests for ChromeOS Embedded Controller protocol. + */ + +#include + +#include +#include + +#include "cros_ec.h" + +#define BUFSIZE 512 + +struct cros_ec_proto_test_priv { + struct cros_ec_device ec_dev; + u8 dout[BUFSIZE]; + u8 din[BUFSIZE]; + struct cros_ec_command *msg; + u8 _msg[BUFSIZE]; +}; + +static void cros_ec_proto_test_prepare_tx_legacy_normal(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct cros_ec_command *msg = priv->msg; + int ret, i; + u8 csum; + + ec_dev->proto_version = 2; + + msg->command = EC_CMD_HELLO; + msg->outsize = EC_PROTO2_MAX_PARAM_SIZE; + msg->data[0] = 0xde; + msg->data[1] = 0xad; + msg->data[2] = 0xbe; + msg->data[3] = 0xef; + + ret = cros_ec_prepare_tx(ec_dev, msg); + + KUNIT_EXPECT_EQ(test, ret, EC_MSG_TX_PROTO_BYTES + EC_PROTO2_MAX_PARAM_SIZE); + KUNIT_EXPECT_EQ(test, ec_dev->dout[0], EC_CMD_VERSION0); + KUNIT_EXPECT_EQ(test, ec_dev->dout[1], EC_CMD_HELLO); + KUNIT_EXPECT_EQ(test, ec_dev->dout[2], EC_PROTO2_MAX_PARAM_SIZE); + KUNIT_EXPECT_EQ(test, EC_MSG_TX_HEADER_BYTES, 3); + KUNIT_EXPECT_EQ(test, ec_dev->dout[EC_MSG_TX_HEADER_BYTES + 0], 0xde); + KUNIT_EXPECT_EQ(test, ec_dev->dout[EC_MSG_TX_HEADER_BYTES + 1], 0xad); + KUNIT_EXPECT_EQ(test, ec_dev->dout[EC_MSG_TX_HEADER_BYTES + 2], 0xbe); + KUNIT_EXPECT_EQ(test, ec_dev->dout[EC_MSG_TX_HEADER_BYTES + 3], 0xef); + for (i = 4; i < EC_PROTO2_MAX_PARAM_SIZE; ++i) + KUNIT_EXPECT_EQ(test, ec_dev->dout[EC_MSG_TX_HEADER_BYTES + i], 0); + + csum = EC_CMD_VERSION0; + csum += EC_CMD_HELLO; + csum += EC_PROTO2_MAX_PARAM_SIZE; + csum += 0xde; + csum += 0xad; + csum += 0xbe; + csum += 0xef; + KUNIT_EXPECT_EQ(test, + ec_dev->dout[EC_MSG_TX_HEADER_BYTES + EC_PROTO2_MAX_PARAM_SIZE], + csum); +} + +static void cros_ec_proto_test_prepare_tx_legacy_bad_msg_outsize(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct cros_ec_command *msg = priv->msg; + int ret; + + ec_dev->proto_version = 2; + + msg->outsize = EC_PROTO2_MAX_PARAM_SIZE + 1; + + ret = cros_ec_prepare_tx(ec_dev, msg); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); +} + +static void cros_ec_proto_test_prepare_tx_normal(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct cros_ec_command *msg = priv->msg; + struct ec_host_request *request = (struct ec_host_request *)ec_dev->dout; + int ret, i; + u8 csum; + + msg->command = EC_CMD_HELLO; + msg->outsize = 0x88; + msg->data[0] = 0xde; + msg->data[1] = 0xad; + msg->data[2] = 0xbe; + msg->data[3] = 0xef; + + ret = cros_ec_prepare_tx(ec_dev, msg); + + KUNIT_EXPECT_EQ(test, ret, sizeof(*request) + 0x88); + + KUNIT_EXPECT_EQ(test, request->struct_version, EC_HOST_REQUEST_VERSION); + KUNIT_EXPECT_EQ(test, request->command, EC_CMD_HELLO); + KUNIT_EXPECT_EQ(test, request->command_version, 0); + KUNIT_EXPECT_EQ(test, request->data_len, 0x88); + KUNIT_EXPECT_EQ(test, ec_dev->dout[sizeof(*request) + 0], 0xde); + KUNIT_EXPECT_EQ(test, ec_dev->dout[sizeof(*request) + 1], 0xad); + KUNIT_EXPECT_EQ(test, ec_dev->dout[sizeof(*request) + 2], 0xbe); + KUNIT_EXPECT_EQ(test, ec_dev->dout[sizeof(*request) + 3], 0xef); + for (i = 4; i < 0x88; ++i) + KUNIT_EXPECT_EQ(test, ec_dev->dout[sizeof(*request) + i], 0); + + csum = EC_HOST_REQUEST_VERSION; + csum += EC_CMD_HELLO; + csum += 0x88; + csum += 0xde; + csum += 0xad; + csum += 0xbe; + csum += 0xef; + KUNIT_EXPECT_EQ(test, request->checksum, (u8)-csum); +} + +static void cros_ec_proto_test_prepare_tx_bad_msg_outsize(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct cros_ec_command *msg = priv->msg; + int ret; + + msg->outsize = ec_dev->dout_size - sizeof(struct ec_host_request) + 1; + + ret = cros_ec_prepare_tx(ec_dev, msg); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); +} + +static int cros_ec_proto_test_init(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv; + struct cros_ec_device *ec_dev; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + test->priv = priv; + + ec_dev = &priv->ec_dev; + ec_dev->dout = (u8 *)priv->dout; + ec_dev->dout_size = ARRAY_SIZE(priv->dout); + ec_dev->din = (u8 *)priv->din; + ec_dev->din_size = ARRAY_SIZE(priv->din); + ec_dev->proto_version = EC_HOST_REQUEST_VERSION; + + priv->msg = (struct cros_ec_command *)priv->_msg; + + return 0; +} + +static struct kunit_case cros_ec_proto_test_cases[] = { + KUNIT_CASE(cros_ec_proto_test_prepare_tx_legacy_normal), + KUNIT_CASE(cros_ec_proto_test_prepare_tx_legacy_bad_msg_outsize), + KUNIT_CASE(cros_ec_proto_test_prepare_tx_normal), + KUNIT_CASE(cros_ec_proto_test_prepare_tx_bad_msg_outsize), + {} +}; + +static struct kunit_suite cros_ec_proto_test_suite = { + .name = "cros_ec_proto_test", + .init = cros_ec_proto_test_init, + .test_cases = cros_ec_proto_test_cases, +}; + +kunit_test_suite(cros_ec_proto_test_suite); + +MODULE_LICENSE("GPL"); From 23a34e3a9d00829f6bed67004a751d5b48f6084a Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 18 May 2022 17:18:12 +0800 Subject: [PATCH 0029/1436] platform/chrome: cros_ec_proto: factor legacy out from cros_ec_prepare_tx() cros_ec_prepare_tx() mixed the code for both versions. To be neat and to make it clear, factor the legacy part out as a separate function, rename the function, and update the comments. Specifically, - prepare_tx(), for current protocol version (i.e. 3). - prepare_tx_legacy(), for protocol version <= 2. Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220518091814.2028579-3-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 51 ++++++++++++++----------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index ff767dccdf0f..01ab58b3269b 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -52,8 +52,8 @@ static int cros_ec_map_error(uint32_t result) return ret; } -static int prepare_packet(struct cros_ec_device *ec_dev, - struct cros_ec_command *msg) +static int prepare_tx(struct cros_ec_device *ec_dev, + struct cros_ec_command *msg) { struct ec_host_request *request; u8 *out; @@ -85,6 +85,28 @@ static int prepare_packet(struct cros_ec_device *ec_dev, return sizeof(*request) + msg->outsize; } +static int prepare_tx_legacy(struct cros_ec_device *ec_dev, + struct cros_ec_command *msg) +{ + u8 *out; + u8 csum; + int i; + + if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE) + return -EINVAL; + + out = ec_dev->dout; + out[0] = EC_CMD_VERSION0 + msg->version; + out[1] = msg->command; + out[2] = msg->outsize; + csum = out[0] + out[1] + out[2]; + for (i = 0; i < msg->outsize; i++) + csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i]; + out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = csum; + + return EC_MSG_TX_PROTO_BYTES + msg->outsize; +} + static int send_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) { @@ -161,35 +183,18 @@ static int send_command(struct cros_ec_device *ec_dev, * @ec_dev: Device to register. * @msg: Message to write. * - * This is intended to be used by all ChromeOS EC drivers, but at present - * only SPI uses it. Once LPC uses the same protocol it can start using it. - * I2C could use it now, with a refactor of the existing code. + * This is used by all ChromeOS EC drivers to prepare the outgoing message + * according to different protocol versions. * * Return: number of prepared bytes on success or negative error code. */ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) { - u8 *out; - u8 csum; - int i; - if (ec_dev->proto_version > 2) - return prepare_packet(ec_dev, msg); + return prepare_tx(ec_dev, msg); - if (msg->outsize > EC_PROTO2_MAX_PARAM_SIZE) - return -EINVAL; - - out = ec_dev->dout; - out[0] = EC_CMD_VERSION0 + msg->version; - out[1] = msg->command; - out[2] = msg->outsize; - csum = out[0] + out[1] + out[2]; - for (i = 0; i < msg->outsize; i++) - csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->data[i]; - out[EC_MSG_TX_HEADER_BYTES + msg->outsize] = csum; - - return EC_MSG_TX_PROTO_BYTES + msg->outsize; + return prepare_tx_legacy(ec_dev, msg); } EXPORT_SYMBOL(cros_ec_prepare_tx); From 97b11dd6350a1d5fb076df69ebbf504eb5c4fd57 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 18 May 2022 17:18:13 +0800 Subject: [PATCH 0030/1436] platform/chrome: cros_ec_proto: update cros_ec_check_result() comment At first glance, cros_ec_check_result() is quite like cros_ec_map_error(). They check for `ec_msg->result` and return corresponding errors. However, as calling from `pkt_xfer` and `cmd_xfer`, cros_ec_check_result() should not report furthermore errors. -EAGAIN is the only exception. See [1][2][3] for some known userland programs' code. The return code from ioctl only denotes the EC communication status. Userland programs would further analyze the `result` in struct cros_ec_command* for follow-up actions (e.g. [4]). To clarify, update the function comment. [1]: https://crrev.com/54400e93a75ef440a83d6eaac2cec066daf99cf0/util/comm-dev.c#154 [2]: https://crrev.com/fe32670a89bf59e1aff84bba9dd3295657b85e9b/cros_ec_dev.c#296 [3]: https://crrev.com/4e19eb1d89de0422ff1bbd3f7260b131c761098c/drivers/google/cros_ec_dev.c#120 [4]: https://crrev.com/54400e93a75ef440a83d6eaac2cec066daf99cf0/util/comm-dev.c#164 Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220518091814.2028579-4-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 01ab58b3269b..13ced9d2dd71 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -204,9 +204,12 @@ EXPORT_SYMBOL(cros_ec_prepare_tx); * @msg: Message to check. * * This is used by ChromeOS EC drivers to check the ec_msg->result for - * errors and to warn about them. + * EC_RES_IN_PROGRESS and to warn about them. * - * Return: 0 on success or negative error code. + * The function should not check for furthermore error codes. Otherwise, + * it would break the ABI. + * + * Return: -EAGAIN if ec_msg->result == EC_RES_IN_PROGRESS. Otherwise, 0. */ int cros_ec_check_result(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) From 4319cbd4ed99003e0c981728ab1626c25be7af4a Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 18 May 2022 17:18:14 +0800 Subject: [PATCH 0031/1436] platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_check_result() cros_ec_check_result() is used to check if the EC communication success but EC responded EC_RES_IN_PROGRESS. It should return 0 even if EC wasn't happy about the host command. Add Kunit tests for cros_ec_check_result(). Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220518091814.2028579-5-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 41 ++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 61abb18ac00b..25c4fca5c165 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -132,6 +132,46 @@ static void cros_ec_proto_test_prepare_tx_bad_msg_outsize(struct kunit *test) KUNIT_EXPECT_EQ(test, ret, -EINVAL); } +static void cros_ec_proto_test_check_result(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct cros_ec_command *msg = priv->msg; + int ret, i; + static enum ec_status status[] = { + EC_RES_SUCCESS, + EC_RES_INVALID_COMMAND, + EC_RES_ERROR, + EC_RES_INVALID_PARAM, + EC_RES_ACCESS_DENIED, + EC_RES_INVALID_RESPONSE, + EC_RES_INVALID_VERSION, + EC_RES_INVALID_CHECKSUM, + EC_RES_UNAVAILABLE, + EC_RES_TIMEOUT, + EC_RES_OVERFLOW, + EC_RES_INVALID_HEADER, + EC_RES_REQUEST_TRUNCATED, + EC_RES_RESPONSE_TOO_BIG, + EC_RES_BUS_ERROR, + EC_RES_BUSY, + EC_RES_INVALID_HEADER_VERSION, + EC_RES_INVALID_HEADER_CRC, + EC_RES_INVALID_DATA_CRC, + EC_RES_DUP_UNAVAILABLE, + }; + + for (i = 0; i < ARRAY_SIZE(status); ++i) { + msg->result = status[i]; + ret = cros_ec_check_result(ec_dev, msg); + KUNIT_EXPECT_EQ(test, ret, 0); + } + + msg->result = EC_RES_IN_PROGRESS; + ret = cros_ec_check_result(ec_dev, msg); + KUNIT_EXPECT_EQ(test, ret, -EAGAIN); +} + static int cros_ec_proto_test_init(struct kunit *test) { struct cros_ec_proto_test_priv *priv; @@ -159,6 +199,7 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_prepare_tx_legacy_bad_msg_outsize), KUNIT_CASE(cros_ec_proto_test_prepare_tx_normal), KUNIT_CASE(cros_ec_proto_test_prepare_tx_bad_msg_outsize), + KUNIT_CASE(cros_ec_proto_test_check_result), {} }; From 8d5976089c97a4beeeda4de59e2fba9862946893 Mon Sep 17 00:00:00 2001 From: Xiang wangx Date: Mon, 6 Jun 2022 10:23:13 +0800 Subject: [PATCH 0032/1436] platform/chrome: cros_ec_commands: Fix syntax errors in comments Delete the redundant word 'using'. Signed-off-by: Xiang wangx Reviewed-by: Tzung-Bi Shih Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220606022313.22912-1-wangxiang@cdjrlc.com --- include/linux/platform_data/cros_ec_commands.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 8cfa8cfca77e..e59f51c41a1c 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -787,7 +787,7 @@ struct ec_host_response { * * Packets always start with a request or response header. They are followed * by data_len bytes of data. If the data_crc_present flag is set, the data - * bytes are followed by a CRC-8 of that data, using using x^8 + x^2 + x + 1 + * bytes are followed by a CRC-8 of that data, using x^8 + x^2 + x + 1 * polynomial. * * Host algorithm when sending a request q: From f0b9246952860f986c8501199e3b08575f91882e Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 May 2022 13:11:20 +0200 Subject: [PATCH 0033/1436] staging: qlge: fix typo in comment Spelling mistake (triple letters) in comment. Detected with the help of Coccinelle. Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20220521111145.81697-70-Julia.Lawall@inria.fr Signed-off-by: Greg Kroah-Hartman --- drivers/staging/qlge/qlge_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c index 113a3efd12e9..8c35d4c4b851 100644 --- a/drivers/staging/qlge/qlge_main.c +++ b/drivers/staging/qlge/qlge_main.c @@ -1976,7 +1976,7 @@ static unsigned long qlge_process_mac_rx_intr(struct qlge_adapter *qdev, vlan_id); } else { /* Non-TCP/UDP large frames that span multiple buffers - * can be processed corrrectly by the split frame logic. + * can be processed correctly by the split frame logic. */ qlge_process_mac_split_rx_intr(qdev, rx_ring, ib_mac_rsp, vlan_id); From dcda884deb9cb1ca72e795e8c590ac05a8a02ea1 Mon Sep 17 00:00:00 2001 From: Phillip Potter Date: Fri, 20 May 2022 23:09:53 +0100 Subject: [PATCH 0034/1436] staging: r8188eu: convert pr_info_once call in core/rtw_fw.c Convert pr_info_once call in core/rtw_fw.c to a dev_info_once call, as ultimately, this results in the printing of the driver name anyway (r8188eu) which is equally clear and removes the need for the "R8188EU: " part of the format string. Suggested-by: Pavel Skripkin Signed-off-by: Phillip Potter Link: https://lore.kernel.org/r/20220520220953.11840-1-phil@philpotter.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_fw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_fw.c b/drivers/staging/r8188eu/core/rtw_fw.c index 0451e5177644..87dc0e97652a 100644 --- a/drivers/staging/r8188eu/core/rtw_fw.c +++ b/drivers/staging/r8188eu/core/rtw_fw.c @@ -259,9 +259,9 @@ int rtl8188e_firmware_download(struct adapter *padapter) fwhdr = (struct rt_firmware_hdr *)dvobj->firmware.data; if (IS_FW_HEADER_EXIST(fwhdr)) { - pr_info_once("R8188EU: Firmware Version %d, SubVersion %d, Signature 0x%x\n", - le16_to_cpu(fwhdr->version), fwhdr->subversion, - le16_to_cpu(fwhdr->signature)); + dev_info_once(device, "Firmware Version %d, SubVersion %d, Signature 0x%x\n", + le16_to_cpu(fwhdr->version), fwhdr->subversion, + le16_to_cpu(fwhdr->signature)); fw_data = fw_data + sizeof(struct rt_firmware_hdr); fw_size = fw_size - sizeof(struct rt_firmware_hdr); From 21c752ce5df20125af8f1f097f8bd6e237c9bdd7 Mon Sep 17 00:00:00 2001 From: Srivathsan Sivakumar Date: Wed, 25 May 2022 02:05:44 -0400 Subject: [PATCH 0035/1436] staging: rts5208: spi.c: fix codestyle error in dynamic debug code reduce number of spaces in dev_dbg() code format the commit and changelog more clearly Signed-off-by: Srivathsan Sivakumar Link: https://lore.kernel.org/r/Yo3HOPPKnWHez7ES@Sassy Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rts5208/spi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/rts5208/spi.c b/drivers/staging/rts5208/spi.c index f1e9e80044ed..e88fe1a998f8 100644 --- a/drivers/staging/rts5208/spi.c +++ b/drivers/staging/rts5208/spi.c @@ -460,10 +460,8 @@ int spi_set_parameter(struct scsi_cmnd *srb, struct rtsx_chip *chip) spi->clk_div = ((u16)(srb->cmnd[4]) << 8) | srb->cmnd[5]; spi->write_en = srb->cmnd[6]; - dev_dbg(rtsx_dev(chip), "%s: ", __func__); - dev_dbg(rtsx_dev(chip), "spi_clock = %d, ", spi->spi_clock); - dev_dbg(rtsx_dev(chip), "clk_div = %d, ", spi->clk_div); - dev_dbg(rtsx_dev(chip), "write_en = %d\n", spi->write_en); + dev_dbg(rtsx_dev(chip), "spi_clock = %d, clk_div = %d, write_en = %d\n", + spi->spi_clock, spi->clk_div, spi->write_en); return STATUS_SUCCESS; } From 864a821c787ba7594cc4df7a01be03dc56637cdb Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Sat, 28 May 2022 00:53:50 +0200 Subject: [PATCH 0036/1436] staging: sm750fb: fix camelCase function name Change camelCase function name sii164GetVendorID to sii164_get_vendor_id as suggested by checkpatch.pl Signed-off-by: Nam Cao Link: https://lore.kernel.org/r/20220527225350.GA220436@nam-dell Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_dvi.c | 2 +- drivers/staging/sm750fb/ddk750_sii164.c | 6 +++--- drivers/staging/sm750fb/ddk750_sii164.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/sm750fb/ddk750_dvi.c b/drivers/staging/sm750fb/ddk750_dvi.c index 029d9acec47d..e0c7ff3352bf 100644 --- a/drivers/staging/sm750fb/ddk750_dvi.c +++ b/drivers/staging/sm750fb/ddk750_dvi.c @@ -15,7 +15,7 @@ static struct dvi_ctrl_device dcft_supported_dvi_controller[] = { #ifdef DVI_CTRL_SII164 { .init = sii164InitChip, - .get_vendor_id = sii164GetVendorID, + .get_vendor_id = sii164_get_vendor_id, .get_device_id = sii164GetDeviceID, #ifdef SII164_FULL_FUNCTIONS .reset_chip = sii164ResetChip, diff --git a/drivers/staging/sm750fb/ddk750_sii164.c b/drivers/staging/sm750fb/ddk750_sii164.c index 73e0e9f41ec5..3da1796cd7aa 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.c +++ b/drivers/staging/sm750fb/ddk750_sii164.c @@ -29,13 +29,13 @@ static char *gDviCtrlChipName = "Silicon Image SiI 164"; #endif /* - * sii164GetVendorID + * sii164_get_vendor_id * This function gets the vendor ID of the DVI controller chip. * * Output: * Vendor ID */ -unsigned short sii164GetVendorID(void) +unsigned short sii164_get_vendor_id(void) { unsigned short vendorID; @@ -140,7 +140,7 @@ long sii164InitChip(unsigned char edge_select, #endif /* Check if SII164 Chip exists */ - if ((sii164GetVendorID() == SII164_VENDOR_ID) && + if ((sii164_get_vendor_id() == SII164_VENDOR_ID) && (sii164GetDeviceID() == SII164_DEVICE_ID)) { /* * Initialize SII164 controller chip. diff --git a/drivers/staging/sm750fb/ddk750_sii164.h b/drivers/staging/sm750fb/ddk750_sii164.h index d940cb729066..ca330f6a43e2 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.h +++ b/drivers/staging/sm750fb/ddk750_sii164.h @@ -27,7 +27,7 @@ long sii164InitChip(unsigned char edgeSelect, unsigned char pllFilterEnable, unsigned char pllFilterValue); -unsigned short sii164GetVendorID(void); +unsigned short sii164_get_vendor_id(void); unsigned short sii164GetDeviceID(void); #ifdef SII164_FULL_FUNCTIONS From 2e07715abac4f47e32723041e766d9053fe74b17 Mon Sep 17 00:00:00 2001 From: Uri Arev Date: Mon, 23 May 2022 21:22:26 +0300 Subject: [PATCH 0037/1436] staging: greybus: Fix indentation in fw-management.c Reported by Checkpatch: CHECK: Alignment should match open parenthesis Signed-off-by: Uri Arev Link: https://lore.kernel.org/r/20220523182226.405159-1-me@wantyapps.xyz Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/fw-management.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/greybus/fw-management.c b/drivers/staging/greybus/fw-management.c index 687c6405c65b..3342b84597da 100644 --- a/drivers/staging/greybus/fw-management.c +++ b/drivers/staging/greybus/fw-management.c @@ -102,7 +102,7 @@ unlock: } static int fw_mgmt_interface_fw_version_operation(struct fw_mgmt *fw_mgmt, - struct fw_mgmt_ioc_get_intf_version *fw_info) + struct fw_mgmt_ioc_get_intf_version *fw_info) { struct gb_connection *connection = fw_mgmt->connection; struct gb_fw_mgmt_interface_fw_version_response response; @@ -240,7 +240,7 @@ static int fw_mgmt_interface_fw_loaded_operation(struct gb_operation *op) } static int fw_mgmt_backend_fw_version_operation(struct fw_mgmt *fw_mgmt, - struct fw_mgmt_ioc_get_backend_version *fw_info) + struct fw_mgmt_ioc_get_backend_version *fw_info) { struct gb_connection *connection = fw_mgmt->connection; struct gb_fw_mgmt_backend_fw_version_request request; @@ -473,7 +473,7 @@ static int fw_mgmt_ioctl(struct fw_mgmt *fw_mgmt, unsigned int cmd, return -EFAULT; ret = fw_mgmt_backend_fw_update_operation(fw_mgmt, - backend_update.firmware_tag); + backend_update.firmware_tag); if (ret) return ret; From 4cb07b36c8e295b1163de79410c188c12d4917bd Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:48:43 +0200 Subject: [PATCH 0038/1436] staging: vt6655: Replace MACvSetCurrBCNLength with VNSvOutPortW Replace macro MACvSetCurrBCNLength with VNSvOutPortW and as it was the only user, it can now be removed. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/8ff556c84b3a4a70e8151965bcf6357e1de61bd1.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.h | 5 ----- drivers/staging/vt6655/rxtx.c | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 57ae3bdbdb2d..23ebae99e0ae 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -570,11 +570,6 @@ do { \ VNSvOutPortD(iobase + MAC_REG_BCNDMAPTR, \ dwCurrDescAddr) -/* set the chip with current BCN length */ -#define MACvSetCurrBCNLength(iobase, wCurrBCNLength) \ - VNSvOutPortW(iobase + MAC_REG_BCNDMACTL + 2, \ - wCurrBCNLength) - #define MACvWriteBSSIDAddress(iobase, pbyEtherAddr) \ do { \ iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 71cbfa607d96..54b0556f500f 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1422,7 +1422,7 @@ static int vnt_beacon_xmit(struct vnt_private *priv, MACvSetCurrBCNTxDescAddr(priv->port_offset, priv->tx_beacon_dma); - MACvSetCurrBCNLength(priv->port_offset, priv->wBCNBufLen); + VNSvOutPortW(priv->port_offset + MAC_REG_BCNDMACTL + 2, priv->wBCNBufLen); /* Set auto Transmit on */ MACvRegBitsOn(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); /* Poll Transmit the adapter */ From 33028eea5cf34036ee038448ef4278cf48cb0322 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:48:49 +0200 Subject: [PATCH 0039/1436] staging: vt6655: Replace VNSvOutPortW with iowrite16 Replace macro VNSvOutPortW with iowrite16 because it replaces just one line. The name of macro and the arguments use CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/ded437e27cffb040865d4afe47e447c2d0d6f0b8.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/card.c | 29 ++++++++++------------------ drivers/staging/vt6655/device_main.c | 3 +-- drivers/staging/vt6655/mac.h | 4 ++-- drivers/staging/vt6655/power.c | 4 ++-- drivers/staging/vt6655/rf.c | 2 +- drivers/staging/vt6655/rxtx.c | 2 +- drivers/staging/vt6655/upc.h | 3 --- 7 files changed, 17 insertions(+), 30 deletions(-) diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 2cde0082fc03..72043a29b543 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -326,7 +326,7 @@ bool CARDbSetBeaconPeriod(struct vnt_private *priv, qwNextTBTT = CARDqGetNextTBTT(qwNextTBTT, wBeaconInterval); /* set HW beacon interval */ - VNSvOutPortW(priv->port_offset + MAC_REG_BI, wBeaconInterval); + iowrite16(wBeaconInterval, priv->port_offset + MAC_REG_BI); priv->wBeaconInterval = wBeaconInterval; /* Set NextTBTT */ VNSvOutPortD(priv->port_offset + MAC_REG_NEXTTBTT, (u32)qwNextTBTT); @@ -587,68 +587,59 @@ void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type) bb_type, &byTxRate, &byRsvTime); - VNSvOutPortW(priv->port_offset + MAC_REG_RSPINF_A_6, - MAKEWORD(byTxRate, byRsvTime)); + iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_6); /* RSPINF_a_9 */ s_vCalculateOFDMRParameter(RATE_9M, bb_type, &byTxRate, &byRsvTime); - VNSvOutPortW(priv->port_offset + MAC_REG_RSPINF_A_9, - MAKEWORD(byTxRate, byRsvTime)); + iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_9); /* RSPINF_a_12 */ s_vCalculateOFDMRParameter(RATE_12M, bb_type, &byTxRate, &byRsvTime); - VNSvOutPortW(priv->port_offset + MAC_REG_RSPINF_A_12, - MAKEWORD(byTxRate, byRsvTime)); + iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_12); /* RSPINF_a_18 */ s_vCalculateOFDMRParameter(RATE_18M, bb_type, &byTxRate, &byRsvTime); - VNSvOutPortW(priv->port_offset + MAC_REG_RSPINF_A_18, - MAKEWORD(byTxRate, byRsvTime)); + iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_18); /* RSPINF_a_24 */ s_vCalculateOFDMRParameter(RATE_24M, bb_type, &byTxRate, &byRsvTime); - VNSvOutPortW(priv->port_offset + MAC_REG_RSPINF_A_24, - MAKEWORD(byTxRate, byRsvTime)); + iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_24); /* RSPINF_a_36 */ s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)priv, RATE_36M), bb_type, &byTxRate, &byRsvTime); - VNSvOutPortW(priv->port_offset + MAC_REG_RSPINF_A_36, - MAKEWORD(byTxRate, byRsvTime)); + iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_36); /* RSPINF_a_48 */ s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)priv, RATE_48M), bb_type, &byTxRate, &byRsvTime); - VNSvOutPortW(priv->port_offset + MAC_REG_RSPINF_A_48, - MAKEWORD(byTxRate, byRsvTime)); + iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_48); /* RSPINF_a_54 */ s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)priv, RATE_54M), bb_type, &byTxRate, &byRsvTime); - VNSvOutPortW(priv->port_offset + MAC_REG_RSPINF_A_54, - MAKEWORD(byTxRate, byRsvTime)); + iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_54); /* RSPINF_a_72 */ s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)priv, RATE_54M), bb_type, &byTxRate, &byRsvTime); - VNSvOutPortW(priv->port_offset + MAC_REG_RSPINF_A_72, - MAKEWORD(byTxRate, byRsvTime)); + iowrite16(MAKEWORD(byTxRate, byRsvTime), priv->port_offset + MAC_REG_RSPINF_A_72); /* Set to Page0 */ MACvSelectPage0(priv->port_offset); diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index afaf331fe125..5f28d9ea4232 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1060,8 +1060,7 @@ static void vnt_interrupt_process(struct vnt_private *priv) if (isr & ISR_FETALERR) { pr_debug(" ISR_FETALERR\n"); iowrite8(0, priv->port_offset + MAC_REG_SOFTPWRCTL); - VNSvOutPortW(priv->port_offset + - MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPECTI); + iowrite16(SOFTPWRCTL_SWPECTI, priv->port_offset + MAC_REG_SOFTPWRCTL); device_error(priv, isr); } diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 23ebae99e0ae..ebadf527a911 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -548,7 +548,7 @@ do { \ do { \ unsigned short wData; \ wData = ioread16(iobase + byRegOfs); \ - VNSvOutPortW(iobase + byRegOfs, wData | (wBits)); \ + iowrite16(wData | (wBits), iobase + byRegOfs); \ } while (0) #define MACvRegBitsOff(iobase, byRegOfs, byBits) \ @@ -562,7 +562,7 @@ do { \ do { \ unsigned short wData; \ wData = ioread16(iobase + byRegOfs); \ - VNSvOutPortW(iobase + byRegOfs, wData & ~(wBits)); \ + iowrite16(wData & ~(wBits), iobase + byRegOfs); \ } while (0) /* set the chip with current BCN tx descriptor address */ diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c index 06066fa56dd5..0bd2ddc61648 100644 --- a/drivers/staging/vt6655/power.c +++ b/drivers/staging/vt6655/power.c @@ -52,10 +52,10 @@ void PSvEnablePowerSaving(struct vnt_private *priv, u16 wAID = priv->current_aid | BIT(14) | BIT(15); /* set period of power up before TBTT */ - VNSvOutPortW(priv->port_offset + MAC_REG_PWBT, C_PWBT); + iowrite16(C_PWBT, priv->port_offset + MAC_REG_PWBT); if (priv->op_mode != NL80211_IFTYPE_ADHOC) { /* set AID */ - VNSvOutPortW(priv->port_offset + MAC_REG_AIDATIM, wAID); + iowrite16(wAID, priv->port_offset + MAC_REG_AIDATIM); } /* Set AutoSleep */ diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c index ee5e2e0d9a8c..ff6f654df2d2 100644 --- a/drivers/staging/vt6655/rf.c +++ b/drivers/staging/vt6655/rf.c @@ -350,7 +350,7 @@ bool rf_write_wake_prog_syn(struct vnt_private *priv, unsigned char rf_type, unsigned char sleep_count = 0; unsigned short idx = MISCFIFO_SYNDATA_IDX; - VNSvOutPortW(iobase + MAC_REG_MISCFFNDEX, 0); + iowrite16(0, iobase + MAC_REG_MISCFFNDEX); switch (rf_type) { case RF_AIROHA: case RF_AL2230S: diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 54b0556f500f..390b27b02562 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1422,7 +1422,7 @@ static int vnt_beacon_xmit(struct vnt_private *priv, MACvSetCurrBCNTxDescAddr(priv->port_offset, priv->tx_beacon_dma); - VNSvOutPortW(priv->port_offset + MAC_REG_BCNDMACTL + 2, priv->wBCNBufLen); + iowrite16(priv->wBCNBufLen, priv->port_offset + MAC_REG_BCNDMACTL + 2); /* Set auto Transmit on */ MACvRegBitsOn(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); /* Poll Transmit the adapter */ diff --git a/drivers/staging/vt6655/upc.h b/drivers/staging/vt6655/upc.h index 2a47f5782b71..0f2f7df00b3a 100644 --- a/drivers/staging/vt6655/upc.h +++ b/drivers/staging/vt6655/upc.h @@ -20,9 +20,6 @@ /* For memory mapped IO */ -#define VNSvOutPortW(dwIOAddress, wData) \ - iowrite16((u16)(wData), dwIOAddress) - #define VNSvOutPortD(dwIOAddress, dwData) \ iowrite32((u32)(dwData), dwIOAddress) From 0fd13e6b1acee1c42569e70f93444b0c5fd7a348 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:48:55 +0200 Subject: [PATCH 0040/1436] staging: vt6655: Replace MACvWriteISR with VNSvOutPortD Replace macro MACvWriteISR with VNSvOutPortD and as it was the only user, it can now be removed. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/80cd68a83807209230a898ab0260188adfad4158.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 2 +- drivers/staging/vt6655/mac.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 5f28d9ea4232..41bc87d80ad8 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1055,7 +1055,7 @@ static void vnt_interrupt_process(struct vnt_private *priv) * update ISR counter */ while (isr && priv->vif) { - MACvWriteISR(priv->port_offset, isr); + VNSvOutPortD(priv->port_offset + MAC_REG_ISR, isr); if (isr & ISR_FETALERR) { pr_debug(" ISR_FETALERR\n"); diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index ebadf527a911..42b216897218 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -648,9 +648,6 @@ do { \ iowrite8(byOrgValue, iobase + MAC_REG_STICKHW); \ } while (0) -#define MACvWriteISR(iobase, dwValue) \ - VNSvOutPortD(iobase + MAC_REG_ISR, dwValue) - #define MACvIntEnable(iobase, dwMask) \ VNSvOutPortD(iobase + MAC_REG_IMR, dwMask) From 159ed04755489cf9d43ee361899f736418c4c340 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:49:00 +0200 Subject: [PATCH 0041/1436] staging: vt6655: Replace MACvIntEnable with VNSvOutPortD Replace macro MACvIntEnable with VNSvOutPortD and as it was only used twice, it can now be removed. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/182b9f8edd1ce3f6ff12a2942e990dae0f80099a.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 6 +++--- drivers/staging/vt6655/mac.h | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 41bc87d80ad8..d9515eff05c3 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1134,7 +1134,7 @@ static void vnt_interrupt_work(struct work_struct *work) if (priv->vif) vnt_interrupt_process(priv); - MACvIntEnable(priv->port_offset, IMR_MASK_VALUE); + VNSvOutPortD(priv->port_offset + MAC_REG_IMR, IMR_MASK_VALUE); } static irqreturn_t vnt_interrupt(int irq, void *arg) @@ -1252,8 +1252,8 @@ static int vnt_start(struct ieee80211_hw *hw) device_init_registers(priv); - dev_dbg(&priv->pcid->dev, "call MACvIntEnable\n"); - MACvIntEnable(priv->port_offset, IMR_MASK_VALUE); + dev_dbg(&priv->pcid->dev, "enable MAC interrupt\n"); + VNSvOutPortD(priv->port_offset + MAC_REG_IMR, IMR_MASK_VALUE); ieee80211_wake_queues(hw); diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 42b216897218..8b3ba94dd02e 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -648,9 +648,6 @@ do { \ iowrite8(byOrgValue, iobase + MAC_REG_STICKHW); \ } while (0) -#define MACvIntEnable(iobase, dwMask) \ - VNSvOutPortD(iobase + MAC_REG_IMR, dwMask) - #define MACvIntDisable(iobase) \ VNSvOutPortD(iobase + MAC_REG_IMR, 0) From a79922905a08559775468ba0a81659501cabcfea Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:49:05 +0200 Subject: [PATCH 0042/1436] staging: vt6655: Replace MACvIntDisable with VNSvOutPortD Replace macro MACvIntDisable with VNSvOutPortD and as it was only used twice, it can now be removed. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/937422bb879d8f1f58978bedc8d15559d28581c7.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 2 +- drivers/staging/vt6655/mac.c | 2 +- drivers/staging/vt6655/mac.h | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index d9515eff05c3..29ee0fd893cc 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1143,7 +1143,7 @@ static irqreturn_t vnt_interrupt(int irq, void *arg) schedule_work(&priv->interrupt_work); - MACvIntDisable(priv->port_offset); + VNSvOutPortD(priv->port_offset + MAC_REG_IMR, 0); return IRQ_HANDLED; } diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index 88ddd0676463..24eab18972d2 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -458,7 +458,7 @@ bool MACbShutdown(struct vnt_private *priv) { void __iomem *io_base = priv->port_offset; /* disable MAC IMR */ - MACvIntDisable(io_base); + VNSvOutPortD(io_base + MAC_REG_IMR, 0); MACvSetLoopbackMode(priv, MAC_LB_INTERNAL); /* stop the adapter */ if (!MACbSafeStop(priv)) { diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 8b3ba94dd02e..a1d5eb52ddc4 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -648,9 +648,6 @@ do { \ iowrite8(byOrgValue, iobase + MAC_REG_STICKHW); \ } while (0) -#define MACvIntDisable(iobase) \ - VNSvOutPortD(iobase + MAC_REG_IMR, 0) - #define MACvSelectPage0(iobase) \ iowrite8(0, iobase + MAC_REG_PAGE1SEL) From 6b2564abdf178a7f911a783561ac2865b6545298 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:49:10 +0200 Subject: [PATCH 0043/1436] staging: vt6655: Replace MACvSetCurrBCNTxDescAddr with VNSvOutPortD Replace macro MACvSetCurrBCNTxDescAddr with VNSvOutPortD and as it was only used twice, it can now be removed. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/1db079979f7e0e3535463d9f31204aa708c6f680.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/card.c | 3 +-- drivers/staging/vt6655/mac.h | 5 ----- drivers/staging/vt6655/rxtx.c | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 72043a29b543..23804cd72477 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -411,8 +411,7 @@ void CARDvSafeResetTx(struct vnt_private *priv) MACvSetCurrTXDescAddr(TYPE_AC0DMA, priv, priv->td1_pool_dma); /* set MAC Beacon TX pointer */ - MACvSetCurrBCNTxDescAddr(priv->port_offset, - (priv->tx_beacon_dma)); + VNSvOutPortD(priv->port_offset + MAC_REG_BCNDMAPTR, priv->tx_beacon_dma); } /* diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index a1d5eb52ddc4..89a3979aeb10 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -565,11 +565,6 @@ do { \ iowrite16(wData & ~(wBits), iobase + byRegOfs); \ } while (0) -/* set the chip with current BCN tx descriptor address */ -#define MACvSetCurrBCNTxDescAddr(iobase, dwCurrDescAddr) \ - VNSvOutPortD(iobase + MAC_REG_BCNDMAPTR, \ - dwCurrDescAddr) - #define MACvWriteBSSIDAddress(iobase, pbyEtherAddr) \ do { \ iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 390b27b02562..03c2ab8489fa 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1420,7 +1420,7 @@ static int vnt_beacon_xmit(struct vnt_private *priv, priv->wBCNBufLen = sizeof(*short_head) + skb->len; - MACvSetCurrBCNTxDescAddr(priv->port_offset, priv->tx_beacon_dma); + VNSvOutPortD(priv->port_offset + MAC_REG_BCNDMAPTR, priv->tx_beacon_dma); iowrite16(priv->wBCNBufLen, priv->port_offset + MAC_REG_BCNDMACTL + 2); /* Set auto Transmit on */ From dc59b9bdddecf92fba40a533f4dea8f46bd99b8b Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:49:15 +0200 Subject: [PATCH 0044/1436] staging: vt6655: Replace MACvRx0PerPktMode with VNSvOutPortD Replace macro MACvRx0PerPktMode with VNSvOutPortD and as it was the only user, it can now be removed. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/3da471693a65adb75a637805ee6d564ddafccdda.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/card.c | 2 +- drivers/staging/vt6655/mac.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 23804cd72477..e907dfd58d1f 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -452,7 +452,7 @@ void CARDvSafeResetRx(struct vnt_private *priv) } /* set perPkt mode */ - MACvRx0PerPktMode(priv->port_offset); + VNSvOutPortD(priv->port_offset + MAC_REG_RXDMACTL0, RX_PERPKT); MACvRx1PerPktMode(priv->port_offset); /* set MAC RD pointer */ MACvSetCurrRx0DescAddr(priv, priv->rd0_pool_dma); diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 89a3979aeb10..161130084936 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -589,9 +589,6 @@ do { \ iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ } while (0) -#define MACvRx0PerPktMode(iobase) \ - VNSvOutPortD(iobase + MAC_REG_RXDMACTL0, RX_PERPKT) - #define MACvRx1PerPktMode(iobase) \ VNSvOutPortD(iobase + MAC_REG_RXDMACTL1, RX_PERPKT) From d371f5fd4f840fdc076a3573ad6361ee76f25c95 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:49:19 +0200 Subject: [PATCH 0045/1436] staging: vt6655: Replace MACvRx1PerPktMode with VNSvOutPortD Replace macro MACvRx1PerPktMode with VNSvOutPortD and as it was the only user, it can now be removed. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/9cb643b9554e33f5be7a2babefbed5eccca14625.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/card.c | 2 +- drivers/staging/vt6655/mac.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index e907dfd58d1f..57ed2120dbc1 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -453,7 +453,7 @@ void CARDvSafeResetRx(struct vnt_private *priv) /* set perPkt mode */ VNSvOutPortD(priv->port_offset + MAC_REG_RXDMACTL0, RX_PERPKT); - MACvRx1PerPktMode(priv->port_offset); + VNSvOutPortD(priv->port_offset + MAC_REG_RXDMACTL1, RX_PERPKT); /* set MAC RD pointer */ MACvSetCurrRx0DescAddr(priv, priv->rd0_pool_dma); diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 161130084936..b68e21c62d2b 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -589,9 +589,6 @@ do { \ iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ } while (0) -#define MACvRx1PerPktMode(iobase) \ - VNSvOutPortD(iobase + MAC_REG_RXDMACTL1, RX_PERPKT) - #define MACvReceive0(iobase) \ do { \ unsigned long dwData; \ From a18263ebc8250eea3e806dfa6e8fa8e85f76eba4 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:49:24 +0200 Subject: [PATCH 0046/1436] staging: vt6655: Replace VNSvOutPortD with iowrite32 Replace macro VNSvOutPortD with iowrite32 because it replaces just one line. The name of macro and the arguments use CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/03b6ff0250aa797f45a855ff2fc76f8013f73dc0.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/baseband.c | 2 +- drivers/staging/vt6655/card.c | 33 +++++++++++++--------------- drivers/staging/vt6655/device_main.c | 22 ++++++++----------- drivers/staging/vt6655/mac.c | 2 +- drivers/staging/vt6655/mac.h | 26 +++++++++++----------- drivers/staging/vt6655/rf.c | 2 +- drivers/staging/vt6655/rxtx.c | 2 +- drivers/staging/vt6655/upc.h | 3 --- 8 files changed, 41 insertions(+), 51 deletions(-) diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c index 577a38fae369..a5412ca0ea68 100644 --- a/drivers/staging/vt6655/baseband.c +++ b/drivers/staging/vt6655/baseband.c @@ -2013,7 +2013,7 @@ bool bb_vt3253_init(struct vnt_private *priv) byVT3253B0_AGC4_RFMD2959[ii][0], byVT3253B0_AGC4_RFMD2959[ii][1]); - VNSvOutPortD(iobase + MAC_REG_ITRTMSET, 0x23); + iowrite32(0x23, iobase + MAC_REG_ITRTMSET); MACvRegBitsOn(iobase, MAC_REG_PAPEDELAY, BIT(0)); } priv->abyBBVGA[0] = 0x18; diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 57ed2120dbc1..7a4a8b3f164e 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -293,10 +293,8 @@ bool CARDbUpdateTSF(struct vnt_private *priv, unsigned char byRxRate, qwTSFOffset = CARDqGetTSFOffset(byRxRate, qwBSSTimestamp, local_tsf); /* adjust TSF, HW's TSF add TSF Offset reg */ - VNSvOutPortD(priv->port_offset + MAC_REG_TSFOFST, - (u32)qwTSFOffset); - VNSvOutPortD(priv->port_offset + MAC_REG_TSFOFST + 4, - (u32)(qwTSFOffset >> 32)); + iowrite32((u32)qwTSFOffset, priv->port_offset + MAC_REG_TSFOFST); + iowrite32((u32)(qwTSFOffset >> 32), priv->port_offset + MAC_REG_TSFOFST + 4); MACvRegBitsOn(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_TSFSYNCEN); } @@ -329,9 +327,8 @@ bool CARDbSetBeaconPeriod(struct vnt_private *priv, iowrite16(wBeaconInterval, priv->port_offset + MAC_REG_BI); priv->wBeaconInterval = wBeaconInterval; /* Set NextTBTT */ - VNSvOutPortD(priv->port_offset + MAC_REG_NEXTTBTT, (u32)qwNextTBTT); - VNSvOutPortD(priv->port_offset + MAC_REG_NEXTTBTT + 4, - (u32)(qwNextTBTT >> 32)); + iowrite32((u32)qwNextTBTT, priv->port_offset + MAC_REG_NEXTTBTT); + iowrite32((u32)(qwNextTBTT >> 32), priv->port_offset + MAC_REG_NEXTTBTT + 4); MACvRegBitsOn(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); return true; @@ -411,7 +408,7 @@ void CARDvSafeResetTx(struct vnt_private *priv) MACvSetCurrTXDescAddr(TYPE_AC0DMA, priv, priv->td1_pool_dma); /* set MAC Beacon TX pointer */ - VNSvOutPortD(priv->port_offset + MAC_REG_BCNDMAPTR, priv->tx_beacon_dma); + iowrite32((u32)priv->tx_beacon_dma, priv->port_offset + MAC_REG_BCNDMAPTR); } /* @@ -452,8 +449,8 @@ void CARDvSafeResetRx(struct vnt_private *priv) } /* set perPkt mode */ - VNSvOutPortD(priv->port_offset + MAC_REG_RXDMACTL0, RX_PERPKT); - VNSvOutPortD(priv->port_offset + MAC_REG_RXDMACTL1, RX_PERPKT); + iowrite32(RX_PERPKT, priv->port_offset + MAC_REG_RXDMACTL0); + iowrite32(RX_PERPKT, priv->port_offset + MAC_REG_RXDMACTL1); /* set MAC RD pointer */ MACvSetCurrRx0DescAddr(priv, priv->rd0_pool_dma); @@ -552,7 +549,7 @@ void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type) /* swap over to get correct write order */ swap(phy.swap[0], phy.swap[1]); - VNSvOutPortD(priv->port_offset + MAC_REG_RSPINF_B_1, phy.field_write); + iowrite32(phy.field_write, priv->port_offset + MAC_REG_RSPINF_B_1); /* RSPINF_b_2 */ vnt_get_phy_field(priv, 14, @@ -561,7 +558,7 @@ void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type) swap(phy.swap[0], phy.swap[1]); - VNSvOutPortD(priv->port_offset + MAC_REG_RSPINF_B_2, phy.field_write); + iowrite32(phy.field_write, priv->port_offset + MAC_REG_RSPINF_B_2); /* RSPINF_b_5 */ vnt_get_phy_field(priv, 14, @@ -570,7 +567,7 @@ void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type) swap(phy.swap[0], phy.swap[1]); - VNSvOutPortD(priv->port_offset + MAC_REG_RSPINF_B_5, phy.field_write); + iowrite32(phy.field_write, priv->port_offset + MAC_REG_RSPINF_B_5); /* RSPINF_b_11 */ vnt_get_phy_field(priv, 14, @@ -579,7 +576,7 @@ void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type) swap(phy.swap[0], phy.swap[1]); - VNSvOutPortD(priv->port_offset + MAC_REG_RSPINF_B_11, phy.field_write); + iowrite32(phy.field_write, priv->port_offset + MAC_REG_RSPINF_B_11); /* RSPINF_a_6 */ s_vCalculateOFDMRParameter(RATE_6M, @@ -798,8 +795,8 @@ void CARDvSetFirstNextTBTT(struct vnt_private *priv, qwNextTBTT = CARDqGetNextTBTT(qwNextTBTT, wBeaconInterval); /* Set NextTBTT */ - VNSvOutPortD(iobase + MAC_REG_NEXTTBTT, (u32)qwNextTBTT); - VNSvOutPortD(iobase + MAC_REG_NEXTTBTT + 4, (u32)(qwNextTBTT >> 32)); + iowrite32((u32)qwNextTBTT, iobase + MAC_REG_NEXTTBTT); + iowrite32((u32)(qwNextTBTT >> 32), iobase + MAC_REG_NEXTTBTT + 4); MACvRegBitsOn(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); } @@ -824,8 +821,8 @@ void CARDvUpdateNextTBTT(struct vnt_private *priv, u64 qwTSF, qwTSF = CARDqGetNextTBTT(qwTSF, wBeaconInterval); /* Set NextTBTT */ - VNSvOutPortD(iobase + MAC_REG_NEXTTBTT, (u32)qwTSF); - VNSvOutPortD(iobase + MAC_REG_NEXTTBTT + 4, (u32)(qwTSF >> 32)); + iowrite32((u32)qwTSF, iobase + MAC_REG_NEXTTBTT); + iowrite32((u32)(qwTSF >> 32), iobase + MAC_REG_NEXTTBTT + 4); MACvRegBitsOn(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); pr_debug("Card:Update Next TBTT[%8llx]\n", qwTSF); } diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 29ee0fd893cc..c32c0328b602 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1055,7 +1055,7 @@ static void vnt_interrupt_process(struct vnt_private *priv) * update ISR counter */ while (isr && priv->vif) { - VNSvOutPortD(priv->port_offset + MAC_REG_ISR, isr); + iowrite32(isr, priv->port_offset + MAC_REG_ISR); if (isr & ISR_FETALERR) { pr_debug(" ISR_FETALERR\n"); @@ -1134,7 +1134,7 @@ static void vnt_interrupt_work(struct work_struct *work) if (priv->vif) vnt_interrupt_process(priv); - VNSvOutPortD(priv->port_offset + MAC_REG_IMR, IMR_MASK_VALUE); + iowrite32(IMR_MASK_VALUE, priv->port_offset + MAC_REG_IMR); } static irqreturn_t vnt_interrupt(int irq, void *arg) @@ -1143,7 +1143,7 @@ static irqreturn_t vnt_interrupt(int irq, void *arg) schedule_work(&priv->interrupt_work); - VNSvOutPortD(priv->port_offset + MAC_REG_IMR, 0); + iowrite32(0, priv->port_offset + MAC_REG_IMR); return IRQ_HANDLED; } @@ -1253,7 +1253,7 @@ static int vnt_start(struct ieee80211_hw *hw) device_init_registers(priv); dev_dbg(&priv->pcid->dev, "enable MAC interrupt\n"); - VNSvOutPortD(priv->port_offset + MAC_REG_IMR, IMR_MASK_VALUE); + iowrite32(IMR_MASK_VALUE, priv->port_offset + MAC_REG_IMR); ieee80211_wake_queues(hw); @@ -1522,20 +1522,16 @@ static void vnt_configure(struct ieee80211_hw *hw, if (priv->mc_list_count > 2) { MACvSelectPage1(priv->port_offset); - VNSvOutPortD(priv->port_offset + - MAC_REG_MAR0, 0xffffffff); - VNSvOutPortD(priv->port_offset + - MAC_REG_MAR0 + 4, 0xffffffff); + iowrite32(0xffffffff, priv->port_offset + MAC_REG_MAR0); + iowrite32(0xffffffff, priv->port_offset + MAC_REG_MAR0 + 4); MACvSelectPage0(priv->port_offset); } else { MACvSelectPage1(priv->port_offset); - VNSvOutPortD(priv->port_offset + - MAC_REG_MAR0, (u32)multicast); - VNSvOutPortD(priv->port_offset + - MAC_REG_MAR0 + 4, - (u32)(multicast >> 32)); + iowrite32((u32)multicast, priv->port_offset + MAC_REG_MAR0); + iowrite32((u32)(multicast >> 32), + priv->port_offset + MAC_REG_MAR0 + 4); MACvSelectPage0(priv->port_offset); } diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index 24eab18972d2..8e789ce055cd 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -458,7 +458,7 @@ bool MACbShutdown(struct vnt_private *priv) { void __iomem *io_base = priv->port_offset; /* disable MAC IMR */ - VNSvOutPortD(io_base + MAC_REG_IMR, 0); + iowrite32(0, io_base + MAC_REG_IMR); MACvSetLoopbackMode(priv, MAC_LB_INTERNAL); /* stop the adapter */ if (!MACbSafeStop(priv)) { diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index b68e21c62d2b..71de3aa7e7c5 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -594,9 +594,9 @@ do { \ unsigned long dwData; \ dwData = ioread32(iobase + MAC_REG_RXDMACTL0); \ if (dwData & DMACTL_RUN) \ - VNSvOutPortD(iobase + MAC_REG_RXDMACTL0, DMACTL_WAKE); \ + iowrite32(DMACTL_WAKE, iobase + MAC_REG_RXDMACTL0); \ else \ - VNSvOutPortD(iobase + MAC_REG_RXDMACTL0, DMACTL_RUN); \ + iowrite32(DMACTL_RUN, iobase + MAC_REG_RXDMACTL0); \ } while (0) #define MACvReceive1(iobase) \ @@ -604,9 +604,9 @@ do { \ unsigned long dwData; \ dwData = ioread32(iobase + MAC_REG_RXDMACTL1); \ if (dwData & DMACTL_RUN) \ - VNSvOutPortD(iobase + MAC_REG_RXDMACTL1, DMACTL_WAKE); \ + iowrite32(DMACTL_WAKE, iobase + MAC_REG_RXDMACTL1); \ else \ - VNSvOutPortD(iobase + MAC_REG_RXDMACTL1, DMACTL_RUN); \ + iowrite32(DMACTL_RUN, iobase + MAC_REG_RXDMACTL1); \ } while (0) #define MACvTransmit0(iobase) \ @@ -614,9 +614,9 @@ do { \ unsigned long dwData; \ dwData = ioread32(iobase + MAC_REG_TXDMACTL0); \ if (dwData & DMACTL_RUN) \ - VNSvOutPortD(iobase + MAC_REG_TXDMACTL0, DMACTL_WAKE); \ + iowrite32(DMACTL_WAKE, iobase + MAC_REG_TXDMACTL0); \ else \ - VNSvOutPortD(iobase + MAC_REG_TXDMACTL0, DMACTL_RUN); \ + iowrite32(DMACTL_RUN, iobase + MAC_REG_TXDMACTL0); \ } while (0) #define MACvTransmitAC0(iobase) \ @@ -624,9 +624,9 @@ do { \ unsigned long dwData; \ dwData = ioread32(iobase + MAC_REG_AC0DMACTL); \ if (dwData & DMACTL_RUN) \ - VNSvOutPortD(iobase + MAC_REG_AC0DMACTL, DMACTL_WAKE); \ + iowrite32(DMACTL_WAKE, iobase + MAC_REG_AC0DMACTL); \ else \ - VNSvOutPortD(iobase + MAC_REG_AC0DMACTL, DMACTL_RUN); \ + iowrite32(DMACTL_RUN, iobase + MAC_REG_AC0DMACTL); \ } while (0) #define MACvClearStckDS(iobase) \ @@ -648,7 +648,7 @@ do { \ unsigned long dwOrgValue; \ dwOrgValue = ioread32(iobase + MAC_REG_ENCFG); \ dwOrgValue = dwOrgValue | ENCFG_PROTECTMD; \ - VNSvOutPortD(iobase + MAC_REG_ENCFG, dwOrgValue); \ + iowrite32((u32)dwOrgValue, iobase + MAC_REG_ENCFG); \ } while (0) #define MACvDisableProtectMD(iobase) \ @@ -656,7 +656,7 @@ do { \ unsigned long dwOrgValue; \ dwOrgValue = ioread32(iobase + MAC_REG_ENCFG); \ dwOrgValue = dwOrgValue & ~ENCFG_PROTECTMD; \ - VNSvOutPortD(iobase + MAC_REG_ENCFG, dwOrgValue); \ + iowrite32((u32)dwOrgValue, iobase + MAC_REG_ENCFG); \ } while (0) #define MACvEnableBarkerPreambleMd(iobase) \ @@ -664,7 +664,7 @@ do { \ unsigned long dwOrgValue; \ dwOrgValue = ioread32(iobase + MAC_REG_ENCFG); \ dwOrgValue = dwOrgValue | ENCFG_BARKERPREAM; \ - VNSvOutPortD(iobase + MAC_REG_ENCFG, dwOrgValue); \ + iowrite32((u32)dwOrgValue, iobase + MAC_REG_ENCFG); \ } while (0) #define MACvDisableBarkerPreambleMd(iobase) \ @@ -672,7 +672,7 @@ do { \ unsigned long dwOrgValue; \ dwOrgValue = ioread32(iobase + MAC_REG_ENCFG); \ dwOrgValue = dwOrgValue & ~ENCFG_BARKERPREAM; \ - VNSvOutPortD(iobase + MAC_REG_ENCFG, dwOrgValue); \ + iowrite32((u32)dwOrgValue, iobase + MAC_REG_ENCFG); \ } while (0) #define MACvSetBBType(iobase, byTyp) \ @@ -681,7 +681,7 @@ do { \ dwOrgValue = ioread32(iobase + MAC_REG_ENCFG); \ dwOrgValue = dwOrgValue & ~ENCFG_BBTYPE_MASK; \ dwOrgValue = dwOrgValue | (unsigned long)byTyp; \ - VNSvOutPortD(iobase + MAC_REG_ENCFG, dwOrgValue); \ + iowrite32((u32)dwOrgValue, iobase + MAC_REG_ENCFG); \ } while (0) #define MACvSetRFLE_LatchBase(iobase) \ diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c index ff6f654df2d2..99850367293a 100644 --- a/drivers/staging/vt6655/rf.c +++ b/drivers/staging/vt6655/rf.c @@ -171,7 +171,7 @@ bool IFRFbWriteEmbedded(struct vnt_private *priv, unsigned long dwData) unsigned short ww; unsigned long dwValue; - VNSvOutPortD(iobase + MAC_REG_IFREGCTL, dwData); + iowrite32((u32)dwData, iobase + MAC_REG_IFREGCTL); /* W_MAX_TIMEOUT is the timeout period */ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 03c2ab8489fa..736681274296 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1420,7 +1420,7 @@ static int vnt_beacon_xmit(struct vnt_private *priv, priv->wBCNBufLen = sizeof(*short_head) + skb->len; - VNSvOutPortD(priv->port_offset + MAC_REG_BCNDMAPTR, priv->tx_beacon_dma); + iowrite32((u32)priv->tx_beacon_dma, priv->port_offset + MAC_REG_BCNDMAPTR); iowrite16(priv->wBCNBufLen, priv->port_offset + MAC_REG_BCNDMACTL + 2); /* Set auto Transmit on */ diff --git a/drivers/staging/vt6655/upc.h b/drivers/staging/vt6655/upc.h index 0f2f7df00b3a..c7966a638fde 100644 --- a/drivers/staging/vt6655/upc.h +++ b/drivers/staging/vt6655/upc.h @@ -20,9 +20,6 @@ /* For memory mapped IO */ -#define VNSvOutPortD(dwIOAddress, dwData) \ - iowrite32((u32)(dwData), dwIOAddress) - /*--------------------- Export Classes ----------------------------*/ /*--------------------- Export Variables --------------------------*/ From 6f58936e1286c45cabf6abf5debf75664b532c2c Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:49:28 +0200 Subject: [PATCH 0047/1436] staging: vt6655: Add missing BE support on 2x iowrite32 Add missing big-endian support when using two times iowrite32 to write 64 Bit. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/974ef7a9244e7caeafd8c176c7b53a6de3c20219.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/card.c | 4 ++++ drivers/staging/vt6655/device_main.c | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 7a4a8b3f164e..abc74a5633c7 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -293,6 +293,7 @@ bool CARDbUpdateTSF(struct vnt_private *priv, unsigned char byRxRate, qwTSFOffset = CARDqGetTSFOffset(byRxRate, qwBSSTimestamp, local_tsf); /* adjust TSF, HW's TSF add TSF Offset reg */ + qwTSFOffset = le64_to_cpu(qwTSFOffset); iowrite32((u32)qwTSFOffset, priv->port_offset + MAC_REG_TSFOFST); iowrite32((u32)(qwTSFOffset >> 32), priv->port_offset + MAC_REG_TSFOFST + 4); MACvRegBitsOn(priv->port_offset, MAC_REG_TFTCTL, @@ -327,6 +328,7 @@ bool CARDbSetBeaconPeriod(struct vnt_private *priv, iowrite16(wBeaconInterval, priv->port_offset + MAC_REG_BI); priv->wBeaconInterval = wBeaconInterval; /* Set NextTBTT */ + qwNextTBTT = le64_to_cpu(qwNextTBTT); iowrite32((u32)qwNextTBTT, priv->port_offset + MAC_REG_NEXTTBTT); iowrite32((u32)(qwNextTBTT >> 32), priv->port_offset + MAC_REG_NEXTTBTT + 4); MACvRegBitsOn(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); @@ -795,6 +797,7 @@ void CARDvSetFirstNextTBTT(struct vnt_private *priv, qwNextTBTT = CARDqGetNextTBTT(qwNextTBTT, wBeaconInterval); /* Set NextTBTT */ + qwNextTBTT = le64_to_cpu(qwNextTBTT); iowrite32((u32)qwNextTBTT, iobase + MAC_REG_NEXTTBTT); iowrite32((u32)(qwNextTBTT >> 32), iobase + MAC_REG_NEXTTBTT + 4); MACvRegBitsOn(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); @@ -821,6 +824,7 @@ void CARDvUpdateNextTBTT(struct vnt_private *priv, u64 qwTSF, qwTSF = CARDqGetNextTBTT(qwTSF, wBeaconInterval); /* Set NextTBTT */ + qwTSF = le64_to_cpu(qwTSF); iowrite32((u32)qwTSF, iobase + MAC_REG_NEXTTBTT); iowrite32((u32)(qwTSF >> 32), iobase + MAC_REG_NEXTTBTT + 4); MACvRegBitsOn(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index c32c0328b602..204994692c90 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1529,6 +1529,7 @@ static void vnt_configure(struct ieee80211_hw *hw, } else { MACvSelectPage1(priv->port_offset); + multicast = le64_to_cpu(multicast); iowrite32((u32)multicast, priv->port_offset + MAC_REG_MAR0); iowrite32((u32)(multicast >> 32), priv->port_offset + MAC_REG_MAR0 + 4); From f551dc6e7646204adf79b7a8e2db417c46b4fbe5 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Sun, 22 May 2022 21:49:33 +0200 Subject: [PATCH 0048/1436] staging: vt6655: Delete upc.h Delete upc.h as all macros have been removed from upc.h. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/b553095c618e7885af5c3e42f9b9b39d95127a44.1653203927.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.h | 2 +- drivers/staging/vt6655/srom.c | 2 +- drivers/staging/vt6655/upc.h | 29 ----------------------------- 3 files changed, 2 insertions(+), 31 deletions(-) delete mode 100644 drivers/staging/vt6655/upc.h diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 71de3aa7e7c5..102e575c965d 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -18,7 +18,7 @@ #ifndef __MAC_H__ #define __MAC_H__ -#include "upc.h" +#include "device.h" /*--------------------- Export Definitions -------------------------*/ /* Registers in the MAC */ diff --git a/drivers/staging/vt6655/srom.c b/drivers/staging/vt6655/srom.c index 722a2cc9a473..ee5ca4db74dc 100644 --- a/drivers/staging/vt6655/srom.c +++ b/drivers/staging/vt6655/srom.c @@ -27,7 +27,7 @@ * */ -#include "upc.h" +#include "device.h" #include "mac.h" #include "srom.h" diff --git a/drivers/staging/vt6655/upc.h b/drivers/staging/vt6655/upc.h deleted file mode 100644 index c7966a638fde..000000000000 --- a/drivers/staging/vt6655/upc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc. - * All rights reserved. - * - * Purpose: Macros to access device - * - * Author: Tevin Chen - * - * Date: Mar 17, 1997 - * - */ - -#ifndef __UPC_H__ -#define __UPC_H__ - -#include "device.h" - -/*--------------------- Export Definitions -------------------------*/ - -/* For memory mapped IO */ - -/*--------------------- Export Classes ----------------------------*/ - -/*--------------------- Export Variables --------------------------*/ - -/*--------------------- Export Functions --------------------------*/ - -#endif /* __UPC_H__ */ From 846d846d6fc8101da1c3d7b8e2d6eb708197cb08 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:18 +0200 Subject: [PATCH 0049/1436] staging: r8188eu: remove unnecessary category check Remove the unnecessary category check in issue_action_BA. category is initialised to 3 (WLAN_CATEGORY_BACK) and never updated. The rtw_set_fixed_ie call gets a pointer to category but it doesn't update the value. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-2-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 94 ++++++++++----------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index faf23fc950c5..f47cf3e7316c 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5415,60 +5415,58 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch pframe = rtw_set_fixed_ie(pframe, 1, &(category), &pattrib->pktlen); pframe = rtw_set_fixed_ie(pframe, 1, &(action), &pattrib->pktlen); - if (category == 3) { - switch (action) { - case 0: /* ADDBA req */ - do { - pmlmeinfo->dialogToken++; - } while (pmlmeinfo->dialogToken == 0); - pframe = rtw_set_fixed_ie(pframe, 1, &pmlmeinfo->dialogToken, &pattrib->pktlen); + switch (action) { + case 0: /* ADDBA req */ + do { + pmlmeinfo->dialogToken++; + } while (pmlmeinfo->dialogToken == 0); + pframe = rtw_set_fixed_ie(pframe, 1, &pmlmeinfo->dialogToken, &pattrib->pktlen); - BA_para_set = (0x1002 | ((status & 0xf) << 2)); /* immediate ack & 64 buffer size */ - le_tmp = cpu_to_le16(BA_para_set); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + BA_para_set = (0x1002 | ((status & 0xf) << 2)); /* immediate ack & 64 buffer size */ + le_tmp = cpu_to_le16(BA_para_set); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); - BA_timeout_value = 5000;/* 5ms */ - le_tmp = cpu_to_le16(BA_timeout_value); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + BA_timeout_value = 5000;/* 5ms */ + le_tmp = cpu_to_le16(BA_timeout_value); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); - psta = rtw_get_stainfo(pstapriv, raddr); - if (psta) { - start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07] & 0xfff) + 1; + psta = rtw_get_stainfo(pstapriv, raddr); + if (psta) { + start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07] & 0xfff) + 1; - psta->BA_starting_seqctrl[status & 0x07] = start_seq; + psta->BA_starting_seqctrl[status & 0x07] = start_seq; - BA_starting_seqctrl = start_seq << 4; - } - le_tmp = cpu_to_le16(BA_starting_seqctrl); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); - break; - case 1: /* ADDBA rsp */ - pframe = rtw_set_fixed_ie(pframe, 1, &pmlmeinfo->ADDBA_req.dialog_token, &pattrib->pktlen); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&status, &pattrib->pktlen); - BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; - BA_para_set |= 0x1000; /* 64 buffer size */ - - if (pregpriv->ampdu_amsdu == 0)/* disabled */ - BA_para_set = BA_para_set & ~BIT(0); - else if (pregpriv->ampdu_amsdu == 1)/* enabled */ - BA_para_set = BA_para_set | BIT(0); - le_tmp = cpu_to_le16(BA_para_set); - - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&pmlmeinfo->ADDBA_req.BA_timeout_value, &pattrib->pktlen); - break; - case 2:/* DELBA */ - BA_para_set = (status & 0x1F) << 3; - le_tmp = cpu_to_le16(BA_para_set); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); - - reason_code = 37;/* Requested from peer STA as it does not want to use the mechanism */ - le_tmp = cpu_to_le16(reason_code); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); - break; - default: - break; + BA_starting_seqctrl = start_seq << 4; } + le_tmp = cpu_to_le16(BA_starting_seqctrl); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + break; + case 1: /* ADDBA rsp */ + pframe = rtw_set_fixed_ie(pframe, 1, &pmlmeinfo->ADDBA_req.dialog_token, &pattrib->pktlen); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&status, &pattrib->pktlen); + BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; + BA_para_set |= 0x1000; /* 64 buffer size */ + + if (pregpriv->ampdu_amsdu == 0)/* disabled */ + BA_para_set = BA_para_set & ~BIT(0); + else if (pregpriv->ampdu_amsdu == 1)/* enabled */ + BA_para_set = BA_para_set | BIT(0); + le_tmp = cpu_to_le16(BA_para_set); + + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&pmlmeinfo->ADDBA_req.BA_timeout_value, &pattrib->pktlen); + break; + case 2:/* DELBA */ + BA_para_set = (status & 0x1F) << 3; + le_tmp = cpu_to_le16(BA_para_set); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + + reason_code = 37;/* Requested from peer STA as it does not want to use the mechanism */ + le_tmp = cpu_to_le16(reason_code); + pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + break; + default: + break; } pattrib->last_txcmdsz = pattrib->pktlen; From f54550fd8419819963d13161e3ee2759b5afe8e1 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:19 +0200 Subject: [PATCH 0050/1436] staging: r8188eu: use defines for the block action codes Replace the numeric values for the block action codes in issue_action_BA with the defines from ieee80211.h. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-3-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index f47cf3e7316c..0265784368e2 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5416,7 +5416,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch pframe = rtw_set_fixed_ie(pframe, 1, &(action), &pattrib->pktlen); switch (action) { - case 0: /* ADDBA req */ + case WLAN_ACTION_ADDBA_REQ: do { pmlmeinfo->dialogToken++; } while (pmlmeinfo->dialogToken == 0); @@ -5441,7 +5441,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch le_tmp = cpu_to_le16(BA_starting_seqctrl); pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); break; - case 1: /* ADDBA rsp */ + case WLAN_ACTION_ADDBA_RESP: pframe = rtw_set_fixed_ie(pframe, 1, &pmlmeinfo->ADDBA_req.dialog_token, &pattrib->pktlen); pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&status, &pattrib->pktlen); BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; @@ -5456,7 +5456,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&pmlmeinfo->ADDBA_req.BA_timeout_value, &pattrib->pktlen); break; - case 2:/* DELBA */ + case WLAN_ACTION_DELBA: BA_para_set = (status & 0x1F) << 3; le_tmp = cpu_to_le16(BA_para_set); pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); From 358d61965682e1473acde0b1238d95e9883f2073 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:20 +0200 Subject: [PATCH 0051/1436] staging: r8188eu: use ieee80211_mgmt in issue_action_BA Define a struct ieee80211_mgmt variable in issue_action_BA, this will make it much simpler to populate the fields of the outoing frame. Use the new mgmt variable to set the type and subtype of the frame. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-4-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 0265784368e2..eec716fea41c 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5376,13 +5376,13 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch struct pkt_attrib *pattrib; u8 *pframe; struct ieee80211_hdr *pwlanhdr; - __le16 *fctrl; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct sta_info *psta; struct sta_priv *pstapriv = &padapter->stapriv; struct registry_priv *pregpriv = &padapter->registrypriv; + struct ieee80211_mgmt *mgmt; pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (!pmgntframe) @@ -5396,9 +5396,9 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; pwlanhdr = (struct ieee80211_hdr *)pframe; + mgmt = (struct ieee80211_mgmt *)pframe; - fctrl = &pwlanhdr->frame_control; - *(fctrl) = 0; + mgmt->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION | IEEE80211_FTYPE_MGMT); /* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */ memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); @@ -5407,7 +5407,6 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); pmlmeext->mgnt_seq++; - SetFrameSubType(pframe, WIFI_ACTION); pframe += sizeof(struct ieee80211_hdr_3addr); pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); From 2f71d4b04029f25a11dca94758a16408e0983185 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:21 +0200 Subject: [PATCH 0052/1436] staging: r8188eu: use mgmt to set the addresses Use the mgmt structure in issue_action_BA to set the three addresses of the outgoing frame. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-5-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index eec716fea41c..f08521cb1ff7 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5400,10 +5400,9 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch mgmt->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION | IEEE80211_FTYPE_MGMT); - /* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */ - memcpy(pwlanhdr->addr1, raddr, ETH_ALEN); - memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN); - memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); + memcpy(mgmt->da, raddr, ETH_ALEN); + memcpy(mgmt->sa, myid(&padapter->eeprompriv), ETH_ALEN); + memcpy(mgmt->bssid, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); pmlmeext->mgnt_seq++; From d7767fc2e24f9e9ce2bc869af814922aca09ff4e Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:22 +0200 Subject: [PATCH 0053/1436] staging: r8188eu: use mgmt to set the sequence number Use the mgmt structure in issue_action_BA to set the sequence number of the outgoing frame. pwlanhdr is now unused, it can be removed. Reported-by: kernel test robot Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-6-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index f08521cb1ff7..e64f2a0ec626 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5375,7 +5375,6 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; u8 *pframe; - struct ieee80211_hdr *pwlanhdr; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -5395,7 +5394,6 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - pwlanhdr = (struct ieee80211_hdr *)pframe; mgmt = (struct ieee80211_mgmt *)pframe; mgmt->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION | IEEE80211_FTYPE_MGMT); @@ -5404,7 +5402,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch memcpy(mgmt->sa, myid(&padapter->eeprompriv), ETH_ALEN); memcpy(mgmt->bssid, get_my_bssid(&pmlmeinfo->network), ETH_ALEN); - SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq); + mgmt->seq_ctrl = cpu_to_le16(pmlmeext->mgnt_seq); pmlmeext->mgnt_seq++; pframe += sizeof(struct ieee80211_hdr_3addr); From 8d1aeb172da21fe8184674ba4efed39327b2284b Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:23 +0200 Subject: [PATCH 0054/1436] staging: r8188eu: use mgmt to set the category Use the mgmt structure in issue_action_BA to set the category of the outgoing frame. Remove the rtw_set_fixed_ie call. We can now use the define directly, the category variable can be removed. rtw_set_fixed_ie increments pattrib->pktlen, we have to do this ourselves now (until we use a proper way to calculate the packet length). Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-7-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index e64f2a0ec626..d693e0a1396b 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5365,7 +5365,6 @@ exit: void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status) { - u8 category = WLAN_CATEGORY_BACK; u16 start_seq; u16 BA_para_set; u16 reason_code; @@ -5408,7 +5407,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch pframe += sizeof(struct ieee80211_hdr_3addr); pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - pframe = rtw_set_fixed_ie(pframe, 1, &(category), &pattrib->pktlen); + mgmt->u.action.category = WLAN_CATEGORY_BACK; + pattrib->pktlen++; pframe = rtw_set_fixed_ie(pframe, 1, &(action), &pattrib->pktlen); switch (action) { From a248ccf6048dd299cb78d596c8bbc4d3b3957efa Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:24 +0200 Subject: [PATCH 0055/1436] staging: r8188eu: use mgmt to set the action codes Use the mgmt structure in issue_action_BA to set the action codes. We have to distinguish between the different message types. We also have to increment the packet length manually as we're no longer calling rtw_set_fixed_ie, which increments the length. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-8-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index d693e0a1396b..aa73afc6e36a 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5409,10 +5409,11 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch mgmt->u.action.category = WLAN_CATEGORY_BACK; pattrib->pktlen++; - pframe = rtw_set_fixed_ie(pframe, 1, &(action), &pattrib->pktlen); switch (action) { case WLAN_ACTION_ADDBA_REQ: + mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; + pattrib->pktlen++; do { pmlmeinfo->dialogToken++; } while (pmlmeinfo->dialogToken == 0); @@ -5438,6 +5439,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); break; case WLAN_ACTION_ADDBA_RESP: + mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; + pattrib->pktlen++; pframe = rtw_set_fixed_ie(pframe, 1, &pmlmeinfo->ADDBA_req.dialog_token, &pattrib->pktlen); pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&status, &pattrib->pktlen); BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; @@ -5453,6 +5456,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&pmlmeinfo->ADDBA_req.BA_timeout_value, &pattrib->pktlen); break; case WLAN_ACTION_DELBA: + mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; + pattrib->pktlen++; BA_para_set = (status & 0x1F) << 3; le_tmp = cpu_to_le16(BA_para_set); pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); From c257851fe75c7da014d42c5e3b88ca9ae2ba65b6 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:25 +0200 Subject: [PATCH 0056/1436] staging: r8188eu: use mgmt to set the dialog token Use the mgmt structure in issue_action_BA to set the dialog token. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-9-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index aa73afc6e36a..ce6327dbc534 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5417,7 +5417,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch do { pmlmeinfo->dialogToken++; } while (pmlmeinfo->dialogToken == 0); - pframe = rtw_set_fixed_ie(pframe, 1, &pmlmeinfo->dialogToken, &pattrib->pktlen); + mgmt->u.action.u.addba_req.dialog_token = pmlmeinfo->dialogToken; + pattrib->pktlen++; BA_para_set = (0x1002 | ((status & 0xf) << 2)); /* immediate ack & 64 buffer size */ le_tmp = cpu_to_le16(BA_para_set); From 34411b19203a0804fcd85c04dff1c44d38712528 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:26 +0200 Subject: [PATCH 0057/1436] staging: r8188eu: use mgmt to set the timeout Use the mgmt structure in issue_action_BA to set the timeout in the outgoing frame. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-10-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index ce6327dbc534..da0c0363eb4d 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5368,7 +5368,6 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch u16 start_seq; u16 BA_para_set; u16 reason_code; - u16 BA_timeout_value; __le16 le_tmp; u16 BA_starting_seqctrl = 0; struct xmit_frame *pmgntframe; @@ -5424,9 +5423,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch le_tmp = cpu_to_le16(BA_para_set); pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); - BA_timeout_value = 5000;/* 5ms */ - le_tmp = cpu_to_le16(BA_timeout_value); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + mgmt->u.action.u.addba_req.timeout = cpu_to_le16(5000); /* 5 ms */ + pattrib->pktlen += 2; psta = rtw_get_stainfo(pstapriv, raddr); if (psta) { From e3e3cdc43e3e92866678ee849cacda4582b0a790 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:27 +0200 Subject: [PATCH 0058/1436] staging: r8188eu: use ieee80211 to set addba capabilities Use the mgmt structure and defines from ieee80211.h to set the capabilities field of an addba request. If issue_action_BA is called with action == WLAN_ACTION_ADDBA_REQ, the status parameter contains the tid. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-11-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index da0c0363eb4d..823c54837364 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5380,6 +5380,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch struct sta_priv *pstapriv = &padapter->stapriv; struct registry_priv *pregpriv = &padapter->registrypriv; struct ieee80211_mgmt *mgmt; + u16 capab; pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (!pmgntframe) @@ -5419,9 +5420,12 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch mgmt->u.action.u.addba_req.dialog_token = pmlmeinfo->dialogToken; pattrib->pktlen++; - BA_para_set = (0x1002 | ((status & 0xf) << 2)); /* immediate ack & 64 buffer size */ - le_tmp = cpu_to_le16(BA_para_set); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + /* immediate ack & 64 buffer size */ + capab = u16_encode_bits(64, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK); + capab |= u16_encode_bits(1, IEEE80211_ADDBA_PARAM_POLICY_MASK); + capab |= u16_encode_bits(status, IEEE80211_ADDBA_PARAM_TID_MASK); + mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); + pattrib->pktlen += 2; mgmt->u.action.u.addba_req.timeout = cpu_to_le16(5000); /* 5 ms */ pattrib->pktlen += 2; From 56580e22fecb7cbe11f9debb8de07662a847d444 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:28 +0200 Subject: [PATCH 0059/1436] staging: r8188eu: use mgmt to set start sequence number Use the mgmt structure in issue_action_BA to set the start sequence number. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-12-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 823c54837364..408aa0a28382 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5438,8 +5438,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch BA_starting_seqctrl = start_seq << 4; } - le_tmp = cpu_to_le16(BA_starting_seqctrl); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + mgmt->u.action.u.addba_req.start_seq_num = cpu_to_le16(BA_starting_seqctrl); + pattrib->pktlen += 2; break; case WLAN_ACTION_ADDBA_RESP: mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; From 76d01595b24c53ff223f888289d362a4dd94420c Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Tue, 24 May 2022 11:00:29 +0200 Subject: [PATCH 0060/1436] staging: r8188eu: calculate the addba request length When issue_action_BA compiles an addba request, it does not add any extensions. start_seq_num is the last field of the addba request. The length of the request is the offset of the end of start_seq_num in the struct ieee80211_mgmt that defines the message. Use offsetofend to calculate this offset and drop the intermediate pktlen increments as we add addba request components. (We have to keep the increments for other message types until we use offsetofend for them as well.) Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220524090029.242584-13-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 408aa0a28382..5446e19d8d09 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5413,22 +5413,18 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch switch (action) { case WLAN_ACTION_ADDBA_REQ: mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; - pattrib->pktlen++; do { pmlmeinfo->dialogToken++; } while (pmlmeinfo->dialogToken == 0); mgmt->u.action.u.addba_req.dialog_token = pmlmeinfo->dialogToken; - pattrib->pktlen++; /* immediate ack & 64 buffer size */ capab = u16_encode_bits(64, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK); capab |= u16_encode_bits(1, IEEE80211_ADDBA_PARAM_POLICY_MASK); capab |= u16_encode_bits(status, IEEE80211_ADDBA_PARAM_TID_MASK); mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); - pattrib->pktlen += 2; mgmt->u.action.u.addba_req.timeout = cpu_to_le16(5000); /* 5 ms */ - pattrib->pktlen += 2; psta = rtw_get_stainfo(pstapriv, raddr); if (psta) { @@ -5439,7 +5435,9 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch BA_starting_seqctrl = start_seq << 4; } mgmt->u.action.u.addba_req.start_seq_num = cpu_to_le16(BA_starting_seqctrl); - pattrib->pktlen += 2; + + pattrib->pktlen = offsetofend(struct ieee80211_mgmt, + u.action.u.addba_req.start_seq_num); break; case WLAN_ACTION_ADDBA_RESP: mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; From a8b088d6d98dafddda9874f98ac2a7cefc51639b Mon Sep 17 00:00:00 2001 From: Hannes Braun Date: Sat, 28 May 2022 14:31:15 +0200 Subject: [PATCH 0061/1436] staging: rtl8723bs: fix placement of braces This patch should eliminate the following errors/warnings emitted by checkpatch.pl: - that open brace { should be on the previous line - else should follow close brace '}' - braces {} are not necessary for single statement blocks Signed-off-by: Hannes Braun Link: https://lore.kernel.org/r/20220528123115.13024-1-hannesbraun@mail.de Signed-off-by: Greg Kroah-Hartman --- .../staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 223 +++++------------- 1 file changed, 65 insertions(+), 158 deletions(-) diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 43b5604c0bca..7240220cf6ae 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -366,9 +366,8 @@ void rtw_cfg80211_ibss_indicate_connect(struct adapter *padapter) int freq = (int)cur_network->network.configuration.ds_config; struct ieee80211_channel *chan; - if (pwdev->iftype != NL80211_IFTYPE_ADHOC) { + if (pwdev->iftype != NL80211_IFTYPE_ADHOC) return; - } if (!rtw_cfg80211_check_bss(padapter)) { struct wlan_bssid_ex *pnetwork = &(padapter->mlmeextpriv.mlmext_info.network); @@ -544,9 +543,8 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa goto exit; } - if (wep_key_len > 0) { + if (wep_key_len > 0) wep_key_len = wep_key_len <= 5 ? 5 : 13; - } if (psecuritypriv->bWepDefaultKeyIdxSet == 0) { /* wep default key has not been set, so use this key index as default key. */ @@ -582,9 +580,8 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); psecuritypriv->dot118021XGrpPrivacy = _WEP40_; - if (param->u.crypt.key_len == 13) { + if (param->u.crypt.key_len == 13) psecuritypriv->dot118021XGrpPrivacy = _WEP104_; - } } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { psecuritypriv->dot118021XGrpPrivacy = _TKIP_; @@ -626,24 +623,16 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa } - if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) /* psk/802_1x */ - { - if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) - { - if (param->u.crypt.set_tx == 1) /* pairwise key */ - { + if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) { /* psk/802_1x */ + if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) { + if (param->u.crypt.set_tx == 1) { /* pairwise key */ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); - if (strcmp(param->u.crypt.alg, "WEP") == 0) - { + if (strcmp(param->u.crypt.alg, "WEP") == 0) { psta->dot118021XPrivacy = _WEP40_; if (param->u.crypt.key_len == 13) - { psta->dot118021XPrivacy = _WEP104_; - } - } - else if (strcmp(param->u.crypt.alg, "TKIP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { psta->dot118021XPrivacy = _TKIP_; /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */ @@ -653,14 +642,10 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa psecuritypriv->busetkipkey = true; - } - else if (strcmp(param->u.crypt.alg, "CCMP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { psta->dot118021XPrivacy = _AES_; - } - else - { + } else { psta->dot118021XPrivacy = _NO_PRIVACY_; } @@ -670,21 +655,14 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa psta->bpairwise_key_installed = true; - } - else/* group key??? */ - { - if (strcmp(param->u.crypt.alg, "WEP") == 0) - { + } else { /* group key??? */ + if (strcmp(param->u.crypt.alg, "WEP") == 0) { memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); psecuritypriv->dot118021XGrpPrivacy = _WEP40_; if (param->u.crypt.key_len == 13) - { psecuritypriv->dot118021XGrpPrivacy = _WEP104_; - } - } - else if (strcmp(param->u.crypt.alg, "TKIP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { psecuritypriv->dot118021XGrpPrivacy = _TKIP_; memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); @@ -696,15 +674,11 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa psecuritypriv->busetkipkey = true; - } - else if (strcmp(param->u.crypt.alg, "CCMP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { psecuritypriv->dot118021XGrpPrivacy = _AES_; memcpy(grpkey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); - } - else - { + } else { psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_; } @@ -717,8 +691,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx); pbcmc_sta = rtw_get_bcmc_stainfo(padapter); - if (pbcmc_sta) - { + if (pbcmc_sta) { pbcmc_sta->ieee8021x_blocked = false; pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;/* rx will use bmc_sta's dot118021XPrivacy */ } @@ -746,20 +719,16 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param param->u.crypt.err = 0; param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; - if (param_len < (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) - { + if (param_len < (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len) { ret = -EINVAL; goto exit; } if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) - { + param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { if (param->u.crypt.idx >= WEP_KEYS - || param->u.crypt.idx >= BIP_MAX_KEYID - ) - { + || param->u.crypt.idx >= BIP_MAX_KEYID) { ret = -EINVAL; goto exit; } @@ -770,19 +739,16 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param } } - if (strcmp(param->u.crypt.alg, "WEP") == 0) - { + if (strcmp(param->u.crypt.alg, "WEP") == 0) { wep_key_idx = param->u.crypt.idx; wep_key_len = param->u.crypt.key_len; - if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) - { + if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) { ret = -EINVAL; goto exit; } - if (psecuritypriv->bWepDefaultKeyIdxSet == 0) - { + if (psecuritypriv->bWepDefaultKeyIdxSet == 0) { /* wep default key has not been set, so use this key index as default key. */ wep_key_len = wep_key_len <= 5 ? 5 : 13; @@ -791,8 +757,7 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; psecuritypriv->dot118021XGrpPrivacy = _WEP40_; - if (wep_key_len == 13) - { + if (wep_key_len == 13) { psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; psecuritypriv->dot118021XGrpPrivacy = _WEP104_; } @@ -809,13 +774,11 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param goto exit; } - if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) /* 802_1x */ - { + if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) { /* 802_1x */ struct sta_info *psta, *pbcmc_sta; struct sta_priv *pstapriv = &padapter->stapriv; - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) /* sta mode */ - { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == true) { /* sta mode */ psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv)); if (psta) { /* Jeff: don't disable ieee8021x_blocked while clearing key */ @@ -824,18 +787,15 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) || - (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) - { + (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) { psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; } - if (param->u.crypt.set_tx == 1)/* pairwise key */ - { + if (param->u.crypt.set_tx == 1) { /* pairwise key */ memcpy(psta->dot118021x_UncstKey.skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); - if (strcmp(param->u.crypt.alg, "TKIP") == 0)/* set mic key */ - { + if (strcmp(param->u.crypt.alg, "TKIP") == 0) { /* set mic key */ /* DEBUG_ERR(("\nset key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len)); */ memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8); memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8); @@ -845,11 +805,8 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param } rtw_setstakey_cmd(padapter, psta, true, true); - } - else/* group key */ - { - if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) - { + } else { /* group key */ + if (strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0) { memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8); memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8); @@ -857,9 +814,7 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx; rtw_set_key(padapter, &padapter->securitypriv, param->u.crypt.idx, 1, true); - } - else if (strcmp(param->u.crypt.alg, "BIP") == 0) - { + } else if (strcmp(param->u.crypt.alg, "BIP") == 0) { /* save the IGTK key, length 16 bytes */ memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey, param->u.crypt.key, (param->u.crypt.key_len > 16 ? 16 : param->u.crypt.key_len)); /* @@ -873,25 +828,19 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param } pbcmc_sta = rtw_get_bcmc_stainfo(padapter); - if (!pbcmc_sta) - { + if (!pbcmc_sta) { /* DEBUG_ERR(("Set OID_802_11_ADD_KEY: bcmc stainfo is null\n")); */ - } - else - { + } else { /* Jeff: don't disable ieee8021x_blocked while clearing key */ if (strcmp(param->u.crypt.alg, "none") != 0) pbcmc_sta->ieee8021x_blocked = false; if ((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled) || - (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) - { + (padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption3Enabled)) { pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm; } } - } - else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) /* adhoc mode */ - { + } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) { /* adhoc mode */ } } @@ -949,39 +898,29 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, if (!mac_addr || is_broadcast_ether_addr(mac_addr)) - { param->u.crypt.set_tx = 0; /* for wpa/wpa2 group key */ - } else { + else param->u.crypt.set_tx = 1; /* for wpa/wpa2 pairwise key */ - } param->u.crypt.idx = key_index; if (params->seq_len && params->seq) - { memcpy(param->u.crypt.seq, (u8 *)params->seq, params->seq_len); - } - if (params->key_len && params->key) - { + if (params->key_len && params->key) { param->u.crypt.key_len = params->key_len; memcpy(param->u.crypt.key, (u8 *)params->key, params->key_len); } - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) - { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { ret = rtw_cfg80211_set_encryption(ndev, param, param_len); - } - else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) - { + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { if (mac_addr) memcpy(param->sta_addr, (void *)mac_addr, ETH_ALEN); ret = rtw_cfg80211_ap_set_encryption(ndev, param, param_len); - } - else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true - || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) - { + } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true + || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) { ret = rtw_cfg80211_set_encryption(ndev, param, param_len); } @@ -1007,8 +946,7 @@ static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev, struct adapter *padapter = rtw_netdev_priv(ndev); struct security_priv *psecuritypriv = &padapter->securitypriv; - if (key_index == psecuritypriv->dot11PrivacyKeyIndex) - { + if (key_index == psecuritypriv->dot11PrivacyKeyIndex) { /* clear the flag of wep default key set. */ psecuritypriv->bWepDefaultKeyIdxSet = 0; } @@ -1024,16 +962,14 @@ static int cfg80211_rtw_set_default_key(struct wiphy *wiphy, struct adapter *padapter = rtw_netdev_priv(ndev); struct security_priv *psecuritypriv = &padapter->securitypriv; - if ((key_index < WEP_KEYS) && ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) || (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_))) /* set wep default key */ - { + if ((key_index < WEP_KEYS) && ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) || (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_))) { /* set wep default key */ psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled; psecuritypriv->dot11PrivacyKeyIndex = key_index; psecuritypriv->dot11PrivacyAlgrthm = _WEP40_; psecuritypriv->dot118021XGrpPrivacy = _WEP40_; - if (psecuritypriv->dot11DefKeylen[key_index] == 13) - { + if (psecuritypriv->dot11DefKeylen[key_index] == 13) { psecuritypriv->dot11PrivacyAlgrthm = _WEP104_; psecuritypriv->dot118021XGrpPrivacy = _WEP104_; } @@ -1071,9 +1007,7 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy, /* for infra./P2PClient mode */ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) - && check_fwstate(pmlmepriv, _FW_LINKED) - ) - { + && check_fwstate(pmlmepriv, _FW_LINKED)) { struct wlan_network *cur_network = &(pmlmepriv->cur_network); if (memcmp((u8 *)mac, cur_network->network.mac_address, ETH_ALEN)) { @@ -1099,9 +1033,7 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy, if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) || check_fwstate(pmlmepriv, WIFI_AP_STATE)) - && check_fwstate(pmlmepriv, _FW_LINKED) - ) - { + && check_fwstate(pmlmepriv, _FW_LINKED)) { /* TODO: should acquire station info... */ } @@ -1121,8 +1053,7 @@ static int cfg80211_rtw_change_iface(struct wiphy *wiphy, struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); int ret = 0; - if (adapter_to_dvobj(padapter)->processing_dev_remove == true) - { + if (adapter_to_dvobj(padapter)->processing_dev_remove == true) { ret = -EPERM; goto exit; } @@ -1141,8 +1072,7 @@ static int cfg80211_rtw_change_iface(struct wiphy *wiphy, old_type = rtw_wdev->iftype; - if (old_type != type) - { + if (old_type != type) { pmlmeext->action_public_rxseq = 0xffff; pmlmeext->action_public_dialog_token = 0xff; } @@ -1164,8 +1094,7 @@ static int cfg80211_rtw_change_iface(struct wiphy *wiphy, rtw_wdev->iftype = type; - if (rtw_set_802_11_infrastructure_mode(padapter, networkType) == false) - { + if (rtw_set_802_11_infrastructure_mode(padapter, networkType) == false) { rtw_wdev->iftype = old_type; ret = -EPERM; goto exit; @@ -1230,9 +1159,7 @@ void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter) /* report network only if the current channel set contains the channel to which this network belongs */ if (rtw_ch_set_search_ch(padapter->mlmeextpriv.channel_set, pnetwork->network.configuration.ds_config) >= 0 - && true == rtw_validate_ssid(&(pnetwork->network.ssid)) - ) - { + && true == rtw_validate_ssid(&(pnetwork->network.ssid))) { /* ev =translate_scan(padapter, a, pnetwork, ev, stop); */ rtw_cfg80211_inform_bss(padapter, pnetwork); } @@ -1249,13 +1176,10 @@ static int rtw_cfg80211_set_probe_req_wpsp2pie(struct adapter *padapter, char *b u8 *wps_ie; struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); - if (len > 0) - { + if (len > 0) { wps_ie = rtw_get_wps_ie(buf, len, NULL, &wps_ielen); - if (wps_ie) - { - if (pmlmepriv->wps_probe_req_ie) - { + if (wps_ie) { + if (pmlmepriv->wps_probe_req_ie) { pmlmepriv->wps_probe_req_ie_len = 0; kfree(pmlmepriv->wps_probe_req_ie); pmlmepriv->wps_probe_req_ie = NULL; @@ -1307,10 +1231,8 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy pwdev_priv->scan_request = request; spin_unlock_bh(&pwdev_priv->scan_req_lock); - if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) - { - if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS|_FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) - { + if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { + if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS|_FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) { need_indicate_scan_done = true; goto check_need_indicate_scan_done; } @@ -1333,15 +1255,13 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy goto check_need_indicate_scan_done; } - if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) - { + if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) { static unsigned long lastscantime = 0; unsigned long passtime; passtime = jiffies_to_msecs(jiffies - lastscantime); lastscantime = jiffies; - if (passtime > 12000) - { + if (passtime > 12000) { need_indicate_scan_done = true; goto check_need_indicate_scan_done; } @@ -1380,9 +1300,7 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy } else if (request->n_channels <= 4) { for (j = request->n_channels - 1; j >= 0; j--) for (i = 0; i < survey_times; i++) - { memcpy(&ch[j*survey_times+i], &ch[j], sizeof(struct rtw_ieee80211_channel)); - } _status = rtw_sitesurvey_cmd(padapter, ssid, RTW_SSID_SCAN_AMOUNT, ch, survey_times * request->n_channels); } else { _status = rtw_sitesurvey_cmd(padapter, ssid, RTW_SSID_SCAN_AMOUNT, NULL, 0); @@ -1391,14 +1309,11 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy if (_status == false) - { ret = -1; - } check_need_indicate_scan_done: kfree(ssid); - if (need_indicate_scan_done) - { + if (need_indicate_scan_done) { rtw_cfg80211_surveydone_event_callback(padapter); rtw_cfg80211_indicate_scan_done(padapter, false); } @@ -1424,9 +1339,7 @@ static int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv, u32 if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) - { psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK; - } return 0; @@ -1585,8 +1498,7 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel if (pairwise_cipher == 0) pairwise_cipher = WPA_CIPHER_NONE; - switch (group_cipher) - { + switch (group_cipher) { case WPA_CIPHER_NONE: padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; @@ -1609,8 +1521,7 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel break; } - switch (pairwise_cipher) - { + switch (pairwise_cipher) { case WPA_CIPHER_NONE: padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; @@ -1731,8 +1642,7 @@ static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) rtw_wdev->iftype = NL80211_IFTYPE_STATION; - if (rtw_set_802_11_infrastructure_mode(padapter, Ndis802_11Infrastructure) == false) - { + if (rtw_set_802_11_infrastructure_mode(padapter, Ndis802_11Infrastructure) == false) { rtw_wdev->iftype = old_type; ret = -EPERM; goto leave_ibss; @@ -1792,9 +1702,8 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, ret = -EBUSY; goto exit; } - if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) { + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) rtw_scan_abort(padapter); - } psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled; psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_; @@ -2287,9 +2196,8 @@ static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, str mon_ndev->ieee80211_ptr = mon_wdev; ret = cfg80211_register_netdevice(mon_ndev); - if (ret) { + if (ret) goto out; - } *ndev = pwdev_priv->pmon_ndev = mon_ndev; memcpy(pwdev_priv->ifname_mon, name, IFNAMSIZ+1); @@ -2402,11 +2310,10 @@ static int rtw_add_beacon(struct adapter *adapter, const u8 *head, size_t head_l rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, WLAN_EID_VENDOR_SPECIFIC, P2P_OUI, 4); rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, WLAN_EID_VENDOR_SPECIFIC, WFD_OUI, 4); - if (rtw_check_beacon_data(adapter, pbuf, len) == _SUCCESS) { + if (rtw_check_beacon_data(adapter, pbuf, len) == _SUCCESS) ret = 0; - } else { + else ret = -EINVAL; - } kfree(pbuf); From a0daad77a402f6d483d577649d49163fb622836b Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Sun, 29 May 2022 18:02:11 +0200 Subject: [PATCH 0062/1436] staging: vt6655: Update function description The function vt6655_get_current_tsf has been updated while its description has not. Update the description to correctly reflect what it does. Signed-off-by: Nam Cao Link: https://lore.kernel.org/r/20220529160211.GA5805@nam-dell Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/card.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index abc74a5633c7..3380c7604e84 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -723,9 +723,9 @@ u64 CARDqGetTSFOffset(unsigned char byRxRate, u64 qwTSF1, u64 qwTSF2) * In: * priv - The adapter to be read * Out: - * qwCurrTSF - Current TSF counter + * none * - * Return Value: true if success; otherwise false + * Return Value: Current TSF counter */ u64 vt6655_get_current_tsf(struct vnt_private *priv) { From d2a4bc3d979fda657729a5ea6b8dc6c6978fabb2 Mon Sep 17 00:00:00 2001 From: Xiang wangx Date: Fri, 3 Jun 2022 21:07:02 +0800 Subject: [PATCH 0063/1436] staging: rtl8192u: Fix syntax errors in comments Delete the redundant word 'tx'. Signed-off-by: Xiang wangx Link: https://lore.kernel.org/r/20220603130702.6926-1-wangxiang@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/r8192U_dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c index 725bf5ca9e34..916618ddc4b7 100644 --- a/drivers/staging/rtl8192u/r8192U_dm.c +++ b/drivers/staging/rtl8192u/r8192U_dm.c @@ -3002,7 +3002,7 @@ static void dm_check_txrateandretrycount(struct net_device *dev) /* for initial tx rate */ /*priv->stats.last_packet_rate = read_nic_byte(dev, INITIAL_TX_RATE_REG);*/ read_nic_byte(dev, INITIAL_TX_RATE_REG, &ieee->softmac_stats.last_packet_rate); - /* for tx tx retry count */ + /* for tx retry count */ /*priv->stats.txretrycount = read_nic_dword(dev, TX_RETRY_COUNT_REG);*/ read_nic_dword(dev, TX_RETRY_COUNT_REG, &ieee->softmac_stats.txretrycount); } From d8d307e681f8bb0ef60ecc8b0e7762ab836cb1fc Mon Sep 17 00:00:00 2001 From: Adrien Thierry Date: Wed, 18 May 2022 15:11:12 -0400 Subject: [PATCH 0064/1436] staging: vchiq_arm: add reference to vchiq device in vchiq_state Add a reference to the vchiq device in the vchiq_state structure. This allows the device structure to be passed around, which will be useful in order to get rid of the global g_dev structure. This change will also make it possible to use standard kernel logging macros instead of the custom ones. Tested-by: Stefan Wahren Signed-off-by: Adrien Thierry Link: https://lore.kernel.org/r/20220518191126.60396-2-athierry@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 2 +- .../staging/vc04_services/interface/vchiq_arm/vchiq_core.c | 4 +++- .../staging/vc04_services/interface/vchiq_arm/vchiq_core.h | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 0596ac61e286..e6e0737c85fc 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -519,7 +519,7 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) *(char **)&g_fragments_base[i * g_fragments_size] = NULL; sema_init(&g_free_fragments_sema, MAX_FRAGMENTS); - err = vchiq_init_state(state, vchiq_slot_zero); + err = vchiq_init_state(state, vchiq_slot_zero, dev); if (err) return err; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 8f99272dbd6f..0d5c39d7c6e2 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -2142,7 +2142,7 @@ vchiq_init_slots(void *mem_base, int mem_size) } int -vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero) +vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero, struct device *dev) { struct vchiq_shared_state *local; struct vchiq_shared_state *remote; @@ -2169,6 +2169,8 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero) memset(state, 0, sizeof(struct vchiq_state)); + state->dev = dev; + /* * initialize shared state pointers */ diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 1ddc661642a9..8b3e2b697c33 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -314,6 +314,7 @@ struct vchiq_slot_zero { }; struct vchiq_state { + struct device *dev; int id; int initialised; enum vchiq_connstate conn_state; @@ -457,7 +458,7 @@ extern struct vchiq_slot_zero * vchiq_init_slots(void *mem_base, int mem_size); extern int -vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero); +vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero, struct device *dev); extern enum vchiq_status vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instance); From 813fa44c74225203d82a8f608ef524b2bd71c3df Mon Sep 17 00:00:00 2001 From: Adrien Thierry Date: Wed, 18 May 2022 15:11:13 -0400 Subject: [PATCH 0065/1436] staging: vchiq_arm: get rid of global device structure Get rid of the global g_dev structure. This is part of an effort to address TODO item "Get rid of all non essential global structures and create a proper per device structure" I chose to pass the vchiq_instance around instead of the device reference because in order to get rid of the 'vchiq_states' global array in the future, we will need another way to access the vchiq_state in the 'handle_to_service' function. Therefore, we will need to pass the vchiq_instance to it (or the vchiq_state), and also pass it to functions higher up in the caller chain, such as 'vchiq_bulk_transmit' and friends which are used in the bcm2835-audio consumer. Tested-by: Stefan Wahren Signed-off-by: Adrien Thierry Link: https://lore.kernel.org/r/20220518191126.60396-3-athierry@redhat.com Signed-off-by: Greg Kroah-Hartman --- .../bcm2835-audio/bcm2835-vchiq.c | 7 ++- .../include/linux/raspberrypi/vchiq.h | 12 ++-- .../interface/vchiq_arm/vchiq_arm.c | 63 +++++++++---------- .../interface/vchiq_arm/vchiq_core.c | 14 ++--- .../interface/vchiq_arm/vchiq_core.h | 10 +-- .../interface/vchiq_arm/vchiq_dev.c | 2 +- .../vc04_services/vchiq-mmal/mmal-vchiq.c | 2 +- 7 files changed, 53 insertions(+), 57 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c index e429b33b4d39..701abe430877 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c @@ -322,6 +322,8 @@ int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream, unsigned int size, void *src) { struct bcm2835_audio_instance *instance = alsa_stream->instance; + struct bcm2835_vchi_ctx *vchi_ctx = alsa_stream->chip->vchi_ctx; + struct vchiq_instance *vchiq_instance = vchi_ctx->instance; struct vc_audio_msg m = { .type = VC_AUDIO_MSG_TYPE_WRITE, .write.count = size, @@ -343,9 +345,8 @@ int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream, count = size; if (!instance->max_packet) { /* Send the message to the videocore */ - status = vchiq_bulk_transmit(instance->service_handle, src, - count, NULL, - VCHIQ_BULK_MODE_BLOCKING); + status = vchiq_bulk_transmit(vchiq_instance, instance->service_handle, src, count, + NULL, VCHIQ_BULK_MODE_BLOCKING); } else { while (count > 0) { int bytes = min(instance->max_packet, count); diff --git a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h index c93f2f3e87bb..715f02e7f1e1 100644 --- a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h +++ b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h @@ -96,12 +96,12 @@ extern void vchiq_release_message(unsigned int service, struct vchiq_header *header); extern int vchiq_queue_kernel_message(unsigned int handle, void *data, unsigned int size); -extern enum vchiq_status vchiq_bulk_transmit(unsigned int service, - const void *data, unsigned int size, void *userdata, - enum vchiq_bulk_mode mode); -extern enum vchiq_status vchiq_bulk_receive(unsigned int service, - void *data, unsigned int size, void *userdata, - enum vchiq_bulk_mode mode); +extern enum vchiq_status vchiq_bulk_transmit(struct vchiq_instance *instance, unsigned int service, + const void *data, unsigned int size, void *userdata, + enum vchiq_bulk_mode mode); +extern enum vchiq_status vchiq_bulk_receive(struct vchiq_instance *instance, unsigned int service, + void *data, unsigned int size, void *userdata, + enum vchiq_bulk_mode mode); extern void *vchiq_get_service_userdata(unsigned int service); extern enum vchiq_status vchiq_get_peer_version(unsigned int handle, short *peer_version); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index e6e0737c85fc..3b447c635c3f 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -148,12 +148,11 @@ static unsigned int g_fragments_size; static char *g_fragments_base; static char *g_free_fragments; static struct semaphore g_free_fragments_sema; -static struct device *g_dev; static DEFINE_SEMAPHORE(g_free_fragments_mutex); static enum vchiq_status -vchiq_blocking_bulk_transfer(unsigned int handle, void *data, +vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data, unsigned int size, enum vchiq_bulk_dir dir); static irqreturn_t @@ -175,17 +174,17 @@ vchiq_doorbell_irq(int irq, void *dev_id) } static void -cleanup_pagelistinfo(struct vchiq_pagelist_info *pagelistinfo) +cleanup_pagelistinfo(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo) { if (pagelistinfo->scatterlist_mapped) { - dma_unmap_sg(g_dev, pagelistinfo->scatterlist, + dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist, pagelistinfo->num_pages, pagelistinfo->dma_dir); } if (pagelistinfo->pages_need_release) unpin_user_pages(pagelistinfo->pages, pagelistinfo->num_pages); - dma_free_coherent(g_dev, pagelistinfo->pagelist_buffer_size, + dma_free_coherent(instance->state->dev, pagelistinfo->pagelist_buffer_size, pagelistinfo->pagelist, pagelistinfo->dma_addr); } @@ -212,7 +211,7 @@ is_adjacent_block(u32 *addrs, u32 addr, unsigned int k) */ static struct vchiq_pagelist_info * -create_pagelist(char *buf, char __user *ubuf, +create_pagelist(struct vchiq_instance *instance, char *buf, char __user *ubuf, size_t count, unsigned short type) { struct pagelist *pagelist; @@ -250,7 +249,7 @@ create_pagelist(char *buf, char __user *ubuf, /* Allocate enough storage to hold the page pointers and the page * list */ - pagelist = dma_alloc_coherent(g_dev, pagelist_size, &dma_addr, + pagelist = dma_alloc_coherent(instance->state->dev, pagelist_size, &dma_addr, GFP_KERNEL); vchiq_log_trace(vchiq_arm_log_level, "%s - %pK", __func__, pagelist); @@ -292,7 +291,7 @@ create_pagelist(char *buf, char __user *ubuf, size_t bytes = PAGE_SIZE - off; if (!pg) { - cleanup_pagelistinfo(pagelistinfo); + cleanup_pagelistinfo(instance, pagelistinfo); return NULL; } @@ -315,7 +314,7 @@ create_pagelist(char *buf, char __user *ubuf, /* This is probably due to the process being killed */ if (actual_pages > 0) unpin_user_pages(pages, actual_pages); - cleanup_pagelistinfo(pagelistinfo); + cleanup_pagelistinfo(instance, pagelistinfo); return NULL; } /* release user pages */ @@ -338,13 +337,13 @@ create_pagelist(char *buf, char __user *ubuf, count -= len; } - dma_buffers = dma_map_sg(g_dev, + dma_buffers = dma_map_sg(instance->state->dev, scatterlist, num_pages, pagelistinfo->dma_dir); if (dma_buffers == 0) { - cleanup_pagelistinfo(pagelistinfo); + cleanup_pagelistinfo(instance, pagelistinfo); return NULL; } @@ -378,7 +377,7 @@ create_pagelist(char *buf, char __user *ubuf, char *fragments; if (down_interruptible(&g_free_fragments_sema)) { - cleanup_pagelistinfo(pagelistinfo); + cleanup_pagelistinfo(instance, pagelistinfo); return NULL; } @@ -397,7 +396,7 @@ create_pagelist(char *buf, char __user *ubuf, } static void -free_pagelist(struct vchiq_pagelist_info *pagelistinfo, +free_pagelist(struct vchiq_instance *instance, struct vchiq_pagelist_info *pagelistinfo, int actual) { struct pagelist *pagelist = pagelistinfo->pagelist; @@ -411,7 +410,7 @@ free_pagelist(struct vchiq_pagelist_info *pagelistinfo, * NOTE: dma_unmap_sg must be called before the * cpu can touch any of the data/pages. */ - dma_unmap_sg(g_dev, pagelistinfo->scatterlist, + dma_unmap_sg(instance->state->dev, pagelistinfo->scatterlist, pagelistinfo->num_pages, pagelistinfo->dma_dir); pagelistinfo->scatterlist_mapped = 0; @@ -460,7 +459,7 @@ free_pagelist(struct vchiq_pagelist_info *pagelistinfo, set_page_dirty(pages[i]); } - cleanup_pagelistinfo(pagelistinfo); + cleanup_pagelistinfo(instance, pagelistinfo); } int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) @@ -547,7 +546,6 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) return err ? : -ENXIO; } - g_dev = dev; vchiq_log_info(vchiq_arm_log_level, "vchiq_init - done (slots %pK, phys %pad)", vchiq_slot_zero, &slot_phys); @@ -615,12 +613,12 @@ remote_event_signal(struct remote_event *event) } int -vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset, +vchiq_prepare_bulk_data(struct vchiq_instance *instance, struct vchiq_bulk *bulk, void *offset, void __user *uoffset, int size, int dir) { struct vchiq_pagelist_info *pagelistinfo; - pagelistinfo = create_pagelist(offset, uoffset, size, + pagelistinfo = create_pagelist(instance, offset, uoffset, size, (dir == VCHIQ_BULK_RECEIVE) ? PAGELIST_READ : PAGELIST_WRITE); @@ -640,10 +638,10 @@ vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset, } void -vchiq_complete_bulk(struct vchiq_bulk *bulk) +vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bulk) { if (bulk && bulk->remote_data && bulk->actual) - free_pagelist((struct vchiq_pagelist_info *)bulk->remote_data, + free_pagelist(instance, (struct vchiq_pagelist_info *)bulk->remote_data, bulk->actual); } @@ -834,8 +832,8 @@ failed: EXPORT_SYMBOL(vchiq_open_service); enum vchiq_status -vchiq_bulk_transmit(unsigned int handle, const void *data, unsigned int size, - void *userdata, enum vchiq_bulk_mode mode) +vchiq_bulk_transmit(struct vchiq_instance *instance, unsigned int handle, const void *data, + unsigned int size, void *userdata, enum vchiq_bulk_mode mode) { enum vchiq_status status; @@ -843,13 +841,13 @@ vchiq_bulk_transmit(unsigned int handle, const void *data, unsigned int size, switch (mode) { case VCHIQ_BULK_MODE_NOCALLBACK: case VCHIQ_BULK_MODE_CALLBACK: - status = vchiq_bulk_transfer(handle, + status = vchiq_bulk_transfer(instance, handle, (void *)data, NULL, size, userdata, mode, VCHIQ_BULK_TRANSMIT); break; case VCHIQ_BULK_MODE_BLOCKING: - status = vchiq_blocking_bulk_transfer(handle, (void *)data, size, + status = vchiq_blocking_bulk_transfer(instance, handle, (void *)data, size, VCHIQ_BULK_TRANSMIT); break; default: @@ -871,8 +869,8 @@ vchiq_bulk_transmit(unsigned int handle, const void *data, unsigned int size, } EXPORT_SYMBOL(vchiq_bulk_transmit); -enum vchiq_status vchiq_bulk_receive(unsigned int handle, void *data, - unsigned int size, void *userdata, +enum vchiq_status vchiq_bulk_receive(struct vchiq_instance *instance, unsigned int handle, + void *data, unsigned int size, void *userdata, enum vchiq_bulk_mode mode) { enum vchiq_status status; @@ -881,12 +879,12 @@ enum vchiq_status vchiq_bulk_receive(unsigned int handle, void *data, switch (mode) { case VCHIQ_BULK_MODE_NOCALLBACK: case VCHIQ_BULK_MODE_CALLBACK: - status = vchiq_bulk_transfer(handle, data, NULL, + status = vchiq_bulk_transfer(instance, handle, data, NULL, size, userdata, mode, VCHIQ_BULK_RECEIVE); break; case VCHIQ_BULK_MODE_BLOCKING: - status = vchiq_blocking_bulk_transfer(handle, (void *)data, size, + status = vchiq_blocking_bulk_transfer(instance, handle, (void *)data, size, VCHIQ_BULK_RECEIVE); break; default: @@ -909,10 +907,9 @@ enum vchiq_status vchiq_bulk_receive(unsigned int handle, void *data, EXPORT_SYMBOL(vchiq_bulk_receive); static enum vchiq_status -vchiq_blocking_bulk_transfer(unsigned int handle, void *data, unsigned int size, - enum vchiq_bulk_dir dir) +vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *data, + unsigned int size, enum vchiq_bulk_dir dir) { - struct vchiq_instance *instance; struct vchiq_service *service; enum vchiq_status status; struct bulk_waiter_node *waiter = NULL, *iter; @@ -921,8 +918,6 @@ vchiq_blocking_bulk_transfer(unsigned int handle, void *data, unsigned int size, if (!service) return VCHIQ_ERROR; - instance = service->instance; - vchiq_service_put(service); mutex_lock(&instance->bulk_waiter_list_mutex); @@ -959,7 +954,7 @@ vchiq_blocking_bulk_transfer(unsigned int handle, void *data, unsigned int size, } } - status = vchiq_bulk_transfer(handle, data, NULL, size, + status = vchiq_bulk_transfer(instance, handle, data, NULL, size, &waiter->bulk_waiter, VCHIQ_BULK_MODE_BLOCKING, dir); if ((status != VCHIQ_RETRY) || fatal_signal_pending(current) || !waiter->bulk_waiter.bulk) { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 0d5c39d7c6e2..04eec18835da 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -1441,7 +1441,7 @@ abort_outstanding_bulks(struct vchiq_service *service, } if (queue->process != queue->local_insert) { - vchiq_complete_bulk(bulk); + vchiq_complete_bulk(service->instance, bulk); vchiq_log_info(SRVTRACE_LEVEL(service), "%s %c%c%c%c d:%d ABORTED - tx len:%d, rx len:%d", @@ -1769,7 +1769,7 @@ parse_message(struct vchiq_state *state, struct vchiq_header *header) DEBUG_TRACE(PARSE_LINE); WARN_ON(queue->process == queue->local_insert); - vchiq_complete_bulk(bulk); + vchiq_complete_bulk(service->instance, bulk); queue->process++; mutex_unlock(&service->bulk_mutex); DEBUG_TRACE(PARSE_LINE); @@ -2998,9 +2998,9 @@ vchiq_remove_service(unsigned int handle) * When called in blocking mode, the userdata field points to a bulk_waiter * structure. */ -enum vchiq_status vchiq_bulk_transfer(unsigned int handle, void *offset, void __user *uoffset, - int size, void *userdata, enum vchiq_bulk_mode mode, - enum vchiq_bulk_dir dir) +enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, + void *offset, void __user *uoffset, int size, void *userdata, + enum vchiq_bulk_mode mode, enum vchiq_bulk_dir dir) { struct vchiq_service *service = find_service_by_handle(handle); struct vchiq_bulk_queue *queue; @@ -3077,7 +3077,7 @@ enum vchiq_status vchiq_bulk_transfer(unsigned int handle, void *offset, void __ bulk->size = size; bulk->actual = VCHIQ_BULK_ACTUAL_ABORTED; - if (vchiq_prepare_bulk_data(bulk, offset, uoffset, size, dir)) + if (vchiq_prepare_bulk_data(instance, bulk, offset, uoffset, size, dir)) goto unlock_error_exit; wmb(); @@ -3141,7 +3141,7 @@ waiting: unlock_both_error_exit: mutex_unlock(&state->slot_mutex); cancel_bulk_error_exit: - vchiq_complete_bulk(bulk); + vchiq_complete_bulk(service->instance, bulk); unlock_error_exit: mutex_unlock(&service->bulk_mutex); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 8b3e2b697c33..2eca7b31fff5 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -488,8 +488,8 @@ extern void remote_event_pollall(struct vchiq_state *state); extern enum vchiq_status -vchiq_bulk_transfer(unsigned int handle, void *offset, void __user *uoffset, - int size, void *userdata, enum vchiq_bulk_mode mode, +vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned int handle, void *offset, + void __user *uoffset, int size, void *userdata, enum vchiq_bulk_mode mode, enum vchiq_bulk_dir dir); extern int @@ -555,10 +555,10 @@ vchiq_queue_message(unsigned int handle, void *context, size_t size); -int vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset, void __user *uoffset, - int size, int dir); +int vchiq_prepare_bulk_data(struct vchiq_instance *instance, struct vchiq_bulk *bulk, void *offset, + void __user *uoffset, int size, int dir); -void vchiq_complete_bulk(struct vchiq_bulk *bulk); +void vchiq_complete_bulk(struct vchiq_instance *instance, struct vchiq_bulk *bulk); void remote_event_signal(struct remote_event *event); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c index 66bbfec332ba..077e3fcbd651 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c @@ -330,7 +330,7 @@ static int vchiq_irq_queue_bulk_tx_rx(struct vchiq_instance *instance, userdata = args->userdata; } - status = vchiq_bulk_transfer(args->handle, NULL, args->data, args->size, + status = vchiq_bulk_transfer(instance, args->handle, NULL, args->data, args->size, userdata, args->mode, dir); if (!waiter) { diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c index 845b20e4d05a..145021af93b2 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c @@ -293,7 +293,7 @@ static void buffer_to_host_work_cb(struct work_struct *work) len = 8; /* queue the bulk submission */ vchiq_use_service(instance->service_handle); - ret = vchiq_bulk_receive(instance->service_handle, + ret = vchiq_bulk_receive(instance->vchiq_instance, instance->service_handle, msg_context->u.bulk.buffer->buffer, /* Actual receive needs to be a multiple * of 4 bytes From 726e79f8a64891552ffe272e05f49ed9710fca89 Mon Sep 17 00:00:00 2001 From: Adrien Thierry Date: Wed, 18 May 2022 15:11:14 -0400 Subject: [PATCH 0066/1436] staging: vchiq_arm: pass vchiq instance to service callbacks In order to remove the 'vchiq_states' global array, we need to pass the vchiq_instance reference to the 'handle_to_service' function, as well as to all functions that call 'handle_to_service'. This will allow accessing the vchiq state through the vchiq instance instead of through the global array. 'handle_to_service' is called by 'service_callback'. Therefore, pass the vchiq instance reference to 'service_callback'. This also requires adding the vchiq instance reference to the service callbacks prototype, and update all other callbacks accordingly. Tested-by: Stefan Wahren Signed-off-by: Adrien Thierry Link: https://lore.kernel.org/r/20220518191126.60396-4-athierry@redhat.com Signed-off-by: Greg Kroah-Hartman --- .../staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c | 3 ++- .../vc04_services/include/linux/raspberrypi/vchiq.h | 8 ++++++-- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 9 ++++----- .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 4 ++-- .../vc04_services/interface/vchiq_arm/vchiq_core.c | 3 ++- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 3 ++- 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c index 701abe430877..c32c8c93a615 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c @@ -89,7 +89,8 @@ static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance, return bcm2835_audio_send_msg(instance, &m, wait); } -static enum vchiq_status audio_vchi_callback(enum vchiq_reason reason, +static enum vchiq_status audio_vchi_callback(struct vchiq_instance *vchiq_instance, + enum vchiq_reason reason, struct vchiq_header *header, unsigned int handle, void *userdata) { diff --git a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h index 715f02e7f1e1..97537d3b1d28 100644 --- a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h +++ b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h @@ -53,9 +53,12 @@ struct vchiq_element { unsigned int size; }; +struct vchiq_instance; + struct vchiq_service_base { int fourcc; - enum vchiq_status (*callback)(enum vchiq_reason reason, + enum vchiq_status (*callback)(struct vchiq_instance *instance, + enum vchiq_reason reason, struct vchiq_header *header, unsigned int handle, void *bulk_userdata); @@ -71,7 +74,8 @@ struct vchiq_completion_data_kernel { struct vchiq_service_params_kernel { int fourcc; - enum vchiq_status (*callback)(enum vchiq_reason reason, + enum vchiq_status (*callback)(struct vchiq_instance *instance, + enum vchiq_reason reason, struct vchiq_header *header, unsigned int handle, void *bulk_userdata); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 3b447c635c3f..ffb24298e26b 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -1041,8 +1041,8 @@ add_completion(struct vchiq_instance *instance, enum vchiq_reason reason, } enum vchiq_status -service_callback(enum vchiq_reason reason, struct vchiq_header *header, - unsigned int handle, void *bulk_userdata) +service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, + struct vchiq_header *header, unsigned int handle, void *bulk_userdata) { /* * How do we ensure the callback goes to the right client? @@ -1052,7 +1052,6 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header, */ struct user_service *user_service; struct vchiq_service *service; - struct vchiq_instance *instance; bool skip_completion = false; DEBUG_INITIALISE(g_state.local); @@ -1067,7 +1066,6 @@ service_callback(enum vchiq_reason reason, struct vchiq_header *header, } user_service = (struct user_service *)service->base.userdata; - instance = user_service->instance; if (!instance || instance->closing) { rcu_read_unlock(); @@ -1313,7 +1311,8 @@ vchiq_get_state(void) */ static enum vchiq_status -vchiq_keepalive_vchiq_callback(enum vchiq_reason reason, +vchiq_keepalive_vchiq_callback(struct vchiq_instance *instance, + enum vchiq_reason reason, struct vchiq_header *header, unsigned int service_user, void *bulk_user) { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index 2aa46b119a46..f671c3976ab7 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -138,8 +138,8 @@ static inline int vchiq_register_chrdev(struct device *parent) { return 0; } #endif /* IS_ENABLED(CONFIG_VCHIQ_CDEV) */ extern enum vchiq_status -service_callback(enum vchiq_reason reason, struct vchiq_header *header, - unsigned int handle, void *bulk_userdata); +service_callback(struct vchiq_instance *vchiq_instance, enum vchiq_reason reason, + struct vchiq_header *header, unsigned int handle, void *bulk_userdata); extern void free_bulk_waiter(struct vchiq_instance *instance); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 04eec18835da..547af55d3859 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -466,7 +466,8 @@ make_service_callback(struct vchiq_service *service, enum vchiq_reason reason, vchiq_log_trace(vchiq_core_log_level, "%d: callback:%d (%s, %pK, %pK)", service->state->id, service->localport, reason_names[reason], header, bulk_userdata); - status = service->base.callback(reason, header, service->handle, bulk_userdata); + status = service->base.callback(service->instance, reason, header, service->handle, + bulk_userdata); if (status == VCHIQ_ERROR) { vchiq_log_warning(vchiq_core_log_level, "%d: ignoring ERROR from callback to service %x", diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c index 145021af93b2..55f290b64d6a 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c @@ -548,7 +548,8 @@ static void bulk_abort_cb(struct vchiq_mmal_instance *instance, } /* incoming event service callback */ -static enum vchiq_status service_callback(enum vchiq_reason reason, +static enum vchiq_status service_callback(struct vchiq_instance *vchiq_instance, + enum vchiq_reason reason, struct vchiq_header *header, unsigned int handle, void *bulk_ctx) { From 14780bb174266e155e2b586fe9ba716087f91269 Mon Sep 17 00:00:00 2001 From: Adrien Thierry Date: Wed, 18 May 2022 15:11:15 -0400 Subject: [PATCH 0067/1436] staging: vchiq_arm: pass vchiq instance to 'find_service_by_handle' In order to remove the 'vchiq_states' global array, we need to pass the vchiq_instance reference to the 'handle_to_service' function, as well as to all functions that call 'handle_to_service'. This will allow accessing the vchiq state through the vchiq instance instead of through the global array. 'handle_to_service' is called by 'find_service_by_handle'. Therefore, pass the vchiq instance reference to 'find_service_by_handle' and to its callers. Tested-by: Stefan Wahren Signed-off-by: Adrien Thierry Link: https://lore.kernel.org/r/20220518191126.60396-5-athierry@redhat.com Signed-off-by: Greg Kroah-Hartman --- .../bcm2835-audio/bcm2835-vchiq.c | 27 +++++---- .../include/linux/raspberrypi/vchiq.h | 26 +++++---- .../interface/vchiq_arm/vchiq_arm.c | 16 +++--- .../interface/vchiq_arm/vchiq_arm.h | 4 +- .../interface/vchiq_arm/vchiq_core.c | 47 ++++++++-------- .../interface/vchiq_arm/vchiq_core.h | 9 +-- .../interface/vchiq_arm/vchiq_dev.c | 36 ++++++------ .../vc04_services/vchiq-mmal/mmal-vchiq.c | 56 +++++++++---------- 8 files changed, 118 insertions(+), 103 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c index c32c8c93a615..aa2ab0df7af5 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c @@ -25,12 +25,14 @@ MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio"); static void bcm2835_audio_lock(struct bcm2835_audio_instance *instance) { mutex_lock(&instance->vchi_mutex); - vchiq_use_service(instance->service_handle); + vchiq_use_service(instance->alsa_stream->chip->vchi_ctx->instance, + instance->service_handle); } static void bcm2835_audio_unlock(struct bcm2835_audio_instance *instance) { - vchiq_release_service(instance->service_handle); + vchiq_release_service(instance->alsa_stream->chip->vchi_ctx->instance, + instance->service_handle); mutex_unlock(&instance->vchi_mutex); } @@ -44,8 +46,8 @@ static int bcm2835_audio_send_msg_locked(struct bcm2835_audio_instance *instance init_completion(&instance->msg_avail_comp); } - status = vchiq_queue_kernel_message(instance->service_handle, - m, sizeof(*m)); + status = vchiq_queue_kernel_message(instance->alsa_stream->chip->vchi_ctx->instance, + instance->service_handle, m, sizeof(*m)); if (status) { dev_err(instance->dev, "vchi message queue failed: %d, msg=%d\n", @@ -115,7 +117,7 @@ static enum vchiq_status audio_vchi_callback(struct vchiq_instance *vchiq_instan dev_err(instance->dev, "unexpected callback type=%d\n", m->type); } - vchiq_release_message(handle, header); + vchiq_release_message(vchiq_instance, instance->service_handle, header); return VCHIQ_SUCCESS; } @@ -144,7 +146,8 @@ vc_vchi_audio_init(struct vchiq_instance *vchiq_instance, } /* Finished with the service for now */ - vchiq_release_service(instance->service_handle); + vchiq_release_service(instance->alsa_stream->chip->vchi_ctx->instance, + instance->service_handle); return 0; } @@ -154,10 +157,12 @@ static void vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance) int status; mutex_lock(&instance->vchi_mutex); - vchiq_use_service(instance->service_handle); + vchiq_use_service(instance->alsa_stream->chip->vchi_ctx->instance, + instance->service_handle); /* Close all VCHI service connections */ - status = vchiq_close_service(instance->service_handle); + status = vchiq_close_service(instance->alsa_stream->chip->vchi_ctx->instance, + instance->service_handle); if (status) { dev_err(instance->dev, "failed to close VCHI service connection (status=%d)\n", @@ -227,7 +232,7 @@ int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream) goto deinit; bcm2835_audio_lock(instance); - vchiq_get_peer_version(instance->service_handle, + vchiq_get_peer_version(vchi_ctx->instance, instance->service_handle, &instance->peer_version); bcm2835_audio_unlock(instance); if (instance->peer_version < 2 || force_bulk) @@ -352,8 +357,8 @@ int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream, while (count > 0) { int bytes = min(instance->max_packet, count); - status = vchiq_queue_kernel_message(instance->service_handle, - src, bytes); + status = vchiq_queue_kernel_message(vchiq_instance, + instance->service_handle, src, bytes); src += bytes; count -= bytes; } diff --git a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h index 97537d3b1d28..0d3833e9773c 100644 --- a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h +++ b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h @@ -92,14 +92,17 @@ extern enum vchiq_status vchiq_connect(struct vchiq_instance *instance); extern enum vchiq_status vchiq_open_service(struct vchiq_instance *instance, const struct vchiq_service_params_kernel *params, unsigned int *pservice); -extern enum vchiq_status vchiq_close_service(unsigned int service); -extern enum vchiq_status vchiq_use_service(unsigned int service); -extern enum vchiq_status vchiq_release_service(unsigned int service); -extern void vchiq_msg_queue_push(unsigned int handle, struct vchiq_header *header); -extern void vchiq_release_message(unsigned int service, - struct vchiq_header *header); -extern int vchiq_queue_kernel_message(unsigned int handle, void *data, - unsigned int size); +extern enum vchiq_status vchiq_close_service(struct vchiq_instance *instance, + unsigned int service); +extern enum vchiq_status vchiq_use_service(struct vchiq_instance *instance, unsigned int service); +extern enum vchiq_status vchiq_release_service(struct vchiq_instance *instance, + unsigned int service); +extern void vchiq_msg_queue_push(struct vchiq_instance *instance, unsigned int handle, + struct vchiq_header *header); +extern void vchiq_release_message(struct vchiq_instance *instance, unsigned int service, + struct vchiq_header *header); +extern int vchiq_queue_kernel_message(struct vchiq_instance *instance, unsigned int handle, + void *data, unsigned int size); extern enum vchiq_status vchiq_bulk_transmit(struct vchiq_instance *instance, unsigned int service, const void *data, unsigned int size, void *userdata, enum vchiq_bulk_mode mode); @@ -107,8 +110,9 @@ extern enum vchiq_status vchiq_bulk_receive(struct vchiq_instance *instance, uns void *data, unsigned int size, void *userdata, enum vchiq_bulk_mode mode); extern void *vchiq_get_service_userdata(unsigned int service); -extern enum vchiq_status vchiq_get_peer_version(unsigned int handle, - short *peer_version); -extern struct vchiq_header *vchiq_msg_hold(unsigned int handle); +extern enum vchiq_status vchiq_get_peer_version(struct vchiq_instance *instance, + unsigned int handle, + short *peer_version); +extern struct vchiq_header *vchiq_msg_hold(struct vchiq_instance *instance, unsigned int handle); #endif /* VCHIQ_H */ diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index ffb24298e26b..a5f0a756b32c 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -819,7 +819,7 @@ vchiq_open_service(struct vchiq_instance *instance, *phandle = service->handle; status = vchiq_open_service_internal(service, current->pid); if (status != VCHIQ_SUCCESS) { - vchiq_remove_service(service->handle); + vchiq_remove_service(instance, service->handle); *phandle = VCHIQ_SERVICE_HANDLE_INVALID; } } @@ -914,7 +914,7 @@ vchiq_blocking_bulk_transfer(struct vchiq_instance *instance, unsigned int handl enum vchiq_status status; struct bulk_waiter_node *waiter = NULL, *iter; - service = find_service_by_handle(handle); + service = find_service_by_handle(instance, handle); if (!service) return VCHIQ_ERROR; @@ -1381,14 +1381,14 @@ vchiq_keepalive_thread_func(void *v) */ while (uc--) { atomic_inc(&arm_state->ka_use_ack_count); - status = vchiq_use_service(ka_handle); + status = vchiq_use_service(instance, ka_handle); if (status != VCHIQ_SUCCESS) { vchiq_log_error(vchiq_susp_log_level, "%s vchiq_use_service error %d", __func__, status); } } while (rc--) { - status = vchiq_release_service(ka_handle); + status = vchiq_release_service(instance, ka_handle); if (status != VCHIQ_SUCCESS) { vchiq_log_error(vchiq_susp_log_level, "%s vchiq_release_service error %d", __func__, @@ -1584,10 +1584,10 @@ vchiq_instance_set_trace(struct vchiq_instance *instance, int trace) } enum vchiq_status -vchiq_use_service(unsigned int handle) +vchiq_use_service(struct vchiq_instance *instance, unsigned int handle) { enum vchiq_status ret = VCHIQ_ERROR; - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); if (service) { ret = vchiq_use_internal(service->state, service, USE_TYPE_SERVICE); @@ -1598,10 +1598,10 @@ vchiq_use_service(unsigned int handle) EXPORT_SYMBOL(vchiq_use_service); enum vchiq_status -vchiq_release_service(unsigned int handle) +vchiq_release_service(struct vchiq_instance *instance, unsigned int handle) { enum vchiq_status ret = VCHIQ_ERROR; - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); if (service) { ret = vchiq_release_internal(service->state, service); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index f671c3976ab7..2851ef6b9cd0 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -86,10 +86,10 @@ extern struct vchiq_state * vchiq_get_state(void); enum vchiq_status -vchiq_use_service(unsigned int handle); +vchiq_use_service(struct vchiq_instance *instance, unsigned int handle); extern enum vchiq_status -vchiq_release_service(unsigned int handle); +vchiq_release_service(struct vchiq_instance *instance, unsigned int handle); extern enum vchiq_status vchiq_check_service(struct vchiq_service *service); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 547af55d3859..7217e3070ffe 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -235,7 +235,7 @@ set_service_state(struct vchiq_service *service, int newstate) } struct vchiq_service * -find_service_by_handle(unsigned int handle) +find_service_by_handle(struct vchiq_instance *instance, unsigned int handle) { struct vchiq_service *service; @@ -476,7 +476,7 @@ make_service_callback(struct vchiq_service *service, enum vchiq_reason reason, } if (reason != VCHIQ_MESSAGE_AVAILABLE) - vchiq_release_message(service->handle, header); + vchiq_release_message(service->instance, service->handle, header); return status; } @@ -2290,9 +2290,10 @@ fail_free_handler_thread: return ret; } -void vchiq_msg_queue_push(unsigned int handle, struct vchiq_header *header) +void vchiq_msg_queue_push(struct vchiq_instance *instance, unsigned int handle, + struct vchiq_header *header) { - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); int pos; if (!service) @@ -2312,9 +2313,9 @@ void vchiq_msg_queue_push(unsigned int handle, struct vchiq_header *header) } EXPORT_SYMBOL(vchiq_msg_queue_push); -struct vchiq_header *vchiq_msg_hold(unsigned int handle) +struct vchiq_header *vchiq_msg_hold(struct vchiq_instance *instance, unsigned int handle) { - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); struct vchiq_header *header; int pos; @@ -2869,16 +2870,16 @@ vchiq_shutdown_internal(struct vchiq_state *state, struct vchiq_instance *instan /* Find all services registered to this client and remove them. */ i = 0; while ((service = next_service_by_instance(state, instance, &i)) != NULL) { - (void)vchiq_remove_service(service->handle); + (void)vchiq_remove_service(instance, service->handle); vchiq_service_put(service); } } enum vchiq_status -vchiq_close_service(unsigned int handle) +vchiq_close_service(struct vchiq_instance *instance, unsigned int handle) { /* Unregister the service */ - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); enum vchiq_status status = VCHIQ_SUCCESS; if (!service) @@ -2933,10 +2934,10 @@ vchiq_close_service(unsigned int handle) EXPORT_SYMBOL(vchiq_close_service); enum vchiq_status -vchiq_remove_service(unsigned int handle) +vchiq_remove_service(struct vchiq_instance *instance, unsigned int handle) { /* Unregister the service */ - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); enum vchiq_status status = VCHIQ_SUCCESS; if (!service) @@ -3003,7 +3004,7 @@ enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned void *offset, void __user *uoffset, int size, void *userdata, enum vchiq_bulk_mode mode, enum vchiq_bulk_dir dir) { - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); struct vchiq_bulk_queue *queue; struct vchiq_bulk *bulk; struct vchiq_state *state; @@ -3153,13 +3154,13 @@ error_exit: } enum vchiq_status -vchiq_queue_message(unsigned int handle, +vchiq_queue_message(struct vchiq_instance *instance, unsigned int handle, ssize_t (*copy_callback)(void *context, void *dest, size_t offset, size_t maxsize), void *context, size_t size) { - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); enum vchiq_status status = VCHIQ_ERROR; int data_id; @@ -3202,12 +3203,13 @@ error_exit: return status; } -int vchiq_queue_kernel_message(unsigned int handle, void *data, unsigned int size) +int vchiq_queue_kernel_message(struct vchiq_instance *instance, unsigned int handle, void *data, + unsigned int size) { enum vchiq_status status; while (1) { - status = vchiq_queue_message(handle, memcpy_copy_callback, + status = vchiq_queue_message(instance, handle, memcpy_copy_callback, data, size); /* @@ -3226,10 +3228,10 @@ int vchiq_queue_kernel_message(unsigned int handle, void *data, unsigned int siz EXPORT_SYMBOL(vchiq_queue_kernel_message); void -vchiq_release_message(unsigned int handle, +vchiq_release_message(struct vchiq_instance *instance, unsigned int handle, struct vchiq_header *header) { - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); struct vchiq_shared_state *remote; struct vchiq_state *state; int slot_index; @@ -3268,10 +3270,10 @@ release_message_sync(struct vchiq_state *state, struct vchiq_header *header) } enum vchiq_status -vchiq_get_peer_version(unsigned int handle, short *peer_version) +vchiq_get_peer_version(struct vchiq_instance *instance, unsigned int handle, short *peer_version) { enum vchiq_status status = VCHIQ_ERROR; - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); if (!service) goto exit; @@ -3303,9 +3305,10 @@ void vchiq_get_config(struct vchiq_config *config) } int -vchiq_set_service_option(unsigned int handle, enum vchiq_service_option option, int value) +vchiq_set_service_option(struct vchiq_instance *instance, unsigned int handle, + enum vchiq_service_option option, int value) { - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service = find_service_by_handle(instance, handle); struct vchiq_service_quota *quota; int ret = -EINVAL; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 2eca7b31fff5..34d8fef7af14 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -521,7 +521,7 @@ handle_to_service(unsigned int handle) } extern struct vchiq_service * -find_service_by_handle(unsigned int handle); +find_service_by_handle(struct vchiq_instance *instance, unsigned int handle); extern struct vchiq_service * find_service_by_port(struct vchiq_state *state, unsigned int localport); @@ -549,7 +549,7 @@ extern void vchiq_service_put(struct vchiq_service *service); extern enum vchiq_status -vchiq_queue_message(unsigned int handle, +vchiq_queue_message(struct vchiq_instance *instance, unsigned int handle, ssize_t (*copy_callback)(void *context, void *dest, size_t offset, size_t maxsize), void *context, @@ -596,12 +596,13 @@ void vchiq_set_conn_state(struct vchiq_state *state, enum vchiq_connstate newsta void vchiq_log_dump_mem(const char *label, u32 addr, const void *void_mem, size_t num_bytes); -enum vchiq_status vchiq_remove_service(unsigned int service); +enum vchiq_status vchiq_remove_service(struct vchiq_instance *instance, unsigned int service); int vchiq_get_client_id(unsigned int service); void vchiq_get_config(struct vchiq_config *config); -int vchiq_set_service_option(unsigned int service, enum vchiq_service_option option, int value); +int vchiq_set_service_option(struct vchiq_instance *instance, unsigned int service, + enum vchiq_service_option option, int value); #endif diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c index 077e3fcbd651..adb616d97652 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c @@ -108,8 +108,8 @@ static ssize_t vchiq_ioc_copy_element_data(void *context, void *dest, } static int -vchiq_ioc_queue_message(unsigned int handle, struct vchiq_element *elements, - unsigned long count) +vchiq_ioc_queue_message(struct vchiq_instance *instance, unsigned int handle, + struct vchiq_element *elements, unsigned long count) { struct vchiq_io_copy_callback_context context; enum vchiq_status status = VCHIQ_SUCCESS; @@ -127,7 +127,7 @@ vchiq_ioc_queue_message(unsigned int handle, struct vchiq_element *elements, total_size += elements[i].size; } - status = vchiq_queue_message(handle, vchiq_ioc_copy_element_data, + status = vchiq_queue_message(instance, handle, vchiq_ioc_copy_element_data, &context, total_size); if (status == VCHIQ_ERROR) @@ -191,7 +191,7 @@ static int vchiq_ioc_create_service(struct vchiq_instance *instance, if (args->is_open) { status = vchiq_open_service_internal(service, instance->pid); if (status != VCHIQ_SUCCESS) { - vchiq_remove_service(service->handle); + vchiq_remove_service(instance, service->handle); return (status == VCHIQ_RETRY) ? -EINTR : -EIO; } @@ -266,7 +266,7 @@ static int vchiq_ioc_dequeue_message(struct vchiq_instance *instance, /* Copy to user space if msgbuf is not NULL */ if (!args->buf || (copy_to_user(args->buf, header->data, header->size) == 0)) { ret = header->size; - vchiq_release_message(service->handle, header); + vchiq_release_message(instance, service->handle, header); } else { ret = -EFAULT; } @@ -529,7 +529,7 @@ static int vchiq_ioc_await_completion(struct vchiq_instance *instance, } /* Now it has been copied, the message can be released. */ - vchiq_release_message(service->handle, header); + vchiq_release_message(instance, service->handle, header); /* The completion must point to the msgbuf. */ user_completion.header = msgbuf; @@ -596,7 +596,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) i = 0; while ((service = next_service_by_instance(instance->state, instance, &i))) { - status = vchiq_remove_service(service->handle); + status = vchiq_remove_service(instance, service->handle); vchiq_service_put(service); if (status != VCHIQ_SUCCESS) break; @@ -649,7 +649,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; if (put_user(args.handle, &argp->handle)) { - vchiq_remove_service(args.handle); + vchiq_remove_service(instance, args.handle); ret = -EFAULT; } } break; @@ -673,8 +673,8 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) */ if (!user_service->close_pending) { status = (cmd == VCHIQ_IOC_CLOSE_SERVICE) ? - vchiq_close_service(service->handle) : - vchiq_remove_service(service->handle); + vchiq_close_service(instance, service->handle) : + vchiq_remove_service(instance, service->handle); if (status != VCHIQ_SUCCESS) break; } @@ -731,7 +731,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (copy_from_user(elements, args.elements, args.count * sizeof(struct vchiq_element)) == 0) - ret = vchiq_ioc_queue_message(args.handle, elements, + ret = vchiq_ioc_queue_message(instance, args.handle, elements, args.count); else ret = -EFAULT; @@ -827,7 +827,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) break; } - ret = vchiq_set_service_option(args.handle, args.option, + ret = vchiq_set_service_option(instance, args.handle, args.option, args.value); } break; @@ -908,6 +908,7 @@ vchiq_compat_ioctl_create_service(struct file *file, unsigned int cmd, { struct vchiq_create_service args; struct vchiq_create_service32 args32; + struct vchiq_instance *instance = file->private_data; long ret; if (copy_from_user(&args32, ptrargs32, sizeof(args32))) @@ -926,12 +927,12 @@ vchiq_compat_ioctl_create_service(struct file *file, unsigned int cmd, .handle = args32.handle, }; - ret = vchiq_ioc_create_service(file->private_data, &args); + ret = vchiq_ioc_create_service(instance, &args); if (ret < 0) return ret; if (put_user(args.handle, &ptrargs32->handle)) { - vchiq_remove_service(args.handle); + vchiq_remove_service(instance, args.handle); return -EFAULT; } @@ -960,6 +961,7 @@ vchiq_compat_ioctl_queue_message(struct file *file, struct vchiq_queue_message args; struct vchiq_queue_message32 args32; struct vchiq_service *service; + struct vchiq_instance *instance = file->private_data; int ret; if (copy_from_user(&args32, arg, sizeof(args32))) @@ -974,7 +976,7 @@ vchiq_compat_ioctl_queue_message(struct file *file, if (args32.count > MAX_ELEMENTS) return -EINVAL; - service = find_service_for_instance(file->private_data, args.handle); + service = find_service_for_instance(instance, args.handle); if (!service) return -EINVAL; @@ -994,7 +996,7 @@ vchiq_compat_ioctl_queue_message(struct file *file, compat_ptr(element32[count].data); elements[count].size = element32[count].size; } - ret = vchiq_ioc_queue_message(args.handle, elements, + ret = vchiq_ioc_queue_message(instance, args.handle, elements, args.count); } else { ret = -EINVAL; @@ -1261,7 +1263,7 @@ static int vchiq_release(struct inode *inode, struct file *file) spin_unlock(&msg_queue_spinlock); if (header) - vchiq_release_message(service->handle, header); + vchiq_release_message(instance, service->handle, header); spin_lock(&msg_queue_spinlock); } diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c index 55f290b64d6a..4c29cb7794a1 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c @@ -292,7 +292,7 @@ static void buffer_to_host_work_cb(struct work_struct *work) /* Dummy receive to ensure the buffers remain in order */ len = 8; /* queue the bulk submission */ - vchiq_use_service(instance->service_handle); + vchiq_use_service(instance->vchiq_instance, instance->service_handle); ret = vchiq_bulk_receive(instance->vchiq_instance, instance->service_handle, msg_context->u.bulk.buffer->buffer, /* Actual receive needs to be a multiple @@ -302,7 +302,7 @@ static void buffer_to_host_work_cb(struct work_struct *work) msg_context, VCHIQ_BULK_MODE_CALLBACK); - vchiq_release_service(instance->service_handle); + vchiq_release_service(instance->vchiq_instance, instance->service_handle); if (ret != 0) pr_err("%s: ctx: %p, vchiq_bulk_receive failed %d\n", @@ -436,15 +436,15 @@ buffer_from_host(struct vchiq_mmal_instance *instance, /* no payload in message */ m.u.buffer_from_host.payload_in_message = 0; - vchiq_use_service(instance->service_handle); + vchiq_use_service(instance->vchiq_instance, instance->service_handle); - ret = vchiq_queue_kernel_message(instance->service_handle, &m, + ret = vchiq_queue_kernel_message(instance->vchiq_instance, instance->service_handle, &m, sizeof(struct mmal_msg_header) + sizeof(m.u.buffer_from_host)); if (ret) atomic_dec(&port->buffers_with_vpu); - vchiq_release_service(instance->service_handle); + vchiq_release_service(instance->vchiq_instance, instance->service_handle); return ret; } @@ -573,25 +573,25 @@ static enum vchiq_status service_callback(struct vchiq_instance *vchiq_instance, /* handling is different for buffer messages */ switch (msg->h.type) { case MMAL_MSG_TYPE_BUFFER_FROM_HOST: - vchiq_release_message(handle, header); + vchiq_release_message(vchiq_instance, handle, header); break; case MMAL_MSG_TYPE_EVENT_TO_HOST: event_to_host_cb(instance, msg, msg_len); - vchiq_release_message(handle, header); + vchiq_release_message(vchiq_instance, handle, header); break; case MMAL_MSG_TYPE_BUFFER_TO_HOST: buffer_to_host_cb(instance, msg, msg_len); - vchiq_release_message(handle, header); + vchiq_release_message(vchiq_instance, handle, header); break; default: /* messages dependent on header context to complete */ if (!msg->h.context) { pr_err("received message context was null!\n"); - vchiq_release_message(handle, header); + vchiq_release_message(vchiq_instance, handle, header); break; } @@ -600,7 +600,7 @@ static enum vchiq_status service_callback(struct vchiq_instance *vchiq_instance, if (!msg_context) { pr_err("received invalid message context %u!\n", msg->h.context); - vchiq_release_message(handle, header); + vchiq_release_message(vchiq_instance, handle, header); break; } @@ -679,13 +679,13 @@ static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance, DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len), ">>> sync message"); - vchiq_use_service(instance->service_handle); + vchiq_use_service(instance->vchiq_instance, instance->service_handle); - ret = vchiq_queue_kernel_message(instance->service_handle, msg, + ret = vchiq_queue_kernel_message(instance->vchiq_instance, instance->service_handle, msg, sizeof(struct mmal_msg_header) + payload_len); - vchiq_release_service(instance->service_handle); + vchiq_release_service(instance->vchiq_instance, instance->service_handle); if (ret) { pr_err("error %d queuing message\n", ret); @@ -825,7 +825,7 @@ static int port_info_set(struct vchiq_mmal_instance *instance, port->component->handle, port->handle); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -920,7 +920,7 @@ release_msg: pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret, port->component->handle, port->handle); - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -968,7 +968,7 @@ static int create_component(struct vchiq_mmal_instance *instance, component->inputs, component->outputs, component->clocks); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -1001,7 +1001,7 @@ static int destroy_component(struct vchiq_mmal_instance *instance, release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -1033,7 +1033,7 @@ static int enable_component(struct vchiq_mmal_instance *instance, ret = -rmsg->u.component_enable_reply.status; release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -1066,7 +1066,7 @@ static int disable_component(struct vchiq_mmal_instance *instance, release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -1098,7 +1098,7 @@ static int get_version(struct vchiq_mmal_instance *instance, *minor_out = rmsg->u.version.minor; release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -1140,7 +1140,7 @@ static int port_action_port(struct vchiq_mmal_instance *instance, port_action_type_names[action_type], action_type); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -1188,7 +1188,7 @@ static int port_action_handle(struct vchiq_mmal_instance *instance, action_type, connect_component_handle, connect_port_handle); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -1229,7 +1229,7 @@ static int port_parameter_set(struct vchiq_mmal_instance *instance, ret, port->component->handle, port->handle, parameter_id); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -1288,7 +1288,7 @@ static int port_parameter_get(struct vchiq_mmal_instance *instance, ret, port->component->handle, port->handle, parameter_id); release_msg: - vchiq_release_message(instance->service_handle, rmsg_handle); + vchiq_release_message(instance->vchiq_instance, instance->service_handle, rmsg_handle); return ret; } @@ -1833,9 +1833,9 @@ int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance) if (mutex_lock_interruptible(&instance->vchiq_mutex)) return -EINTR; - vchiq_use_service(instance->service_handle); + vchiq_use_service(instance->vchiq_instance, instance->service_handle); - status = vchiq_close_service(instance->service_handle); + status = vchiq_close_service(instance->vchiq_instance, instance->service_handle); if (status != 0) pr_err("mmal-vchiq: VCHIQ close failed\n"); @@ -1923,14 +1923,14 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) goto err_close_services; } - vchiq_release_service(instance->service_handle); + vchiq_release_service(instance->vchiq_instance, instance->service_handle); *out_instance = instance; return 0; err_close_services: - vchiq_close_service(instance->service_handle); + vchiq_close_service(instance->vchiq_instance, instance->service_handle); destroy_workqueue(instance->bulk_wq); err_free: kfree(instance); From bad44825fbf5ad9e97fec09d96c74d8a91685d2a Mon Sep 17 00:00:00 2001 From: Adrien Thierry Date: Wed, 18 May 2022 15:11:16 -0400 Subject: [PATCH 0068/1436] staging: vchiq_arm: pass vchiq instance to 'vchiq_get_client_id' In order to remove the 'vchiq_states' global array, we need to pass the vchiq_instance reference to the 'handle_to_service' function, as well as to all functions that call 'handle_to_service'. This will allow accessing the vchiq state through the vchiq instance instead of through the global array. 'handle_to_service' is called by 'vchiq_get_client_id'. Therefore, pass the vchiq instance reference to it. Tested-by: Stefan Wahren Signed-off-by: Adrien Thierry Link: https://lore.kernel.org/r/20220518191126.60396-6-athierry@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c | 2 +- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h | 2 +- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 7217e3070ffe..d6853e23564c 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -398,7 +398,7 @@ vchiq_service_put(struct vchiq_service *service) } int -vchiq_get_client_id(unsigned int handle) +vchiq_get_client_id(struct vchiq_instance *instance, unsigned int handle) { struct vchiq_service *service; int id; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 34d8fef7af14..c08d1f8e0cf3 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -598,7 +598,7 @@ void vchiq_log_dump_mem(const char *label, u32 addr, const void *void_mem, size_ enum vchiq_status vchiq_remove_service(struct vchiq_instance *instance, unsigned int service); -int vchiq_get_client_id(unsigned int service); +int vchiq_get_client_id(struct vchiq_instance *instance, unsigned int service); void vchiq_get_config(struct vchiq_config *config); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c index adb616d97652..7e297494437e 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_dev.c @@ -788,7 +788,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case VCHIQ_IOC_GET_CLIENT_ID: { unsigned int handle = (unsigned int)arg; - ret = vchiq_get_client_id(handle); + ret = vchiq_get_client_id(instance, handle); } break; case VCHIQ_IOC_GET_CONFIG: { From f23f8a05a13bf9ea3e5143cc7195c5f91697d0f8 Mon Sep 17 00:00:00 2001 From: Adrien Thierry Date: Wed, 18 May 2022 15:11:17 -0400 Subject: [PATCH 0069/1436] staging: vchiq_arm: pass vchiq instance to 'vchiq_get_service_userdata' In order to remove the 'vchiq_states' global array, we need to pass the vchiq_instance reference to the 'handle_to_service' function, as well as to all functions that call 'handle_to_service'. This will allow accessing the vchiq state through the vchiq instance instead of through the global array. 'handle_to_service' is called by 'vchiq_get_service_userdata'. Therefore, pass the vchiq instance reference to it. Tested-by: Stefan Wahren Signed-off-by: Adrien Thierry Link: https://lore.kernel.org/r/20220518191126.60396-7-athierry@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c | 3 ++- .../staging/vc04_services/include/linux/raspberrypi/vchiq.h | 2 +- drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c | 2 +- drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c index aa2ab0df7af5..f4c2c9506d86 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c @@ -96,7 +96,8 @@ static enum vchiq_status audio_vchi_callback(struct vchiq_instance *vchiq_instan struct vchiq_header *header, unsigned int handle, void *userdata) { - struct bcm2835_audio_instance *instance = vchiq_get_service_userdata(handle); + struct bcm2835_audio_instance *instance = vchiq_get_service_userdata(vchiq_instance, + handle); struct vc_audio_msg *m; if (reason != VCHIQ_MESSAGE_AVAILABLE) diff --git a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h index 0d3833e9773c..db1441c0cc66 100644 --- a/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h +++ b/drivers/staging/vc04_services/include/linux/raspberrypi/vchiq.h @@ -109,7 +109,7 @@ extern enum vchiq_status vchiq_bulk_transmit(struct vchiq_instance *instance, un extern enum vchiq_status vchiq_bulk_receive(struct vchiq_instance *instance, unsigned int service, void *data, unsigned int size, void *userdata, enum vchiq_bulk_mode mode); -extern void *vchiq_get_service_userdata(unsigned int service); +extern void *vchiq_get_service_userdata(struct vchiq_instance *instance, unsigned int service); extern enum vchiq_status vchiq_get_peer_version(struct vchiq_instance *instance, unsigned int handle, short *peer_version); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index d6853e23564c..d4fed18b1baa 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -411,7 +411,7 @@ vchiq_get_client_id(struct vchiq_instance *instance, unsigned int handle) } void * -vchiq_get_service_userdata(unsigned int handle) +vchiq_get_service_userdata(struct vchiq_instance *instance, unsigned int handle) { void *userdata; struct vchiq_service *service; diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c index 4c29cb7794a1..cb921c94996a 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c @@ -553,7 +553,7 @@ static enum vchiq_status service_callback(struct vchiq_instance *vchiq_instance, struct vchiq_header *header, unsigned int handle, void *bulk_ctx) { - struct vchiq_mmal_instance *instance = vchiq_get_service_userdata(handle); + struct vchiq_mmal_instance *instance = vchiq_get_service_userdata(vchiq_instance, handle); u32 msg_len; struct mmal_msg *msg; struct mmal_msg_context *msg_context; From 6d02150cdf7618139f60c926b52fca4e8efefb52 Mon Sep 17 00:00:00 2001 From: Adrien Thierry Date: Wed, 18 May 2022 15:11:18 -0400 Subject: [PATCH 0070/1436] staging: vchiq_arm: pass vchiq instance to 'handle_to_service' In order to remove the 'vchiq_states' global array, we need to pass the vchiq_instance reference to the 'handle_to_service' function. This will allow accessing the vchiq state through the vchiq instance instead of through the global array. Tested-by: Stefan Wahren Signed-off-by: Adrien Thierry Link: https://lore.kernel.org/r/20220518191126.60396-8-athierry@redhat.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 2 +- .../vc04_services/interface/vchiq_arm/vchiq_core.c | 10 +++++----- .../vc04_services/interface/vchiq_arm/vchiq_core.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index a5f0a756b32c..3bcb893d14a1 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -1059,7 +1059,7 @@ service_callback(struct vchiq_instance *instance, enum vchiq_reason reason, DEBUG_TRACE(SERVICE_CALLBACK_LINE); rcu_read_lock(); - service = handle_to_service(handle); + service = handle_to_service(instance, handle); if (WARN_ON(!service)) { rcu_read_unlock(); return VCHIQ_SUCCESS; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index d4fed18b1baa..be2ee84686b7 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -240,7 +240,7 @@ find_service_by_handle(struct vchiq_instance *instance, unsigned int handle) struct vchiq_service *service; rcu_read_lock(); - service = handle_to_service(handle); + service = handle_to_service(instance, handle); if (service && service->srvstate != VCHIQ_SRVSTATE_FREE && service->handle == handle && kref_get_unless_zero(&service->ref_count)) { @@ -281,7 +281,7 @@ find_service_for_instance(struct vchiq_instance *instance, unsigned int handle) struct vchiq_service *service; rcu_read_lock(); - service = handle_to_service(handle); + service = handle_to_service(instance, handle); if (service && service->srvstate != VCHIQ_SRVSTATE_FREE && service->handle == handle && service->instance == instance && @@ -302,7 +302,7 @@ find_closed_service_for_instance(struct vchiq_instance *instance, unsigned int h struct vchiq_service *service; rcu_read_lock(); - service = handle_to_service(handle); + service = handle_to_service(instance, handle); if (service && (service->srvstate == VCHIQ_SRVSTATE_FREE || service->srvstate == VCHIQ_SRVSTATE_CLOSED) && @@ -404,7 +404,7 @@ vchiq_get_client_id(struct vchiq_instance *instance, unsigned int handle) int id; rcu_read_lock(); - service = handle_to_service(handle); + service = handle_to_service(instance, handle); id = service ? service->client_id : 0; rcu_read_unlock(); return id; @@ -417,7 +417,7 @@ vchiq_get_service_userdata(struct vchiq_instance *instance, unsigned int handle) struct vchiq_service *service; rcu_read_lock(); - service = handle_to_service(handle); + service = handle_to_service(instance, handle); userdata = service ? service->base.userdata : NULL; rcu_read_unlock(); return userdata; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index c08d1f8e0cf3..3eb70d688c4e 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -509,7 +509,7 @@ request_poll(struct vchiq_state *state, struct vchiq_service *service, int poll_type); static inline struct vchiq_service * -handle_to_service(unsigned int handle) +handle_to_service(struct vchiq_instance *instance, unsigned int handle) { int idx = handle & (VCHIQ_MAX_SERVICES - 1); struct vchiq_state *state = vchiq_states[(handle / VCHIQ_MAX_SERVICES) & From ed57d93e7752c6347d7d5336509ee72d5d6368a4 Mon Sep 17 00:00:00 2001 From: Adrien Thierry Date: Wed, 18 May 2022 15:11:19 -0400 Subject: [PATCH 0071/1436] staging: vchiq_arm: use state from vchiq instance In 'handle_to_service', access the vchiq state from the vchiq instance instead of the global 'vchiq_states' array. This will allow getting rid of the global 'vchiq_states' array. Tested-by: Stefan Wahren Signed-off-by: Adrien Thierry Link: https://lore.kernel.org/r/20220518191126.60396-9-athierry@redhat.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_core.c | 7 +++++++ .../vc04_services/interface/vchiq_arm/vchiq_core.h | 12 +----------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index be2ee84686b7..cd23d18f8b3c 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -13,6 +13,7 @@ #include #include +#include "vchiq_arm.h" #include "vchiq_core.h" #define VCHIQ_SLOT_HANDLER_STACK 8192 @@ -234,6 +235,12 @@ set_service_state(struct vchiq_service *service, int newstate) service->srvstate = newstate; } +struct vchiq_service *handle_to_service(struct vchiq_instance *instance, unsigned int handle) +{ + int idx = handle & (VCHIQ_MAX_SERVICES - 1); + + return rcu_dereference(instance->state->services[idx]); +} struct vchiq_service * find_service_by_handle(struct vchiq_instance *instance, unsigned int handle) { diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 3eb70d688c4e..bdd4611005e0 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -508,17 +508,7 @@ extern void request_poll(struct vchiq_state *state, struct vchiq_service *service, int poll_type); -static inline struct vchiq_service * -handle_to_service(struct vchiq_instance *instance, unsigned int handle) -{ - int idx = handle & (VCHIQ_MAX_SERVICES - 1); - struct vchiq_state *state = vchiq_states[(handle / VCHIQ_MAX_SERVICES) & - (VCHIQ_MAX_STATES - 1)]; - - if (!state) - return NULL; - return rcu_dereference(state->services[idx]); -} +struct vchiq_service *handle_to_service(struct vchiq_instance *instance, unsigned int handle); extern struct vchiq_service * find_service_by_handle(struct vchiq_instance *instance, unsigned int handle); From 1dbcdf74a902fccaf7bf135ba08ffa4f40723539 Mon Sep 17 00:00:00 2001 From: Adrien Thierry Date: Wed, 18 May 2022 15:11:20 -0400 Subject: [PATCH 0072/1436] staging: vchiq_arm: remove global 'vchiq_states' array Remove global 'vchiq_states' array, which is not used anymore. This is part of an effort to address TODO item "Get rid of all non essential global structures and create a proper per device structure" Tested-by: Stefan Wahren Signed-off-by: Adrien Thierry Link: https://lore.kernel.org/r/20220518191126.60396-10-athierry@redhat.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_core.c | 8 -------- .../vc04_services/interface/vchiq_arm/vchiq_core.h | 2 -- 2 files changed, 10 deletions(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index cd23d18f8b3c..7b9c100eb74d 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -162,7 +162,6 @@ int vchiq_sync_log_level = VCHIQ_LOG_DEFAULT; DEFINE_SPINLOCK(bulk_waiter_spinlock); static DEFINE_SPINLOCK(quota_spinlock); -struct vchiq_state *vchiq_states[VCHIQ_MAX_STATES]; static unsigned int handle_seq; static const char *const srvstate_names[] = { @@ -2157,11 +2156,6 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero, s char threadname[16]; int i, ret; - if (vchiq_states[0]) { - pr_err("%s: VCHIQ state already initialized\n", __func__); - return -EINVAL; - } - local = &slot_zero->slave; remote = &slot_zero->master; @@ -2282,8 +2276,6 @@ vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero, s wake_up_process(state->recycle_thread); wake_up_process(state->sync_thread); - vchiq_states[0] = state; - /* Indicate readiness to the other side */ local->initialised = 1; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index bdd4611005e0..8b4a38f5b3f2 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -449,8 +449,6 @@ extern int vchiq_core_log_level; extern int vchiq_core_msg_log_level; extern int vchiq_sync_log_level; -extern struct vchiq_state *vchiq_states[VCHIQ_MAX_STATES]; - extern const char * get_conn_state_name(enum vchiq_connstate conn_state); From 0ffa2a3a702e7ee159be938e11e3e7fd81a96fc3 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:48:05 +0200 Subject: [PATCH 0073/1436] staging: r8188eu: use ieee80211 defines for back action codes Replace the driver-specific defines for back action codes with the defines from ieee80211.h. Signed-off-by: Martin Kaiser Tested-by: Pavel Skripkin Link: https://lore.kernel.org/r/20220602194807.281115-2-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 6 +++--- drivers/staging/r8188eu/include/ieee80211.h | 7 ------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 5446e19d8d09..de9590de38ce 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5623,7 +5623,7 @@ unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) if (initiator == 0) { /* recipient */ for (tid = 0; tid < MAXTID; tid++) { if (psta->recvreorder_ctrl[tid].enable) { - issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator) & 0x1F)); + issue_action_BA(padapter, addr, WLAN_ACTION_DELBA, (((tid << 1) | initiator) & 0x1F)); psta->recvreorder_ctrl[tid].enable = false; psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; } @@ -5631,7 +5631,7 @@ unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) } else if (initiator == 1) { /* originator */ for (tid = 0; tid < MAXTID; tid++) { if (psta->htpriv.agg_enable_bitmap & BIT(tid)) { - issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator) & 0x1F)); + issue_action_BA(padapter, addr, WLAN_ACTION_DELBA, (((tid << 1) | initiator) & 0x1F)); psta->htpriv.agg_enable_bitmap &= ~BIT(tid); psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); } @@ -7475,7 +7475,7 @@ u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf) if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && (pmlmeinfo->HT_enable)) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { - issue_action_BA(padapter, pparm->addr, RTW_WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid); + issue_action_BA(padapter, pparm->addr, WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid); _set_timer(&psta->addba_retry_timer, ADDBA_TO); } else { psta->htpriv.candidate_tid_bitmap &= ~BIT(pparm->tid); diff --git a/drivers/staging/r8188eu/include/ieee80211.h b/drivers/staging/r8188eu/include/ieee80211.h index 15636a808f52..e7a4f8af497a 100644 --- a/drivers/staging/r8188eu/include/ieee80211.h +++ b/drivers/staging/r8188eu/include/ieee80211.h @@ -624,13 +624,6 @@ enum _PUBLIC_ACTION { ACT_PUBLIC_MAX }; -/* BACK action code */ -enum rtw_ieee80211_back_actioncode { - RTW_WLAN_ACTION_ADDBA_REQ = 0, - RTW_WLAN_ACTION_ADDBA_RESP = 1, - RTW_WLAN_ACTION_DELBA = 2, -}; - #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) * 00:50:F2 */ #define WME_OUI_TYPE 2 From e8ab382811e50e1933bc7d388a02bb0f5414a124 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:48:07 +0200 Subject: [PATCH 0074/1436] staging: r8188eu: fix the declaration of process_pwrbit_data Fix the declaration of process_pwrbit_data. Make the function static and remove its prototype. Signed-off-by: Martin Kaiser Tested-by: Pavel Skripkin Link: https://lore.kernel.org/r/20220602194807.281115-4-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index df518439aea2..fe3d597fea69 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -452,8 +452,7 @@ static int recv_decache(struct recv_frame *precv_frame, u8 bretry, struct stainf return _SUCCESS; } -void process_pwrbit_data(struct adapter *padapter, struct recv_frame *precv_frame); -void process_pwrbit_data(struct adapter *padapter, struct recv_frame *precv_frame) +static void process_pwrbit_data(struct adapter *padapter, struct recv_frame *precv_frame) { unsigned char pwrbit; u8 *ptr = precv_frame->rx_data; From 79053469559d0cf0d4106fb8b3784b8cd9fa4f61 Mon Sep 17 00:00:00 2001 From: Haowen Bai Date: Wed, 1 Jun 2022 19:49:24 +0800 Subject: [PATCH 0075/1436] staging: r8188eu: Drop redundant memset overwritten by memcpy The region set by the call to memset is immediately overwritten by the subsequent call to memcpy. So we drop redundant memset. Signed-off-by: Haowen Bai Link: https://lore.kernel.org/r/1654084164-10869-1-git-send-email-baihaowen@meizu.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_ioctl_set.c | 1 - drivers/staging/r8188eu/core/rtw_mlme.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_ioctl_set.c b/drivers/staging/r8188eu/core/rtw_ioctl_set.c index 7ba75f73e47e..17f6bcbeebf4 100644 --- a/drivers/staging/r8188eu/core/rtw_ioctl_set.c +++ b/drivers/staging/r8188eu/core/rtw_ioctl_set.c @@ -71,7 +71,6 @@ u8 rtw_do_join(struct adapter *padapter) pibss = padapter->registrypriv.dev_network.MacAddress; - memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); rtw_update_registrypriv_dev_network(padapter); diff --git a/drivers/staging/r8188eu/core/rtw_mlme.c b/drivers/staging/r8188eu/core/rtw_mlme.c index 5a815642c3f6..56c8bd5f4c60 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme.c +++ b/drivers/staging/r8188eu/core/rtw_mlme.c @@ -676,7 +676,6 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY); - memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); rtw_update_registrypriv_dev_network(adapter); @@ -1253,7 +1252,6 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network)); - memset(&pdev_network->Ssid, 0, sizeof(struct ndis_802_11_ssid)); memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct ndis_802_11_ssid)); rtw_update_registrypriv_dev_network(adapter); From 80c968a04a381dc0e690960c60ffd6b6aee7e157 Mon Sep 17 00:00:00 2001 From: Jared Kangas Date: Sun, 5 Jun 2022 16:18:06 -0700 Subject: [PATCH 0076/1436] staging: greybus: audio: fix loop cursor use after iteration gbaudio_dapm_free_controls() iterates over widgets using list_for_each_entry_safe(), which leaves the loop cursor pointing to a meaningless structure if it completes a traversal of the list. The cursor was set to NULL at the end of the loop body, but would be overwritten by the final loop cursor update. Because of this behavior, the widget could be non-null after the loop even if the widget wasn't found, and the cleanup logic would treat the pointer as a valid widget to free. To fix this, introduce a temporary variable to act as the loop cursor and copy it to a variable that can be accessed after the loop finishes. This was detected with the help of Coccinelle. Signed-off-by: Jared Kangas Link: https://lore.kernel.org/r/20220605231806.720085-1-kangas.jd@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio_helper.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/staging/greybus/audio_helper.c b/drivers/staging/greybus/audio_helper.c index 843760675876..07461a5d97c7 100644 --- a/drivers/staging/greybus/audio_helper.c +++ b/drivers/staging/greybus/audio_helper.c @@ -115,7 +115,7 @@ int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm, int num) { int i; - struct snd_soc_dapm_widget *w, *next_w; + struct snd_soc_dapm_widget *w, *next_w, *tmp_w; #ifdef CONFIG_DEBUG_FS struct dentry *parent = dapm->debugfs_dapm; struct dentry *debugfs_w = NULL; @@ -124,13 +124,14 @@ int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm, mutex_lock(&dapm->card->dapm_mutex); for (i = 0; i < num; i++) { /* below logic can be optimized to identify widget pointer */ - list_for_each_entry_safe(w, next_w, &dapm->card->widgets, + w = NULL; + list_for_each_entry_safe(tmp_w, next_w, &dapm->card->widgets, list) { - if (w->dapm != dapm) - continue; - if (!strcmp(w->name, widget->name)) + if (tmp_w->dapm == dapm && + !strcmp(tmp_w->name, widget->name)) { + w = tmp_w; break; - w = NULL; + } } if (!w) { dev_err(dapm->dev, "%s: widget not found\n", From 0e01f8931c7a360f76c00b636950f80d283bfcd3 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:16 +0200 Subject: [PATCH 0077/1436] staging: r8188eu: use mgmt to set resp dialog token Use the mgmt structure to set the dialog token of an addba response. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-2-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index de9590de38ce..5b0319106815 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5442,7 +5442,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch case WLAN_ACTION_ADDBA_RESP: mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; pattrib->pktlen++; - pframe = rtw_set_fixed_ie(pframe, 1, &pmlmeinfo->ADDBA_req.dialog_token, &pattrib->pktlen); + mgmt->u.action.u.addba_resp.dialog_token = pmlmeinfo->ADDBA_req.dialog_token; + pattrib->pktlen++; pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&status, &pattrib->pktlen); BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; BA_para_set |= 0x1000; /* 64 buffer size */ From e2643fd46cc34a26a8d9eab76d179d5416e03344 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:17 +0200 Subject: [PATCH 0078/1436] staging: r8188eu: use mgmt to set the addba resp status Use the mgmt struct to set the addba response status. The caller passes the status code in host endianness, we have to convert it to little endian. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-3-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 5b0319106815..51f0585859c7 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5444,7 +5444,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch pattrib->pktlen++; mgmt->u.action.u.addba_resp.dialog_token = pmlmeinfo->ADDBA_req.dialog_token; pattrib->pktlen++; - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&status, &pattrib->pktlen); + mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); + pattrib->pktlen += 2; BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; BA_para_set |= 0x1000; /* 64 buffer size */ From 140529aec4687a7865c315e70988896d377b0fce Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:18 +0200 Subject: [PATCH 0079/1436] staging: r8188eu: use mgmt to set the addba resp timeout Use the mgmt struct to set the addba response timeout. Copy the timeout from the saved addba request. The timeout field is already le16, we don't have to convert the endianness. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-4-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 51f0585859c7..8c562c510e6a 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5456,7 +5456,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch le_tmp = cpu_to_le16(BA_para_set); pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&pmlmeinfo->ADDBA_req.BA_timeout_value, &pattrib->pktlen); + mgmt->u.action.u.addba_resp.timeout = pmlmeinfo->ADDBA_req.BA_timeout_value; + pattrib->pktlen += 2; break; case WLAN_ACTION_DELBA: mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; From 8836faf7196b233bb2baf7dc2b84bfe9f34efe11 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:19 +0200 Subject: [PATCH 0080/1436] staging: r8188eu: use ieee80211 to set addba resp capabilities Use the mgmt structure and defines from ieee80211.h to set the capabilities field of an addba response. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-5-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 8c562c510e6a..3b684401f964 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5446,16 +5446,11 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch pattrib->pktlen++; mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); pattrib->pktlen += 2; - BA_para_set = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; - BA_para_set |= 0x1000; /* 64 buffer size */ - - if (pregpriv->ampdu_amsdu == 0)/* disabled */ - BA_para_set = BA_para_set & ~BIT(0); - else if (pregpriv->ampdu_amsdu == 1)/* enabled */ - BA_para_set = BA_para_set | BIT(0); - le_tmp = cpu_to_le16(BA_para_set); - - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + capab = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; + capab |= u16_encode_bits(64, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK); + capab |= u16_encode_bits(pregpriv->ampdu_amsdu, IEEE80211_ADDBA_PARAM_AMSDU_MASK); + mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); + pattrib->pktlen += 2; mgmt->u.action.u.addba_resp.timeout = pmlmeinfo->ADDBA_req.BA_timeout_value; pattrib->pktlen += 2; break; From c67eea0c34101ba199e500c825edf0a080cdfd45 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:20 +0200 Subject: [PATCH 0081/1436] staging: r8188eu: calculate the addba response length An addba response always ends with the timeout field. The length of the addba response is the offset of the end of the timeout field in the struct ieee80211_mgmt that defines the message. Use offsetofend to calculate this offset and drop the intermediate pktlen increments as we add addba response components. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-6-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 3b684401f964..55e347bb9a6a 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5441,18 +5441,14 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch break; case WLAN_ACTION_ADDBA_RESP: mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; - pattrib->pktlen++; mgmt->u.action.u.addba_resp.dialog_token = pmlmeinfo->ADDBA_req.dialog_token; - pattrib->pktlen++; mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); - pattrib->pktlen += 2; capab = le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f; capab |= u16_encode_bits(64, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK); capab |= u16_encode_bits(pregpriv->ampdu_amsdu, IEEE80211_ADDBA_PARAM_AMSDU_MASK); mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); - pattrib->pktlen += 2; mgmt->u.action.u.addba_resp.timeout = pmlmeinfo->ADDBA_req.BA_timeout_value; - pattrib->pktlen += 2; + pattrib->pktlen = offsetofend(struct ieee80211_mgmt, u.action.u.addba_resp.timeout); break; case WLAN_ACTION_DELBA: mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; From c5727d76ca0cf84d1d8b4fd7bb28920a4d440c11 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:21 +0200 Subject: [PATCH 0082/1436] staging: r8188eu: use mgmt to set the delba reason code Use the mgmt struct to set the delba reason code. Replace the numeric value with a define and remove the temporary variable. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-7-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 55e347bb9a6a..dd9f7f2b36ef 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5367,7 +5367,6 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch { u16 start_seq; u16 BA_para_set; - u16 reason_code; __le16 le_tmp; u16 BA_starting_seqctrl = 0; struct xmit_frame *pmgntframe; @@ -5457,9 +5456,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch le_tmp = cpu_to_le16(BA_para_set); pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); - reason_code = 37;/* Requested from peer STA as it does not want to use the mechanism */ - le_tmp = cpu_to_le16(reason_code); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); + mgmt->u.action.u.delba.reason_code = cpu_to_le16(WLAN_STATUS_REQUEST_DECLINED); + pattrib->pktlen += 2; break; default: break; From 9120436aa9883da6fde9fa66d3afe503df3c44ae Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:22 +0200 Subject: [PATCH 0083/1436] staging: r8188eu: use mgmt to set delba params Use the mgmt struct to set the delba parameters. Use the exact same value for the parameters as the current code. Remove a dead increment of pframe, we don't use pframe for the delba message any more. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-8-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index dd9f7f2b36ef..46b770ea7f33 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5366,8 +5366,6 @@ exit: void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status) { u16 start_seq; - u16 BA_para_set; - __le16 le_tmp; u16 BA_starting_seqctrl = 0; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; @@ -5403,7 +5401,6 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch mgmt->seq_ctrl = cpu_to_le16(pmlmeext->mgnt_seq); pmlmeext->mgnt_seq++; - pframe += sizeof(struct ieee80211_hdr_3addr); pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); mgmt->u.action.category = WLAN_CATEGORY_BACK; @@ -5452,10 +5449,8 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch case WLAN_ACTION_DELBA: mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; pattrib->pktlen++; - BA_para_set = (status & 0x1F) << 3; - le_tmp = cpu_to_le16(BA_para_set); - pframe = rtw_set_fixed_ie(pframe, 2, (unsigned char *)&le_tmp, &pattrib->pktlen); - + mgmt->u.action.u.delba.params = cpu_to_le16((status & 0x1F) << 3); + pattrib->pktlen += 2; mgmt->u.action.u.delba.reason_code = cpu_to_le16(WLAN_STATUS_REQUEST_DECLINED); pattrib->pktlen += 2; break; From 3d7deed4ec52d2018f81d0e798966b551c7d1487 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:23 +0200 Subject: [PATCH 0084/1436] staging: r8188eu: clarify the contents of the delba params The delba parameters field contains an initiator/receiver flag and the tid. The caller of issue_action_BA passes these components in the status parameter. Extract the two components from status and use u16_encode_bits to copy them into the parameters field. This should clarify what's going on and should make it easier to replace the status parameter in the future. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-9-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 46b770ea7f33..049c206fb72a 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5377,7 +5377,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch struct sta_priv *pstapriv = &padapter->stapriv; struct registry_priv *pregpriv = &padapter->registrypriv; struct ieee80211_mgmt *mgmt; - u16 capab; + u16 capab, params; pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (!pmgntframe) @@ -5450,6 +5450,9 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; pattrib->pktlen++; mgmt->u.action.u.delba.params = cpu_to_le16((status & 0x1F) << 3); + params = u16_encode_bits((status & 0x1), IEEE80211_DELBA_PARAM_INITIATOR_MASK); + params |= u16_encode_bits((status >> 1) & 0xF, IEEE80211_DELBA_PARAM_TID_MASK); + mgmt->u.action.u.delba.params = cpu_to_le16(params); pattrib->pktlen += 2; mgmt->u.action.u.delba.reason_code = cpu_to_le16(WLAN_STATUS_REQUEST_DECLINED); pattrib->pktlen += 2; From d8f2cff63249fdf7f2cf78e70344613db1fc4e53 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:24 +0200 Subject: [PATCH 0085/1436] staging: r8188eu: calculate the delba length Use offsetofend to calculate the length of the delba message. We are now calculating all message lengths based on the offset of their last field. All intermediate updates of pattrib->pktlen can be removed. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-10-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 049c206fb72a..aaf6a2e5c52c 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5401,10 +5401,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch mgmt->seq_ctrl = cpu_to_le16(pmlmeext->mgnt_seq); pmlmeext->mgnt_seq++; - pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr); - mgmt->u.action.category = WLAN_CATEGORY_BACK; - pattrib->pktlen++; switch (action) { case WLAN_ACTION_ADDBA_REQ: @@ -5448,14 +5445,12 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch break; case WLAN_ACTION_DELBA: mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; - pattrib->pktlen++; mgmt->u.action.u.delba.params = cpu_to_le16((status & 0x1F) << 3); params = u16_encode_bits((status & 0x1), IEEE80211_DELBA_PARAM_INITIATOR_MASK); params |= u16_encode_bits((status >> 1) & 0xF, IEEE80211_DELBA_PARAM_TID_MASK); mgmt->u.action.u.delba.params = cpu_to_le16(params); - pattrib->pktlen += 2; mgmt->u.action.u.delba.reason_code = cpu_to_le16(WLAN_STATUS_REQUEST_DECLINED); - pattrib->pktlen += 2; + pattrib->pktlen = offsetofend(struct ieee80211_mgmt, u.action.u.delba.reason_code); break; default: break; From 979315ccedf45ba5b74313c463f9d94b87411932 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:25 +0200 Subject: [PATCH 0086/1436] staging: r8188eu: remove the pframe variable Remove the pframe variable, it is no longer used for populating fields of the outgoing frame. pmgntframe->buf_addr is already a u8 *, we can drop the (u8 *) cast. Increment the u8 *pmgntframe->buf_addr by TXDESC_OFFSET before we cast it to struct ieee80211_mgmt *. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-11-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index aaf6a2e5c52c..957aabec520e 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5369,7 +5369,6 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch u16 BA_starting_seqctrl = 0; struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; - u8 *pframe; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -5389,8 +5388,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET); - pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET; - mgmt = (struct ieee80211_mgmt *)pframe; + mgmt = (struct ieee80211_mgmt *)(pmgntframe->buf_addr + TXDESC_OFFSET); mgmt->frame_control = cpu_to_le16(IEEE80211_STYPE_ACTION | IEEE80211_FTYPE_MGMT); From 3e763d3dc62697733877ccb2d3c219dfd2404cd9 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 2 Jun 2022 21:37:26 +0200 Subject: [PATCH 0087/1436] staging: r8188eu: use u8, u16 in issue_action_BA prototype Use u8 and u16 in the issue_action_BA prototype. The code expects these parameters to be exactly 8 and 16 bits wide. Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220602193726.280922-12-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 2 +- drivers/staging/r8188eu/include/rtw_mlme_ext.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 957aabec520e..87bf37f33606 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5363,7 +5363,7 @@ exit: return ret; } -void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned char action, unsigned short status) +void issue_action_BA(struct adapter *padapter, unsigned char *raddr, u8 action, u16 status) { u16 start_seq; u16 BA_starting_seqctrl = 0; diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h index 573d65b175cc..71864733b1c0 100644 --- a/drivers/staging/r8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h @@ -524,8 +524,7 @@ int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason); int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int try_cnt, int wait_ms); -void issue_action_BA(struct adapter *padapter, unsigned char *raddr, - unsigned char action, unsigned short status); +void issue_action_BA(struct adapter *padapter, unsigned char *raddr, u8 action, u16 status); unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr); unsigned int send_beacon(struct adapter *padapter); bool get_beacon_valid_bit(struct adapter *adapter); From 990f4b85d7d9bb954a24ada7145947dec501fe3d Mon Sep 17 00:00:00 2001 From: Gil Fine Date: Thu, 26 May 2022 13:59:16 +0300 Subject: [PATCH 0088/1436] thunderbolt: Silently ignore CLx enabling in case CLx is not supported We can't enable CLx if it is not supported either by the host or device, or by the USB4/TBT link (e.g. when an optical cable is used). We silently ignore CLx enabling in this case. Signed-off-by: Gil Fine Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tb.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 9a3214fb5038..8ab3530dfa0d 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -575,6 +575,7 @@ static void tb_scan_port(struct tb_port *port) struct tb_cm *tcm = tb_priv(port->sw->tb); struct tb_port *upstream_port; struct tb_switch *sw; + int ret; if (tb_is_upstream_port(port)) return; @@ -663,7 +664,9 @@ static void tb_scan_port(struct tb_port *port) tb_switch_lane_bonding_enable(sw); /* Set the link configured */ tb_switch_configure_link(sw); - if (tb_switch_enable_clx(sw, TB_CL0S)) + /* Silently ignore CLx enabling in case CLx is not supported */ + ret = tb_switch_enable_clx(sw, TB_CL0S); + if (ret && ret != -EOPNOTSUPP) tb_sw_warn(sw, "failed to enable CLx on upstream port\n"); tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_HIFI, @@ -1446,12 +1449,15 @@ static int tb_suspend_noirq(struct tb *tb) static void tb_restore_children(struct tb_switch *sw) { struct tb_port *port; + int ret; /* No need to restore if the router is already unplugged */ if (sw->is_unplugged) return; - if (tb_switch_enable_clx(sw, TB_CL0S)) + /* Silently ignore CLx re-enabling in case CLx is not supported */ + ret = tb_switch_enable_clx(sw, TB_CL0S); + if (ret && ret != -EOPNOTSUPP) tb_sw_warn(sw, "failed to re-enable CLx on upstream port\n"); /* From 418a5a3d6596f62424b24192b642d959d4c73d25 Mon Sep 17 00:00:00 2001 From: Gil Fine Date: Thu, 26 May 2022 13:59:17 +0300 Subject: [PATCH 0089/1436] thunderbolt: CLx disable before system suspend only if previously enabled Disable CLx before system suspended only if previously was enabled. Signed-off-by: Gil Fine Signed-off-by: Mika Westerberg --- drivers/thunderbolt/switch.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 561e1d77240e..0395229a3562 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -3134,8 +3134,10 @@ void tb_switch_suspend(struct tb_switch *sw, bool runtime) * Actually only needed for Titan Ridge but for simplicity can be * done for USB4 device too as CLx is re-enabled at resume. */ - if (tb_switch_disable_clx(sw, TB_CL0S)) - tb_sw_warn(sw, "failed to disable CLx on upstream port\n"); + if (tb_switch_is_clx_enabled(sw)) { + if (tb_switch_disable_clx(sw, TB_CL0S)) + tb_sw_warn(sw, "failed to disable CLx on upstream port\n"); + } err = tb_plug_events_active(sw, false); if (err) From b4e08d5d08192699e68ffa796bd2c3ab58af5730 Mon Sep 17 00:00:00 2001 From: Gil Fine Date: Thu, 26 May 2022 13:59:18 +0300 Subject: [PATCH 0090/1436] thunderbolt: Fix typos in CLx enabling Fix few typos in CLx enabling. Signed-off-by: Gil Fine Signed-off-by: Mika Westerberg --- drivers/thunderbolt/switch.c | 2 +- drivers/thunderbolt/tmu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index 0395229a3562..e584077b2f4f 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -3556,7 +3556,7 @@ static int tb_switch_enable_cl0s(struct tb_switch *sw) * to improve performance. CLx is enabled only if both sides of the link * support CLx, and if both sides of the link are not configured as two * single lane links and only if the link is not inter-domain link. The - * complete set of conditions is descibed in CM Guide 1.0 section 8.1. + * complete set of conditions is described in CM Guide 1.0 section 8.1. * * Return: Returns 0 on success or an error code on failure. */ diff --git a/drivers/thunderbolt/tmu.c b/drivers/thunderbolt/tmu.c index e4a07a26f693..b656659d02fb 100644 --- a/drivers/thunderbolt/tmu.c +++ b/drivers/thunderbolt/tmu.c @@ -606,7 +606,7 @@ int tb_switch_tmu_enable(struct tb_switch *sw) /** * tb_switch_tmu_configure() - Configure the TMU rate and directionality * @sw: Router whose mode to change - * @rate: Rate to configure Off/LowRes/HiFi + * @rate: Rate to configure Off/Normal/HiFi * @unidirectional: If uni-directional (bi-directional otherwise) * * Selects the rate of the TMU and directionality (uni-directional or From 5fd6b9a5cbe63fea4c490fee8af34144a139a266 Mon Sep 17 00:00:00 2001 From: Gil Fine Date: Thu, 26 May 2022 13:59:19 +0300 Subject: [PATCH 0091/1436] thunderbolt: Change downstream router's TMU rate in both TMU uni/bidir mode In case of uni-directional time sync, TMU handshake is initiated by upstream router. In case of bi-directional time sync, TMU handshake is initiated by downstream router. In order to handle correctly the case of uni-directional mode, we avoid changing the upstream router's rate to off, because it might have another downstream router plugged that is set to uni-directional mode (and we don't want to change its mode). Instead, we always change downstream router's rate. Signed-off-by: Gil Fine Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tmu.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/thunderbolt/tmu.c b/drivers/thunderbolt/tmu.c index b656659d02fb..985ca43b8f39 100644 --- a/drivers/thunderbolt/tmu.c +++ b/drivers/thunderbolt/tmu.c @@ -359,13 +359,14 @@ int tb_switch_tmu_disable(struct tb_switch *sw) * In case of uni-directional time sync, TMU handshake is * initiated by upstream router. In case of bi-directional * time sync, TMU handshake is initiated by downstream router. - * Therefore, we change the rate to off in the respective - * router. + * We change downstream router's rate to off for both uni/bidir + * cases although it is needed only for the bi-directional mode. + * We avoid changing upstream router's mode since it might + * have another downstream router plugged, that is set to + * uni-directional mode and we don't want to change it's TMU + * mode. */ - if (unidirectional) - tb_switch_tmu_rate_write(parent, TB_SWITCH_TMU_RATE_OFF); - else - tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF); + tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF); tb_port_tmu_time_sync_disable(up); ret = tb_port_tmu_time_sync_disable(down); From b017a46d486cd4113b1856f3fd611f54cd0f9c03 Mon Sep 17 00:00:00 2001 From: Gil Fine Date: Thu, 26 May 2022 13:59:20 +0300 Subject: [PATCH 0092/1436] thunderbolt: Add CL1 support for USB4 and Titan Ridge routers In this patch we add support for a second low power state of the link: CL1. Low power states (called collectively CLx) are used to reduce transmitter and receiver power when a high-speed lane is idle. We enable it, if both sides of the link support it, and only for the first hop router (i.e. the first device that connected to the host router). This is needed for better thermal management. Signed-off-by: Gil Fine Signed-off-by: Mika Westerberg --- drivers/thunderbolt/switch.c | 89 ++++++++--------- drivers/thunderbolt/tb.c | 55 ++++++++--- drivers/thunderbolt/tb.h | 46 ++++----- drivers/thunderbolt/tb_regs.h | 6 ++ drivers/thunderbolt/tmu.c | 177 ++++++++++++++++++++++++++++------ 5 files changed, 266 insertions(+), 107 deletions(-) diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c index e584077b2f4f..244f8cd38b25 100644 --- a/drivers/thunderbolt/switch.c +++ b/drivers/thunderbolt/switch.c @@ -3133,10 +3133,12 @@ void tb_switch_suspend(struct tb_switch *sw, bool runtime) /* * Actually only needed for Titan Ridge but for simplicity can be * done for USB4 device too as CLx is re-enabled at resume. + * CL0s and CL1 are enabled and supported together. */ - if (tb_switch_is_clx_enabled(sw)) { - if (tb_switch_disable_clx(sw, TB_CL0S)) - tb_sw_warn(sw, "failed to disable CLx on upstream port\n"); + if (tb_switch_is_clx_enabled(sw, TB_CL1)) { + if (tb_switch_disable_clx(sw, TB_CL1)) + tb_sw_warn(sw, "failed to disable %s on upstream port\n", + tb_switch_clx_name(TB_CL1)); } err = tb_plug_events_active(sw, false); @@ -3428,13 +3430,12 @@ static bool tb_port_clx_supported(struct tb_port *port, enum tb_clx clx) } switch (clx) { - case TB_CL0S: - /* CL0s support requires also CL1 support */ + case TB_CL1: + /* CL0s and CL1 are enabled and supported together */ mask = LANE_ADP_CS_0_CL0S_SUPPORT | LANE_ADP_CS_0_CL1_SUPPORT; break; - /* For now we support only CL0s. Not CL1, CL2 */ - case TB_CL1: + /* For now we support only CL0s and CL1. Not CL2 */ case TB_CL2: default: return false; @@ -3448,18 +3449,18 @@ static bool tb_port_clx_supported(struct tb_port *port, enum tb_clx clx) return !!(val & mask); } -static inline bool tb_port_cl0s_supported(struct tb_port *port) -{ - return tb_port_clx_supported(port, TB_CL0S); -} - -static int __tb_port_cl0s_set(struct tb_port *port, bool enable) +static int __tb_port_clx_set(struct tb_port *port, enum tb_clx clx, bool enable) { u32 phy, mask; int ret; - /* To enable CL0s also required to enable CL1 */ - mask = LANE_ADP_CS_1_CL0S_ENABLE | LANE_ADP_CS_1_CL1_ENABLE; + /* CL0s and CL1 are enabled and supported together */ + if (clx == TB_CL1) + mask = LANE_ADP_CS_1_CL0S_ENABLE | LANE_ADP_CS_1_CL1_ENABLE; + else + /* For now we support only CL0s and CL1. Not CL2 */ + return -EOPNOTSUPP; + ret = tb_port_read(port, &phy, TB_CFG_PORT, port->cap_phy + LANE_ADP_CS_1, 1); if (ret) @@ -3474,20 +3475,20 @@ static int __tb_port_cl0s_set(struct tb_port *port, bool enable) port->cap_phy + LANE_ADP_CS_1, 1); } -static int tb_port_cl0s_disable(struct tb_port *port) +static int tb_port_clx_disable(struct tb_port *port, enum tb_clx clx) { - return __tb_port_cl0s_set(port, false); + return __tb_port_clx_set(port, clx, false); } -static int tb_port_cl0s_enable(struct tb_port *port) +static int tb_port_clx_enable(struct tb_port *port, enum tb_clx clx) { - return __tb_port_cl0s_set(port, true); + return __tb_port_clx_set(port, clx, true); } -static int tb_switch_enable_cl0s(struct tb_switch *sw) +static int __tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx) { struct tb_switch *parent = tb_switch_parent(sw); - bool up_cl0s_support, down_cl0s_support; + bool up_clx_support, down_clx_support; struct tb_port *up, *down; int ret; @@ -3512,37 +3513,37 @@ static int tb_switch_enable_cl0s(struct tb_switch *sw) up = tb_upstream_port(sw); down = tb_port_at(tb_route(sw), parent); - up_cl0s_support = tb_port_cl0s_supported(up); - down_cl0s_support = tb_port_cl0s_supported(down); + up_clx_support = tb_port_clx_supported(up, clx); + down_clx_support = tb_port_clx_supported(down, clx); - tb_port_dbg(up, "CL0s %ssupported\n", - up_cl0s_support ? "" : "not "); - tb_port_dbg(down, "CL0s %ssupported\n", - down_cl0s_support ? "" : "not "); + tb_port_dbg(up, "%s %ssupported\n", tb_switch_clx_name(clx), + up_clx_support ? "" : "not "); + tb_port_dbg(down, "%s %ssupported\n", tb_switch_clx_name(clx), + down_clx_support ? "" : "not "); - if (!up_cl0s_support || !down_cl0s_support) + if (!up_clx_support || !down_clx_support) return -EOPNOTSUPP; - ret = tb_port_cl0s_enable(up); + ret = tb_port_clx_enable(up, clx); if (ret) return ret; - ret = tb_port_cl0s_enable(down); + ret = tb_port_clx_enable(down, clx); if (ret) { - tb_port_cl0s_disable(up); + tb_port_clx_disable(up, clx); return ret; } ret = tb_switch_mask_clx_objections(sw); if (ret) { - tb_port_cl0s_disable(up); - tb_port_cl0s_disable(down); + tb_port_clx_disable(up, clx); + tb_port_clx_disable(down, clx); return ret; } - sw->clx = TB_CL0S; + sw->clx = clx; - tb_port_dbg(up, "CL0s enabled\n"); + tb_port_dbg(up, "%s enabled\n", tb_switch_clx_name(clx)); return 0; } @@ -3575,15 +3576,16 @@ int tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx) return 0; switch (clx) { - case TB_CL0S: - return tb_switch_enable_cl0s(sw); + case TB_CL1: + /* CL0s and CL1 are enabled and supported together */ + return __tb_switch_enable_clx(sw, clx); default: return -EOPNOTSUPP; } } -static int tb_switch_disable_cl0s(struct tb_switch *sw) +static int __tb_switch_disable_clx(struct tb_switch *sw, enum tb_clx clx) { struct tb_switch *parent = tb_switch_parent(sw); struct tb_port *up, *down; @@ -3605,17 +3607,17 @@ static int tb_switch_disable_cl0s(struct tb_switch *sw) up = tb_upstream_port(sw); down = tb_port_at(tb_route(sw), parent); - ret = tb_port_cl0s_disable(up); + ret = tb_port_clx_disable(up, clx); if (ret) return ret; - ret = tb_port_cl0s_disable(down); + ret = tb_port_clx_disable(down, clx); if (ret) return ret; sw->clx = TB_CLX_DISABLE; - tb_port_dbg(up, "CL0s disabled\n"); + tb_port_dbg(up, "%s disabled\n", tb_switch_clx_name(clx)); return 0; } @@ -3632,8 +3634,9 @@ int tb_switch_disable_clx(struct tb_switch *sw, enum tb_clx clx) return 0; switch (clx) { - case TB_CL0S: - return tb_switch_disable_cl0s(sw); + case TB_CL1: + /* CL0s and CL1 are enabled and supported together */ + return __tb_switch_disable_clx(sw, clx); default: return -EOPNOTSUPP; diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 8ab3530dfa0d..8e9fdc4e0650 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -215,7 +215,7 @@ static int tb_enable_tmu(struct tb_switch *sw) int ret; /* If it is already enabled in correct mode, don't touch it */ - if (tb_switch_tmu_hifi_is_enabled(sw, sw->tmu.unidirectional_request)) + if (tb_switch_tmu_is_enabled(sw, sw->tmu.unidirectional_request)) return 0; ret = tb_switch_tmu_disable(sw); @@ -664,13 +664,24 @@ static void tb_scan_port(struct tb_port *port) tb_switch_lane_bonding_enable(sw); /* Set the link configured */ tb_switch_configure_link(sw); - /* Silently ignore CLx enabling in case CLx is not supported */ - ret = tb_switch_enable_clx(sw, TB_CL0S); + /* + * CL0s and CL1 are enabled and supported together. + * Silently ignore CLx enabling in case CLx is not supported. + */ + ret = tb_switch_enable_clx(sw, TB_CL1); if (ret && ret != -EOPNOTSUPP) - tb_sw_warn(sw, "failed to enable CLx on upstream port\n"); + tb_sw_warn(sw, "failed to enable %s on upstream port\n", + tb_switch_clx_name(TB_CL1)); - tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_HIFI, - tb_switch_is_clx_enabled(sw)); + if (tb_switch_is_clx_enabled(sw, TB_CL1)) + /* + * To support highest CLx state, we set router's TMU to + * Normal-Uni mode. + */ + tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_NORMAL, true); + else + /* If CLx disabled, configure router's TMU to HiFi-Bidir mode*/ + tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_HIFI, false); if (tb_enable_tmu(sw)) tb_sw_warn(sw, "failed to enable TMU\n"); @@ -1410,7 +1421,12 @@ static int tb_start(struct tb *tb) return ret; } - tb_switch_tmu_configure(tb->root_switch, TB_SWITCH_TMU_RATE_HIFI, false); + /* + * To support highest CLx state, we set host router's TMU to + * Normal mode. + */ + tb_switch_tmu_configure(tb->root_switch, TB_SWITCH_TMU_RATE_NORMAL, + false); /* Enable TMU if it is off */ tb_switch_tmu_enable(tb->root_switch); /* Full scan to discover devices added before the driver was loaded. */ @@ -1455,16 +1471,25 @@ static void tb_restore_children(struct tb_switch *sw) if (sw->is_unplugged) return; - /* Silently ignore CLx re-enabling in case CLx is not supported */ - ret = tb_switch_enable_clx(sw, TB_CL0S); - if (ret && ret != -EOPNOTSUPP) - tb_sw_warn(sw, "failed to re-enable CLx on upstream port\n"); - /* - * tb_switch_tmu_configure() was already called when the switch was - * added before entering system sleep or runtime suspend, - * so no need to call it again before enabling TMU. + * CL0s and CL1 are enabled and supported together. + * Silently ignore CLx re-enabling in case CLx is not supported. */ + ret = tb_switch_enable_clx(sw, TB_CL1); + if (ret && ret != -EOPNOTSUPP) + tb_sw_warn(sw, "failed to re-enable %s on upstream port\n", + tb_switch_clx_name(TB_CL1)); + + if (tb_switch_is_clx_enabled(sw, TB_CL1)) + /* + * To support highest CLx state, we set router's TMU to + * Normal-Uni mode. + */ + tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_NORMAL, true); + else + /* If CLx disabled, configure router's TMU to HiFi-Bidir mode*/ + tb_switch_tmu_configure(sw, TB_SWITCH_TMU_RATE_HIFI, false); + if (tb_enable_tmu(sw)) tb_sw_warn(sw, "failed to restore TMU configuration\n"); diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 4602c69913fa..3882b6eb9f51 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -13,6 +13,7 @@ #include #include #include +#include #include "tb_regs.h" #include "ctl.h" @@ -111,7 +112,7 @@ struct tb_switch_tmu { enum tb_clx { TB_CLX_DISABLE, - TB_CL0S, + /* CL0s and CL1 are enabled and supported together */ TB_CL1, TB_CL2, }; @@ -934,45 +935,46 @@ void tb_switch_tmu_configure(struct tb_switch *sw, enum tb_switch_tmu_rate rate, bool unidirectional); /** - * tb_switch_tmu_hifi_is_enabled() - Checks if the specified TMU mode is enabled + * tb_switch_tmu_is_enabled() - Checks if the specified TMU mode is enabled * @sw: Router whose TMU mode to check * @unidirectional: If uni-directional (bi-directional otherwise) * * Return true if hardware TMU configuration matches the one passed in - * as parameter. That is HiFi and either uni-directional or bi-directional. + * as parameter. That is HiFi/Normal and either uni-directional or bi-directional. */ -static inline bool tb_switch_tmu_hifi_is_enabled(const struct tb_switch *sw, - bool unidirectional) +static inline bool tb_switch_tmu_is_enabled(const struct tb_switch *sw, + bool unidirectional) { - return sw->tmu.rate == TB_SWITCH_TMU_RATE_HIFI && + return sw->tmu.rate == sw->tmu.rate_request && sw->tmu.unidirectional == unidirectional; } +static inline const char *tb_switch_clx_name(enum tb_clx clx) +{ + switch (clx) { + /* CL0s and CL1 are enabled and supported together */ + case TB_CL1: + return "CL0s/CL1"; + default: + return "unknown"; + } +} + int tb_switch_enable_clx(struct tb_switch *sw, enum tb_clx clx); int tb_switch_disable_clx(struct tb_switch *sw, enum tb_clx clx); /** * tb_switch_is_clx_enabled() - Checks if the CLx is enabled - * @sw: Router to check the CLx state for + * @sw: Router to check for the CLx + * @clx: The CLx state to check for * - * Checks if the CLx is enabled on the router upstream link. + * Checks if the specified CLx is enabled on the router upstream link. * Not applicable for a host router. */ -static inline bool tb_switch_is_clx_enabled(const struct tb_switch *sw) +static inline bool tb_switch_is_clx_enabled(const struct tb_switch *sw, + enum tb_clx clx) { - return sw->clx != TB_CLX_DISABLE; -} - -/** - * tb_switch_is_cl0s_enabled() - Checks if the CL0s is enabled - * @sw: Router to check for the CL0s - * - * Checks if the CL0s is enabled on the router upstream link. - * Not applicable for a host router. - */ -static inline bool tb_switch_is_cl0s_enabled(const struct tb_switch *sw) -{ - return sw->clx == TB_CL0S; + return sw->clx == clx; } /** diff --git a/drivers/thunderbolt/tb_regs.h b/drivers/thunderbolt/tb_regs.h index 6a16f61a72a1..166054110388 100644 --- a/drivers/thunderbolt/tb_regs.h +++ b/drivers/thunderbolt/tb_regs.h @@ -234,6 +234,7 @@ enum usb4_switch_op { /* Router TMU configuration */ #define TMU_RTR_CS_0 0x00 +#define TMU_RTR_CS_0_FREQ_WIND_MASK GENMASK(26, 16) #define TMU_RTR_CS_0_TD BIT(27) #define TMU_RTR_CS_0_UCAP BIT(30) #define TMU_RTR_CS_1 0x01 @@ -244,6 +245,11 @@ enum usb4_switch_op { #define TMU_RTR_CS_3_LOCAL_TIME_NS_MASK GENMASK(15, 0) #define TMU_RTR_CS_3_TS_PACKET_INTERVAL_MASK GENMASK(31, 16) #define TMU_RTR_CS_3_TS_PACKET_INTERVAL_SHIFT 16 +#define TMU_RTR_CS_15 0xf +#define TMU_RTR_CS_15_FREQ_AVG_MASK GENMASK(5, 0) +#define TMU_RTR_CS_15_DELAY_AVG_MASK GENMASK(11, 6) +#define TMU_RTR_CS_15_OFFSET_AVG_MASK GENMASK(17, 12) +#define TMU_RTR_CS_15_ERROR_AVG_MASK GENMASK(23, 18) #define TMU_RTR_CS_22 0x16 #define TMU_RTR_CS_24 0x18 #define TMU_RTR_CS_25 0x19 diff --git a/drivers/thunderbolt/tmu.c b/drivers/thunderbolt/tmu.c index 985ca43b8f39..e822ab90338b 100644 --- a/drivers/thunderbolt/tmu.c +++ b/drivers/thunderbolt/tmu.c @@ -11,6 +11,55 @@ #include "tb.h" +static int tb_switch_set_tmu_mode_params(struct tb_switch *sw, + enum tb_switch_tmu_rate rate) +{ + u32 freq_meas_wind[2] = { 30, 800 }; + u32 avg_const[2] = { 4, 8 }; + u32 freq, avg, val; + int ret; + + if (rate == TB_SWITCH_TMU_RATE_NORMAL) { + freq = freq_meas_wind[0]; + avg = avg_const[0]; + } else if (rate == TB_SWITCH_TMU_RATE_HIFI) { + freq = freq_meas_wind[1]; + avg = avg_const[1]; + } else { + return 0; + } + + ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, + sw->tmu.cap + TMU_RTR_CS_0, 1); + if (ret) + return ret; + + val &= ~TMU_RTR_CS_0_FREQ_WIND_MASK; + val |= FIELD_PREP(TMU_RTR_CS_0_FREQ_WIND_MASK, freq); + + ret = tb_sw_write(sw, &val, TB_CFG_SWITCH, + sw->tmu.cap + TMU_RTR_CS_0, 1); + if (ret) + return ret; + + ret = tb_sw_read(sw, &val, TB_CFG_SWITCH, + sw->tmu.cap + TMU_RTR_CS_15, 1); + if (ret) + return ret; + + val &= ~TMU_RTR_CS_15_FREQ_AVG_MASK & + ~TMU_RTR_CS_15_DELAY_AVG_MASK & + ~TMU_RTR_CS_15_OFFSET_AVG_MASK & + ~TMU_RTR_CS_15_ERROR_AVG_MASK; + val |= FIELD_PREP(TMU_RTR_CS_15_FREQ_AVG_MASK, avg) | + FIELD_PREP(TMU_RTR_CS_15_DELAY_AVG_MASK, avg) | + FIELD_PREP(TMU_RTR_CS_15_OFFSET_AVG_MASK, avg) | + FIELD_PREP(TMU_RTR_CS_15_ERROR_AVG_MASK, avg); + + return tb_sw_write(sw, &val, TB_CFG_SWITCH, + sw->tmu.cap + TMU_RTR_CS_15, 1); +} + static const char *tb_switch_tmu_mode_name(const struct tb_switch *sw) { bool root_switch = !tb_route(sw); @@ -348,7 +397,7 @@ int tb_switch_tmu_disable(struct tb_switch *sw) if (tb_route(sw)) { - bool unidirectional = tb_switch_tmu_hifi_is_enabled(sw, true); + bool unidirectional = sw->tmu.unidirectional; struct tb_switch *parent = tb_switch_parent(sw); struct tb_port *down, *up; int ret; @@ -412,6 +461,7 @@ static void __tb_switch_tmu_off(struct tb_switch *sw, bool unidirectional) else tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_OFF); + tb_switch_set_tmu_mode_params(sw, sw->tmu.rate); tb_port_tmu_unidirectional_disable(down); tb_port_tmu_unidirectional_disable(up); } @@ -493,7 +543,11 @@ static int __tb_switch_tmu_enable_unidirectional(struct tb_switch *sw) up = tb_upstream_port(sw); down = tb_port_at(tb_route(sw), parent); - ret = tb_switch_tmu_rate_write(parent, TB_SWITCH_TMU_RATE_HIFI); + ret = tb_switch_tmu_rate_write(parent, sw->tmu.rate_request); + if (ret) + return ret; + + ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.rate_request); if (ret) return ret; @@ -520,7 +574,83 @@ out: return ret; } -static int tb_switch_tmu_hifi_enable(struct tb_switch *sw) +static void __tb_switch_tmu_change_mode_prev(struct tb_switch *sw) +{ + struct tb_switch *parent = tb_switch_parent(sw); + struct tb_port *down, *up; + + down = tb_port_at(tb_route(sw), parent); + up = tb_upstream_port(sw); + /* + * In case of any failure in one of the steps when change mode, + * get back to the TMU configurations in previous mode. + * In case of additional failures in the functions below, + * ignore them since the caller shall already report a failure. + */ + tb_port_tmu_set_unidirectional(down, sw->tmu.unidirectional); + if (sw->tmu.unidirectional_request) + tb_switch_tmu_rate_write(parent, sw->tmu.rate); + else + tb_switch_tmu_rate_write(sw, sw->tmu.rate); + + tb_switch_set_tmu_mode_params(sw, sw->tmu.rate); + tb_port_tmu_set_unidirectional(up, sw->tmu.unidirectional); +} + +static int __tb_switch_tmu_change_mode(struct tb_switch *sw) +{ + struct tb_switch *parent = tb_switch_parent(sw); + struct tb_port *up, *down; + int ret; + + up = tb_upstream_port(sw); + down = tb_port_at(tb_route(sw), parent); + ret = tb_port_tmu_set_unidirectional(down, sw->tmu.unidirectional_request); + if (ret) + goto out; + + if (sw->tmu.unidirectional_request) + ret = tb_switch_tmu_rate_write(parent, sw->tmu.rate_request); + else + ret = tb_switch_tmu_rate_write(sw, sw->tmu.rate_request); + if (ret) + return ret; + + ret = tb_switch_set_tmu_mode_params(sw, sw->tmu.rate_request); + if (ret) + return ret; + + ret = tb_port_tmu_set_unidirectional(up, sw->tmu.unidirectional_request); + if (ret) + goto out; + + ret = tb_port_tmu_time_sync_enable(down); + if (ret) + goto out; + + ret = tb_port_tmu_time_sync_enable(up); + if (ret) + goto out; + + return 0; + +out: + __tb_switch_tmu_change_mode_prev(sw); + return ret; +} + +/** + * tb_switch_tmu_enable() - Enable TMU on a router + * @sw: Router whose TMU to enable + * + * Enables TMU of a router to be in uni-directional Normal/HiFi + * or bi-directional HiFi mode. Calling tb_switch_tmu_configure() is required + * before calling this function, to select the mode Normal/HiFi and + * directionality (uni-directional/bi-directional). + * In HiFi mode all tunneling should work. In Normal mode, DP tunneling can't + * work. Uni-directional mode is required for CLx (Link Low-Power) to work. + */ +int tb_switch_tmu_enable(struct tb_switch *sw) { bool unidirectional = sw->tmu.unidirectional_request; int ret; @@ -536,12 +666,15 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw) if (!tb_switch_is_clx_supported(sw)) return 0; - if (tb_switch_tmu_hifi_is_enabled(sw, sw->tmu.unidirectional_request)) + if (tb_switch_tmu_is_enabled(sw, sw->tmu.unidirectional_request)) return 0; if (tb_switch_is_titan_ridge(sw) && unidirectional) { - /* Titan Ridge supports only CL0s */ - if (!tb_switch_is_cl0s_enabled(sw)) + /* + * Titan Ridge supports CL0s and CL1 only. CL0s and CL1 are + * enabled and supported together. + */ + if (!tb_switch_is_clx_enabled(sw, TB_CL1)) return -EOPNOTSUPP; ret = tb_switch_tmu_objection_mask(sw); @@ -558,7 +691,11 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw) return ret; if (tb_route(sw)) { - /* The used mode changes are from OFF to HiFi-Uni/HiFi-BiDir */ + /* + * The used mode changes are from OFF to + * HiFi-Uni/HiFi-BiDir/Normal-Uni or from Normal-Uni to + * HiFi-Uni. + */ if (sw->tmu.rate == TB_SWITCH_TMU_RATE_OFF) { if (unidirectional) ret = __tb_switch_tmu_enable_unidirectional(sw); @@ -566,6 +703,10 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw) ret = __tb_switch_tmu_enable_bidirectional(sw); if (ret) return ret; + } else if (sw->tmu.rate == TB_SWITCH_TMU_RATE_NORMAL) { + ret = __tb_switch_tmu_change_mode(sw); + if (ret) + return ret; } sw->tmu.unidirectional = unidirectional; } else { @@ -575,35 +716,17 @@ static int tb_switch_tmu_hifi_enable(struct tb_switch *sw) * of the child node - see above. * Here only the host router' rate configuration is written. */ - ret = tb_switch_tmu_rate_write(sw, TB_SWITCH_TMU_RATE_HIFI); + ret = tb_switch_tmu_rate_write(sw, sw->tmu.rate_request); if (ret) return ret; } - sw->tmu.rate = TB_SWITCH_TMU_RATE_HIFI; + sw->tmu.rate = sw->tmu.rate_request; tb_sw_dbg(sw, "TMU: mode set to: %s\n", tb_switch_tmu_mode_name(sw)); return tb_switch_tmu_set_time_disruption(sw, false); } -/** - * tb_switch_tmu_enable() - Enable TMU on a router - * @sw: Router whose TMU to enable - * - * Enables TMU of a router to be in uni-directional or bi-directional HiFi mode. - * Calling tb_switch_tmu_configure() is required before calling this function, - * to select the mode HiFi and directionality (uni-directional/bi-directional). - * In both modes all tunneling should work. Uni-directional mode is required for - * CLx (Link Low-Power) to work. - */ -int tb_switch_tmu_enable(struct tb_switch *sw) -{ - if (sw->tmu.rate_request == TB_SWITCH_TMU_RATE_NORMAL) - return -EOPNOTSUPP; - - return tb_switch_tmu_hifi_enable(sw); -} - /** * tb_switch_tmu_configure() - Configure the TMU rate and directionality * @sw: Router whose mode to change From 3084b48fa13931400f316e2b9ffdd98b8ba6600e Mon Sep 17 00:00:00 2001 From: Gil Fine Date: Thu, 26 May 2022 13:59:21 +0300 Subject: [PATCH 0093/1436] thunderbolt: Change TMU mode to HiFi uni-directional once DisplayPort tunneled Here we configure TMU mode to HiFi uni-directional once DP tunnel is created. This is due to accuracy requirement for DP tunneling as appears in CM guide 1.0, section 7.3.2. Due to Intel hardware limitation, once we changed the TMU mode to HiFi uni-directional (when DP tunnel exists), we don't change TMU mode back to normal uni-directional, even if DP tunnel is torn down later. Signed-off-by: Gil Fine Signed-off-by: Mika Westerberg --- drivers/thunderbolt/tb.c | 13 +++++++++++++ drivers/thunderbolt/tb.h | 2 ++ drivers/thunderbolt/tmu.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 8e9fdc4e0650..9853f6c7e81d 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -118,6 +118,13 @@ static void tb_switch_discover_tunnels(struct tb_switch *sw, switch (port->config.type) { case TB_TYPE_DP_HDMI_IN: tunnel = tb_tunnel_discover_dp(tb, port, alloc_hopids); + /* + * In case of DP tunnel exists, change host router's + * 1st children TMU mode to HiFi for CL0s to work. + */ + if (tunnel) + tb_switch_enable_tmu_1st_child(tb->root_switch, + TB_SWITCH_TMU_RATE_HIFI); break; case TB_TYPE_PCIE_DOWN: @@ -979,6 +986,12 @@ static void tb_tunnel_dp(struct tb *tb) list_add_tail(&tunnel->list, &tcm->tunnel_list); tb_reclaim_usb3_bandwidth(tb, in, out); + /* + * In case of DP tunnel exists, change host router's 1st children + * TMU mode to HiFi for CL0s to work. + */ + tb_switch_enable_tmu_1st_child(tb->root_switch, TB_SWITCH_TMU_RATE_HIFI); + return; err_free: diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h index 3882b6eb9f51..e2f50fd90ba9 100644 --- a/drivers/thunderbolt/tb.h +++ b/drivers/thunderbolt/tb.h @@ -934,6 +934,8 @@ int tb_switch_tmu_enable(struct tb_switch *sw); void tb_switch_tmu_configure(struct tb_switch *sw, enum tb_switch_tmu_rate rate, bool unidirectional); +void tb_switch_enable_tmu_1st_child(struct tb_switch *sw, + enum tb_switch_tmu_rate rate); /** * tb_switch_tmu_is_enabled() - Checks if the specified TMU mode is enabled * @sw: Router whose TMU mode to check diff --git a/drivers/thunderbolt/tmu.c b/drivers/thunderbolt/tmu.c index e822ab90338b..626aca3124b1 100644 --- a/drivers/thunderbolt/tmu.c +++ b/drivers/thunderbolt/tmu.c @@ -742,3 +742,32 @@ void tb_switch_tmu_configure(struct tb_switch *sw, sw->tmu.unidirectional_request = unidirectional; sw->tmu.rate_request = rate; } + +static int tb_switch_tmu_config_enable(struct device *dev, void *rate) +{ + if (tb_is_switch(dev)) { + struct tb_switch *sw = tb_to_switch(dev); + + tb_switch_tmu_configure(sw, *(enum tb_switch_tmu_rate *)rate, + tb_switch_is_clx_enabled(sw, TB_CL1)); + if (tb_switch_tmu_enable(sw)) + tb_sw_dbg(sw, "fail switching TMU mode for 1st depth router\n"); + } + + return 0; +} + +/** + * tb_switch_enable_tmu_1st_child - Configure and enable TMU for 1st chidren + * @sw: The router to configure and enable it's children TMU + * @rate: Rate of the TMU to configure the router's chidren to + * + * Configures and enables the TMU mode of 1st depth children of the specified + * router to the specified rate. + */ +void tb_switch_enable_tmu_1st_child(struct tb_switch *sw, + enum tb_switch_tmu_rate rate) +{ + device_for_each_child(&sw->dev, &rate, + tb_switch_tmu_config_enable); +} From e173b7d46c0413f004450bfc48f45bfc0f0f2fc2 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 26 May 2022 21:01:54 +0800 Subject: [PATCH 0094/1436] thunderbolt: Fix some kernel-doc comments Remove some warnings found by running scripts/kernel-doc, which is caused by using 'make W=1'. drivers/thunderbolt/ctl.c:701: warning: expecting prototype for tb_cfg_start(). Prototype was for tb_ctl_start() instead drivers/thunderbolt/ctl.c:722: warning: expecting prototype for tb_ctrl_stop(). Prototype was for tb_ctl_stop() instead drivers/thunderbolt/ctl.c:930: warning: expecting prototype for tb_cfg_write(). Prototype was for tb_cfg_write_raw() instead Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: Mika Westerberg --- drivers/thunderbolt/ctl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index e92c658dba1c..e5ede5debfb0 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -694,7 +694,7 @@ void tb_ctl_free(struct tb_ctl *ctl) } /** - * tb_cfg_start() - start/resume the control channel + * tb_ctl_start() - start/resume the control channel * @ctl: Control channel to start */ void tb_ctl_start(struct tb_ctl *ctl) @@ -710,7 +710,7 @@ void tb_ctl_start(struct tb_ctl *ctl) } /** - * tb_ctrl_stop() - pause the control channel + * tb_ctl_stop() - pause the control channel * @ctl: Control channel to stop * * All invocations of ctl->callback will have finished after this method @@ -912,7 +912,7 @@ struct tb_cfg_result tb_cfg_read_raw(struct tb_ctl *ctl, void *buffer, } /** - * tb_cfg_write() - write from buffer into config space + * tb_cfg_write_raw() - write from buffer into config space * @ctl: Pointer to the control channel * @buffer: Data to write * @route: Route string of the router From 7ec58378a985618909ffae18e4ac0de2ae625f33 Mon Sep 17 00:00:00 2001 From: George D Sworo Date: Wed, 1 Jun 2022 15:41:02 -0700 Subject: [PATCH 0095/1436] thunderbolt: Add support for Intel Raptor Lake Intel Raptor Lake has the same integrated Thunderbolt/USB4 controller as Intel Alder Lake. By default it is still using firmware based connection manager so we can use most of the Alder Lake flows. Signed-off-by: George D Sworo Signed-off-by: Mika Westerberg --- drivers/thunderbolt/icm.c | 2 ++ drivers/thunderbolt/nhi.c | 4 ++++ drivers/thunderbolt/nhi.h | 2 ++ 3 files changed, 8 insertions(+) diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index fff0c740c8f3..ae38f0d25a8d 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -2516,6 +2516,8 @@ struct tb *icm_probe(struct tb_nhi *nhi) case PCI_DEVICE_ID_INTEL_TGL_H_NHI1: case PCI_DEVICE_ID_INTEL_ADL_NHI0: case PCI_DEVICE_ID_INTEL_ADL_NHI1: + case PCI_DEVICE_ID_INTEL_RPL_NHI0: + case PCI_DEVICE_ID_INTEL_RPL_NHI1: icm->is_supported = icm_tgl_is_supported; icm->driver_ready = icm_icl_driver_ready; icm->set_uuid = icm_icl_set_uuid; diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index 1333b158a95e..cb8c9c4ae93a 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -1410,6 +1410,10 @@ static struct pci_device_id nhi_ids[] = { .driver_data = (kernel_ulong_t)&icl_nhi_ops }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_NHI1), .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL_NHI0), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL_NHI1), + .driver_data = (kernel_ulong_t)&icl_nhi_ops }, /* Any USB4 compliant host */ { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_USB4, ~0) }, diff --git a/drivers/thunderbolt/nhi.h b/drivers/thunderbolt/nhi.h index 69083aab2736..f09da5b62233 100644 --- a/drivers/thunderbolt/nhi.h +++ b/drivers/thunderbolt/nhi.h @@ -80,6 +80,8 @@ extern const struct tb_nhi_ops icl_nhi_ops; #define PCI_DEVICE_ID_INTEL_TGL_NHI1 0x9a1d #define PCI_DEVICE_ID_INTEL_TGL_H_NHI0 0x9a1f #define PCI_DEVICE_ID_INTEL_TGL_H_NHI1 0x9a21 +#define PCI_DEVICE_ID_INTEL_RPL_NHI0 0xa73e +#define PCI_DEVICE_ID_INTEL_RPL_NHI1 0xa76d #define PCI_CLASS_SERIAL_USB_USB4 0x0c0340 From 39d649602be2ceb3f8f8e98483d09e4d71133c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Wed, 1 Jun 2022 10:17:58 +0200 Subject: [PATCH 0096/1436] of: constify of_property_check_flags() prop argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This argument is not modified and thus can be set as const. Signed-off-by: Clément Léger Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220601081801.348571-2-clement.leger@bootlin.com --- include/linux/of.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/of.h b/include/linux/of.h index f0a5d6b10c5a..d74fd82a6963 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -207,7 +207,7 @@ static inline void of_node_clear_flag(struct device_node *n, unsigned long flag) } #if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC) -static inline int of_property_check_flag(struct property *p, unsigned long flag) +static inline int of_property_check_flag(const struct property *p, unsigned long flag) { return test_bit(flag, &p->_flags); } @@ -814,7 +814,8 @@ static inline void of_node_clear_flag(struct device_node *n, unsigned long flag) { } -static inline int of_property_check_flag(struct property *p, unsigned long flag) +static inline int of_property_check_flag(const struct property *p, + unsigned long flag) { return 0; } From 442feb3174dc7b801fc9703c9c9113bf5e1e3caf Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sun, 29 May 2022 15:26:37 +0200 Subject: [PATCH 0097/1436] dt-bindings: ps2-gpio: convert binding to json-schema Convert the ps2-gpio dt-binding documentation to DT schema format using the json-schema. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Danilo Krummrich Reviewed-by: Linus Walleij Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220529132638.13420-1-danilokrummrich@dk-develop.de --- .../devicetree/bindings/serio/ps2-gpio.txt | 23 -------- .../devicetree/bindings/serio/ps2-gpio.yaml | 58 +++++++++++++++++++ 2 files changed, 58 insertions(+), 23 deletions(-) delete mode 100644 Documentation/devicetree/bindings/serio/ps2-gpio.txt create mode 100644 Documentation/devicetree/bindings/serio/ps2-gpio.yaml diff --git a/Documentation/devicetree/bindings/serio/ps2-gpio.txt b/Documentation/devicetree/bindings/serio/ps2-gpio.txt deleted file mode 100644 index 7b7bc9cdf986..000000000000 --- a/Documentation/devicetree/bindings/serio/ps2-gpio.txt +++ /dev/null @@ -1,23 +0,0 @@ -Device-Tree binding for ps/2 gpio device - -Required properties: - - compatible = "ps2-gpio" - - data-gpios: the data pin - - clk-gpios: the clock pin - - interrupts: Should trigger on the falling edge of the clock line. - -Optional properties: - - write-enable: Indicates whether write function is provided - to serio device. Possibly providing the write fn will not work, because - of the tough timing requirements. - -Example nodes: - -ps2@0 { - compatible = "ps2-gpio"; - interrupt-parent = <&gpio>; - interrupts = <23 IRQ_TYPE_EDGE_FALLING>; - data-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; - clk-gpios = <&gpio 23 GPIO_ACTIVE_HIGH>; - write-enable; -}; diff --git a/Documentation/devicetree/bindings/serio/ps2-gpio.yaml b/Documentation/devicetree/bindings/serio/ps2-gpio.yaml new file mode 100644 index 000000000000..304132fd30c5 --- /dev/null +++ b/Documentation/devicetree/bindings/serio/ps2-gpio.yaml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serio/ps2-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Bindings for GPIO based PS/2 + +maintainers: + - Danilo Krummrich + +properties: + compatible: + const: ps2-gpio + + data-gpios: + description: + the gpio used for the data signal + maxItems: 1 + + clk-gpios: + description: + the gpio used for the clock signal + maxItems: 1 + + interrupts: + description: + The given interrupt should trigger on the falling edge of the clock line. + maxItems: 1 + + write-enable: + type: boolean + description: + Indicates whether write function is provided to serio device. Possibly + providing the write function will not work, because of the tough timing + requirements. + +required: + - compatible + - data-gpios + - clk-gpios + - interrupts + +additionalProperties: false + +examples: + - | + #include + #include + + ps2 { + compatible = "ps2-gpio"; + interrupt-parent = <&gpio>; + interrupts = <23 IRQ_TYPE_EDGE_FALLING>; + data-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; + clk-gpios = <&gpio 23 GPIO_ACTIVE_HIGH>; + write-enable; + }; From ef17936654043829ac527a2e0483d944eaba30aa Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Sun, 29 May 2022 15:26:38 +0200 Subject: [PATCH 0098/1436] dt-bindings: ps2-gpio: document bus signals open drain The PS/2 bus defines data and clock line to be open drain, this should be reflected in the gpio flags set in the binding. Especially, this is important since the clock line sometimes is driven by the host while being used as interrupt source. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Danilo Krummrich Reviewed-by: Linus Walleij Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220529132638.13420-2-danilokrummrich@dk-develop.de --- .../devicetree/bindings/serio/ps2-gpio.yaml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/serio/ps2-gpio.yaml b/Documentation/devicetree/bindings/serio/ps2-gpio.yaml index 304132fd30c5..a63d9172346f 100644 --- a/Documentation/devicetree/bindings/serio/ps2-gpio.yaml +++ b/Documentation/devicetree/bindings/serio/ps2-gpio.yaml @@ -15,12 +15,18 @@ properties: data-gpios: description: - the gpio used for the data signal + the gpio used for the data signal - this should be flagged as + active high using open drain with (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN) + from since the signal is open drain by + definition maxItems: 1 clk-gpios: description: - the gpio used for the clock signal + the gpio used for the clock signal - this should be flagged as + active high using open drain with (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN) + from since the signal is open drain by + definition maxItems: 1 interrupts: @@ -52,7 +58,7 @@ examples: compatible = "ps2-gpio"; interrupt-parent = <&gpio>; interrupts = <23 IRQ_TYPE_EDGE_FALLING>; - data-gpios = <&gpio 24 GPIO_ACTIVE_HIGH>; - clk-gpios = <&gpio 23 GPIO_ACTIVE_HIGH>; + data-gpios = <&gpio 24 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + clk-gpios = <&gpio 23 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; write-enable; }; From f06e4c9ec81e7884bd93c4126023c6c74168ac7d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 19 May 2022 15:41:06 +0200 Subject: [PATCH 0099/1436] dt-bindings: display: bridge: sil,sii9022: Convert to json-schema Convert the Silicon Image sii902x HDMI bridge Device Tree binding documentation to json-schema. Add missing sil,sii9022-cpi and sil,sii9022-tpi compatible values. Signed-off-by: Geert Uytterhoeven Reviewed-by: Rob Herring Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/2f8e12b4980a82788c1dd413ceedf8d144fdca91.1652967387.git.geert+renesas@glider.be --- .../bindings/display/bridge/sii902x.txt | 78 ----------- .../bindings/display/bridge/sil,sii9022.yaml | 131 ++++++++++++++++++ 2 files changed, 131 insertions(+), 78 deletions(-) delete mode 100644 Documentation/devicetree/bindings/display/bridge/sii902x.txt create mode 100644 Documentation/devicetree/bindings/display/bridge/sil,sii9022.yaml diff --git a/Documentation/devicetree/bindings/display/bridge/sii902x.txt b/Documentation/devicetree/bindings/display/bridge/sii902x.txt deleted file mode 100644 index 3bc760cc31cb..000000000000 --- a/Documentation/devicetree/bindings/display/bridge/sii902x.txt +++ /dev/null @@ -1,78 +0,0 @@ -sii902x HDMI bridge bindings - -Required properties: - - compatible: "sil,sii9022" - - reg: i2c address of the bridge - -Optional properties: - - interrupts: describe the interrupt line used to inform the host - about hotplug events. - - reset-gpios: OF device-tree gpio specification for RST_N pin. - - iovcc-supply: I/O Supply Voltage (1.8V or 3.3V) - - cvcc12-supply: Digital Core Supply Voltage (1.2V) - - HDMI audio properties: - - #sound-dai-cells: <0> or <1>. <0> if only i2s or spdif pin - is wired, <1> if the both are wired. HDMI audio is - configured only if this property is found. - - sil,i2s-data-lanes: Array of up to 4 integers with values of 0-3 - Each integer indicates which i2s pin is connected to which - audio fifo. The first integer selects i2s audio pin for the - first audio fifo#0 (HDMI channels 1&2), second for fifo#1 - (HDMI channels 3&4), and so on. There is 4 fifos and 4 i2s - pins (SD0 - SD3). Any i2s pin can be connected to any fifo, - but there can be no gaps. E.g. an i2s pin must be mapped to - fifo#0 and fifo#1 before mapping a channel to fifo#2. Default - value is <0>, describing SD0 pin beiging routed to hdmi audio - fifo #0. - - clocks: phandle and clock specifier for each clock listed in - the clock-names property - - clock-names: "mclk" - Describes SII902x MCLK input. MCLK can be used to produce - HDMI audio CTS values. This property follows - Documentation/devicetree/bindings/clock/clock-bindings.txt - consumer binding. - - If HDMI audio is configured the sii902x device becomes an I2S - and/or spdif audio codec component (e.g a digital audio sink), - that can be used in configuring a full audio devices with - simple-card or audio-graph-card binding. See their binding - documents on how to describe the way the sii902x device is - connected to the rest of the audio system: - Documentation/devicetree/bindings/sound/simple-card.yaml - Documentation/devicetree/bindings/sound/audio-graph-card.yaml - Note: In case of the audio-graph-card binding the used port - index should be 3. - -Optional subnodes: - - video input: this subnode can contain a video input port node - to connect the bridge to a display controller output (See this - documentation [1]). - -[1]: Documentation/devicetree/bindings/media/video-interfaces.txt - -Example: - hdmi-bridge@39 { - compatible = "sil,sii9022"; - reg = <0x39>; - reset-gpios = <&pioA 1 0>; - iovcc-supply = <&v3v3_hdmi>; - cvcc12-supply = <&v1v2_hdmi>; - - #sound-dai-cells = <0>; - sil,i2s-data-lanes = < 0 1 2 >; - clocks = <&mclk>; - clock-names = "mclk"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - bridge_in: endpoint { - remote-endpoint = <&dc_out>; - }; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/display/bridge/sil,sii9022.yaml b/Documentation/devicetree/bindings/display/bridge/sil,sii9022.yaml new file mode 100644 index 000000000000..5a69547ad3d7 --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/sil,sii9022.yaml @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/sil,sii9022.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Silicon Image sii902x HDMI bridge + +maintainers: + - Boris Brezillon + +properties: + compatible: + oneOf: + - items: + - enum: + - sil,sii9022-cpi # CEC Programming Interface + - sil,sii9022-tpi # Transmitter Programming Interface + - const: sil,sii9022 + - const: sil,sii9022 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + description: Interrupt line used to inform the host about hotplug events. + + reset-gpios: + maxItems: 1 + + iovcc-supply: + description: I/O Supply Voltage (1.8V or 3.3V) + + cvcc12-supply: + description: Digital Core Supply Voltage (1.2V) + + '#sound-dai-cells': + enum: [ 0, 1 ] + description: | + <0> if only I2S or S/PDIF pin is wired, + <1> if both are wired. + HDMI audio is configured only if this property is found. + If HDMI audio is configured, the sii902x device becomes an I2S and/or + S/PDIF audio codec component (e.g. a digital audio sink), that can be + used in configuring full audio devices with simple-card or + audio-graph-card bindings. See their binding documents on how to describe + the way the + sii902x device is connected to the rest of the audio system: + Documentation/devicetree/bindings/sound/simple-card.yaml + Documentation/devicetree/bindings/sound/audio-graph-card.yaml + Note: In case of the audio-graph-card binding the used port index should + be 3. + + sil,i2s-data-lanes: + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 4 + uniqueItems: true + items: + enum: [ 0, 1, 2, 3 ] + description: + Each integer indicates which I2S pin is connected to which audio FIFO. + The first integer selects the I2S audio pin for the first audio FIFO#0 + (HDMI channels 1&2), the second for FIFO#1 (HDMI channels 3&4), and so + on. There are 4 FIFOs and 4 I2S pins (SD0 - SD3). Any I2S pin can be + connected to any FIFO, but there can be no gaps. E.g. an I2S pin must be + mapped to FIFO#0 and FIFO#1 before mapping a channel to FIFO#2. The + default value is <0>, describing SD0 pin being routed to HDMI audio + FIFO#0. + + clocks: + maxItems: 1 + description: MCLK input. MCLK can be used to produce HDMI audio CTS values. + + clock-names: + const: mclk + + ports: + $ref: /schemas/graph.yaml#/properties/ports + + properties: + port@0: + $ref: /schemas/graph.yaml#/properties/port + description: Parallel RGB input port + + port@1: + $ref: /schemas/graph.yaml#/properties/port + description: HDMI output port + + port@3: + $ref: /schemas/graph.yaml#/properties/port + description: Sound input port + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + hdmi-bridge@39 { + compatible = "sil,sii9022"; + reg = <0x39>; + reset-gpios = <&pioA 1 0>; + iovcc-supply = <&v3v3_hdmi>; + cvcc12-supply = <&v1v2_hdmi>; + + #sound-dai-cells = <0>; + sil,i2s-data-lanes = < 0 1 2 >; + clocks = <&mclk>; + clock-names = "mclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + bridge_in: endpoint { + remote-endpoint = <&dc_out>; + }; + }; + }; + }; + }; From 5e9c7546b2be9ac4d0881e23c2c30371f8d92cd9 Mon Sep 17 00:00:00 2001 From: Daniel Watson Date: Mon, 6 Jun 2022 23:11:13 -0700 Subject: [PATCH 0100/1436] staging: r8188eu: fix declaration to match 'foo *bar' put '*' next to variable to match kernel style from checkpatch Signed-off-by: Daniel Watson Link: https://lore.kernel.org/r/20220607061113.32633-1-ozzloy@challenge-bot.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/include/rtw_io.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/include/rtw_io.h b/drivers/staging/r8188eu/include/rtw_io.h index 6910e2b430e2..0e390eda5b4d 100644 --- a/drivers/staging/r8188eu/include/rtw_io.h +++ b/drivers/staging/r8188eu/include/rtw_io.h @@ -283,7 +283,7 @@ void free_io_queue(struct adapter *adapter); void async_bus_io(struct io_queue *pio_q); void bus_sync_io(struct io_queue *pio_q); u32 _ioreq2rwmem(struct io_queue *pio_q); -void dev_power_down(struct adapter * Adapter, u8 bpwrup); +void dev_power_down(struct adapter *Adapter, u8 bpwrup); #define PlatformEFIOWrite1Byte(_a,_b,_c) \ rtw_write8(_a,_b,_c) From e2b925edc55aa79d2c72889de1d7edd11e1c06f3 Mon Sep 17 00:00:00 2001 From: Steve Lemuel Date: Mon, 6 Jun 2022 17:57:45 +0800 Subject: [PATCH 0101/1436] staging: greybus: loopback: fix a spelling error. asynchronus -> asynchronous Signed-off-by: Steve Lemuel Link: https://lore.kernel.org/r/SYBP282MB347864E247D2EC70BF46F9A3A0A29@SYBP282MB3478.AUSP282.PROD.OUTLOOK.COM Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/loopback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c index 2471448ba42a..1a61fce98056 100644 --- a/drivers/staging/greybus/loopback.c +++ b/drivers/staging/greybus/loopback.c @@ -870,7 +870,7 @@ static int gb_loopback_fn(void *data) if (gb->send_count == gb->iteration_max) { mutex_unlock(&gb->mutex); - /* Wait for synchronous and asynchronus completion */ + /* Wait for synchronous and asynchronous completion */ gb_loopback_async_wait_all(gb); /* Mark complete unless user-space has poked us */ From 18697b479330508491928a0d8593ba6c005591b7 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Mon, 6 Jun 2022 08:40:55 +0200 Subject: [PATCH 0102/1436] staging: r8188eu: remove HW_VAR_SLOT_TIME from SetHwReg8188EU() In order to get rid of the function SetHwReg8188EU() remove the HW_VAR_SLOT_TIME case from that function and move the functionality into a static function in rtw_wlan_util.c. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220606064055.12565-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_wlan_util.c | 26 +++++++++++++++++++- drivers/staging/r8188eu/hal/usb_halinit.c | 24 ------------------ drivers/staging/r8188eu/include/hal_intf.h | 1 - 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_wlan_util.c b/drivers/staging/r8188eu/core/rtw_wlan_util.c index 392a65783f32..9f0a823b6e52 100644 --- a/drivers/staging/r8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/r8188eu/core/rtw_wlan_util.c @@ -1348,6 +1348,30 @@ static void set_ack_preamble(struct adapter *adapter, bool short_preamble) rtw_write8(adapter, REG_RRSR + 2, val8); }; +static void set_slot_time(struct adapter *adapter, u8 slot_time) +{ + u8 u1bAIFS, aSifsTime; + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + rtw_write8(adapter, REG_SLOT, slot_time); + + if (pmlmeinfo->WMM_enable == 0) { + if (pmlmeext->cur_wireless_mode == WIRELESS_11B) + aSifsTime = 10; + else + aSifsTime = 16; + + u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime); + + /* Temporary removed, 2008.06.20. */ + rtw_write8(adapter, REG_EDCA_VO_PARAM, u1bAIFS); + rtw_write8(adapter, REG_EDCA_VI_PARAM, u1bAIFS); + rtw_write8(adapter, REG_EDCA_BE_PARAM, u1bAIFS); + rtw_write8(adapter, REG_EDCA_BK_PARAM, u1bAIFS); + } +} + void update_capinfo(struct adapter *Adapter, u16 updateCap) { struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; @@ -1386,7 +1410,7 @@ void update_capinfo(struct adapter *Adapter, u16 updateCap) } } - SetHwReg8188EU(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime); + set_slot_time(Adapter, pmlmeinfo->slotTime); } void update_wireless_mode(struct adapter *padapter) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index a217272a07f8..895619fea501 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -1036,30 +1036,6 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR) | RCR_CBSSID_BCN); } break; - case HW_VAR_SLOT_TIME: - { - u8 u1bAIFS, aSifsTime; - struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - - rtw_write8(Adapter, REG_SLOT, val[0]); - - if (pmlmeinfo->WMM_enable == 0) { - if (pmlmeext->cur_wireless_mode == WIRELESS_11B) - aSifsTime = 10; - else - aSifsTime = 16; - - u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime); - - /* Temporary removed, 2008.06.20. */ - rtw_write8(Adapter, REG_EDCA_VO_PARAM, u1bAIFS); - rtw_write8(Adapter, REG_EDCA_VI_PARAM, u1bAIFS); - rtw_write8(Adapter, REG_EDCA_BE_PARAM, u1bAIFS); - rtw_write8(Adapter, REG_EDCA_BK_PARAM, u1bAIFS); - } - } - break; case HW_VAR_DM_FLAG: podmpriv->SupportAbility = *((u8 *)val); break; diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index a56f3d6ca399..0104ee463a10 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -13,7 +13,6 @@ enum hw_variables { HW_VAR_BASIC_RATE, HW_VAR_CORRECT_TSF, HW_VAR_MLME_SITESURVEY, - HW_VAR_SLOT_TIME, HW_VAR_DM_FLAG, HW_VAR_DM_FUNC_OP, HW_VAR_DM_FUNC_RESET, From cbf9c4b9617b6767886a913705ca14b7600c77db Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Tue, 31 May 2022 09:44:46 +0530 Subject: [PATCH 0103/1436] of: check previous kernel's ima-kexec-buffer against memory bounds Presently ima_get_kexec_buffer() doesn't check if the previous kernel's ima-kexec-buffer lies outside the addressable memory range. This can result in a kernel panic if the new kernel is booted with 'mem=X' arg and the ima-kexec-buffer was allocated beyond that range by the previous kernel. The panic is usually of the form below: $ sudo kexec --initrd initrd vmlinux --append='mem=16G' BUG: Unable to handle kernel data access on read at 0xc000c01fff7f0000 Faulting instruction address: 0xc000000000837974 Oops: Kernel access of bad area, sig: 11 [#1] NIP [c000000000837974] ima_restore_measurement_list+0x94/0x6c0 LR [c00000000083b55c] ima_load_kexec_buffer+0xac/0x160 Call Trace: [c00000000371fa80] [c00000000083b55c] ima_load_kexec_buffer+0xac/0x160 [c00000000371fb00] [c0000000020512c4] ima_init+0x80/0x108 [c00000000371fb70] [c0000000020514dc] init_ima+0x4c/0x120 [c00000000371fbf0] [c000000000012240] do_one_initcall+0x60/0x2c0 [c00000000371fcc0] [c000000002004ad0] kernel_init_freeable+0x344/0x3ec [c00000000371fda0] [c0000000000128a4] kernel_init+0x34/0x1b0 [c00000000371fe10] [c00000000000ce64] ret_from_kernel_thread+0x5c/0x64 Instruction dump: f92100b8 f92100c0 90e10090 910100a0 4182050c 282a0017 3bc00000 40810330 7c0802a6 fb610198 7c9b2378 f80101d0 2c090001 40820614 e9240010 ---[ end trace 0000000000000000 ]--- Fix this issue by checking returned PFN range of previous kernel's ima-kexec-buffer with page_is_ram() to ensure correct memory bounds. Fixes: 467d27824920 ("powerpc: ima: get the kexec buffer passed by the previous kernel") Cc: Frank Rowand Cc: Prakhar Srivastava Cc: Lakshmi Ramasubramanian Cc: Thiago Jung Bauermann Cc: Rob Herring Cc: Ritesh Harjani Cc: Robin Murphy Signed-off-by: Vaibhav Jain Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220531041446.3334259-1-vaibhav@linux.ibm.com --- drivers/of/kexec.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c index 8d374cc552be..91b04b04eec4 100644 --- a/drivers/of/kexec.c +++ b/drivers/of/kexec.c @@ -126,6 +126,7 @@ int ima_get_kexec_buffer(void **addr, size_t *size) { int ret, len; unsigned long tmp_addr; + unsigned long start_pfn, end_pfn; size_t tmp_size; const void *prop; @@ -140,6 +141,22 @@ int ima_get_kexec_buffer(void **addr, size_t *size) if (ret) return ret; + /* Do some sanity on the returned size for the ima-kexec buffer */ + if (!tmp_size) + return -ENOENT; + + /* + * Calculate the PFNs for the buffer and ensure + * they are with in addressable memory. + */ + start_pfn = PHYS_PFN(tmp_addr); + end_pfn = PHYS_PFN(tmp_addr + tmp_size - 1); + if (!page_is_ram(start_pfn) || !page_is_ram(end_pfn)) { + pr_warn("IMA buffer at 0x%lx, size = 0x%zx beyond memory\n", + tmp_addr, tmp_size); + return -EINVAL; + } + *addr = __va(tmp_addr); *size = tmp_size; From 72ca190052700d56dc130a106ce66651ba155835 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 29 May 2022 12:49:22 +0200 Subject: [PATCH 0104/1436] dt-bindings: vendor-prefixes: document several vendors for Aspeed BMC boards Add vendor prefixes for manufacturers of Aspeed SoC based BMC boards: ASrock, ByteDance, Ingrasys, Inventec and Quanta. Move also bticino to proper alphabetical place. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220529104928.79636-1-krzysztof.kozlowski@linaro.org --- .../devicetree/bindings/vendor-prefixes.yaml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 6bb20b4554d7..93a836400328 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -141,6 +141,8 @@ patternProperties: description: ASIX Electronics Corporation "^aspeed,.*": description: ASPEED Technology Inc. + "^asrock,.*": + description: ASRock Inc. "^asus,.*": description: AsusTek Computer Inc. "^atlas,.*": @@ -195,12 +197,14 @@ patternProperties: description: Broadcom Corporation "^bsh,.*": description: BSH Hausgeraete GmbH + "^bticino,.*": + description: Bticino International "^buffalo,.*": description: Buffalo, Inc. "^bur,.*": description: B&R Industrial Automation GmbH - "^bticino,.*": - description: Bticino International + "^bytedance,.*": + description: ByteDance Ltd. "^calamp,.*": description: CalAmp Corp. "^calaosystems,.*": @@ -544,6 +548,8 @@ patternProperties: description: Shenzhen Hugsun Technology Co. Ltd. "^hwacom,.*": description: HwaCom Systems Inc. + "^hxt,.*": + description: HXT Semiconductor "^hycon,.*": description: Hycon Technology Corp. "^hydis,.*": @@ -578,6 +584,8 @@ patternProperties: description: Infineon Technologies "^inforce,.*": description: Inforce Computing + "^ingrasys,.*": + description: Ingrasys Technology Inc. "^ivo,.*": description: InfoVision Optoelectronics Kunshan Co. Ltd. "^ingenic,.*": @@ -598,6 +606,8 @@ patternProperties: description: Inter Control Group "^invensense,.*": description: InvenSense Inc. + "^inventec,.*": + description: Inventec "^inversepath,.*": description: Inverse Path "^iom,.*": @@ -1010,6 +1020,8 @@ patternProperties: description: Shenzhen QiShenglong Industrialist Co., Ltd. "^qnap,.*": description: QNAP Systems, Inc. + "^quanta,.*": + description: Quanta Computer Inc. "^radxa,.*": description: Radxa "^raidsonic,.*": From 015cd0043503a1691ba28529e21478fe0822f3ff Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 6 Jun 2022 20:18:01 +0000 Subject: [PATCH 0105/1436] regulator: cros-ec: Use common cros_ec_command() Reduce code duplication by using the common cros_ec_command() function instead of the locally defined variant. Cc: Stephen Boyd Signed-off-by: Prashant Malani Reviewed-by: Stephen Boyd Reviewed-by: Guenter Roeck Acked-by: Mark Brown Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220606201825.763788-2-pmalani@chromium.org --- drivers/regulator/cros-ec-regulator.c | 54 ++++++--------------------- 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/drivers/regulator/cros-ec-regulator.c b/drivers/regulator/cros-ec-regulator.c index c4754f3cf233..1c5fc74a4776 100644 --- a/drivers/regulator/cros-ec-regulator.c +++ b/drivers/regulator/cros-ec-regulator.c @@ -22,36 +22,6 @@ struct cros_ec_regulator_data { u16 num_voltages; }; -static int cros_ec_cmd(struct cros_ec_device *ec, u32 version, u32 command, - void *outdata, u32 outsize, void *indata, u32 insize) -{ - struct cros_ec_command *msg; - int ret; - - msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); - if (!msg) - return -ENOMEM; - - msg->version = version; - msg->command = command; - msg->outsize = outsize; - msg->insize = insize; - - if (outdata && outsize > 0) - memcpy(msg->data, outdata, outsize); - - ret = cros_ec_cmd_xfer_status(ec, msg); - if (ret < 0) - goto cleanup; - - if (insize) - memcpy(indata, msg->data, insize); - -cleanup: - kfree(msg); - return ret; -} - static int cros_ec_regulator_enable(struct regulator_dev *dev) { struct cros_ec_regulator_data *data = rdev_get_drvdata(dev); @@ -60,8 +30,8 @@ static int cros_ec_regulator_enable(struct regulator_dev *dev) .enable = 1, }; - return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, - sizeof(cmd), NULL, 0); + return cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, + sizeof(cmd), NULL, 0); } static int cros_ec_regulator_disable(struct regulator_dev *dev) @@ -72,8 +42,8 @@ static int cros_ec_regulator_disable(struct regulator_dev *dev) .enable = 0, }; - return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, - sizeof(cmd), NULL, 0); + return cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, + sizeof(cmd), NULL, 0); } static int cros_ec_regulator_is_enabled(struct regulator_dev *dev) @@ -85,8 +55,8 @@ static int cros_ec_regulator_is_enabled(struct regulator_dev *dev) struct ec_response_regulator_is_enabled resp; int ret; - ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_IS_ENABLED, &cmd, - sizeof(cmd), &resp, sizeof(resp)); + ret = cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_IS_ENABLED, &cmd, + sizeof(cmd), &resp, sizeof(resp)); if (ret < 0) return ret; return resp.enabled; @@ -112,8 +82,8 @@ static int cros_ec_regulator_get_voltage(struct regulator_dev *dev) struct ec_response_regulator_get_voltage resp; int ret; - ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_VOLTAGE, &cmd, - sizeof(cmd), &resp, sizeof(resp)); + ret = cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_GET_VOLTAGE, &cmd, + sizeof(cmd), &resp, sizeof(resp)); if (ret < 0) return ret; return resp.voltage_mv * 1000; @@ -138,8 +108,8 @@ static int cros_ec_regulator_set_voltage(struct regulator_dev *dev, int min_uV, if (min_mV > max_mV) return -EINVAL; - return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_SET_VOLTAGE, &cmd, - sizeof(cmd), NULL, 0); + return cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_SET_VOLTAGE, &cmd, + sizeof(cmd), NULL, 0); } static const struct regulator_ops cros_ec_regulator_voltage_ops = { @@ -160,8 +130,8 @@ static int cros_ec_regulator_init_info(struct device *dev, struct ec_response_regulator_get_info resp; int ret; - ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_INFO, &cmd, - sizeof(cmd), &resp, sizeof(resp)); + ret = cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_GET_INFO, &cmd, + sizeof(cmd), &resp, sizeof(resp)); if (ret < 0) return ret; From b1d288d9c3c5ca28df062214656a59cf7ee370e0 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 6 Jun 2022 20:18:03 +0000 Subject: [PATCH 0106/1436] platform/chrome: cros_ec_proto: Rename cros_ec_command function cros_ec_command() is the name of a function as well as a struct, as such it can confuse indexing tools (like ctags). Avoid this by renaming it to cros_ec_cmd(). Update all the callsites to use the new name. This patch is a find-and-replace, so should not introduce any functional changes. Suggested-by: Stephen Boyd Signed-off-by: Prashant Malani Acked-by: Lee Jones Reviewed-by: Stephen Boyd Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220606201825.763788-3-pmalani@chromium.org --- drivers/mfd/cros_ec_dev.c | 4 +-- drivers/platform/chrome/cros_ec_proto.c | 22 ++++++------ drivers/platform/chrome/cros_ec_typec.c | 39 ++++++++++----------- drivers/platform/chrome/cros_usbpd_notify.c | 4 +-- drivers/regulator/cros-ec-regulator.c | 24 ++++++------- include/linux/platform_data/cros_ec_proto.h | 2 +- 6 files changed, 47 insertions(+), 48 deletions(-) diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 596731caf407..02d4271dfe06 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -250,8 +250,8 @@ static int ec_device_probe(struct platform_device *pdev) * The PCHG device cannot be detected by sending EC_FEATURE_GET_CMD, but * it can be detected by querying the number of peripheral chargers. */ - retval = cros_ec_command(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0, - &pchg_count, sizeof(pchg_count)); + retval = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0, + &pchg_count, sizeof(pchg_count)); if (retval >= 0 && pchg_count.port_count) { retval = mfd_add_hotplug_devices(ec->dev, cros_ec_pchg_cells, diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 13ced9d2dd71..b6bea183ee28 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -860,8 +860,8 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature) if (features->flags[0] == -1U && features->flags[1] == -1U) { /* features bitmap not read yet */ - ret = cros_ec_command(ec->ec_dev, 0, EC_CMD_GET_FEATURES + ec->cmd_offset, - NULL, 0, features, sizeof(*features)); + ret = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_GET_FEATURES + ec->cmd_offset, + NULL, 0, features, sizeof(*features)); if (ret < 0) { dev_warn(ec->dev, "cannot get EC features: %d\n", ret); memset(features, 0, sizeof(*features)); @@ -942,7 +942,7 @@ int cros_ec_get_sensor_count(struct cros_ec_dev *ec) EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count); /** - * cros_ec_command - Send a command to the EC. + * cros_ec_cmd - Send a command to the EC. * * @ec_dev: EC device * @version: EC command version @@ -954,13 +954,13 @@ EXPORT_SYMBOL_GPL(cros_ec_get_sensor_count); * * Return: >= 0 on success, negative error number on failure. */ -int cros_ec_command(struct cros_ec_device *ec_dev, - unsigned int version, - int command, - void *outdata, - int outsize, - void *indata, - int insize) +int cros_ec_cmd(struct cros_ec_device *ec_dev, + unsigned int version, + int command, + void *outdata, + int outsize, + void *indata, + int insize) { struct cros_ec_command *msg; int ret; @@ -987,4 +987,4 @@ error: kfree(msg); return ret; } -EXPORT_SYMBOL_GPL(cros_ec_command); +EXPORT_SYMBOL_GPL(cros_ec_cmd); diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 7cb2e35c4ded..d6088ba447af 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -525,8 +525,8 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, enum typec_orientation orientation; int ret; - ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO, - &req, sizeof(req), &resp, sizeof(resp)); + ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_INFO, + &req, sizeof(req), &resp, sizeof(resp)); if (ret < 0) { dev_warn(typec->dev, "Failed to get mux info for port: %d, err = %d\n", port_num, ret); @@ -585,8 +585,8 @@ mux_ack: /* Sending Acknowledgment to EC */ mux_ack.port = port_num; - if (cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack, - sizeof(mux_ack), NULL, 0) < 0) + if (cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_MUX_ACK, &mux_ack, + sizeof(mux_ack), NULL, 0) < 0) dev_warn(typec->dev, "Failed to send Mux ACK to EC for port: %d\n", port_num); @@ -754,8 +754,8 @@ static int cros_typec_handle_sop_prime_disc(struct cros_typec_data *typec, int p int ret = 0; memset(disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE); - ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), - disc, EC_PROTO2_MAX_RESPONSE_SIZE); + ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), + disc, EC_PROTO2_MAX_RESPONSE_SIZE); if (ret < 0) { dev_err(typec->dev, "Failed to get SOP' discovery data for port: %d\n", port_num); goto sop_prime_disc_exit; @@ -837,8 +837,8 @@ static int cros_typec_handle_sop_disc(struct cros_typec_data *typec, int port_nu typec_partner_set_pd_revision(port->partner, pd_revision); memset(sop_disc, 0, EC_PROTO2_MAX_RESPONSE_SIZE); - ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), - sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE); + ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_DISCOVERY, &req, sizeof(req), + sop_disc, EC_PROTO2_MAX_RESPONSE_SIZE); if (ret < 0) { dev_err(typec->dev, "Failed to get SOP discovery data for port: %d\n", port_num); goto disc_exit; @@ -870,8 +870,8 @@ static int cros_typec_send_clear_event(struct cros_typec_data *typec, int port_n .clear_events_mask = events_mask, }; - return cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req, - sizeof(req), NULL, 0); + return cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_CONTROL, &req, + sizeof(req), NULL, 0); } static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num) @@ -882,8 +882,8 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num }; int ret; - ret = cros_ec_command(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req), - &resp, sizeof(resp)); + ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req), + &resp, sizeof(resp)); if (ret < 0) { dev_warn(typec->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num); return; @@ -960,9 +960,9 @@ static int cros_typec_port_update(struct cros_typec_data *typec, int port_num) req.mux = USB_PD_CTRL_MUX_NO_CHANGE; req.swap = USB_PD_CTRL_SWAP_NONE; - ret = cros_ec_command(typec->ec, typec->pd_ctrl_ver, - EC_CMD_USB_PD_CONTROL, &req, sizeof(req), - &resp, sizeof(resp)); + ret = cros_ec_cmd(typec->ec, typec->pd_ctrl_ver, + EC_CMD_USB_PD_CONTROL, &req, sizeof(req), + &resp, sizeof(resp)); if (ret < 0) return ret; @@ -997,9 +997,8 @@ static int cros_typec_get_cmd_version(struct cros_typec_data *typec) /* We're interested in the PD control command version. */ req_v1.cmd = EC_CMD_USB_PD_CONTROL; - ret = cros_ec_command(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS, - &req_v1, sizeof(req_v1), &resp, - sizeof(resp)); + ret = cros_ec_cmd(typec->ec, 1, EC_CMD_GET_CMD_VERSIONS, + &req_v1, sizeof(req_v1), &resp, sizeof(resp)); if (ret < 0) return ret; @@ -1090,8 +1089,8 @@ static int cros_typec_probe(struct platform_device *pdev) typec->typec_cmd_supported = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_CMD); typec->needs_mux_ack = cros_ec_check_features(ec_dev, EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK); - ret = cros_ec_command(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0, - &resp, sizeof(resp)); + ret = cros_ec_cmd(typec->ec, 0, EC_CMD_USB_PD_PORTS, NULL, 0, + &resp, sizeof(resp)); if (ret < 0) return ret; diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index 91ce6be91aac..4b5a81c9dc6d 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -71,8 +71,8 @@ static void cros_usbpd_get_event_and_notify(struct device *dev, } /* Check for PD host events on EC. */ - ret = cros_ec_command(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS, - NULL, 0, &host_event_status, sizeof(host_event_status)); + ret = cros_ec_cmd(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS, + NULL, 0, &host_event_status, sizeof(host_event_status)); if (ret < 0) { dev_warn(dev, "Can't get host event status (err: %d)\n", ret); goto send_notify; diff --git a/drivers/regulator/cros-ec-regulator.c b/drivers/regulator/cros-ec-regulator.c index 1c5fc74a4776..1591636f86c3 100644 --- a/drivers/regulator/cros-ec-regulator.c +++ b/drivers/regulator/cros-ec-regulator.c @@ -30,8 +30,8 @@ static int cros_ec_regulator_enable(struct regulator_dev *dev) .enable = 1, }; - return cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, - sizeof(cmd), NULL, 0); + return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, + sizeof(cmd), NULL, 0); } static int cros_ec_regulator_disable(struct regulator_dev *dev) @@ -42,8 +42,8 @@ static int cros_ec_regulator_disable(struct regulator_dev *dev) .enable = 0, }; - return cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, - sizeof(cmd), NULL, 0); + return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, + sizeof(cmd), NULL, 0); } static int cros_ec_regulator_is_enabled(struct regulator_dev *dev) @@ -55,8 +55,8 @@ static int cros_ec_regulator_is_enabled(struct regulator_dev *dev) struct ec_response_regulator_is_enabled resp; int ret; - ret = cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_IS_ENABLED, &cmd, - sizeof(cmd), &resp, sizeof(resp)); + ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_IS_ENABLED, &cmd, + sizeof(cmd), &resp, sizeof(resp)); if (ret < 0) return ret; return resp.enabled; @@ -82,8 +82,8 @@ static int cros_ec_regulator_get_voltage(struct regulator_dev *dev) struct ec_response_regulator_get_voltage resp; int ret; - ret = cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_GET_VOLTAGE, &cmd, - sizeof(cmd), &resp, sizeof(resp)); + ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_VOLTAGE, &cmd, + sizeof(cmd), &resp, sizeof(resp)); if (ret < 0) return ret; return resp.voltage_mv * 1000; @@ -108,8 +108,8 @@ static int cros_ec_regulator_set_voltage(struct regulator_dev *dev, int min_uV, if (min_mV > max_mV) return -EINVAL; - return cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_SET_VOLTAGE, &cmd, - sizeof(cmd), NULL, 0); + return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_SET_VOLTAGE, &cmd, + sizeof(cmd), NULL, 0); } static const struct regulator_ops cros_ec_regulator_voltage_ops = { @@ -130,8 +130,8 @@ static int cros_ec_regulator_init_info(struct device *dev, struct ec_response_regulator_get_info resp; int ret; - ret = cros_ec_command(data->ec_dev, 0, EC_CMD_REGULATOR_GET_INFO, &cmd, - sizeof(cmd), &resp, sizeof(resp)); + ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_INFO, &cmd, + sizeof(cmd), &resp, sizeof(resp)); if (ret < 0) return ret; diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 138fd912c808..816da4eef3e5 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -231,7 +231,7 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature); int cros_ec_get_sensor_count(struct cros_ec_dev *ec); -int cros_ec_command(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata, +int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata, int outsize, void *indata, int insize); /** From f87e15fbf6d8cdb51f953338d41a4a52ad1aca14 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 6 Jun 2022 20:18:05 +0000 Subject: [PATCH 0107/1436] platform/chrome: cros_ec_proto: Update size arg types cros_ec_cmd() takes 2 size arguments. Update them to be of the more appropriate type size_t. Suggested-by: Stephen Boyd Signed-off-by: Prashant Malani Reviewed-by: Stephen Boyd Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220606201825.763788-4-pmalani@chromium.org --- drivers/platform/chrome/cros_ec_proto.c | 4 ++-- include/linux/platform_data/cros_ec_proto.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index b6bea183ee28..cefabfe45551 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -958,9 +958,9 @@ int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata, - int outsize, + size_t outsize, void *indata, - int insize) + size_t insize) { struct cros_ec_command *msg; int ret; diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 816da4eef3e5..85e29300f63d 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -232,7 +232,7 @@ bool cros_ec_check_features(struct cros_ec_dev *ec, int feature); int cros_ec_get_sensor_count(struct cros_ec_dev *ec); int cros_ec_cmd(struct cros_ec_device *ec_dev, unsigned int version, int command, void *outdata, - int outsize, void *indata, int insize); + size_t outsize, void *indata, size_t insize); /** * cros_ec_get_time_ns() - Return time in ns. From 00f08d99dd7d3ab3d8cb1fa356e857fcccbbdde8 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 2 May 2022 00:07:25 +0200 Subject: [PATCH 0108/1436] KVM: nSVM: Sync next_rip field from vmcb12 to vmcb02 The next_rip field of a VMCB is *not* an output-only field for a VMRUN. This field value (instead of the saved guest RIP) in used by the CPU for the return address pushed on stack when injecting a software interrupt or INT3 or INTO exception. Make sure this field gets synced from vmcb12 to vmcb02 when entering L2 or loading a nested state and NRIPS is exposed to L1. If NRIPS is supported in hardware but not exposed to L1 (nrips=0 or hidden by userspace), stuff vmcb02's next_rip from the new L2 RIP to emulate a !NRIPS CPU (which saves RIP on the stack as-is). Reviewed-by: Maxim Levitsky Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Signed-off-by: Maciej S. Szmigiero Message-Id: Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/nested.c | 22 +++++++++++++++++++--- arch/x86/kvm/svm/svm.h | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 3361258640a2..e8aa95a74564 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -371,6 +371,7 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu, to->nested_ctl = from->nested_ctl; to->event_inj = from->event_inj; to->event_inj_err = from->event_inj_err; + to->next_rip = from->next_rip; to->nested_cr3 = from->nested_cr3; to->virt_ext = from->virt_ext; to->pause_filter_count = from->pause_filter_count; @@ -608,7 +609,8 @@ static void nested_vmcb02_prepare_save(struct vcpu_svm *svm, struct vmcb *vmcb12 } } -static void nested_vmcb02_prepare_control(struct vcpu_svm *svm) +static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, + unsigned long vmcb12_rip) { u32 int_ctl_vmcb01_bits = V_INTR_MASKING_MASK; u32 int_ctl_vmcb12_bits = V_TPR_MASK | V_IRQ_INJECTION_BITS_MASK; @@ -662,6 +664,19 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm) vmcb02->control.event_inj = svm->nested.ctl.event_inj; vmcb02->control.event_inj_err = svm->nested.ctl.event_inj_err; + /* + * next_rip is consumed on VMRUN as the return address pushed on the + * stack for injected soft exceptions/interrupts. If nrips is exposed + * to L1, take it verbatim from vmcb12. If nrips is supported in + * hardware but not exposed to L1, stuff the actual L2 RIP to emulate + * what a nrips=0 CPU would do (L1 is responsible for advancing RIP + * prior to injecting the event). + */ + if (svm->nrips_enabled) + vmcb02->control.next_rip = svm->nested.ctl.next_rip; + else if (boot_cpu_has(X86_FEATURE_NRIPS)) + vmcb02->control.next_rip = vmcb12_rip; + vmcb02->control.virt_ext = vmcb01->control.virt_ext & LBR_CTL_ENABLE_MASK; if (svm->lbrv_enabled) @@ -745,7 +760,7 @@ int enter_svm_guest_mode(struct kvm_vcpu *vcpu, u64 vmcb12_gpa, nested_svm_copy_common_state(svm->vmcb01.ptr, svm->nested.vmcb02.ptr); svm_switch_vmcb(svm, &svm->nested.vmcb02); - nested_vmcb02_prepare_control(svm); + nested_vmcb02_prepare_control(svm, vmcb12->save.rip); nested_vmcb02_prepare_save(svm, vmcb12); ret = nested_svm_load_cr3(&svm->vcpu, svm->nested.save.cr3, @@ -1418,6 +1433,7 @@ static void nested_copy_vmcb_cache_to_control(struct vmcb_control_area *dst, dst->nested_ctl = from->nested_ctl; dst->event_inj = from->event_inj; dst->event_inj_err = from->event_inj_err; + dst->next_rip = from->next_rip; dst->nested_cr3 = from->nested_cr3; dst->virt_ext = from->virt_ext; dst->pause_filter_count = from->pause_filter_count; @@ -1602,7 +1618,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu, nested_copy_vmcb_control_to_cache(svm, ctl); svm_switch_vmcb(svm, &svm->nested.vmcb02); - nested_vmcb02_prepare_control(svm); + nested_vmcb02_prepare_control(svm, svm->vmcb->save.rip); /* * While the nested guest CR3 is already checked and set by diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 500348c1cb35..de076d658390 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -139,6 +139,7 @@ struct vmcb_ctrl_area_cached { u64 nested_ctl; u32 event_inj; u32 event_inj_err; + u64 next_rip; u64 nested_cr3; u64 virt_ext; u32 clean; From f17c31c48e5cde9895a491d91c424eeeada3e134 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 2 May 2022 00:07:26 +0200 Subject: [PATCH 0109/1436] KVM: SVM: Don't BUG if userspace injects an interrupt with GIF=0 Don't BUG/WARN on interrupt injection due to GIF being cleared, since it's trivial for userspace to force the situation via KVM_SET_VCPU_EVENTS (even if having at least a WARN there would be correct for KVM internally generated injections). kernel BUG at arch/x86/kvm/svm/svm.c:3386! invalid opcode: 0000 [#1] SMP CPU: 15 PID: 926 Comm: smm_test Not tainted 5.17.0-rc3+ #264 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:svm_inject_irq+0xab/0xb0 [kvm_amd] Code: <0f> 0b 0f 1f 00 0f 1f 44 00 00 80 3d ac b3 01 00 00 55 48 89 f5 53 RSP: 0018:ffffc90000b37d88 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff88810a234ac0 RCX: 0000000000000006 RDX: 0000000000000000 RSI: ffffc90000b37df7 RDI: ffff88810a234ac0 RBP: ffffc90000b37df7 R08: ffff88810a1fa410 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 R13: ffff888109571000 R14: ffff88810a234ac0 R15: 0000000000000000 FS: 0000000001821380(0000) GS:ffff88846fdc0000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f74fc550008 CR3: 000000010a6fe000 CR4: 0000000000350ea0 Call Trace: inject_pending_event+0x2f7/0x4c0 [kvm] kvm_arch_vcpu_ioctl_run+0x791/0x17a0 [kvm] kvm_vcpu_ioctl+0x26d/0x650 [kvm] __x64_sys_ioctl+0x82/0xb0 do_syscall_64+0x3b/0xc0 entry_SYSCALL_64_after_hwframe+0x44/0xae Fixes: 219b65dcf6c0 ("KVM: SVM: Improve nested interrupt injection") Cc: stable@vger.kernel.org Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Signed-off-by: Maciej S. Szmigiero Message-Id: <35426af6e123cbe91ec7ce5132ce72521f02b1b5.1651440202.git.maciej.szmigiero@oracle.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/svm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 2628452a5156..a191ec138636 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3392,8 +3392,6 @@ static void svm_inject_irq(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); - BUG_ON(!(gif_set(svm))); - trace_kvm_inj_virq(vcpu->arch.interrupt.nr); ++vcpu->stat.irq_injections; From cd9e6da8048c5b40315ee2d929b6230ce1252c3c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 2 May 2022 00:07:27 +0200 Subject: [PATCH 0110/1436] KVM: SVM: Unwind "speculative" RIP advancement if INTn injection "fails" Unwind the RIP advancement done by svm_queue_exception() when injecting an INT3 ultimately "fails" due to the CPU encountering a VM-Exit while vectoring the injected event, even if the exception reported by the CPU isn't the same event that was injected. If vectoring INT3 encounters an exception, e.g. #NP, and vectoring the #NP encounters an intercepted exception, e.g. #PF when KVM is using shadow paging, then the #NP will be reported as the event that was in-progress. Note, this is still imperfect, as it will get a false positive if the INT3 is cleanly injected, no VM-Exit occurs before the IRET from the INT3 handler in the guest, the instruction following the INT3 generates an exception (directly or indirectly), _and_ vectoring that exception encounters an exception that is intercepted by KVM. The false positives could theoretically be solved by further analyzing the vectoring event, e.g. by comparing the error code against the expected error code were an exception to occur when vectoring the original injected exception, but SVM without NRIPS is a complete disaster, trying to make it 100% correct is a waste of time. Reviewed-by: Maxim Levitsky Fixes: 66b7138f9136 ("KVM: SVM: Emulate nRIP feature when reinjecting INT3") Signed-off-by: Sean Christopherson Signed-off-by: Maciej S. Szmigiero Message-Id: <450133cf0a026cb9825a2ff55d02cb136a1cb111.1651440202.git.maciej.szmigiero@oracle.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/svm.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index a191ec138636..c1506069e67c 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3706,6 +3706,18 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK; type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK; + /* + * If NextRIP isn't enabled, KVM must manually advance RIP prior to + * injecting the soft exception/interrupt. That advancement needs to + * be unwound if vectoring didn't complete. Note, the _new_ event may + * not be the injected event, e.g. if KVM injected an INTn, the INTn + * hit a #NP in the guest, and the #NP encountered a #PF, the #NP will + * be the reported vectored event, but RIP still needs to be unwound. + */ + if (int3_injected && type == SVM_EXITINTINFO_TYPE_EXEPT && + kvm_is_linear_rip(vcpu, svm->int3_rip)) + kvm_rip_write(vcpu, kvm_rip_read(vcpu) - int3_injected); + switch (type) { case SVM_EXITINTINFO_TYPE_NMI: vcpu->arch.nmi_injected = true; @@ -3719,16 +3731,11 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) /* * In case of software exceptions, do not reinject the vector, - * but re-execute the instruction instead. Rewind RIP first - * if we emulated INT3 before. + * but re-execute the instruction instead. */ - if (kvm_exception_is_soft(vector)) { - if (vector == BP_VECTOR && int3_injected && - kvm_is_linear_rip(vcpu, svm->int3_rip)) - kvm_rip_write(vcpu, - kvm_rip_read(vcpu) - int3_injected); + if (kvm_exception_is_soft(vector)) break; - } + if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) { u32 err = svm->vmcb->control.exit_int_info_err; kvm_requeue_exception_e(vcpu, vector, err); From 3741aec4c38fa4123ab08ae552f05366d4fd05d8 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 2 May 2022 00:07:28 +0200 Subject: [PATCH 0111/1436] KVM: SVM: Stuff next_rip on emulated INT3 injection if NRIPS is supported If NRIPS is supported in hardware but disabled in KVM, set next_rip to the next RIP when advancing RIP as part of emulating INT3 injection. There is no flag to tell the CPU that KVM isn't using next_rip, and so leaving next_rip is left as is will result in the CPU pushing garbage onto the stack when vectoring the injected event. Reviewed-by: Maxim Levitsky Fixes: 66b7138f9136 ("KVM: SVM: Emulate nRIP feature when reinjecting INT3") Signed-off-by: Sean Christopherson Signed-off-by: Maciej S. Szmigiero Message-Id: Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/svm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index c1506069e67c..8c3c6bba6ccd 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -392,6 +392,10 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu) */ (void)svm_skip_emulated_instruction(vcpu); rip = kvm_rip_read(vcpu); + + if (boot_cpu_has(X86_FEATURE_NRIPS)) + svm->vmcb->control.next_rip = rip; + svm->int3_rip = rip + svm->vmcb->save.cs.base; svm->int3_injected = rip - old_rip; } @@ -3709,7 +3713,7 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) /* * If NextRIP isn't enabled, KVM must manually advance RIP prior to * injecting the soft exception/interrupt. That advancement needs to - * be unwound if vectoring didn't complete. Note, the _new_ event may + * be unwound if vectoring didn't complete. Note, the new event may * not be the injected event, e.g. if KVM injected an INTn, the INTn * hit a #NP in the guest, and the #NP encountered a #PF, the #NP will * be the reported vectored event, but RIP still needs to be unwound. From 6ef88d6e36c2b4b3886ec9967cafabe4424d27d5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 2 May 2022 00:07:29 +0200 Subject: [PATCH 0112/1436] KVM: SVM: Re-inject INT3/INTO instead of retrying the instruction Re-inject INT3/INTO instead of retrying the instruction if the CPU encountered an intercepted exception while vectoring the software exception, e.g. if vectoring INT3 encounters a #PF and KVM is using shadow paging. Retrying the instruction is architecturally wrong, e.g. will result in a spurious #DB if there's a code breakpoint on the INT3/O, and lack of re-injection also breaks nested virtualization, e.g. if L1 injects a software exception and vectoring the injected exception encounters an exception that is intercepted by L0 but not L1. Due to, ahem, deficiencies in the SVM architecture, acquiring the next RIP may require flowing through the emulator even if NRIPS is supported, as the CPU clears next_rip if the VM-Exit is due to an exception other than "exceptions caused by the INT3, INTO, and BOUND instructions". To deal with this, "skip" the instruction to calculate next_rip (if it's not already known), and then unwind the RIP write and any side effects (RFLAGS updates). Save the computed next_rip and use it to re-stuff next_rip if injection doesn't complete. This allows KVM to do the right thing if next_rip was known prior to injection, e.g. if L1 injects a soft event into L2, and there is no backing INTn instruction, e.g. if L1 is injecting an arbitrary event. Note, it's impossible to guarantee architectural correctness given SVM's architectural flaws. E.g. if the guest executes INTn (no KVM injection), an exit occurs while vectoring the INTn, and the guest modifies the code stream while the exit is being handled, KVM will compute the incorrect next_rip due to "skipping" the wrong instruction. A future enhancement to make this less awful would be for KVM to detect that the decoded instruction is not the correct INTn and drop the to-be-injected soft event (retrying is a lesser evil compared to shoving the wrong RIP on the exception stack). Reported-by: Maciej S. Szmigiero Signed-off-by: Sean Christopherson Signed-off-by: Maciej S. Szmigiero Message-Id: <65cb88deab40bc1649d509194864312a89bbe02e.1651440202.git.maciej.szmigiero@oracle.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/nested.c | 26 +++++++ arch/x86/kvm/svm/svm.c | 140 +++++++++++++++++++++++++++----------- arch/x86/kvm/svm/svm.h | 6 +- 3 files changed, 129 insertions(+), 43 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index e8aa95a74564..525117a49c18 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -609,6 +609,21 @@ static void nested_vmcb02_prepare_save(struct vcpu_svm *svm, struct vmcb *vmcb12 } } +static inline bool is_evtinj_soft(u32 evtinj) +{ + u32 type = evtinj & SVM_EVTINJ_TYPE_MASK; + u8 vector = evtinj & SVM_EVTINJ_VEC_MASK; + + if (!(evtinj & SVM_EVTINJ_VALID)) + return false; + + /* + * Intentionally return false for SOFT events, SVM doesn't yet support + * re-injecting soft interrupts. + */ + return type == SVM_EVTINJ_TYPE_EXEPT && kvm_exception_is_soft(vector); +} + static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, unsigned long vmcb12_rip) { @@ -677,6 +692,16 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, else if (boot_cpu_has(X86_FEATURE_NRIPS)) vmcb02->control.next_rip = vmcb12_rip; + if (is_evtinj_soft(vmcb02->control.event_inj)) { + svm->soft_int_injected = true; + svm->soft_int_csbase = svm->vmcb->save.cs.base; + svm->soft_int_old_rip = vmcb12_rip; + if (svm->nrips_enabled) + svm->soft_int_next_rip = svm->nested.ctl.next_rip; + else + svm->soft_int_next_rip = vmcb12_rip; + } + vmcb02->control.virt_ext = vmcb01->control.virt_ext & LBR_CTL_ENABLE_MASK; if (svm->lbrv_enabled) @@ -849,6 +874,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu) out_exit_err: svm->nested.nested_run_pending = 0; + svm->soft_int_injected = false; svm->vmcb->control.exit_code = SVM_EXIT_ERR; svm->vmcb->control.exit_code_hi = 0; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 8c3c6bba6ccd..ec37647ca068 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -342,9 +342,11 @@ static void svm_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) } -static int svm_skip_emulated_instruction(struct kvm_vcpu *vcpu) +static int __svm_skip_emulated_instruction(struct kvm_vcpu *vcpu, + bool commit_side_effects) { struct vcpu_svm *svm = to_svm(vcpu); + unsigned long old_rflags; /* * SEV-ES does not expose the next RIP. The RIP update is controlled by @@ -359,18 +361,75 @@ static int svm_skip_emulated_instruction(struct kvm_vcpu *vcpu) } if (!svm->next_rip) { + if (unlikely(!commit_side_effects)) + old_rflags = svm->vmcb->save.rflags; + if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP)) return 0; + + if (unlikely(!commit_side_effects)) + svm->vmcb->save.rflags = old_rflags; } else { kvm_rip_write(vcpu, svm->next_rip); } done: - svm_set_interrupt_shadow(vcpu, 0); + if (likely(commit_side_effects)) + svm_set_interrupt_shadow(vcpu, 0); return 1; } +static int svm_skip_emulated_instruction(struct kvm_vcpu *vcpu) +{ + return __svm_skip_emulated_instruction(vcpu, true); +} + +static int svm_update_soft_interrupt_rip(struct kvm_vcpu *vcpu) +{ + unsigned long rip, old_rip = kvm_rip_read(vcpu); + struct vcpu_svm *svm = to_svm(vcpu); + + /* + * Due to architectural shortcomings, the CPU doesn't always provide + * NextRIP, e.g. if KVM intercepted an exception that occurred while + * the CPU was vectoring an INTO/INT3 in the guest. Temporarily skip + * the instruction even if NextRIP is supported to acquire the next + * RIP so that it can be shoved into the NextRIP field, otherwise + * hardware will fail to advance guest RIP during event injection. + * Drop the exception/interrupt if emulation fails and effectively + * retry the instruction, it's the least awful option. If NRIPS is + * in use, the skip must not commit any side effects such as clearing + * the interrupt shadow or RFLAGS.RF. + */ + if (!__svm_skip_emulated_instruction(vcpu, !nrips)) + return -EIO; + + rip = kvm_rip_read(vcpu); + + /* + * Save the injection information, even when using next_rip, as the + * VMCB's next_rip will be lost (cleared on VM-Exit) if the injection + * doesn't complete due to a VM-Exit occurring while the CPU is + * vectoring the event. Decoding the instruction isn't guaranteed to + * work as there may be no backing instruction, e.g. if the event is + * being injected by L1 for L2, or if the guest is patching INT3 into + * a different instruction. + */ + svm->soft_int_injected = true; + svm->soft_int_csbase = svm->vmcb->save.cs.base; + svm->soft_int_old_rip = old_rip; + svm->soft_int_next_rip = rip; + + if (nrips) + kvm_rip_write(vcpu, old_rip); + + if (static_cpu_has(X86_FEATURE_NRIPS)) + svm->vmcb->control.next_rip = rip; + + return 0; +} + static void svm_queue_exception(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -380,25 +439,9 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu) kvm_deliver_exception_payload(vcpu); - if (nr == BP_VECTOR && !nrips) { - unsigned long rip, old_rip = kvm_rip_read(vcpu); - - /* - * For guest debugging where we have to reinject #BP if some - * INT3 is guest-owned: - * Emulate nRIP by moving RIP forward. Will fail if injection - * raises a fault that is not intercepted. Still better than - * failing in all cases. - */ - (void)svm_skip_emulated_instruction(vcpu); - rip = kvm_rip_read(vcpu); - - if (boot_cpu_has(X86_FEATURE_NRIPS)) - svm->vmcb->control.next_rip = rip; - - svm->int3_rip = rip + svm->vmcb->save.cs.base; - svm->int3_injected = rip - old_rip; - } + if (kvm_exception_is_soft(nr) && + svm_update_soft_interrupt_rip(vcpu)) + return; svm->vmcb->control.event_inj = nr | SVM_EVTINJ_VALID @@ -3677,15 +3720,46 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu) svm->vmcb->control.int_ctl |= cr8 & V_TPR_MASK; } +static void svm_complete_soft_interrupt(struct kvm_vcpu *vcpu, u8 vector, + int type) +{ + struct vcpu_svm *svm = to_svm(vcpu); + + /* + * If NRIPS is enabled, KVM must snapshot the pre-VMRUN next_rip that's + * associated with the original soft exception/interrupt. next_rip is + * cleared on all exits that can occur while vectoring an event, so KVM + * needs to manually set next_rip for re-injection. Unlike the !nrips + * case below, this needs to be done if and only if KVM is re-injecting + * the same event, i.e. if the event is a soft exception/interrupt, + * otherwise next_rip is unused on VMRUN. + */ + if (nrips && type == SVM_EXITINTINFO_TYPE_EXEPT && + kvm_exception_is_soft(vector) && + kvm_is_linear_rip(vcpu, svm->soft_int_old_rip + svm->soft_int_csbase)) + svm->vmcb->control.next_rip = svm->soft_int_next_rip; + /* + * If NRIPS isn't enabled, KVM must manually advance RIP prior to + * injecting the soft exception/interrupt. That advancement needs to + * be unwound if vectoring didn't complete. Note, the new event may + * not be the injected event, e.g. if KVM injected an INTn, the INTn + * hit a #NP in the guest, and the #NP encountered a #PF, the #NP will + * be the reported vectored event, but RIP still needs to be unwound. + */ + else if (!nrips && type == SVM_EXITINTINFO_TYPE_EXEPT && + kvm_is_linear_rip(vcpu, svm->soft_int_next_rip + svm->soft_int_csbase)) + kvm_rip_write(vcpu, svm->soft_int_old_rip); +} + static void svm_complete_interrupts(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); u8 vector; int type; u32 exitintinfo = svm->vmcb->control.exit_int_info; - unsigned int3_injected = svm->int3_injected; + bool soft_int_injected = svm->soft_int_injected; - svm->int3_injected = 0; + svm->soft_int_injected = false; /* * If we've made progress since setting HF_IRET_MASK, we've @@ -3710,17 +3784,8 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) vector = exitintinfo & SVM_EXITINTINFO_VEC_MASK; type = exitintinfo & SVM_EXITINTINFO_TYPE_MASK; - /* - * If NextRIP isn't enabled, KVM must manually advance RIP prior to - * injecting the soft exception/interrupt. That advancement needs to - * be unwound if vectoring didn't complete. Note, the new event may - * not be the injected event, e.g. if KVM injected an INTn, the INTn - * hit a #NP in the guest, and the #NP encountered a #PF, the #NP will - * be the reported vectored event, but RIP still needs to be unwound. - */ - if (int3_injected && type == SVM_EXITINTINFO_TYPE_EXEPT && - kvm_is_linear_rip(vcpu, svm->int3_rip)) - kvm_rip_write(vcpu, kvm_rip_read(vcpu) - int3_injected); + if (soft_int_injected) + svm_complete_soft_interrupt(vcpu, vector, type); switch (type) { case SVM_EXITINTINFO_TYPE_NMI: @@ -3733,13 +3798,6 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) if (vector == X86_TRAP_VC) break; - /* - * In case of software exceptions, do not reinject the vector, - * but re-execute the instruction instead. - */ - if (kvm_exception_is_soft(vector)) - break; - if (exitintinfo & SVM_EXITINTINFO_VALID_ERR) { u32 err = svm->vmcb->control.exit_int_info_err; kvm_requeue_exception_e(vcpu, vector, err); diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index de076d658390..f0b6111ee5b1 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -230,8 +230,10 @@ struct vcpu_svm { bool nmi_singlestep; u64 nmi_singlestep_guest_rflags; - unsigned int3_injected; - unsigned long int3_rip; + unsigned long soft_int_csbase; + unsigned long soft_int_old_rip; + unsigned long soft_int_next_rip; + bool soft_int_injected; /* optional nested SVM features that are enabled for this guest */ bool nrips_enabled : 1; From 7e5b5ef8dca3229a5226eabf53bdc7b67ebd07ad Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 2 May 2022 00:07:30 +0200 Subject: [PATCH 0113/1436] KVM: SVM: Re-inject INTn instead of retrying the insn on "failure" Re-inject INTn software interrupts instead of retrying the instruction if the CPU encountered an intercepted exception while vectoring the INTn, e.g. if KVM intercepted a #PF when utilizing shadow paging. Retrying the instruction is architecturally wrong e.g. will result in a spurious #DB if there's a code breakpoint on the INT3/O, and lack of re-injection also breaks nested virtualization, e.g. if L1 injects a software interrupt and vectoring the injected interrupt encounters an exception that is intercepted by L0 but not L1. Signed-off-by: Sean Christopherson Signed-off-by: Maciej S. Szmigiero Message-Id: <1654ad502f860948e4f2d57b8bd881d67301f785.1651440202.git.maciej.szmigiero@oracle.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/nested.c | 7 +++---- arch/x86/kvm/svm/svm.c | 23 +++++++++++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 525117a49c18..0d25dea40796 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -617,10 +617,9 @@ static inline bool is_evtinj_soft(u32 evtinj) if (!(evtinj & SVM_EVTINJ_VALID)) return false; - /* - * Intentionally return false for SOFT events, SVM doesn't yet support - * re-injecting soft interrupts. - */ + if (type == SVM_EVTINJ_TYPE_SOFT) + return true; + return type == SVM_EVTINJ_TYPE_EXEPT && kvm_exception_is_soft(vector); } diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index ec37647ca068..6248967d4a77 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3438,12 +3438,22 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu) static void svm_inject_irq(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); + u32 type; + + if (vcpu->arch.interrupt.soft) { + if (svm_update_soft_interrupt_rip(vcpu)) + return; + + type = SVM_EVTINJ_TYPE_SOFT; + } else { + type = SVM_EVTINJ_TYPE_INTR; + } trace_kvm_inj_virq(vcpu->arch.interrupt.nr); ++vcpu->stat.irq_injections; svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr | - SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR; + SVM_EVTINJ_VALID | type; } void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode, @@ -3723,6 +3733,8 @@ static inline void sync_lapic_to_cr8(struct kvm_vcpu *vcpu) static void svm_complete_soft_interrupt(struct kvm_vcpu *vcpu, u8 vector, int type) { + bool is_exception = (type == SVM_EXITINTINFO_TYPE_EXEPT); + bool is_soft = (type == SVM_EXITINTINFO_TYPE_SOFT); struct vcpu_svm *svm = to_svm(vcpu); /* @@ -3734,8 +3746,7 @@ static void svm_complete_soft_interrupt(struct kvm_vcpu *vcpu, u8 vector, * the same event, i.e. if the event is a soft exception/interrupt, * otherwise next_rip is unused on VMRUN. */ - if (nrips && type == SVM_EXITINTINFO_TYPE_EXEPT && - kvm_exception_is_soft(vector) && + if (nrips && (is_soft || (is_exception && kvm_exception_is_soft(vector))) && kvm_is_linear_rip(vcpu, svm->soft_int_old_rip + svm->soft_int_csbase)) svm->vmcb->control.next_rip = svm->soft_int_next_rip; /* @@ -3746,7 +3757,7 @@ static void svm_complete_soft_interrupt(struct kvm_vcpu *vcpu, u8 vector, * hit a #NP in the guest, and the #NP encountered a #PF, the #NP will * be the reported vectored event, but RIP still needs to be unwound. */ - else if (!nrips && type == SVM_EXITINTINFO_TYPE_EXEPT && + else if (!nrips && (is_soft || is_exception) && kvm_is_linear_rip(vcpu, svm->soft_int_next_rip + svm->soft_int_csbase)) kvm_rip_write(vcpu, svm->soft_int_old_rip); } @@ -3808,9 +3819,13 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) case SVM_EXITINTINFO_TYPE_INTR: kvm_queue_interrupt(vcpu, vector, false); break; + case SVM_EXITINTINFO_TYPE_SOFT: + kvm_queue_interrupt(vcpu, vector, true); + break; default: break; } + } static void svm_cancel_injection(struct kvm_vcpu *vcpu) From a61d7c5432ac5a953bbcec17af031661c2bd201d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 2 May 2022 00:07:31 +0200 Subject: [PATCH 0114/1436] KVM: x86: Trace re-injected exceptions Trace exceptions that are re-injected, not just those that KVM is injecting for the first time. Debugging re-injection bugs is painful enough as is, not having visibility into what KVM is doing only makes things worse. Delay propagating pending=>injected in the non-reinjection path so that the tracing can properly identify reinjected exceptions. Signed-off-by: Sean Christopherson Reviewed-by: Maxim Levitsky Signed-off-by: Maciej S. Szmigiero Message-Id: <25470690a38b4d2b32b6204875dd35676c65c9f2.1651440202.git.maciej.szmigiero@oracle.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/trace.h | 12 ++++++++---- arch/x86/kvm/x86.c | 16 +++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index de4762517569..d07428e660e3 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -358,25 +358,29 @@ TRACE_EVENT(kvm_inj_virq, * Tracepoint for kvm interrupt injection: */ TRACE_EVENT(kvm_inj_exception, - TP_PROTO(unsigned exception, bool has_error, unsigned error_code), - TP_ARGS(exception, has_error, error_code), + TP_PROTO(unsigned exception, bool has_error, unsigned error_code, + bool reinjected), + TP_ARGS(exception, has_error, error_code, reinjected), TP_STRUCT__entry( __field( u8, exception ) __field( u8, has_error ) __field( u32, error_code ) + __field( bool, reinjected ) ), TP_fast_assign( __entry->exception = exception; __entry->has_error = has_error; __entry->error_code = error_code; + __entry->reinjected = reinjected; ), - TP_printk("%s (0x%x)", + TP_printk("%s (0x%x)%s", __print_symbolic(__entry->exception, kvm_trace_sym_exc), /* FIXME: don't print error_code if not present */ - __entry->has_error ? __entry->error_code : 0) + __entry->has_error ? __entry->error_code : 0, + __entry->reinjected ? " [reinjected]" : "") ); /* diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 921b1139c303..c9f3ad89bf4c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9408,6 +9408,11 @@ int kvm_check_nested_events(struct kvm_vcpu *vcpu) static void kvm_inject_exception(struct kvm_vcpu *vcpu) { + trace_kvm_inj_exception(vcpu->arch.exception.nr, + vcpu->arch.exception.has_error_code, + vcpu->arch.exception.error_code, + vcpu->arch.exception.injected); + if (vcpu->arch.exception.error_code && !is_protmode(vcpu)) vcpu->arch.exception.error_code = false; static_call(kvm_x86_queue_exception)(vcpu); @@ -9465,13 +9470,6 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit) /* try to inject new event if pending */ if (vcpu->arch.exception.pending) { - trace_kvm_inj_exception(vcpu->arch.exception.nr, - vcpu->arch.exception.has_error_code, - vcpu->arch.exception.error_code); - - vcpu->arch.exception.pending = false; - vcpu->arch.exception.injected = true; - if (exception_type(vcpu->arch.exception.nr) == EXCPT_FAULT) __kvm_set_rflags(vcpu, kvm_get_rflags(vcpu) | X86_EFLAGS_RF); @@ -9485,6 +9483,10 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit) } kvm_inject_exception(vcpu); + + vcpu->arch.exception.pending = false; + vcpu->arch.exception.injected = true; + can_inject = false; } From 21d4c575eb4a1e6d956b61b5e9c162895fa7d4ba Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 2 May 2022 00:07:32 +0200 Subject: [PATCH 0115/1436] KVM: x86: Print error code in exception injection tracepoint iff valid Print the error code in the exception injection tracepoint if and only if the exception has an error code. Define the entire error code sequence as a set of formatted strings, print empty strings if there's no error code, and abuse __print_symbolic() by passing it an empty array to coerce it into printing the error code as a hex string. Signed-off-by: Sean Christopherson Reviewed-by: Maxim Levitsky Signed-off-by: Maciej S. Szmigiero Message-Id: Signed-off-by: Paolo Bonzini --- arch/x86/kvm/trace.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index d07428e660e3..385436d12024 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -376,10 +376,11 @@ TRACE_EVENT(kvm_inj_exception, __entry->reinjected = reinjected; ), - TP_printk("%s (0x%x)%s", + TP_printk("%s%s%s%s%s", __print_symbolic(__entry->exception, kvm_trace_sym_exc), - /* FIXME: don't print error_code if not present */ - __entry->has_error ? __entry->error_code : 0, + !__entry->has_error ? "" : " (", + !__entry->has_error ? "" : __print_symbolic(__entry->error_code, { }), + !__entry->has_error ? "" : ")", __entry->reinjected ? " [reinjected]" : "") ); From 2d61391270a3ceb95b3dd536ea13002e653323b6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 2 May 2022 00:07:33 +0200 Subject: [PATCH 0116/1436] KVM: x86: Differentiate Soft vs. Hard IRQs vs. reinjected in tracepoint In the IRQ injection tracepoint, differentiate between Hard IRQs and Soft "IRQs", i.e. interrupts that are reinjected after incomplete delivery of a software interrupt from an INTn instruction. Tag reinjected interrupts as such, even though the information is usually redundant since soft interrupts are only ever reinjected by KVM. Though rare in practice, a hard IRQ can be reinjected. Signed-off-by: Sean Christopherson [MSS: change "kvm_inj_virq" event "reinjected" field type to bool] Signed-off-by: Maciej S. Szmigiero Message-Id: <9664d49b3bd21e227caa501cff77b0569bebffe2.1651440202.git.maciej.szmigiero@oracle.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/svm/svm.c | 5 +++-- arch/x86/kvm/trace.h | 16 +++++++++++----- arch/x86/kvm/vmx/vmx.c | 4 ++-- arch/x86/kvm/x86.c | 4 ++-- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 959d66b9be94..8109805b5429 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1405,7 +1405,7 @@ struct kvm_x86_ops { u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu); void (*patch_hypercall)(struct kvm_vcpu *vcpu, unsigned char *hypercall_addr); - void (*inject_irq)(struct kvm_vcpu *vcpu); + void (*inject_irq)(struct kvm_vcpu *vcpu, bool reinjected); void (*inject_nmi)(struct kvm_vcpu *vcpu); void (*queue_exception)(struct kvm_vcpu *vcpu); void (*cancel_injection)(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 6248967d4a77..0f4d38e5ceab 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3435,7 +3435,7 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu) ++vcpu->stat.nmi_injections; } -static void svm_inject_irq(struct kvm_vcpu *vcpu) +static void svm_inject_irq(struct kvm_vcpu *vcpu, bool reinjected) { struct vcpu_svm *svm = to_svm(vcpu); u32 type; @@ -3449,7 +3449,8 @@ static void svm_inject_irq(struct kvm_vcpu *vcpu) type = SVM_EVTINJ_TYPE_INTR; } - trace_kvm_inj_virq(vcpu->arch.interrupt.nr); + trace_kvm_inj_virq(vcpu->arch.interrupt.nr, + vcpu->arch.interrupt.soft, reinjected); ++vcpu->stat.irq_injections; svm->vmcb->control.event_inj = vcpu->arch.interrupt.nr | diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index 385436d12024..fd28dd40b813 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -333,18 +333,24 @@ TRACE_EVENT_KVM_EXIT(kvm_exit); * Tracepoint for kvm interrupt injection: */ TRACE_EVENT(kvm_inj_virq, - TP_PROTO(unsigned int irq), - TP_ARGS(irq), + TP_PROTO(unsigned int vector, bool soft, bool reinjected), + TP_ARGS(vector, soft, reinjected), TP_STRUCT__entry( - __field( unsigned int, irq ) + __field( unsigned int, vector ) + __field( bool, soft ) + __field( bool, reinjected ) ), TP_fast_assign( - __entry->irq = irq; + __entry->vector = vector; + __entry->soft = soft; + __entry->reinjected = reinjected; ), - TP_printk("irq %u", __entry->irq) + TP_printk("%s 0x%x%s", + __entry->soft ? "Soft/INTn" : "IRQ", __entry->vector, + __entry->reinjected ? " [reinjected]" : "") ); #define EXS(x) { x##_VECTOR, "#" #x } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index e1aa14743cdb..9714ae95589f 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4573,13 +4573,13 @@ static void vmx_enable_nmi_window(struct kvm_vcpu *vcpu) exec_controls_setbit(to_vmx(vcpu), CPU_BASED_NMI_WINDOW_EXITING); } -static void vmx_inject_irq(struct kvm_vcpu *vcpu) +static void vmx_inject_irq(struct kvm_vcpu *vcpu, bool reinjected) { struct vcpu_vmx *vmx = to_vmx(vcpu); uint32_t intr; int irq = vcpu->arch.interrupt.nr; - trace_kvm_inj_virq(irq); + trace_kvm_inj_virq(irq, vcpu->arch.interrupt.soft, reinjected); ++vcpu->stat.irq_injections; if (vmx->rmode.vm86_active) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c9f3ad89bf4c..501606e02688 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9448,7 +9448,7 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit) static_call(kvm_x86_inject_nmi)(vcpu); can_inject = false; } else if (vcpu->arch.interrupt.injected) { - static_call(kvm_x86_inject_irq)(vcpu); + static_call(kvm_x86_inject_irq)(vcpu, true); can_inject = false; } } @@ -9539,7 +9539,7 @@ static int inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit) goto out; if (r) { kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu), false); - static_call(kvm_x86_inject_irq)(vcpu); + static_call(kvm_x86_inject_irq)(vcpu, false); WARN_ON(static_call(kvm_x86_interrupt_allowed)(vcpu, true) < 0); } if (kvm_cpu_has_injectable_intr(vcpu)) From 159fc6fa3b7db24db85598115cc43dc47196919e Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 2 May 2022 00:07:34 +0200 Subject: [PATCH 0117/1436] KVM: nSVM: Transparently handle L1 -> L2 NMI re-injection A NMI that L1 wants to inject into its L2 should be directly re-injected, without causing L0 side effects like engaging NMI blocking for L1. It's also worth noting that in this case it is L1 responsibility to track the NMI window status for its L2 guest. Signed-off-by: Maciej S. Szmigiero Message-Id: Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/nested.c | 12 ++++++++++++ arch/x86/kvm/svm/svm.c | 7 +++++++ arch/x86/kvm/svm/svm.h | 1 + 3 files changed, 20 insertions(+) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 0d25dea40796..688f86b9202a 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -623,6 +623,16 @@ static inline bool is_evtinj_soft(u32 evtinj) return type == SVM_EVTINJ_TYPE_EXEPT && kvm_exception_is_soft(vector); } +static bool is_evtinj_nmi(u32 evtinj) +{ + u32 type = evtinj & SVM_EVTINJ_TYPE_MASK; + + if (!(evtinj & SVM_EVTINJ_VALID)) + return false; + + return type == SVM_EVTINJ_TYPE_NMI; +} + static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, unsigned long vmcb12_rip) { @@ -691,6 +701,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, else if (boot_cpu_has(X86_FEATURE_NRIPS)) vmcb02->control.next_rip = vmcb12_rip; + svm->nmi_l1_to_l2 = is_evtinj_nmi(vmcb02->control.event_inj); if (is_evtinj_soft(vmcb02->control.event_inj)) { svm->soft_int_injected = true; svm->soft_int_csbase = svm->vmcb->save.cs.base; @@ -873,6 +884,7 @@ int nested_svm_vmrun(struct kvm_vcpu *vcpu) out_exit_err: svm->nested.nested_run_pending = 0; + svm->nmi_l1_to_l2 = false; svm->soft_int_injected = false; svm->vmcb->control.exit_code = SVM_EXIT_ERR; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 0f4d38e5ceab..5fda7e7102f2 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3429,6 +3429,10 @@ static void svm_inject_nmi(struct kvm_vcpu *vcpu) struct vcpu_svm *svm = to_svm(vcpu); svm->vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_NMI; + + if (svm->nmi_l1_to_l2) + return; + vcpu->arch.hflags |= HF_NMI_MASK; if (!sev_es_guest(vcpu->kvm)) svm_set_intercept(svm, INTERCEPT_IRET); @@ -3769,8 +3773,10 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) u8 vector; int type; u32 exitintinfo = svm->vmcb->control.exit_int_info; + bool nmi_l1_to_l2 = svm->nmi_l1_to_l2; bool soft_int_injected = svm->soft_int_injected; + svm->nmi_l1_to_l2 = false; svm->soft_int_injected = false; /* @@ -3802,6 +3808,7 @@ static void svm_complete_interrupts(struct kvm_vcpu *vcpu) switch (type) { case SVM_EXITINTINFO_TYPE_NMI: vcpu->arch.nmi_injected = true; + svm->nmi_l1_to_l2 = nmi_l1_to_l2; break; case SVM_EXITINTINFO_TYPE_EXEPT: /* diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index f0b6111ee5b1..24b5c73a8c87 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -229,6 +229,7 @@ struct vcpu_svm { bool nmi_singlestep; u64 nmi_singlestep_guest_rflags; + bool nmi_l1_to_l2; unsigned long soft_int_csbase; unsigned long soft_int_old_rip; From d8969871253a4704f007b307b2dd6232d1e40da8 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 2 May 2022 00:07:35 +0200 Subject: [PATCH 0118/1436] KVM: selftests: nSVM: Add svm_nested_soft_inject_test Add a KVM self-test that checks whether a nSVM L1 is able to successfully inject a software interrupt, a soft exception and a NMI into its L2 guest. In practice, this tests both the next_rip field consistency and L1-injected event with intervening L0 VMEXIT during its delivery: the first nested VMRUN (that's also trying to inject a software interrupt) will immediately trigger a L0 NPF. This L0 NPF will have zero in its CPU-returned next_rip field, which if incorrectly reused by KVM will trigger a #PF when trying to return to such address 0 from the interrupt handler. For NMI injection this tests whether the L1 NMI state isn't getting incorrectly mixed with the L2 NMI state if a L1 -> L2 NMI needs to be re-injected. Reviewed-by: Maxim Levitsky [sean: check exact L2 RIP on first soft interrupt] Signed-off-by: Sean Christopherson Signed-off-by: Maciej S. Szmigiero Message-Id: Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/.gitignore | 3 +- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/include/x86_64/processor.h | 17 ++ .../selftests/kvm/include/x86_64/svm_util.h | 12 + .../testing/selftests/kvm/x86_64/evmcs_test.c | 1 - .../selftests/kvm/x86_64/hyperv_svm_test.c | 5 - .../kvm/x86_64/svm_nested_soft_inject_test.c | 217 ++++++++++++++++++ 7 files changed, 249 insertions(+), 7 deletions(-) create mode 100644 tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 4509a3a7eeae..82e764d71ca7 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -36,9 +36,10 @@ /x86_64/state_test /x86_64/svm_vmcall_test /x86_64/svm_int_ctl_test -/x86_64/tsc_scaling_sync +/x86_64/svm_nested_soft_inject_test /x86_64/sync_regs_test /x86_64/tsc_msrs_test +/x86_64/tsc_scaling_sync /x86_64/userspace_io_test /x86_64/userspace_msr_exit_test /x86_64/vmx_apic_access_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 81470a99ed1c..f2647b88a8a0 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -66,6 +66,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/state_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_preemption_timer_test TEST_GEN_PROGS_x86_64 += x86_64/svm_vmcall_test TEST_GEN_PROGS_x86_64 += x86_64/svm_int_ctl_test +TEST_GEN_PROGS_x86_64 += x86_64/svm_nested_soft_inject_test TEST_GEN_PROGS_x86_64 += x86_64/tsc_scaling_sync TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test TEST_GEN_PROGS_x86_64 += x86_64/userspace_io_test diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index d0d51adec76e..4fd870f37b9e 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -17,6 +17,8 @@ #include "../kvm_util.h" +#define NMI_VECTOR 0x02 + #define X86_EFLAGS_FIXED (1u << 1) #define X86_CR4_VME (1ul << 0) @@ -385,6 +387,21 @@ static inline void cpu_relax(void) asm volatile("rep; nop" ::: "memory"); } +#define vmmcall() \ + __asm__ __volatile__( \ + "vmmcall\n" \ + ) + +#define ud2() \ + __asm__ __volatile__( \ + "ud2\n" \ + ) + +#define hlt() \ + __asm__ __volatile__( \ + "hlt\n" \ + ) + bool is_intel_cpu(void); bool is_amd_cpu(void); diff --git a/tools/testing/selftests/kvm/include/x86_64/svm_util.h b/tools/testing/selftests/kvm/include/x86_64/svm_util.h index a25aabd8f5e7..136ba6a5d027 100644 --- a/tools/testing/selftests/kvm/include/x86_64/svm_util.h +++ b/tools/testing/selftests/kvm/include/x86_64/svm_util.h @@ -16,6 +16,8 @@ #define CPUID_SVM_BIT 2 #define CPUID_SVM BIT_ULL(CPUID_SVM_BIT) +#define SVM_EXIT_EXCP_BASE 0x040 +#define SVM_EXIT_HLT 0x078 #define SVM_EXIT_MSR 0x07c #define SVM_EXIT_VMMCALL 0x081 @@ -36,6 +38,16 @@ struct svm_test_data { uint64_t msr_gpa; }; +#define stgi() \ + __asm__ __volatile__( \ + "stgi\n" \ + ) + +#define clgi() \ + __asm__ __volatile__( \ + "clgi\n" \ + ) + struct svm_test_data *vcpu_alloc_svm(struct kvm_vm *vm, vm_vaddr_t *p_svm_gva); void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_rsp); void run_guest(struct vmcb *vmcb, uint64_t vmcb_gpa); diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c index d12e043aa2ee..e161c6dd7a02 100644 --- a/tools/testing/selftests/kvm/x86_64/evmcs_test.c +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c @@ -19,7 +19,6 @@ #include "vmx.h" #define VCPU_ID 5 -#define NMI_VECTOR 2 static int ud_count; diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c index 21f5ca9197da..994b33fd8724 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c @@ -42,11 +42,6 @@ struct hv_enlightenments { */ #define VMCB_HV_NESTED_ENLIGHTENMENTS (1U << 31) -static inline void vmmcall(void) -{ - __asm__ __volatile__("vmmcall"); -} - void l2_guest_code(void) { GUEST_SYNC(3); diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c new file mode 100644 index 000000000000..f94f1b449aef --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * Based on: + * svm_int_ctl_test + * + * Copyright (C) 2021, Red Hat, Inc. + * + */ + +#include +#include +#include +#include "apic.h" +#include "kvm_util.h" +#include "processor.h" +#include "svm_util.h" +#include "test_util.h" +#include "../lib/kvm_util_internal.h" + +#define VCPU_ID 0 +#define INT_NR 0x20 +#define X86_FEATURE_NRIPS BIT(3) + +static_assert(ATOMIC_INT_LOCK_FREE == 2, "atomic int is not lockless"); + +static unsigned int bp_fired; +static void guest_bp_handler(struct ex_regs *regs) +{ + bp_fired++; +} + +static unsigned int int_fired; +static void l2_guest_code_int(void); + +static void guest_int_handler(struct ex_regs *regs) +{ + int_fired++; + GUEST_ASSERT_2(regs->rip == (unsigned long)l2_guest_code_int, + regs->rip, (unsigned long)l2_guest_code_int); +} + +static void l2_guest_code_int(void) +{ + GUEST_ASSERT_1(int_fired == 1, int_fired); + vmmcall(); + ud2(); + + GUEST_ASSERT_1(bp_fired == 1, bp_fired); + hlt(); +} + +static atomic_int nmi_stage; +#define nmi_stage_get() atomic_load_explicit(&nmi_stage, memory_order_acquire) +#define nmi_stage_inc() atomic_fetch_add_explicit(&nmi_stage, 1, memory_order_acq_rel) +static void guest_nmi_handler(struct ex_regs *regs) +{ + nmi_stage_inc(); + + if (nmi_stage_get() == 1) { + vmmcall(); + GUEST_ASSERT(false); + } else { + GUEST_ASSERT_1(nmi_stage_get() == 3, nmi_stage_get()); + GUEST_DONE(); + } +} + +static void l2_guest_code_nmi(void) +{ + ud2(); +} + +static void l1_guest_code(struct svm_test_data *svm, uint64_t is_nmi, uint64_t idt_alt) +{ + #define L2_GUEST_STACK_SIZE 64 + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + struct vmcb *vmcb = svm->vmcb; + + if (is_nmi) + x2apic_enable(); + + /* Prepare for L2 execution. */ + generic_svm_setup(svm, + is_nmi ? l2_guest_code_nmi : l2_guest_code_int, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + vmcb->control.intercept_exceptions |= BIT(PF_VECTOR) | BIT(UD_VECTOR); + vmcb->control.intercept |= BIT(INTERCEPT_NMI) | BIT(INTERCEPT_HLT); + + if (is_nmi) { + vmcb->control.event_inj = SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_NMI; + } else { + vmcb->control.event_inj = INT_NR | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_SOFT; + /* The return address pushed on stack */ + vmcb->control.next_rip = vmcb->save.rip; + } + + run_guest(vmcb, svm->vmcb_gpa); + GUEST_ASSERT_3(vmcb->control.exit_code == SVM_EXIT_VMMCALL, + vmcb->control.exit_code, + vmcb->control.exit_info_1, vmcb->control.exit_info_2); + + if (is_nmi) { + clgi(); + x2apic_write_reg(APIC_ICR, APIC_DEST_SELF | APIC_INT_ASSERT | APIC_DM_NMI); + + GUEST_ASSERT_1(nmi_stage_get() == 1, nmi_stage_get()); + nmi_stage_inc(); + + stgi(); + /* self-NMI happens here */ + while (true) + cpu_relax(); + } + + /* Skip over VMMCALL */ + vmcb->save.rip += 3; + + /* Switch to alternate IDT to cause intervening NPF again */ + vmcb->save.idtr.base = idt_alt; + vmcb->control.clean = 0; /* &= ~BIT(VMCB_DT) would be enough */ + + vmcb->control.event_inj = BP_VECTOR | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_EXEPT; + /* The return address pushed on stack, skip over UD2 */ + vmcb->control.next_rip = vmcb->save.rip + 2; + + run_guest(vmcb, svm->vmcb_gpa); + GUEST_ASSERT_3(vmcb->control.exit_code == SVM_EXIT_HLT, + vmcb->control.exit_code, + vmcb->control.exit_info_1, vmcb->control.exit_info_2); + + GUEST_DONE(); +} + +static void run_test(bool is_nmi) +{ + struct kvm_vm *vm; + vm_vaddr_t svm_gva; + vm_vaddr_t idt_alt_vm; + struct kvm_guest_debug debug; + + pr_info("Running %s test\n", is_nmi ? "NMI" : "soft int"); + + vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(vm, VCPU_ID); + + vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler); + vm_install_exception_handler(vm, BP_VECTOR, guest_bp_handler); + vm_install_exception_handler(vm, INT_NR, guest_int_handler); + + vcpu_alloc_svm(vm, &svm_gva); + + if (!is_nmi) { + void *idt, *idt_alt; + + idt_alt_vm = vm_vaddr_alloc_page(vm); + idt_alt = addr_gva2hva(vm, idt_alt_vm); + idt = addr_gva2hva(vm, vm->idt); + memcpy(idt_alt, idt, getpagesize()); + } else { + idt_alt_vm = 0; + } + vcpu_args_set(vm, VCPU_ID, 3, svm_gva, (uint64_t)is_nmi, (uint64_t)idt_alt_vm); + + memset(&debug, 0, sizeof(debug)); + vcpu_set_guest_debug(vm, VCPU_ID, &debug); + + struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct ucall uc; + + alarm(2); + vcpu_run(vm, VCPU_ID); + alarm(0); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_ABORT: + TEST_FAIL("%s at %s:%ld, vals = 0x%lx 0x%lx 0x%lx", (const char *)uc.args[0], + __FILE__, uc.args[1], uc.args[2], uc.args[3], uc.args[4]); + break; + /* NOT REACHED */ + case UCALL_DONE: + goto done; + default: + TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd); + } +done: + kvm_vm_free(vm); +} + +int main(int argc, char *argv[]) +{ + struct kvm_cpuid_entry2 *cpuid; + + /* Tell stdout not to buffer its content */ + setbuf(stdout, NULL); + + nested_svm_check_supported(); + + cpuid = kvm_get_supported_cpuid_entry(0x8000000a); + TEST_ASSERT(cpuid->edx & X86_FEATURE_NRIPS, + "KVM with nSVM is supposed to unconditionally advertise nRIP Save\n"); + + atomic_init(&nmi_stage, 0); + + run_test(false); + run_test(true); + + return 0; +} From 9fb3565743d58352f00964bf47213b88aff4bb82 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 13 May 2022 19:49:59 +0000 Subject: [PATCH 0119/1436] KVM: x86/mmu: Drop RWX=0 SPTEs during ept_sync_page() All of sync_page()'s existing checks filter out only !PRESENT gPTE, because without execute-only, all upper levels are guaranteed to be at least READABLE. However, if EPT with execute-only support is in use by L1, KVM can create an SPTE that is shadow-present but guest-inaccessible (RWX=0) if the upper level combined permissions are R (or RW) and the leaf EPTE is changed from R (or RW) to X. Because the EPTE is considered present when viewed in isolation, and no reserved bits are set, FNAME(prefetch_invalid_gpte) will consider the GPTE valid, and cause a not-present SPTE to be created. The SPTE is "correct": the guest translation is inaccessible because the combined protections of all levels yield RWX=0, and KVM will just redirect any vmexits to the guest. If EPT A/D bits are disabled, KVM can mistake the SPTE for an access-tracked SPTE, but again such confusion isn't fatal, as the "saved" protections are also RWX=0. However, creating a useless SPTE in general means that KVM messed up something, even if this particular goof didn't manifest as a functional bug. So, drop SPTEs whose new protections will yield a RWX=0 SPTE, and add a WARN in make_spte() to detect creation of SPTEs that will result in RWX=0 protections. Fixes: d95c55687e11 ("kvm: mmu: track read permission explicitly for shadow EPT page tables") Cc: David Matlack Cc: Ben Gardon Signed-off-by: Sean Christopherson Message-Id: <20220513195000.99371-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/paging_tmpl.h | 9 ++++++++- arch/x86/kvm/mmu/spte.c | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index db80f7ccaa4e..1576e65b3b1f 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -1053,7 +1053,14 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) if (sync_mmio_spte(vcpu, &sp->spt[i], gfn, pte_access)) continue; - if (gfn != sp->gfns[i]) { + /* + * Drop the SPTE if the new protections would result in a RWX=0 + * SPTE or if the gfn is changing. The RWX=0 case only affects + * EPT with execute-only support, i.e. EPT without an effective + * "present" bit, as all other paging modes will create a + * read-only SPTE if pte_access is zero. + */ + if ((!pte_access && !shadow_present_mask) || gfn != sp->gfns[i]) { drop_spte(vcpu->kvm, &sp->spt[i]); flush = true; continue; diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index b5960bbde7f7..cda1851ec155 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -129,6 +129,8 @@ bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, u64 spte = SPTE_MMU_PRESENT_MASK; bool wrprot = false; + WARN_ON_ONCE(!pte_access && !shadow_present_mask); + if (sp->role.ad_disabled) spte |= SPTE_TDP_AD_DISABLED_MASK; else if (kvm_mmu_page_ad_need_write_protect(sp)) From b8b9156ec6ef69baa487185205f2be833267776b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 13 May 2022 19:50:00 +0000 Subject: [PATCH 0120/1436] KVM: x86/mmu: Comment FNAME(sync_page) to document TLB flushing logic Add a comment to FNAME(sync_page) to explain why the TLB flushing logic conspiculously doesn't handle the scenario of guest protections being reduced. Specifically, if synchronizing a SPTE drops execute protections, KVM will not emit a TLB flush, whereas dropping writable or clearing A/D bits does trigger a flush via mmu_spte_update(). Architecturally, until the GPTE is implicitly or explicitly flushed from the guest's perspective, KVM is not required to flush any old, stale translations. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Message-Id: <20220513195000.99371-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/paging_tmpl.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 1576e65b3b1f..fe35d8fd3276 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -1077,6 +1077,15 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) flush |= mmu_spte_update(sptep, spte); } + /* + * Note, any flush is purely for KVM's correctness, e.g. when dropping + * an existing SPTE or clearing W/A/D bits to ensure an mmu_notifier + * unmap or dirty logging event doesn't fail to flush. The guest is + * responsible for flushing the TLB to ensure any changes in protection + * bits are recognized, i.e. until the guest flushes or page faults on + * a relevant address, KVM is architecturally allowed to let vCPUs use + * cached translations with the old protection bits. + */ return flush; } From 465932db25f3664893b66152c7b190afd28c32db Mon Sep 17 00:00:00 2001 From: Robert Hoo Date: Tue, 19 Apr 2022 23:32:40 +0800 Subject: [PATCH 0121/1436] x86/cpu: Add new VMX feature, Tertiary VM-Execution control A new 64-bit control field "tertiary processor-based VM-execution controls", is defined [1]. It's controlled by bit 17 of the primary processor-based VM-execution controls. Different from its brother VM-execution fields, this tertiary VM- execution controls field is 64 bit. So it occupies 2 vmx_feature_leafs, TERTIARY_CTLS_LOW and TERTIARY_CTLS_HIGH. Its companion VMX capability reporting MSR,MSR_IA32_VMX_PROCBASED_CTLS3 (0x492), is also semantically different from its brothers, whose 64 bits consist of all allow-1, rather than 32-bit allow-0 and 32-bit allow-1 [1][2]. Therefore, its init_vmx_capabilities() is a little different from others. [1] ISE 6.2 "VMCS Changes" https://www.intel.com/content/www/us/en/develop/download/intel-architecture-instruction-set-extensions-programming-reference.html [2] SDM Vol3. Appendix A.3 Reviewed-by: Sean Christopherson Reviewed-by: Maxim Levitsky Signed-off-by: Robert Hoo Signed-off-by: Zeng Guang Message-Id: <20220419153240.11549-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/msr-index.h | 1 + arch/x86/include/asm/vmxfeatures.h | 3 ++- arch/x86/kernel/cpu/feat_ctl.c | 9 ++++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 403e83b4adc8..c194995b2e1f 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -980,6 +980,7 @@ #define MSR_IA32_VMX_TRUE_EXIT_CTLS 0x0000048f #define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x00000490 #define MSR_IA32_VMX_VMFUNC 0x00000491 +#define MSR_IA32_VMX_PROCBASED_CTLS3 0x00000492 /* VMX_BASIC bits and bitmasks */ #define VMX_BASIC_VMCS_SIZE_SHIFT 32 diff --git a/arch/x86/include/asm/vmxfeatures.h b/arch/x86/include/asm/vmxfeatures.h index d9a74681a77d..ff20776dc83b 100644 --- a/arch/x86/include/asm/vmxfeatures.h +++ b/arch/x86/include/asm/vmxfeatures.h @@ -5,7 +5,7 @@ /* * Defines VMX CPU feature bits */ -#define NVMXINTS 3 /* N 32-bit words worth of info */ +#define NVMXINTS 5 /* N 32-bit words worth of info */ /* * Note: If the comment begins with a quoted string, that string is used @@ -43,6 +43,7 @@ #define VMX_FEATURE_RDTSC_EXITING ( 1*32+ 12) /* "" VM-Exit on RDTSC */ #define VMX_FEATURE_CR3_LOAD_EXITING ( 1*32+ 15) /* "" VM-Exit on writes to CR3 */ #define VMX_FEATURE_CR3_STORE_EXITING ( 1*32+ 16) /* "" VM-Exit on reads from CR3 */ +#define VMX_FEATURE_TERTIARY_CONTROLS ( 1*32+ 17) /* "" Enable Tertiary VM-Execution Controls */ #define VMX_FEATURE_CR8_LOAD_EXITING ( 1*32+ 19) /* "" VM-Exit on writes to CR8 */ #define VMX_FEATURE_CR8_STORE_EXITING ( 1*32+ 20) /* "" VM-Exit on reads from CR8 */ #define VMX_FEATURE_VIRTUAL_TPR ( 1*32+ 21) /* "vtpr" TPR virtualization, a.k.a. TPR shadow */ diff --git a/arch/x86/kernel/cpu/feat_ctl.c b/arch/x86/kernel/cpu/feat_ctl.c index da696eb4821a..993697e71854 100644 --- a/arch/x86/kernel/cpu/feat_ctl.c +++ b/arch/x86/kernel/cpu/feat_ctl.c @@ -15,6 +15,8 @@ enum vmx_feature_leafs { MISC_FEATURES = 0, PRIMARY_CTLS, SECONDARY_CTLS, + TERTIARY_CTLS_LOW, + TERTIARY_CTLS_HIGH, NR_VMX_FEATURE_WORDS, }; @@ -22,7 +24,7 @@ enum vmx_feature_leafs { static void init_vmx_capabilities(struct cpuinfo_x86 *c) { - u32 supported, funcs, ept, vpid, ign; + u32 supported, funcs, ept, vpid, ign, low, high; BUILD_BUG_ON(NVMXINTS != NR_VMX_FEATURE_WORDS); @@ -42,6 +44,11 @@ static void init_vmx_capabilities(struct cpuinfo_x86 *c) rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS2, &ign, &supported); c->vmx_capability[SECONDARY_CTLS] = supported; + /* All 64 bits of tertiary controls MSR are allowed-1 settings. */ + rdmsr_safe(MSR_IA32_VMX_PROCBASED_CTLS3, &low, &high); + c->vmx_capability[TERTIARY_CTLS_LOW] = low; + c->vmx_capability[TERTIARY_CTLS_HIGH] = high; + rdmsr(MSR_IA32_VMX_PINBASED_CTLS, ign, supported); rdmsr_safe(MSR_IA32_VMX_VMFUNC, &ign, &funcs); From ed3905ba60384ab8c73b421c3618375e58080a9a Mon Sep 17 00:00:00 2001 From: Robert Hoo Date: Tue, 19 Apr 2022 23:33:18 +0800 Subject: [PATCH 0122/1436] KVM: VMX: Extend BUILD_CONTROLS_SHADOW macro to support 64-bit variation The Tertiary VM-Exec Control, different from previous control fields, is 64 bit. So extend BUILD_CONTROLS_SHADOW() by adding a 'bit' parameter, to support both 32 bit and 64 bit fields' auxiliary functions building. Suggested-by: Sean Christopherson Reviewed-by: Maxim Levitsky Reviewed-by: Sean Christopherson Signed-off-by: Robert Hoo Signed-off-by: Zeng Guang Message-Id: <20220419153318.11595-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.h | 56 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index b98c7e96697a..56be4cd4edaf 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -456,35 +456,35 @@ static inline u8 vmx_get_rvi(void) return vmcs_read16(GUEST_INTR_STATUS) & 0xff; } -#define BUILD_CONTROLS_SHADOW(lname, uname) \ -static inline void lname##_controls_set(struct vcpu_vmx *vmx, u32 val) \ -{ \ - if (vmx->loaded_vmcs->controls_shadow.lname != val) { \ - vmcs_write32(uname, val); \ - vmx->loaded_vmcs->controls_shadow.lname = val; \ - } \ -} \ -static inline u32 __##lname##_controls_get(struct loaded_vmcs *vmcs) \ -{ \ - return vmcs->controls_shadow.lname; \ -} \ -static inline u32 lname##_controls_get(struct vcpu_vmx *vmx) \ -{ \ - return __##lname##_controls_get(vmx->loaded_vmcs); \ -} \ -static inline void lname##_controls_setbit(struct vcpu_vmx *vmx, u32 val) \ -{ \ - lname##_controls_set(vmx, lname##_controls_get(vmx) | val); \ -} \ -static inline void lname##_controls_clearbit(struct vcpu_vmx *vmx, u32 val) \ -{ \ - lname##_controls_set(vmx, lname##_controls_get(vmx) & ~val); \ +#define BUILD_CONTROLS_SHADOW(lname, uname, bits) \ +static inline void lname##_controls_set(struct vcpu_vmx *vmx, u##bits val) \ +{ \ + if (vmx->loaded_vmcs->controls_shadow.lname != val) { \ + vmcs_write##bits(uname, val); \ + vmx->loaded_vmcs->controls_shadow.lname = val; \ + } \ +} \ +static inline u##bits __##lname##_controls_get(struct loaded_vmcs *vmcs) \ +{ \ + return vmcs->controls_shadow.lname; \ +} \ +static inline u##bits lname##_controls_get(struct vcpu_vmx *vmx) \ +{ \ + return __##lname##_controls_get(vmx->loaded_vmcs); \ +} \ +static inline void lname##_controls_setbit(struct vcpu_vmx *vmx, u##bits val) \ +{ \ + lname##_controls_set(vmx, lname##_controls_get(vmx) | val); \ +} \ +static inline void lname##_controls_clearbit(struct vcpu_vmx *vmx, u##bits val) \ +{ \ + lname##_controls_set(vmx, lname##_controls_get(vmx) & ~val); \ } -BUILD_CONTROLS_SHADOW(vm_entry, VM_ENTRY_CONTROLS) -BUILD_CONTROLS_SHADOW(vm_exit, VM_EXIT_CONTROLS) -BUILD_CONTROLS_SHADOW(pin, PIN_BASED_VM_EXEC_CONTROL) -BUILD_CONTROLS_SHADOW(exec, CPU_BASED_VM_EXEC_CONTROL) -BUILD_CONTROLS_SHADOW(secondary_exec, SECONDARY_VM_EXEC_CONTROL) +BUILD_CONTROLS_SHADOW(vm_entry, VM_ENTRY_CONTROLS, 32) +BUILD_CONTROLS_SHADOW(vm_exit, VM_EXIT_CONTROLS, 32) +BUILD_CONTROLS_SHADOW(pin, PIN_BASED_VM_EXEC_CONTROL, 32) +BUILD_CONTROLS_SHADOW(exec, CPU_BASED_VM_EXEC_CONTROL, 32) +BUILD_CONTROLS_SHADOW(secondary_exec, SECONDARY_VM_EXEC_CONTROL, 32) /* * VMX_REGS_LAZY_LOAD_SET - The set of registers that will be updated in the From 1ad4e5438c67a01620ed67cea959de89f4430515 Mon Sep 17 00:00:00 2001 From: Robert Hoo Date: Tue, 19 Apr 2022 23:34:00 +0800 Subject: [PATCH 0123/1436] KVM: VMX: Detect Tertiary VM-Execution control when setup VMCS config Check VMX features on tertiary execution control in VMCS config setup. Sub-features in tertiary execution control to be enabled are adjusted according to hardware capabilities although no sub-feature is enabled in this patch. EVMCSv1 doesn't support tertiary VM-execution control, so disable it when EVMCSv1 is in use. And define the auxiliary functions for Tertiary control field here, using the new BUILD_CONTROLS_SHADOW(). Reviewed-by: Maxim Levitsky Signed-off-by: Robert Hoo Signed-off-by: Zeng Guang Message-Id: <20220419153400.11642-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/vmx.h | 3 +++ arch/x86/kvm/vmx/capabilities.h | 7 +++++++ arch/x86/kvm/vmx/evmcs.c | 2 ++ arch/x86/kvm/vmx/evmcs.h | 1 + arch/x86/kvm/vmx/vmcs.h | 1 + arch/x86/kvm/vmx/vmx.c | 29 ++++++++++++++++++++++++++++- arch/x86/kvm/vmx/vmx.h | 1 + 7 files changed, 43 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 6c343c6a1855..34ca428fefed 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -31,6 +31,7 @@ #define CPU_BASED_RDTSC_EXITING VMCS_CONTROL_BIT(RDTSC_EXITING) #define CPU_BASED_CR3_LOAD_EXITING VMCS_CONTROL_BIT(CR3_LOAD_EXITING) #define CPU_BASED_CR3_STORE_EXITING VMCS_CONTROL_BIT(CR3_STORE_EXITING) +#define CPU_BASED_ACTIVATE_TERTIARY_CONTROLS VMCS_CONTROL_BIT(TERTIARY_CONTROLS) #define CPU_BASED_CR8_LOAD_EXITING VMCS_CONTROL_BIT(CR8_LOAD_EXITING) #define CPU_BASED_CR8_STORE_EXITING VMCS_CONTROL_BIT(CR8_STORE_EXITING) #define CPU_BASED_TPR_SHADOW VMCS_CONTROL_BIT(VIRTUAL_TPR) @@ -221,6 +222,8 @@ enum vmcs_field { ENCLS_EXITING_BITMAP_HIGH = 0x0000202F, TSC_MULTIPLIER = 0x00002032, TSC_MULTIPLIER_HIGH = 0x00002033, + TERTIARY_VM_EXEC_CONTROL = 0x00002034, + TERTIARY_VM_EXEC_CONTROL_HIGH = 0x00002035, GUEST_PHYSICAL_ADDRESS = 0x00002400, GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401, VMCS_LINK_POINTER = 0x00002800, diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h index 3f430e218375..31f3d88b3e4d 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -59,6 +59,7 @@ struct vmcs_config { u32 pin_based_exec_ctrl; u32 cpu_based_exec_ctrl; u32 cpu_based_2nd_exec_ctrl; + u64 cpu_based_3rd_exec_ctrl; u32 vmexit_ctrl; u32 vmentry_ctrl; struct nested_vmx_msrs nested; @@ -131,6 +132,12 @@ static inline bool cpu_has_secondary_exec_ctrls(void) CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; } +static inline bool cpu_has_tertiary_exec_ctrls(void) +{ + return vmcs_config.cpu_based_exec_ctrl & + CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; +} + static inline bool cpu_has_vmx_virtualize_apic_accesses(void) { return vmcs_config.cpu_based_2nd_exec_ctrl & diff --git a/arch/x86/kvm/vmx/evmcs.c b/arch/x86/kvm/vmx/evmcs.c index 87e3dc10edf4..6a61b1ae7942 100644 --- a/arch/x86/kvm/vmx/evmcs.c +++ b/arch/x86/kvm/vmx/evmcs.c @@ -297,8 +297,10 @@ const unsigned int nr_evmcs_1_fields = ARRAY_SIZE(vmcs_field_to_evmcs_1); #if IS_ENABLED(CONFIG_HYPERV) __init void evmcs_sanitize_exec_ctrls(struct vmcs_config *vmcs_conf) { + vmcs_conf->cpu_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_EXEC_CTRL; vmcs_conf->pin_based_exec_ctrl &= ~EVMCS1_UNSUPPORTED_PINCTRL; vmcs_conf->cpu_based_2nd_exec_ctrl &= ~EVMCS1_UNSUPPORTED_2NDEXEC; + vmcs_conf->cpu_based_3rd_exec_ctrl = 0; vmcs_conf->vmexit_ctrl &= ~EVMCS1_UNSUPPORTED_VMEXIT_CTRL; vmcs_conf->vmentry_ctrl &= ~EVMCS1_UNSUPPORTED_VMENTRY_CTRL; diff --git a/arch/x86/kvm/vmx/evmcs.h b/arch/x86/kvm/vmx/evmcs.h index 8d70f9aea94b..f886a8ff0342 100644 --- a/arch/x86/kvm/vmx/evmcs.h +++ b/arch/x86/kvm/vmx/evmcs.h @@ -50,6 +50,7 @@ DECLARE_STATIC_KEY_FALSE(enable_evmcs); */ #define EVMCS1_UNSUPPORTED_PINCTRL (PIN_BASED_POSTED_INTR | \ PIN_BASED_VMX_PREEMPTION_TIMER) +#define EVMCS1_UNSUPPORTED_EXEC_CTRL (CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) #define EVMCS1_UNSUPPORTED_2NDEXEC \ (SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | \ SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | \ diff --git a/arch/x86/kvm/vmx/vmcs.h b/arch/x86/kvm/vmx/vmcs.h index 2b9d7a7e83f7..ac290a44a693 100644 --- a/arch/x86/kvm/vmx/vmcs.h +++ b/arch/x86/kvm/vmx/vmcs.h @@ -50,6 +50,7 @@ struct vmcs_controls_shadow { u32 pin; u32 exec; u32 secondary_exec; + u64 tertiary_exec; }; /* diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 9714ae95589f..9d3d41b21059 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2412,6 +2412,15 @@ static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, return 0; } +static __init u64 adjust_vmx_controls64(u64 ctl_opt, u32 msr) +{ + u64 allowed; + + rdmsrl(msr, allowed); + + return ctl_opt & allowed; +} + static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, struct vmx_capability *vmx_cap) { @@ -2420,6 +2429,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, u32 _pin_based_exec_control = 0; u32 _cpu_based_exec_control = 0; u32 _cpu_based_2nd_exec_control = 0; + u64 _cpu_based_3rd_exec_control = 0; u32 _vmexit_control = 0; u32 _vmentry_control = 0; @@ -2441,7 +2451,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, opt = CPU_BASED_TPR_SHADOW | CPU_BASED_USE_MSR_BITMAPS | - CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS | + CPU_BASED_ACTIVATE_TERTIARY_CONTROLS; if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, &_cpu_based_exec_control) < 0) return -EIO; @@ -2515,6 +2526,13 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, "1-setting enable VPID VM-execution control\n"); } + if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) { + u64 opt3 = 0; + + _cpu_based_3rd_exec_control = adjust_vmx_controls64(opt3, + MSR_IA32_VMX_PROCBASED_CTLS3); + } + min = VM_EXIT_SAVE_DEBUG_CONTROLS | VM_EXIT_ACK_INTR_ON_EXIT; #ifdef CONFIG_X86_64 min |= VM_EXIT_HOST_ADDR_SPACE_SIZE; @@ -2601,6 +2619,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control; vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control; vmcs_conf->cpu_based_2nd_exec_ctrl = _cpu_based_2nd_exec_control; + vmcs_conf->cpu_based_3rd_exec_ctrl = _cpu_based_3rd_exec_control; vmcs_conf->vmexit_ctrl = _vmexit_control; vmcs_conf->vmentry_ctrl = _vmentry_control; @@ -4222,6 +4241,11 @@ static u32 vmx_exec_control(struct vcpu_vmx *vmx) return exec_control; } +static u64 vmx_tertiary_exec_control(struct vcpu_vmx *vmx) +{ + return vmcs_config.cpu_based_3rd_exec_ctrl; +} + /* * Adjust a single secondary execution control bit to intercept/allow an * instruction in the guest. This is usually done based on whether or not a @@ -4387,6 +4411,9 @@ static void init_vmcs(struct vcpu_vmx *vmx) if (cpu_has_secondary_exec_ctrls()) secondary_exec_controls_set(vmx, vmx_secondary_exec_control(vmx)); + if (cpu_has_tertiary_exec_ctrls()) + tertiary_exec_controls_set(vmx, vmx_tertiary_exec_control(vmx)); + if (enable_apicv && lapic_in_kernel(&vmx->vcpu)) { vmcs_write64(EOI_EXIT_BITMAP0, 0); vmcs_write64(EOI_EXIT_BITMAP1, 0); diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 56be4cd4edaf..c37befcea2c0 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -485,6 +485,7 @@ BUILD_CONTROLS_SHADOW(vm_exit, VM_EXIT_CONTROLS, 32) BUILD_CONTROLS_SHADOW(pin, PIN_BASED_VM_EXEC_CONTROL, 32) BUILD_CONTROLS_SHADOW(exec, CPU_BASED_VM_EXEC_CONTROL, 32) BUILD_CONTROLS_SHADOW(secondary_exec, SECONDARY_VM_EXEC_CONTROL, 32) +BUILD_CONTROLS_SHADOW(tertiary_exec, TERTIARY_VM_EXEC_CONTROL, 64) /* * VMX_REGS_LAZY_LOAD_SET - The set of registers that will be updated in the From 0b85baa5f46de1c6ad6e4b987905df041f2f80f0 Mon Sep 17 00:00:00 2001 From: Robert Hoo Date: Tue, 19 Apr 2022 23:34:41 +0800 Subject: [PATCH 0124/1436] KVM: VMX: Report tertiary_exec_control field in dump_vmcs() Add tertiary_exec_control field report in dump_vmcs(). Meanwhile, reorganize the dump output of VMCS category as follows. Before change: *** Control State *** PinBased=0x000000ff CPUBased=0xb5a26dfa SecondaryExec=0x061037eb EntryControls=0000d1ff ExitControls=002befff After change: *** Control State *** CPUBased=0xb5a26dfa SecondaryExec=0x061037eb TertiaryExec=0x0000000000000010 PinBased=0x000000ff EntryControls=0000d1ff ExitControls=002befff Reviewed-by: Maxim Levitsky Signed-off-by: Robert Hoo Signed-off-by: Zeng Guang Message-Id: <20220419153441.11687-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 9d3d41b21059..4238a55c26e6 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -5872,6 +5872,7 @@ void dump_vmcs(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); u32 vmentry_ctl, vmexit_ctl; u32 cpu_based_exec_ctrl, pin_based_exec_ctrl, secondary_exec_control; + u64 tertiary_exec_control; unsigned long cr4; int efer_slot; @@ -5885,9 +5886,16 @@ void dump_vmcs(struct kvm_vcpu *vcpu) cpu_based_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL); pin_based_exec_ctrl = vmcs_read32(PIN_BASED_VM_EXEC_CONTROL); cr4 = vmcs_readl(GUEST_CR4); - secondary_exec_control = 0; + if (cpu_has_secondary_exec_ctrls()) secondary_exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL); + else + secondary_exec_control = 0; + + if (cpu_has_tertiary_exec_ctrls()) + tertiary_exec_control = vmcs_read64(TERTIARY_VM_EXEC_CONTROL); + else + tertiary_exec_control = 0; pr_err("VMCS %p, last attempted VM-entry on CPU %d\n", vmx->loaded_vmcs->vmcs, vcpu->arch.last_vmentry_cpu); @@ -5987,9 +5995,10 @@ void dump_vmcs(struct kvm_vcpu *vcpu) vmx_dump_msrs("host autoload", &vmx->msr_autoload.host); pr_err("*** Control State ***\n"); - pr_err("PinBased=%08x CPUBased=%08x SecondaryExec=%08x\n", - pin_based_exec_ctrl, cpu_based_exec_ctrl, secondary_exec_control); - pr_err("EntryControls=%08x ExitControls=%08x\n", vmentry_ctl, vmexit_ctl); + pr_err("CPUBased=0x%08x SecondaryExec=0x%08x TertiaryExec=0x%016llx\n", + cpu_based_exec_ctrl, secondary_exec_control, tertiary_exec_control); + pr_err("PinBased=0x%08x EntryControls=%08x ExitControls=%08x\n", + pin_based_exec_ctrl, vmentry_ctl, vmexit_ctl); pr_err("ExceptionBitmap=%08x PFECmask=%08x PFECmatch=%08x\n", vmcs_read32(EXCEPTION_BITMAP), vmcs_read32(PAGE_FAULT_ERROR_CODE_MASK), From 5413bcba7ed57206178d60ee03dd5bb3a460e645 Mon Sep 17 00:00:00 2001 From: Zeng Guang Date: Tue, 19 Apr 2022 23:35:16 +0800 Subject: [PATCH 0125/1436] KVM: x86: Add support for vICR APIC-write VM-Exits in x2APIC mode Upcoming Intel CPUs will support virtual x2APIC MSR writes to the vICR, i.e. will trap and generate an APIC-write VM-Exit instead of intercepting the WRMSR. Add support for handling "nodecode" x2APIC writes, which were previously impossible. Note, x2APIC MSR writes are 64 bits wide. Signed-off-by: Zeng Guang Message-Id: <20220419153516.11739-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index f1bdac3f5aa8..39b805666a18 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -67,6 +67,7 @@ static bool lapic_timer_advance_dynamic __read_mostly; #define LAPIC_TIMER_ADVANCE_NS_MAX 5000 /* step-by-step approximation to mitigate fluctuation */ #define LAPIC_TIMER_ADVANCE_ADJUST_STEP 8 +static int kvm_lapic_msr_read(struct kvm_lapic *apic, u32 reg, u64 *data); static inline void __kvm_lapic_set_reg(char *regs, int reg_off, u32 val) { @@ -2231,10 +2232,27 @@ EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi); /* emulate APIC access in a trap manner */ void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset) { - u32 val = kvm_lapic_get_reg(vcpu->arch.apic, offset); + struct kvm_lapic *apic = vcpu->arch.apic; + u64 val; - /* TODO: optimize to just emulate side effect w/o one more write */ - kvm_lapic_reg_write(vcpu->arch.apic, offset, val); + if (apic_x2apic_mode(apic)) { + /* + * When guest APIC is in x2APIC mode and IPI virtualization + * is enabled, accessing APIC_ICR may cause trap-like VM-exit + * on Intel hardware. Other offsets are not possible. + */ + if (WARN_ON_ONCE(offset != APIC_ICR)) + return; + + kvm_lapic_msr_read(apic, offset, &val); + kvm_apic_send_ipi(apic, (u32)val, (u32)(val >> 32)); + trace_kvm_apic_write(APIC_ICR, val); + } else { + val = kvm_lapic_get_reg(apic, offset); + + /* TODO: optimize to just emulate side effect w/o one more write */ + kvm_lapic_reg_write(apic, offset, (u32)val); + } } EXPORT_SYMBOL_GPL(kvm_apic_write_nodecode); From f08a06c9a35706349f74b7a18deefe3f89f73e8e Mon Sep 17 00:00:00 2001 From: Zeng Guang Date: Tue, 19 Apr 2022 23:36:04 +0800 Subject: [PATCH 0126/1436] KVM: VMX: Clean up vmx_refresh_apicv_exec_ctrl() Remove the condition check cpu_has_secondary_exec_ctrls(). Calling vmx_refresh_apicv_exec_ctrl() premises secondary controls activated and VMCS fields related to APICv valid as well. If it's invoked in wrong circumstance at the worst case, VMX operation will report VMfailValid error without further harmful impact and just functions as if all the secondary controls were 0. Suggested-by: Sean Christopherson Signed-off-by: Zeng Guang Message-Id: <20220419153604.11786-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 4238a55c26e6..3cbe3a38b356 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4201,16 +4201,15 @@ static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) } pin_controls_set(vmx, vmx_pin_based_exec_ctrl(vmx)); - if (cpu_has_secondary_exec_ctrls()) { - if (kvm_vcpu_apicv_active(vcpu)) - secondary_exec_controls_setbit(vmx, - SECONDARY_EXEC_APIC_REGISTER_VIRT | - SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); - else - secondary_exec_controls_clearbit(vmx, - SECONDARY_EXEC_APIC_REGISTER_VIRT | - SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); - } + + if (kvm_vcpu_apicv_active(vcpu)) + secondary_exec_controls_setbit(vmx, + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); + else + secondary_exec_controls_clearbit(vmx, + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); vmx_update_msr_bitmap_x2apic(vcpu); } From 1d5e740d518e02cea46325b3d37135bf9c08982a Mon Sep 17 00:00:00 2001 From: Zeng Guang Date: Tue, 19 Apr 2022 23:44:09 +0800 Subject: [PATCH 0127/1436] KVM: Move kvm_arch_vcpu_precreate() under kvm->lock kvm_arch_vcpu_precreate() targets to handle arch specific VM resource to be prepared prior to the actual creation of vCPU. For example, x86 platform may need do per-VM allocation based on max_vcpu_ids at the first vCPU creation. It probably leads to concurrency control on this allocation as multiple vCPU creation could happen simultaneously. From the architectual point of view, it's necessary to execute kvm_arch_vcpu_precreate() under protect of kvm->lock. Currently only arm64, x86 and s390 have non-nop implementations at the stage of vCPU pre-creation. Remove the lock acquiring in s390's design and make sure all architecture can run kvm_arch_vcpu_precreate() safely under kvm->lock without recrusive lock issue. Suggested-by: Sean Christopherson Signed-off-by: Zeng Guang Message-Id: <20220419154409.11842-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- arch/s390/kvm/kvm-s390.c | 2 -- arch/x86/kvm/x86.c | 2 +- virt/kvm/kvm_main.c | 10 ++++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index ff457a77e22b..72bd5c9b9617 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -3238,9 +3238,7 @@ static int sca_can_add_vcpu(struct kvm *kvm, unsigned int id) if (!sclp.has_esca || !sclp.has_64bscao) return false; - mutex_lock(&kvm->lock); rc = kvm->arch.use_esca ? 0 : sca_switch_to_extended(kvm); - mutex_unlock(&kvm->lock); return rc == 0 && id < KVM_S390_ESCA_CPU_SLOTS; } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 501606e02688..9c2e2b6d1767 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -11242,7 +11242,7 @@ static int sync_regs(struct kvm_vcpu *vcpu) int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) { - if (kvm_check_tsc_unstable() && atomic_read(&kvm->online_vcpus) != 0) + if (kvm_check_tsc_unstable() && kvm->created_vcpus) pr_warn_once("kvm: SMP vm created on host with unstable TSC; " "guest TSC will not be reliable\n"); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 7f79abdbd68d..6dbdcbda0291 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -3768,13 +3768,15 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id) return -EINVAL; } + r = kvm_arch_vcpu_precreate(kvm, id); + if (r) { + mutex_unlock(&kvm->lock); + return r; + } + kvm->created_vcpus++; mutex_unlock(&kvm->lock); - r = kvm_arch_vcpu_precreate(kvm, id); - if (r) - goto vcpu_decrement; - vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL_ACCOUNT); if (!vcpu) { r = -ENOMEM; From 35875316384b71d23dc2a45a969732fc8cab16af Mon Sep 17 00:00:00 2001 From: Zeng Guang Date: Tue, 19 Apr 2022 23:44:44 +0800 Subject: [PATCH 0128/1436] KVM: x86: Allow userspace to set maximum VCPU id for VM Introduce new max_vcpu_ids in KVM for x86 architecture. Userspace can assign maximum possible vcpu id for current VM session using KVM_CAP_MAX_VCPU_ID of KVM_ENABLE_CAP ioctl(). This is done for x86 only because the sole use case is to guide memory allocation for PID-pointer table, a structure needed to enable VMX IPI. By default, max_vcpu_ids set as KVM_MAX_VCPU_IDS. Suggested-by: Sean Christopherson Reviewed-by: Maxim Levitsky Signed-off-by: Zeng Guang Message-Id: <20220419154444.11888-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 21 +++++++++++++++++++++ arch/x86/include/asm/kvm_host.h | 6 ++++++ arch/x86/kvm/x86.c | 20 ++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 94d73ec52aba..421479a67da5 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -7494,6 +7494,27 @@ The valid bits in cap.args[0] are: generate a #UD within the guest. =================================== ============================================ +7.32 KVM_CAP_MAX_VCPU_ID +------------------------ + +:Architectures: x86 +:Target: VM +:Parameters: args[0] - maximum APIC ID value set for current VM +:Returns: 0 on success, -EINVAL if args[0] is beyond KVM_MAX_VCPU_IDS + supported in KVM or if it has been set. + +This capability allows userspace to specify maximum possible APIC ID +assigned for current VM session prior to the creation of vCPUs, saving +memory for data structures indexed by the APIC ID. Userspace is able +to calculate the limit to APIC ID values from designated +CPU topology. + +The value can be changed only until KVM_ENABLE_CAP is set to a nonzero +value or until a vCPU is created. Upon creation of the first vCPU, +if the value was set to zero or KVM_ENABLE_CAP was not invoked, KVM +uses the return value of KVM_CHECK_EXTENSION(KVM_CAP_MAX_VCPU_ID) as +the maximum APIC ID. + 8. Other capabilities. ====================== diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 8109805b5429..9dc8d6d0a67d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1243,6 +1243,12 @@ struct kvm_arch { hpa_t hv_root_tdp; spinlock_t hv_root_tdp_lock; #endif + /* + * VM-scope maximum vCPU ID. Used to determine the size of structures + * that increase along with the maximum vCPU ID, in which case, using + * the global KVM_MAX_VCPU_IDS may lead to significant memory waste. + */ + u32 max_vcpu_ids; }; struct kvm_vm_stat { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 9c2e2b6d1767..25fbb90c7c93 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6087,6 +6087,20 @@ split_irqchip_unlock: } mutex_unlock(&kvm->lock); break; + case KVM_CAP_MAX_VCPU_ID: + r = -EINVAL; + if (cap->args[0] > KVM_MAX_VCPU_IDS) + break; + + mutex_lock(&kvm->lock); + if (kvm->arch.max_vcpu_ids == cap->args[0]) { + r = 0; + } else if (!kvm->arch.max_vcpu_ids) { + kvm->arch.max_vcpu_ids = cap->args[0]; + r = 0; + } + mutex_unlock(&kvm->lock); + break; default: r = -EINVAL; break; @@ -11246,6 +11260,12 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) pr_warn_once("kvm: SMP vm created on host with unstable TSC; " "guest TSC will not be reliable\n"); + if (!kvm->arch.max_vcpu_ids) + kvm->arch.max_vcpu_ids = KVM_MAX_VCPU_IDS; + + if (id >= kvm->arch.max_vcpu_ids) + return -EINVAL; + return 0; } From 753dcf7a8686a750fa6aa4b4ca42c6945fc75ac1 Mon Sep 17 00:00:00 2001 From: Zeng Guang Date: Fri, 22 Apr 2022 21:44:56 +0800 Subject: [PATCH 0129/1436] kvm: selftests: Add KVM_CAP_MAX_VCPU_ID cap test Basic test coverage of KVM_CAP_MAX_VCPU_ID cap. This capability can be enabled before vCPU creation and only allowed to set once. if assigned vcpu id is beyond KVM_CAP_MAX_VCPU_ID capability, vCPU creation will fail. Signed-off-by: Zeng Guang Message-Id: <20220422134456.26655-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../kvm/x86_64/max_vcpuid_cap_test.c | 54 +++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 82e764d71ca7..90a6dea2e84c 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -25,6 +25,7 @@ /x86_64/hyperv_cpuid /x86_64/hyperv_features /x86_64/hyperv_svm_test +/x86_64/max_vcpuid_cap_test /x86_64/mmio_warning_test /x86_64/mmu_role_test /x86_64/platform_info_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index f2647b88a8a0..a014368a2cd2 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -89,6 +89,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/xen_shinfo_test TEST_GEN_PROGS_x86_64 += x86_64/xen_vmcall_test TEST_GEN_PROGS_x86_64 += x86_64/sev_migrate_tests TEST_GEN_PROGS_x86_64 += x86_64/amx_test +TEST_GEN_PROGS_x86_64 += x86_64/max_vcpuid_cap_test TEST_GEN_PROGS_x86_64 += access_tracking_perf_test TEST_GEN_PROGS_x86_64 += demand_paging_test TEST_GEN_PROGS_x86_64 += dirty_log_test diff --git a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c new file mode 100644 index 000000000000..3f6c1ad86cc6 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * maximum APIC ID capability tests + * + * Copyright (C) 2022, Intel, Inc. + * + * Tests for getting/setting maximum APIC ID capability + */ + +#include "kvm_util.h" +#include "../lib/kvm_util_internal.h" + +#define MAX_VCPU_ID 2 + +int main(int argc, char *argv[]) +{ + struct kvm_vm *vm; + struct kvm_enable_cap cap = { 0 }; + int ret; + + vm = vm_create(VM_MODE_DEFAULT, 0, O_RDWR); + + /* Get KVM_CAP_MAX_VCPU_ID cap supported in KVM */ + ret = vm_check_cap(vm, KVM_CAP_MAX_VCPU_ID); + + /* Try to set KVM_CAP_MAX_VCPU_ID beyond KVM cap */ + cap.cap = KVM_CAP_MAX_VCPU_ID; + cap.args[0] = ret + 1; + ret = ioctl(vm->fd, KVM_ENABLE_CAP, &cap); + TEST_ASSERT(ret < 0, + "Unexpected success to enable KVM_CAP_MAX_VCPU_ID" + "beyond KVM cap!\n"); + + /* Set KVM_CAP_MAX_VCPU_ID */ + cap.cap = KVM_CAP_MAX_VCPU_ID; + cap.args[0] = MAX_VCPU_ID; + ret = ioctl(vm->fd, KVM_ENABLE_CAP, &cap); + TEST_ASSERT(ret == 0, + "Unexpected failure to enable KVM_CAP_MAX_VCPU_ID!\n"); + + /* Try to set KVM_CAP_MAX_VCPU_ID again */ + cap.args[0] = MAX_VCPU_ID + 1; + ret = ioctl(vm->fd, KVM_ENABLE_CAP, &cap); + TEST_ASSERT(ret < 0, + "Unexpected success to enable KVM_CAP_MAX_VCPU_ID again\n"); + + /* Create vCPU with id beyond KVM_CAP_MAX_VCPU_ID cap*/ + ret = ioctl(vm->fd, KVM_CREATE_VCPU, MAX_VCPU_ID); + TEST_ASSERT(ret < 0, + "Unexpected success in creating a vCPU with VCPU ID out of range\n"); + + kvm_vm_free(vm); + return 0; +} From d588bb9be1da6aa750aa64875fe57369db983d8b Mon Sep 17 00:00:00 2001 From: Chao Gao Date: Tue, 19 Apr 2022 23:45:10 +0800 Subject: [PATCH 0130/1436] KVM: VMX: enable IPI virtualization With IPI virtualization enabled, the processor emulates writes to APIC registers that would send IPIs. The processor sets the bit corresponding to the vector in target vCPU's PIR and may send a notification (IPI) specified by NDST and NV fields in target vCPU's Posted-Interrupt Descriptor (PID). It is similar to what IOMMU engine does when dealing with posted interrupt from devices. A PID-pointer table is used by the processor to locate the PID of a vCPU with the vCPU's APIC ID. The table size depends on maximum APIC ID assigned for current VM session from userspace. Allocating memory for PID-pointer table is deferred to vCPU creation, because irqchip mode and VM-scope maximum APIC ID is settled at that point. KVM can skip PID-pointer table allocation if !irqchip_in_kernel(). Like VT-d PI, if a vCPU goes to blocked state, VMM needs to switch its notification vector to wakeup vector. This can ensure that when an IPI for blocked vCPUs arrives, VMM can get control and wake up blocked vCPUs. And if a VCPU is preempted, its posted interrupt notification is suppressed. Note that IPI virtualization can only virualize physical-addressing, flat mode, unicast IPIs. Sending other IPIs would still cause a trap-like APIC-write VM-exit and need to be handled by VMM. Signed-off-by: Chao Gao Signed-off-by: Zeng Guang Message-Id: <20220419154510.11938-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm-x86-ops.h | 1 + arch/x86/include/asm/kvm_host.h | 1 + arch/x86/include/asm/vmx.h | 8 +++ arch/x86/include/asm/vmxfeatures.h | 2 + arch/x86/kvm/vmx/capabilities.h | 6 +++ arch/x86/kvm/vmx/posted_intr.c | 15 +++++- arch/x86/kvm/vmx/posted_intr.h | 2 + arch/x86/kvm/vmx/vmx.c | 82 ++++++++++++++++++++++++++++-- arch/x86/kvm/vmx/vmx.h | 7 +++ arch/x86/kvm/x86.c | 2 +- 10 files changed, 119 insertions(+), 7 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index da47f60a4650..6f2f1affbb78 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -21,6 +21,7 @@ KVM_X86_OP(has_emulated_msr) KVM_X86_OP(vcpu_after_set_cpuid) KVM_X86_OP(vm_init) KVM_X86_OP_OPTIONAL(vm_destroy) +KVM_X86_OP_OPTIONAL_RET0(vcpu_precreate) KVM_X86_OP(vcpu_create) KVM_X86_OP(vcpu_free) KVM_X86_OP(vcpu_reset) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 9dc8d6d0a67d..8118c52e3fec 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1347,6 +1347,7 @@ struct kvm_x86_ops { void (*vm_destroy)(struct kvm *kvm); /* Create, but do not attach this VCPU */ + int (*vcpu_precreate)(struct kvm *kvm); int (*vcpu_create)(struct kvm_vcpu *vcpu); void (*vcpu_free)(struct kvm_vcpu *vcpu); void (*vcpu_reset)(struct kvm_vcpu *vcpu, bool init_event); diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 34ca428fefed..89d2172787c5 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -76,6 +76,11 @@ #define SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE VMCS_CONTROL_BIT(USR_WAIT_PAUSE) #define SECONDARY_EXEC_BUS_LOCK_DETECTION VMCS_CONTROL_BIT(BUS_LOCK_DETECTION) +/* + * Definitions of Tertiary Processor-Based VM-Execution Controls. + */ +#define TERTIARY_EXEC_IPI_VIRT VMCS_CONTROL_BIT(IPI_VIRT) + #define PIN_BASED_EXT_INTR_MASK VMCS_CONTROL_BIT(INTR_EXITING) #define PIN_BASED_NMI_EXITING VMCS_CONTROL_BIT(NMI_EXITING) #define PIN_BASED_VIRTUAL_NMIS VMCS_CONTROL_BIT(VIRTUAL_NMIS) @@ -159,6 +164,7 @@ static inline int vmx_misc_mseg_revid(u64 vmx_misc) enum vmcs_field { VIRTUAL_PROCESSOR_ID = 0x00000000, POSTED_INTR_NV = 0x00000002, + LAST_PID_POINTER_INDEX = 0x00000008, GUEST_ES_SELECTOR = 0x00000800, GUEST_CS_SELECTOR = 0x00000802, GUEST_SS_SELECTOR = 0x00000804, @@ -224,6 +230,8 @@ enum vmcs_field { TSC_MULTIPLIER_HIGH = 0x00002033, TERTIARY_VM_EXEC_CONTROL = 0x00002034, TERTIARY_VM_EXEC_CONTROL_HIGH = 0x00002035, + PID_POINTER_TABLE = 0x00002042, + PID_POINTER_TABLE_HIGH = 0x00002043, GUEST_PHYSICAL_ADDRESS = 0x00002400, GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401, VMCS_LINK_POINTER = 0x00002800, diff --git a/arch/x86/include/asm/vmxfeatures.h b/arch/x86/include/asm/vmxfeatures.h index ff20776dc83b..589608c157bf 100644 --- a/arch/x86/include/asm/vmxfeatures.h +++ b/arch/x86/include/asm/vmxfeatures.h @@ -86,4 +86,6 @@ #define VMX_FEATURE_ENCLV_EXITING ( 2*32+ 28) /* "" VM-Exit on ENCLV (leaf dependent) */ #define VMX_FEATURE_BUS_LOCK_DETECTION ( 2*32+ 30) /* "" VM-Exit when bus lock caused */ +/* Tertiary Processor-Based VM-Execution Controls, word 3 */ +#define VMX_FEATURE_IPI_VIRT ( 3*32+ 4) /* Enable IPI virtualization */ #endif /* _ASM_X86_VMXFEATURES_H */ diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h index 31f3d88b3e4d..5f656c9e33be 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -13,6 +13,7 @@ extern bool __read_mostly enable_ept; extern bool __read_mostly enable_unrestricted_guest; extern bool __read_mostly enable_ept_ad_bits; extern bool __read_mostly enable_pml; +extern bool __read_mostly enable_ipiv; extern int __read_mostly pt_mode; #define PT_MODE_SYSTEM 0 @@ -283,6 +284,11 @@ static inline bool cpu_has_vmx_apicv(void) cpu_has_vmx_posted_intr(); } +static inline bool cpu_has_vmx_ipiv(void) +{ + return vmcs_config.cpu_based_3rd_exec_ctrl & TERTIARY_EXEC_IPI_VIRT; +} + static inline bool cpu_has_vmx_flexpriority(void) { return cpu_has_vmx_tpr_shadow() && diff --git a/arch/x86/kvm/vmx/posted_intr.c b/arch/x86/kvm/vmx/posted_intr.c index 07e5fcf5a5aa..237a1f40f939 100644 --- a/arch/x86/kvm/vmx/posted_intr.c +++ b/arch/x86/kvm/vmx/posted_intr.c @@ -177,11 +177,24 @@ static void pi_enable_wakeup_handler(struct kvm_vcpu *vcpu) local_irq_restore(flags); } +static bool vmx_needs_pi_wakeup(struct kvm_vcpu *vcpu) +{ + /* + * The default posted interrupt vector does nothing when + * invoked outside guest mode. Return whether a blocked vCPU + * can be the target of posted interrupts, as is the case when + * using either IPI virtualization or VT-d PI, so that the + * notification vector is switched to the one that calls + * back to the pi_wakeup_handler() function. + */ + return vmx_can_use_ipiv(vcpu) || vmx_can_use_vtd_pi(vcpu->kvm); +} + void vmx_vcpu_pi_put(struct kvm_vcpu *vcpu) { struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); - if (!vmx_can_use_vtd_pi(vcpu->kvm)) + if (!vmx_needs_pi_wakeup(vcpu)) return; if (kvm_vcpu_is_blocking(vcpu) && !vmx_interrupt_blocked(vcpu)) diff --git a/arch/x86/kvm/vmx/posted_intr.h b/arch/x86/kvm/vmx/posted_intr.h index 9a45d5c9f116..26992076552e 100644 --- a/arch/x86/kvm/vmx/posted_intr.h +++ b/arch/x86/kvm/vmx/posted_intr.h @@ -5,6 +5,8 @@ #define POSTED_INTR_ON 0 #define POSTED_INTR_SN 1 +#define PID_TABLE_ENTRY_VALID 1 + /* Posted-Interrupt Descriptor */ struct pi_desc { u32 pir[8]; /* Posted interrupt requested */ diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 3cbe3a38b356..f3175dae25aa 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -105,6 +105,9 @@ module_param(fasteoi, bool, S_IRUGO); module_param(enable_apicv, bool, S_IRUGO); +bool __read_mostly enable_ipiv = true; +module_param(enable_ipiv, bool, 0444); + /* * If nested=1, nested virtualization is supported, i.e., guests may use * VMX and be a hypervisor for its own guests. If nested=0, guests may not @@ -2527,7 +2530,7 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, } if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) { - u64 opt3 = 0; + u64 opt3 = TERTIARY_EXEC_IPI_VIRT; _cpu_based_3rd_exec_control = adjust_vmx_controls64(opt3, MSR_IA32_VMX_PROCBASED_CTLS3); @@ -3874,6 +3877,8 @@ static void vmx_update_msr_bitmap_x2apic(struct kvm_vcpu *vcpu) vmx_enable_intercept_for_msr(vcpu, X2APIC_MSR(APIC_TMCCT), MSR_TYPE_RW); vmx_disable_intercept_for_msr(vcpu, X2APIC_MSR(APIC_EOI), MSR_TYPE_W); vmx_disable_intercept_for_msr(vcpu, X2APIC_MSR(APIC_SELF_IPI), MSR_TYPE_W); + if (enable_ipiv) + vmx_disable_intercept_for_msr(vcpu, X2APIC_MSR(APIC_ICR), MSR_TYPE_RW); } } @@ -4202,14 +4207,19 @@ static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) pin_controls_set(vmx, vmx_pin_based_exec_ctrl(vmx)); - if (kvm_vcpu_apicv_active(vcpu)) + if (kvm_vcpu_apicv_active(vcpu)) { secondary_exec_controls_setbit(vmx, SECONDARY_EXEC_APIC_REGISTER_VIRT | SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); - else + if (enable_ipiv) + tertiary_exec_controls_setbit(vmx, TERTIARY_EXEC_IPI_VIRT); + } else { secondary_exec_controls_clearbit(vmx, SECONDARY_EXEC_APIC_REGISTER_VIRT | SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); + if (enable_ipiv) + tertiary_exec_controls_clearbit(vmx, TERTIARY_EXEC_IPI_VIRT); + } vmx_update_msr_bitmap_x2apic(vcpu); } @@ -4242,7 +4252,16 @@ static u32 vmx_exec_control(struct vcpu_vmx *vmx) static u64 vmx_tertiary_exec_control(struct vcpu_vmx *vmx) { - return vmcs_config.cpu_based_3rd_exec_ctrl; + u64 exec_control = vmcs_config.cpu_based_3rd_exec_ctrl; + + /* + * IPI virtualization relies on APICv. Disable IPI virtualization if + * APICv is inhibited. + */ + if (!enable_ipiv || !kvm_vcpu_apicv_active(&vmx->vcpu)) + exec_control &= ~TERTIARY_EXEC_IPI_VIRT; + + return exec_control; } /* @@ -4390,10 +4409,42 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx) return exec_control; } +static inline int vmx_get_pid_table_order(struct kvm *kvm) +{ + return get_order(kvm->arch.max_vcpu_ids * sizeof(*to_kvm_vmx(kvm)->pid_table)); +} + +static int vmx_alloc_ipiv_pid_table(struct kvm *kvm) +{ + struct page *pages; + struct kvm_vmx *kvm_vmx = to_kvm_vmx(kvm); + + if (!irqchip_in_kernel(kvm) || !enable_ipiv) + return 0; + + if (kvm_vmx->pid_table) + return 0; + + pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, vmx_get_pid_table_order(kvm)); + if (!pages) + return -ENOMEM; + + kvm_vmx->pid_table = (void *)page_address(pages); + return 0; +} + +static int vmx_vcpu_precreate(struct kvm *kvm) +{ + return vmx_alloc_ipiv_pid_table(kvm); +} + #define VMX_XSS_EXIT_BITMAP 0 static void init_vmcs(struct vcpu_vmx *vmx) { + struct kvm *kvm = vmx->vcpu.kvm; + struct kvm_vmx *kvm_vmx = to_kvm_vmx(kvm); + if (nested) nested_vmx_set_vmcs_shadowing_bitmap(); @@ -4425,7 +4476,12 @@ static void init_vmcs(struct vcpu_vmx *vmx) vmcs_write64(POSTED_INTR_DESC_ADDR, __pa((&vmx->pi_desc))); } - if (!kvm_pause_in_guest(vmx->vcpu.kvm)) { + if (vmx_can_use_ipiv(&vmx->vcpu)) { + vmcs_write64(PID_POINTER_TABLE, __pa(kvm_vmx->pid_table)); + vmcs_write16(LAST_PID_POINTER_INDEX, kvm->arch.max_vcpu_ids - 1); + } + + if (!kvm_pause_in_guest(kvm)) { vmcs_write32(PLE_GAP, ple_gap); vmx->ple_window = ple_window; vmx->ple_window_dirty = true; @@ -7116,6 +7172,10 @@ static int vmx_vcpu_create(struct kvm_vcpu *vcpu) goto free_vmcs; } + if (vmx_can_use_ipiv(vcpu)) + WRITE_ONCE(to_kvm_vmx(vcpu->kvm)->pid_table[vcpu->vcpu_id], + __pa(&vmx->pi_desc) | PID_TABLE_ENTRY_VALID); + return 0; free_vmcs: @@ -7750,6 +7810,13 @@ static bool vmx_check_apicv_inhibit_reasons(enum kvm_apicv_inhibit reason) return supported & BIT(reason); } +static void vmx_vm_destroy(struct kvm *kvm) +{ + struct kvm_vmx *kvm_vmx = to_kvm_vmx(kvm); + + free_pages((unsigned long)kvm_vmx->pid_table, vmx_get_pid_table_order(kvm)); +} + static struct kvm_x86_ops vmx_x86_ops __initdata = { .name = "kvm_intel", @@ -7761,7 +7828,9 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = { .vm_size = sizeof(struct kvm_vmx), .vm_init = vmx_vm_init, + .vm_destroy = vmx_vm_destroy, + .vcpu_precreate = vmx_vcpu_precreate, .vcpu_create = vmx_vcpu_create, .vcpu_free = vmx_vcpu_free, .vcpu_reset = vmx_vcpu_reset, @@ -8039,6 +8108,9 @@ static __init int hardware_setup(void) if (!enable_apicv) vmx_x86_ops.sync_pir_to_irr = NULL; + if (!enable_apicv || !cpu_has_vmx_ipiv()) + enable_ipiv = false; + if (cpu_has_vmx_tsc_scaling()) kvm_has_tsc_control = true; diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index c37befcea2c0..d7baedda79e5 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -366,6 +366,8 @@ struct kvm_vmx { unsigned int tss_addr; bool ept_identity_pagetable_done; gpa_t ept_identity_map_addr; + /* Posted Interrupt Descriptor (PID) table for IPI virtualization */ + u64 *pid_table; }; bool nested_vmx_allowed(struct kvm_vcpu *vcpu); @@ -581,4 +583,9 @@ static inline int vmx_get_instr_info_reg2(u32 vmx_instr_info) return (vmx_instr_info >> 28) & 0xf; } +static inline bool vmx_can_use_ipiv(struct kvm_vcpu *vcpu) +{ + return lapic_in_kernel(vcpu) && enable_ipiv; +} + #endif /* __KVM_X86_VMX_H */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 25fbb90c7c93..37fb301f52af 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -11266,7 +11266,7 @@ int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) if (id >= kvm->arch.max_vcpu_ids) return -EINVAL; - return 0; + return static_call(kvm_x86_vcpu_precreate)(kvm); } int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) From fb358e0b811eec233f6db86d591b3af99d23c8e3 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:30 +0800 Subject: [PATCH 0131/1436] perf/x86/intel: Add EPT-Friendly PEBS for Ice Lake Server Add support for EPT-Friendly PEBS, a new CPU feature that enlightens PEBS to translate guest linear address through EPT, and facilitates handling VM-Exits that occur when accessing PEBS records. More information can be found in the December 2021 release of Intel's SDM, Volume 3, 18.9.5 "EPT-Friendly PEBS". This new hardware facility makes sure the guest PEBS records will not be lost, which is available on Intel Ice Lake Server platforms (and later). KVM will check this field through perf_get_x86_pmu_capability() instead of hard coding the CPU models in the KVM code. If it is supported, the guest PEBS capability will be exposed to the guest. Guest PEBS can be enabled when and only when "EPT-Friendly PEBS" is supported and EPT is enabled. Cc: linux-perf-users@vger.kernel.org Signed-off-by: Like Xu Message-Id: <20220411101946.20262-2-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/core.c | 1 + arch/x86/events/intel/core.c | 1 + arch/x86/events/perf_event.h | 3 ++- arch/x86/include/asm/perf_event.h | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 30788894124f..a9ebd096dfb4 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -3002,5 +3002,6 @@ void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) cap->bit_width_fixed = x86_pmu.cntval_bits; cap->events_mask = (unsigned int)x86_pmu.events_maskl; cap->events_mask_len = x86_pmu.events_mask_len; + cap->pebs_ept = x86_pmu.pebs_ept; } EXPORT_SYMBOL_GPL(perf_get_x86_pmu_capability); diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 45024abd929f..96bb0ac7462b 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -6138,6 +6138,7 @@ __init int intel_pmu_init(void) case INTEL_FAM6_ICELAKE_X: case INTEL_FAM6_ICELAKE_D: + x86_pmu.pebs_ept = 1; pmem = true; fallthrough; case INTEL_FAM6_ICELAKE_L: diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 21a5482bcf84..4910dc41433b 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -818,7 +818,8 @@ struct x86_pmu { pebs_prec_dist :1, pebs_no_tlb :1, pebs_no_isolation :1, - pebs_block :1; + pebs_block :1, + pebs_ept :1; int pebs_record_size; int pebs_buffer_size; int max_pebs_events; diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 409725e86f42..f95ab4da6fea 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -206,6 +206,7 @@ struct x86_pmu_capability { int bit_width_fixed; unsigned int events_mask; int events_mask_len; + unsigned int pebs_ept :1; }; /* From 69e575dd4fba51dca9f25db7b2033d730699e7ff Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:31 +0800 Subject: [PATCH 0132/1436] perf/x86/intel: Handle guest PEBS overflow PMI for KVM guest With PEBS virtualization, the guest PEBS records get delivered to the guest DS, and the host pmi handler uses perf_guest_cbs->is_in_guest() to distinguish whether the PMI comes from the guest code like Intel PT. No matter how many guest PEBS counters are overflowed, only triggering one fake event is enough. The fake event causes the KVM PMI callback to be called, thereby injecting the PEBS overflow PMI into the guest. KVM may inject the PMI with BUFFER_OVF set, even if the guest DS is empty. That should really be harmless. Thus guest PEBS handler would retrieve the correct information from its own PEBS records buffer. Cc: linux-perf-users@vger.kernel.org Originally-by: Andi Kleen Co-developed-by: Kan Liang Signed-off-by: Kan Liang Signed-off-by: Like Xu Message-Id: <20220411101946.20262-3-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/intel/core.c | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 96bb0ac7462b..8e5036f32e84 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -2852,6 +2852,47 @@ static void intel_pmu_reset(void) local_irq_restore(flags); } +/* + * We may be running with guest PEBS events created by KVM, and the + * PEBS records are logged into the guest's DS and invisible to host. + * + * In the case of guest PEBS overflow, we only trigger a fake event + * to emulate the PEBS overflow PMI for guest PEBS counters in KVM. + * The guest will then vm-entry and check the guest DS area to read + * the guest PEBS records. + * + * The contents and other behavior of the guest event do not matter. + */ +static void x86_pmu_handle_guest_pebs(struct pt_regs *regs, + struct perf_sample_data *data) +{ + struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); + u64 guest_pebs_idxs = cpuc->pebs_enabled & ~cpuc->intel_ctrl_host_mask; + struct perf_event *event = NULL; + int bit; + + if (!unlikely(perf_guest_state())) + return; + + if (!x86_pmu.pebs_ept || !x86_pmu.pebs_active || + !guest_pebs_idxs) + return; + + for_each_set_bit(bit, (unsigned long *)&guest_pebs_idxs, + INTEL_PMC_IDX_FIXED + x86_pmu.num_counters_fixed) { + event = cpuc->events[bit]; + if (!event->attr.precise_ip) + continue; + + perf_sample_data_init(data, 0, event->hw.last_period); + if (perf_event_overflow(event, data, regs)) + x86_pmu_stop(event, 0); + + /* Inject one fake event is enough. */ + break; + } +} + static int handle_pmi_common(struct pt_regs *regs, u64 status) { struct perf_sample_data data; @@ -2903,6 +2944,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status) u64 pebs_enabled = cpuc->pebs_enabled; handled++; + x86_pmu_handle_guest_pebs(regs, &data); x86_pmu.drain_pebs(regs, &data); status &= intel_ctrl | GLOBAL_STATUS_TRACE_TOPAPMI; From 39a4d779546a993c53cea28e659e8edc9f868af0 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:32 +0800 Subject: [PATCH 0133/1436] perf/x86/core: Pass "struct kvm_pmu *" to determine the guest values Splitting the logic for determining the guest values is unnecessarily confusing, and potentially fragile. Perf should have full knowledge and control of what values are loaded for the guest. If we change .guest_get_msrs() to take a struct kvm_pmu pointer, then it can generate the full set of guest values by grabbing guest ds_area and pebs_data_cfg. Alternatively, .guest_get_msrs() could take the desired guest MSR values directly (ds_area and pebs_data_cfg), but kvm_pmu is vendor agnostic, so we don't see any reason to not just pass the pointer. Suggested-by: Sean Christopherson Signed-off-by: Like Xu Acked-by: Peter Zijlstra (Intel) Message-Id: <20220411101946.20262-4-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/core.c | 4 ++-- arch/x86/events/intel/core.c | 4 ++-- arch/x86/events/perf_event.h | 2 +- arch/x86/include/asm/perf_event.h | 4 ++-- arch/x86/kvm/vmx/vmx.c | 3 ++- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index a9ebd096dfb4..330825160b9a 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -693,9 +693,9 @@ void x86_pmu_disable_all(void) } } -struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr) +struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr, void *data) { - return static_call(x86_pmu_guest_get_msrs)(nr); + return static_call(x86_pmu_guest_get_msrs)(nr, data); } EXPORT_SYMBOL_GPL(perf_guest_get_msrs); diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 8e5036f32e84..b56ead52790a 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3972,7 +3972,7 @@ static int intel_pmu_hw_config(struct perf_event *event) return 0; } -static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr) +static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct perf_guest_switch_msr *arr = cpuc->guest_switch_msrs; @@ -4005,7 +4005,7 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr) return arr; } -static struct perf_guest_switch_msr *core_guest_get_msrs(int *nr) +static struct perf_guest_switch_msr *core_guest_get_msrs(int *nr, void *data) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct perf_guest_switch_msr *arr = cpuc->guest_switch_msrs; diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 4910dc41433b..07fdef4f9ad2 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -903,7 +903,7 @@ struct x86_pmu { /* * Intel host/guest support (KVM) */ - struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr); + struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr, void *data); /* * Check period value for PERF_EVENT_IOC_PERIOD ioctl. diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index f95ab4da6fea..58e2fcbb8bcc 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -519,10 +519,10 @@ static inline void perf_check_microcode(void) { } #endif #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL) -extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr); +extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr, void *data); extern int x86_perf_get_lbr(struct x86_pmu_lbr *lbr); #else -struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr); +struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr, void *data); static inline int x86_perf_get_lbr(struct x86_pmu_lbr *lbr) { return -1; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index f3175dae25aa..070b02162db6 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6794,9 +6794,10 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) { int i, nr_msrs; struct perf_guest_switch_msr *msrs; + struct kvm_pmu *pmu = vcpu_to_pmu(&vmx->vcpu); /* Note, nr_msrs may be garbage if perf_guest_get_msrs() returns NULL. */ - msrs = perf_guest_get_msrs(&nr_msrs); + msrs = perf_guest_get_msrs(&nr_msrs, (void *)pmu); if (!msrs) return; From bef6ecca46ac938ffb352d7fa2f6eafd1b6a41be Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:33 +0800 Subject: [PATCH 0134/1436] KVM: x86/pmu: Set MSR_IA32_MISC_ENABLE_EMON bit when vPMU is enabled On Intel platforms, the software can use the IA32_MISC_ENABLE[7] bit to detect whether the processor supports performance monitoring facility. It depends on the PMU is enabled for the guest, and a software write operation to this available bit will be ignored. The proposal to ignore the toggle in KVM is the way to go and that behavior matches bare metal. Signed-off-by: Like Xu Message-Id: <20220411101946.20262-5-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/pmu_intel.c | 1 + arch/x86/kvm/x86.c | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 37e9eb32e3d9..b7dd24476b52 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -498,6 +498,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) if (!pmu->version) return; + vcpu->arch.ia32_misc_enable_msr |= MSR_IA32_MISC_ENABLE_EMON; perf_get_x86_pmu_capability(&x86_pmu); pmu->nr_arch_gp_counters = min_t(int, eax.split.num_counters, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 37fb301f52af..68ec5cbeb665 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3558,9 +3558,19 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.ia32_tsc_adjust_msr = data; } break; - case MSR_IA32_MISC_ENABLE: + case MSR_IA32_MISC_ENABLE: { + u64 old_val = vcpu->arch.ia32_misc_enable_msr; + u64 pmu_mask = MSR_IA32_MISC_ENABLE_EMON; + + /* + * For a dummy user space, the order of setting vPMU capabilities and + * initialising MSR_IA32_MISC_ENABLE is not strictly guaranteed, so to + * avoid inconsistent functionality we keep the vPMU bits unchanged here. + */ + data &= ~pmu_mask; + data |= old_val & pmu_mask; if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT) && - ((vcpu->arch.ia32_misc_enable_msr ^ data) & MSR_IA32_MISC_ENABLE_MWAIT)) { + ((old_val ^ data) & MSR_IA32_MISC_ENABLE_MWAIT)) { if (!guest_cpuid_has(vcpu, X86_FEATURE_XMM3)) return 1; vcpu->arch.ia32_misc_enable_msr = data; @@ -3569,6 +3579,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.ia32_misc_enable_msr = data; } break; + } case MSR_IA32_SMBASE: if (!msr_info->host_initiated) return 1; From 2c985527dd8d283e786ad7a67e532ef7f6f00fac Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:34 +0800 Subject: [PATCH 0135/1436] KVM: x86/pmu: Introduce the ctrl_mask value for fixed counter The mask value of fixed counter control register should be dynamic adjusted with the number of fixed counters. This patch introduces a variable that includes the reserved bits of fixed counter control registers. This is a generic code refactoring. Co-developed-by: Luwei Kang Signed-off-by: Luwei Kang Signed-off-by: Like Xu Acked-by: Peter Zijlstra (Intel) Message-Id: <20220411101946.20262-6-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx/pmu_intel.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 8118c52e3fec..7458abe81503 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -505,6 +505,7 @@ struct kvm_pmu { unsigned nr_arch_fixed_counters; unsigned available_event_types; u64 fixed_ctr_ctrl; + u64 fixed_ctr_ctrl_mask; u64 global_ctrl; u64 global_status; u64 counter_bitmask[2]; diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index b7dd24476b52..c04d1235316d 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -395,7 +395,7 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_CORE_PERF_FIXED_CTR_CTRL: if (pmu->fixed_ctr_ctrl == data) return 0; - if (!(data & 0xfffffffffffff444ull)) { + if (!(data & pmu->fixed_ctr_ctrl_mask)) { reprogram_fixed_counters(pmu, data); return 0; } @@ -479,6 +479,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) struct kvm_cpuid_entry2 *entry; union cpuid10_eax eax; union cpuid10_edx edx; + int i; pmu->nr_arch_gp_counters = 0; pmu->nr_arch_fixed_counters = 0; @@ -487,6 +488,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->version = 0; pmu->reserved_bits = 0xffffffff00200000ull; pmu->raw_event_mask = X86_RAW_EVENT_MASK; + pmu->fixed_ctr_ctrl_mask = ~0ull; entry = kvm_find_cpuid_entry(vcpu, 0xa, 0); if (!entry || !vcpu->kvm->arch.enable_pmu) @@ -523,6 +525,8 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) setup_fixed_pmc_eventsel(pmu); } + for (i = 0; i < pmu->nr_arch_fixed_counters; i++) + pmu->fixed_ctr_ctrl_mask &= ~(0xbull << (i * 4)); pmu->global_ctrl = ((1ull << pmu->nr_arch_gp_counters) - 1) | (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED); pmu->global_ctrl_mask = ~pmu->global_ctrl; From 0d23dc34a7cefde5ee25c321949579694edbd16d Mon Sep 17 00:00:00 2001 From: "Peter Zijlstra (Intel)" Date: Mon, 11 Apr 2022 18:19:35 +0800 Subject: [PATCH 0136/1436] x86/perf/core: Add pebs_capable to store valid PEBS_COUNTER_MASK value The value of pebs_counter_mask will be accessed frequently for repeated use in the intel_guest_get_msrs(). So it can be optimized instead of endlessly mucking about with branches. Signed-off-by: Peter Zijlstra (Intel) Message-Id: <20220411101946.20262-7-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/intel/core.c | 14 ++++++-------- arch/x86/events/perf_event.h | 1 + 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index b56ead52790a..8c9cb41fc20a 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -2932,10 +2932,7 @@ static int handle_pmi_common(struct pt_regs *regs, u64 status) * counters from the GLOBAL_STATUS mask and we always process PEBS * events via drain_pebs(). */ - if (x86_pmu.flags & PMU_FL_PEBS_ALL) - status &= ~cpuc->pebs_enabled; - else - status &= ~(cpuc->pebs_enabled & PEBS_COUNTER_MASK); + status &= ~(cpuc->pebs_enabled & x86_pmu.pebs_capable); /* * PEBS overflow sets bit 62 in the global status register @@ -3981,10 +3978,7 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) arr[0].msr = MSR_CORE_PERF_GLOBAL_CTRL; arr[0].host = intel_ctrl & ~cpuc->intel_ctrl_guest_mask; arr[0].guest = intel_ctrl & ~cpuc->intel_ctrl_host_mask; - if (x86_pmu.flags & PMU_FL_PEBS_ALL) - arr[0].guest &= ~cpuc->pebs_enabled; - else - arr[0].guest &= ~(cpuc->pebs_enabled & PEBS_COUNTER_MASK); + arr[0].guest &= ~(cpuc->pebs_enabled & x86_pmu.pebs_capable); *nr = 1; if (x86_pmu.pebs && x86_pmu.pebs_no_isolation) { @@ -5692,6 +5686,7 @@ __init int intel_pmu_init(void) x86_pmu.events_mask_len = eax.split.mask_length; x86_pmu.max_pebs_events = min_t(unsigned, MAX_PEBS_EVENTS, x86_pmu.num_counters); + x86_pmu.pebs_capable = PEBS_COUNTER_MASK; /* * Quirk: v2 perfmon does not report fixed-purpose events, so @@ -5876,6 +5871,7 @@ __init int intel_pmu_init(void) x86_pmu.pebs_aliases = NULL; x86_pmu.pebs_prec_dist = true; x86_pmu.lbr_pt_coexist = true; + x86_pmu.pebs_capable = ~0ULL; x86_pmu.flags |= PMU_FL_HAS_RSP_1; x86_pmu.flags |= PMU_FL_PEBS_ALL; x86_pmu.get_event_constraints = glp_get_event_constraints; @@ -6233,6 +6229,7 @@ __init int intel_pmu_init(void) x86_pmu.pebs_aliases = NULL; x86_pmu.pebs_prec_dist = true; x86_pmu.pebs_block = true; + x86_pmu.pebs_capable = ~0ULL; x86_pmu.flags |= PMU_FL_HAS_RSP_1; x86_pmu.flags |= PMU_FL_NO_HT_SHARING; x86_pmu.flags |= PMU_FL_PEBS_ALL; @@ -6278,6 +6275,7 @@ __init int intel_pmu_init(void) x86_pmu.pebs_aliases = NULL; x86_pmu.pebs_prec_dist = true; x86_pmu.pebs_block = true; + x86_pmu.pebs_capable = ~0ULL; x86_pmu.flags |= PMU_FL_HAS_RSP_1; x86_pmu.flags |= PMU_FL_NO_HT_SHARING; x86_pmu.flags |= PMU_FL_PEBS_ALL; diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 07fdef4f9ad2..09c68265b577 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -828,6 +828,7 @@ struct x86_pmu { void (*pebs_aliases)(struct perf_event *event); unsigned long large_pebs_flags; u64 rtm_abort_event; + u64 pebs_capable; /* * Intel LBR From c59a1f106f5cd4843c097069ff1bb2ad72103a67 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:36 +0800 Subject: [PATCH 0137/1436] KVM: x86/pmu: Add IA32_PEBS_ENABLE MSR emulation for extended PEBS If IA32_PERF_CAPABILITIES.PEBS_BASELINE [bit 14] is set, the IA32_PEBS_ENABLE MSR exists and all architecturally enumerated fixed and general-purpose counters have corresponding bits in IA32_PEBS_ENABLE that enable generation of PEBS records. The general-purpose counter bits start at bit IA32_PEBS_ENABLE[0], and the fixed counter bits start at bit IA32_PEBS_ENABLE[32]. When guest PEBS is enabled, the IA32_PEBS_ENABLE MSR will be added to the perf_guest_switch_msr() and atomically switched during the VMX transitions just like CORE_PERF_GLOBAL_CTRL MSR. Based on whether the platform supports x86_pmu.pebs_ept, it has also refactored the way to add more msrs to arr[] in intel_guest_get_msrs() for extensibility. Originally-by: Andi Kleen Co-developed-by: Kan Liang Signed-off-by: Kan Liang Co-developed-by: Luwei Kang Signed-off-by: Luwei Kang Signed-off-by: Like Xu Acked-by: Peter Zijlstra (Intel) Message-Id: <20220411101946.20262-8-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/intel/core.c | 75 ++++++++++++++++++++++++-------- arch/x86/include/asm/kvm_host.h | 3 ++ arch/x86/include/asm/msr-index.h | 6 +++ arch/x86/kvm/vmx/pmu_intel.c | 31 +++++++++++++ arch/x86/kvm/x86.c | 1 + 5 files changed, 98 insertions(+), 18 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 8c9cb41fc20a..70a5c66789df 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3969,33 +3969,72 @@ static int intel_pmu_hw_config(struct perf_event *event) return 0; } +/* + * Currently, the only caller of this function is the atomic_switch_perf_msrs(). + * The host perf conext helps to prepare the values of the real hardware for + * a set of msrs that need to be switched atomically in a vmx transaction. + * + * For example, the pseudocode needed to add a new msr should look like: + * + * arr[(*nr)++] = (struct perf_guest_switch_msr){ + * .msr = the hardware msr address, + * .host = the value the hardware has when it doesn't run a guest, + * .guest = the value the hardware has when it runs a guest, + * }; + * + * These values have nothing to do with the emulated values the guest sees + * when it uses {RD,WR}MSR, which should be handled by the KVM context, + * specifically in the intel_pmu_{get,set}_msr(). + */ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct perf_guest_switch_msr *arr = cpuc->guest_switch_msrs; u64 intel_ctrl = hybrid(cpuc->pmu, intel_ctrl); + u64 pebs_mask = cpuc->pebs_enabled & x86_pmu.pebs_capable; + int global_ctrl, pebs_enable; - arr[0].msr = MSR_CORE_PERF_GLOBAL_CTRL; - arr[0].host = intel_ctrl & ~cpuc->intel_ctrl_guest_mask; - arr[0].guest = intel_ctrl & ~cpuc->intel_ctrl_host_mask; - arr[0].guest &= ~(cpuc->pebs_enabled & x86_pmu.pebs_capable); - *nr = 1; + *nr = 0; + global_ctrl = (*nr)++; + arr[global_ctrl] = (struct perf_guest_switch_msr){ + .msr = MSR_CORE_PERF_GLOBAL_CTRL, + .host = intel_ctrl & ~cpuc->intel_ctrl_guest_mask, + .guest = intel_ctrl & (~cpuc->intel_ctrl_host_mask | ~pebs_mask), + }; - if (x86_pmu.pebs && x86_pmu.pebs_no_isolation) { - /* - * If PMU counter has PEBS enabled it is not enough to - * disable counter on a guest entry since PEBS memory - * write can overshoot guest entry and corrupt guest - * memory. Disabling PEBS solves the problem. - * - * Don't do this if the CPU already enforces it. - */ - arr[1].msr = MSR_IA32_PEBS_ENABLE; - arr[1].host = cpuc->pebs_enabled; - arr[1].guest = 0; - *nr = 2; + if (!x86_pmu.pebs) + return arr; + + /* + * If PMU counter has PEBS enabled it is not enough to + * disable counter on a guest entry since PEBS memory + * write can overshoot guest entry and corrupt guest + * memory. Disabling PEBS solves the problem. + * + * Don't do this if the CPU already enforces it. + */ + if (x86_pmu.pebs_no_isolation) { + arr[(*nr)++] = (struct perf_guest_switch_msr){ + .msr = MSR_IA32_PEBS_ENABLE, + .host = cpuc->pebs_enabled, + .guest = 0, + }; + return arr; } + if (!x86_pmu.pebs_ept) + return arr; + pebs_enable = (*nr)++; + + arr[pebs_enable] = (struct perf_guest_switch_msr){ + .msr = MSR_IA32_PEBS_ENABLE, + .host = cpuc->pebs_enabled & ~cpuc->intel_ctrl_guest_mask, + .guest = pebs_mask & ~cpuc->intel_ctrl_host_mask, + }; + + /* Set hw GLOBAL_CTRL bits for PEBS counter when it runs for guest */ + arr[0].guest |= arr[*nr].guest; + return arr; } diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 7458abe81503..36a5650b9007 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -521,6 +521,9 @@ struct kvm_pmu { DECLARE_BITMAP(all_valid_pmc_idx, X86_PMC_IDX_MAX); DECLARE_BITMAP(pmc_in_use, X86_PMC_IDX_MAX); + u64 pebs_enable; + u64 pebs_enable_mask; + /* * The gate to release perf_events not marked in * pmc_in_use only once in a vcpu time slice. diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index c194995b2e1f..bd1861c9cfa8 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -196,6 +196,12 @@ #define PERF_CAP_PT_IDX 16 #define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6 +#define PERF_CAP_PEBS_TRAP BIT_ULL(6) +#define PERF_CAP_ARCH_REG BIT_ULL(7) +#define PERF_CAP_PEBS_FORMAT 0xf00 +#define PERF_CAP_PEBS_BASELINE BIT_ULL(14) +#define PERF_CAP_PEBS_MASK (PERF_CAP_PEBS_TRAP | PERF_CAP_ARCH_REG | \ + PERF_CAP_PEBS_FORMAT | PERF_CAP_PEBS_BASELINE) #define MSR_IA32_RTIT_CTL 0x00000570 #define RTIT_CTL_TRACEEN BIT(0) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index c04d1235316d..2cd4f8a751be 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -214,6 +214,9 @@ static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) case MSR_CORE_PERF_GLOBAL_OVF_CTRL: ret = pmu->version > 1; break; + case MSR_IA32_PEBS_ENABLE: + ret = vcpu->arch.perf_capabilities & PERF_CAP_PEBS_FORMAT; + break; default: ret = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0) || get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0) || @@ -361,6 +364,9 @@ static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_CORE_PERF_GLOBAL_OVF_CTRL: msr_info->data = 0; return 0; + case MSR_IA32_PEBS_ENABLE: + msr_info->data = pmu->pebs_enable; + return 0; default: if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) || (pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) { @@ -421,6 +427,14 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 0; } break; + case MSR_IA32_PEBS_ENABLE: + if (pmu->pebs_enable == data) + return 0; + if (!(data & pmu->pebs_enable_mask)) { + pmu->pebs_enable = data; + return 0; + } + break; default: if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) || (pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) { @@ -489,6 +503,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->reserved_bits = 0xffffffff00200000ull; pmu->raw_event_mask = X86_RAW_EVENT_MASK; pmu->fixed_ctr_ctrl_mask = ~0ull; + pmu->pebs_enable_mask = ~0ull; entry = kvm_find_cpuid_entry(vcpu, 0xa, 0); if (!entry || !vcpu->kvm->arch.enable_pmu) @@ -560,6 +575,22 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) if (lbr_desc->records.nr) bitmap_set(pmu->all_valid_pmc_idx, INTEL_PMC_IDX_FIXED_VLBR, 1); + + if (vcpu->arch.perf_capabilities & PERF_CAP_PEBS_FORMAT) { + if (vcpu->arch.perf_capabilities & PERF_CAP_PEBS_BASELINE) { + pmu->pebs_enable_mask = ~pmu->global_ctrl; + pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE; + for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { + pmu->fixed_ctr_ctrl_mask &= + ~(1ULL << (INTEL_PMC_IDX_FIXED + i * 4)); + } + } else { + pmu->pebs_enable_mask = + ~((1ull << pmu->nr_arch_gp_counters) - 1); + } + } else { + vcpu->arch.perf_capabilities &= ~PERF_CAP_PEBS_MASK; + } } static void intel_pmu_init(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 68ec5cbeb665..12183c790ed1 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1448,6 +1448,7 @@ static const u32 msrs_to_save_all[] = { MSR_ARCH_PERFMON_EVENTSEL0 + 12, MSR_ARCH_PERFMON_EVENTSEL0 + 13, MSR_ARCH_PERFMON_EVENTSEL0 + 14, MSR_ARCH_PERFMON_EVENTSEL0 + 15, MSR_ARCH_PERFMON_EVENTSEL0 + 16, MSR_ARCH_PERFMON_EVENTSEL0 + 17, + MSR_IA32_PEBS_ENABLE, MSR_K7_EVNTSEL0, MSR_K7_EVNTSEL1, MSR_K7_EVNTSEL2, MSR_K7_EVNTSEL3, MSR_K7_PERFCTR0, MSR_K7_PERFCTR1, MSR_K7_PERFCTR2, MSR_K7_PERFCTR3, From 79f3e3b58386a2fc05054367b905619f741beeb4 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:37 +0800 Subject: [PATCH 0138/1436] KVM: x86/pmu: Reprogram PEBS event to emulate guest PEBS counter When a guest counter is configured as a PEBS counter through IA32_PEBS_ENABLE, a guest PEBS event will be reprogrammed by configuring a non-zero precision level in the perf_event_attr. The guest PEBS overflow PMI bit would be set in the guest GLOBAL_STATUS MSR when PEBS facility generates a PEBS overflow PMI based on guest IA32_DS_AREA MSR. Even with the same counter index and the same event code and mask, guest PEBS events will not be reused for non-PEBS events. Originally-by: Andi Kleen Co-developed-by: Kan Liang Signed-off-by: Kan Liang Signed-off-by: Like Xu Acked-by: Peter Zijlstra (Intel) Message-Id: <20220411101946.20262-9-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 3f868fed9114..cdefcb091ac8 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -86,15 +86,22 @@ static void kvm_pmi_trigger_fn(struct irq_work *irq_work) static inline void __kvm_perf_overflow(struct kvm_pmc *pmc, bool in_pmi) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); + bool skip_pmi = false; /* Ignore counters that have been reprogrammed already. */ if (test_and_set_bit(pmc->idx, pmu->reprogram_pmi)) return; - __set_bit(pmc->idx, (unsigned long *)&pmu->global_status); + if (pmc->perf_event && pmc->perf_event->attr.precise_ip) { + /* Indicate PEBS overflow PMI to guest. */ + skip_pmi = __test_and_set_bit(GLOBAL_STATUS_BUFFER_OVF_BIT, + (unsigned long *)&pmu->global_status); + } else { + __set_bit(pmc->idx, (unsigned long *)&pmu->global_status); + } kvm_make_request(KVM_REQ_PMU, pmc->vcpu); - if (!pmc->intr) + if (!pmc->intr || skip_pmi) return; /* @@ -124,6 +131,7 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, u64 config, bool exclude_user, bool exclude_kernel, bool intr) { + struct kvm_pmu *pmu = pmc_to_pmu(pmc); struct perf_event *event; struct perf_event_attr attr = { .type = type, @@ -135,6 +143,7 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, .exclude_kernel = exclude_kernel, .config = config, }; + bool pebs = test_bit(pmc->idx, (unsigned long *)&pmu->pebs_enable); if (type == PERF_TYPE_HARDWARE && config >= PERF_COUNT_HW_MAX) return; @@ -150,6 +159,23 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, */ attr.sample_period = 0; } + if (pebs) { + /* + * The non-zero precision level of guest event makes the ordinary + * guest event becomes a guest PEBS event and triggers the host + * PEBS PMI handler to determine whether the PEBS overflow PMI + * comes from the host counters or the guest. + * + * For most PEBS hardware events, the difference in the software + * precision levels of guest and host PEBS events will not affect + * the accuracy of the PEBS profiling result, because the "event IP" + * in the PEBS record is calibrated on the guest side. + * + * On Icelake everything is fine. Other hardware (GLC+, TNT+) that + * could possibly care here is unsupported and needs changes. + */ + attr.precise_ip = 1; + } event = perf_event_create_kernel_counter(&attr, -1, current, kvm_perf_overflow, pmc); @@ -163,7 +189,7 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, pmc_to_pmu(pmc)->event_count++; clear_bit(pmc->idx, pmc_to_pmu(pmc)->reprogram_pmi); pmc->is_paused = false; - pmc->intr = intr; + pmc->intr = intr || pebs; } static void pmc_pause_counter(struct kvm_pmc *pmc) @@ -189,6 +215,10 @@ static bool pmc_resume_counter(struct kvm_pmc *pmc) get_sample_period(pmc, pmc->counter))) return false; + if (!test_bit(pmc->idx, (unsigned long *)&pmc_to_pmu(pmc)->pebs_enable) && + pmc->perf_event->attr.precise_ip) + return false; + /* reuse perf_event to serve as pmc_reprogram_counter() does*/ perf_event_enable(pmc->perf_event); pmc->is_paused = false; From 6ebe44366bdeaf3059f2b644bbd99824ae824228 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:38 +0800 Subject: [PATCH 0139/1436] KVM: x86/pmu: Adjust precise_ip to emulate Ice Lake guest PDIR counter The PEBS-PDIR facility on Ice Lake server is supported on IA31_FIXED0 only. If the guest configures counter 32 and PEBS is enabled, the PEBS-PDIR facility is supposed to be used, in which case KVM adjusts attr.precise_ip to 3 and request host perf to assign the exactly requested counter or fail. The CPU model check is also required since some platforms may place the PEBS-PDIR facility in another counter index. Signed-off-by: Like Xu Acked-by: Peter Zijlstra (Intel) Message-Id: <20220411101946.20262-10-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/intel/core.c | 2 +- arch/x86/kvm/pmu.c | 2 ++ arch/x86/kvm/pmu.h | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 70a5c66789df..7ef7fd4ab29b 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -4024,8 +4024,8 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) if (!x86_pmu.pebs_ept) return arr; - pebs_enable = (*nr)++; + pebs_enable = (*nr)++; arr[pebs_enable] = (struct perf_guest_switch_msr){ .msr = MSR_IA32_PEBS_ENABLE, .host = cpuc->pebs_enabled & ~cpuc->intel_ctrl_guest_mask, diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index cdefcb091ac8..162dfe23c071 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -175,6 +175,8 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, * could possibly care here is unsupported and needs changes. */ attr.precise_ip = 1; + if (x86_match_cpu(vmx_icl_pebs_cpu) && pmc->idx == 32) + attr.precise_ip = 3; } event = perf_event_create_kernel_counter(&attr, -1, current, diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index e745f443b6a8..5966ce18a82b 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -4,6 +4,8 @@ #include +#include + #define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu) #define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu)) #define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu) @@ -15,6 +17,12 @@ #define VMWARE_BACKDOOR_PMC_REAL_TIME 0x10001 #define VMWARE_BACKDOOR_PMC_APPARENT_TIME 0x10002 +static const struct x86_cpu_id vmx_icl_pebs_cpu[] = { + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL), + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL), + {} +}; + struct kvm_event_hw_type_mapping { u8 eventsel; u8 unit_mask; From 8183a538cd95f72f11871b35726256ec3bcb9439 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:39 +0800 Subject: [PATCH 0140/1436] KVM: x86/pmu: Add IA32_DS_AREA MSR emulation to support guest DS When CPUID.01H:EDX.DS[21] is set, the IA32_DS_AREA MSR exists and points to the linear address of the first byte of the DS buffer management area, which is used to manage the PEBS records. When guest PEBS is enabled, the MSR_IA32_DS_AREA MSR will be added to the perf_guest_switch_msr() and switched during the VMX transitions just like CORE_PERF_GLOBAL_CTRL MSR. The WRMSR to IA32_DS_AREA MSR brings a #GP(0) if the source register contains a non-canonical address. Originally-by: Andi Kleen Co-developed-by: Kan Liang Signed-off-by: Kan Liang Signed-off-by: Like Xu Acked-by: Peter Zijlstra (Intel) Message-Id: <20220411101946.20262-11-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/intel/core.c | 10 +++++++++- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/vmx/pmu_intel.c | 11 +++++++++++ arch/x86/kvm/x86.c | 2 +- 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 7ef7fd4ab29b..e5e624cae957 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -3990,6 +3991,7 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) { struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); struct perf_guest_switch_msr *arr = cpuc->guest_switch_msrs; + struct kvm_pmu *kvm_pmu = (struct kvm_pmu *)data; u64 intel_ctrl = hybrid(cpuc->pmu, intel_ctrl); u64 pebs_mask = cpuc->pebs_enabled & x86_pmu.pebs_capable; int global_ctrl, pebs_enable; @@ -4022,9 +4024,15 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) return arr; } - if (!x86_pmu.pebs_ept) + if (!kvm_pmu || !x86_pmu.pebs_ept) return arr; + arr[(*nr)++] = (struct perf_guest_switch_msr){ + .msr = MSR_IA32_DS_AREA, + .host = (unsigned long)cpuc->ds, + .guest = kvm_pmu->ds_area, + }; + pebs_enable = (*nr)++; arr[pebs_enable] = (struct perf_guest_switch_msr){ .msr = MSR_IA32_PEBS_ENABLE, diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 36a5650b9007..dc5f68a313b0 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -521,6 +521,7 @@ struct kvm_pmu { DECLARE_BITMAP(all_valid_pmc_idx, X86_PMC_IDX_MAX); DECLARE_BITMAP(pmc_in_use, X86_PMC_IDX_MAX); + u64 ds_area; u64 pebs_enable; u64 pebs_enable_mask; diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 2cd4f8a751be..36ba29b664bf 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -217,6 +217,9 @@ static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) case MSR_IA32_PEBS_ENABLE: ret = vcpu->arch.perf_capabilities & PERF_CAP_PEBS_FORMAT; break; + case MSR_IA32_DS_AREA: + ret = guest_cpuid_has(vcpu, X86_FEATURE_DS); + break; default: ret = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0) || get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0) || @@ -367,6 +370,9 @@ static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_IA32_PEBS_ENABLE: msr_info->data = pmu->pebs_enable; return 0; + case MSR_IA32_DS_AREA: + msr_info->data = pmu->ds_area; + return 0; default: if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) || (pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) { @@ -435,6 +441,11 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 0; } break; + case MSR_IA32_DS_AREA: + if (is_noncanonical_address(data, vcpu)) + return 1; + pmu->ds_area = data; + return 0; default: if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) || (pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 12183c790ed1..ead86072612d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1448,7 +1448,7 @@ static const u32 msrs_to_save_all[] = { MSR_ARCH_PERFMON_EVENTSEL0 + 12, MSR_ARCH_PERFMON_EVENTSEL0 + 13, MSR_ARCH_PERFMON_EVENTSEL0 + 14, MSR_ARCH_PERFMON_EVENTSEL0 + 15, MSR_ARCH_PERFMON_EVENTSEL0 + 16, MSR_ARCH_PERFMON_EVENTSEL0 + 17, - MSR_IA32_PEBS_ENABLE, + MSR_IA32_PEBS_ENABLE, MSR_IA32_DS_AREA, MSR_K7_EVNTSEL0, MSR_K7_EVNTSEL1, MSR_K7_EVNTSEL2, MSR_K7_EVNTSEL3, MSR_K7_PERFCTR0, MSR_K7_PERFCTR1, MSR_K7_PERFCTR2, MSR_K7_PERFCTR3, From 902caeb6841a64072791b1c18f9f56089566865d Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:40 +0800 Subject: [PATCH 0141/1436] KVM: x86/pmu: Add PEBS_DATA_CFG MSR emulation to support adaptive PEBS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If IA32_PERF_CAPABILITIES.PEBS_BASELINE [bit 14] is set, the adaptive PEBS is supported. The PEBS_DATA_CFG MSR and adaptive record enable bits (IA32_PERFEVTSELx.Adaptive_Record and IA32_FIXED_CTR_CTRL. FCx_Adaptive_Record) are also supported. Adaptive PEBS provides software the capability to configure the PEBS records to capture only the data of interest, keeping the record size compact. An overflow of PMCx results in generation of an adaptive PEBS record with state information based on the selections specified in MSR_PEBS_DATA_CFG.By default, the record only contain the Basic group. When guest adaptive PEBS is enabled, the IA32_PEBS_ENABLE MSR will be added to the perf_guest_switch_msr() and switched during the VMX transitions just like CORE_PERF_GLOBAL_CTRL MSR. According to Intel SDM, software is recommended to PEBS Baseline when the following is true. IA32_PERF_CAPABILITIES.PEBS_BASELINE[14] && IA32_PERF_CAPABILITIES.PEBS_FMT[11:8] ≥ 4. Co-developed-by: Luwei Kang Signed-off-by: Luwei Kang Signed-off-by: Like Xu Message-Id: <20220411101946.20262-12-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/intel/core.c | 8 ++++++++ arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/vmx/pmu_intel.c | 20 +++++++++++++++++++- arch/x86/kvm/x86.c | 2 +- 4 files changed, 30 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index e5e624cae957..8f6189f2fbf3 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -4033,6 +4033,14 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) .guest = kvm_pmu->ds_area, }; + if (x86_pmu.intel_cap.pebs_baseline) { + arr[(*nr)++] = (struct perf_guest_switch_msr){ + .msr = MSR_PEBS_DATA_CFG, + .host = cpuc->pebs_data_cfg, + .guest = kvm_pmu->pebs_data_cfg, + }; + } + pebs_enable = (*nr)++; arr[pebs_enable] = (struct perf_guest_switch_msr){ .msr = MSR_IA32_PEBS_ENABLE, diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index dc5f68a313b0..d99c130d0a13 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -524,6 +524,8 @@ struct kvm_pmu { u64 ds_area; u64 pebs_enable; u64 pebs_enable_mask; + u64 pebs_data_cfg; + u64 pebs_data_cfg_mask; /* * The gate to release perf_events not marked in diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 36ba29b664bf..69eb5372c922 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -205,6 +205,7 @@ static bool intel_pmu_is_valid_lbr_msr(struct kvm_vcpu *vcpu, u32 index) static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); + u64 perf_capabilities = vcpu->arch.perf_capabilities; int ret; switch (msr) { @@ -215,11 +216,15 @@ static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) ret = pmu->version > 1; break; case MSR_IA32_PEBS_ENABLE: - ret = vcpu->arch.perf_capabilities & PERF_CAP_PEBS_FORMAT; + ret = perf_capabilities & PERF_CAP_PEBS_FORMAT; break; case MSR_IA32_DS_AREA: ret = guest_cpuid_has(vcpu, X86_FEATURE_DS); break; + case MSR_PEBS_DATA_CFG: + ret = (perf_capabilities & PERF_CAP_PEBS_BASELINE) && + ((perf_capabilities & PERF_CAP_PEBS_FORMAT) > 3); + break; default: ret = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0) || get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0) || @@ -373,6 +378,9 @@ static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_IA32_DS_AREA: msr_info->data = pmu->ds_area; return 0; + case MSR_PEBS_DATA_CFG: + msr_info->data = pmu->pebs_data_cfg; + return 0; default: if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) || (pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) { @@ -446,6 +454,14 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 1; pmu->ds_area = data; return 0; + case MSR_PEBS_DATA_CFG: + if (pmu->pebs_data_cfg == data) + return 0; + if (!(data & pmu->pebs_data_cfg_mask)) { + pmu->pebs_data_cfg = data; + return 0; + } + break; default: if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) || (pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) { @@ -515,6 +531,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->raw_event_mask = X86_RAW_EVENT_MASK; pmu->fixed_ctr_ctrl_mask = ~0ull; pmu->pebs_enable_mask = ~0ull; + pmu->pebs_data_cfg_mask = ~0ull; entry = kvm_find_cpuid_entry(vcpu, 0xa, 0); if (!entry || !vcpu->kvm->arch.enable_pmu) @@ -595,6 +612,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->fixed_ctr_ctrl_mask &= ~(1ULL << (INTEL_PMC_IDX_FIXED + i * 4)); } + pmu->pebs_data_cfg_mask = ~0xff00000full; } else { pmu->pebs_enable_mask = ~((1ull << pmu->nr_arch_gp_counters) - 1); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ead86072612d..2d9456b4874b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1448,7 +1448,7 @@ static const u32 msrs_to_save_all[] = { MSR_ARCH_PERFMON_EVENTSEL0 + 12, MSR_ARCH_PERFMON_EVENTSEL0 + 13, MSR_ARCH_PERFMON_EVENTSEL0 + 14, MSR_ARCH_PERFMON_EVENTSEL0 + 15, MSR_ARCH_PERFMON_EVENTSEL0 + 16, MSR_ARCH_PERFMON_EVENTSEL0 + 17, - MSR_IA32_PEBS_ENABLE, MSR_IA32_DS_AREA, + MSR_IA32_PEBS_ENABLE, MSR_IA32_DS_AREA, MSR_PEBS_DATA_CFG, MSR_K7_EVNTSEL0, MSR_K7_EVNTSEL1, MSR_K7_EVNTSEL2, MSR_K7_EVNTSEL3, MSR_K7_PERFCTR0, MSR_K7_PERFCTR1, MSR_K7_PERFCTR2, MSR_K7_PERFCTR3, From d10551738f6adcc3e6040fc846b171e72e94f0e9 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:41 +0800 Subject: [PATCH 0142/1436] KVM: x86: Set PEBS_UNAVAIL in IA32_MISC_ENABLE when PEBS is enabled The bit 12 represents "Processor Event Based Sampling Unavailable (RO)" : 1 = PEBS is not supported. 0 = PEBS is supported. A write to this PEBS_UNAVL available bit will bring #GP(0) when guest PEBS is enabled. Some PEBS drivers in guest may care about this bit. Signed-off-by: Like Xu Message-Id: <20220411101946.20262-13-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/pmu_intel.c | 2 ++ arch/x86/kvm/x86.c | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 69eb5372c922..02cad8e08ed0 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -605,6 +605,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) bitmap_set(pmu->all_valid_pmc_idx, INTEL_PMC_IDX_FIXED_VLBR, 1); if (vcpu->arch.perf_capabilities & PERF_CAP_PEBS_FORMAT) { + vcpu->arch.ia32_misc_enable_msr &= ~MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL; if (vcpu->arch.perf_capabilities & PERF_CAP_PEBS_BASELINE) { pmu->pebs_enable_mask = ~pmu->global_ctrl; pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE; @@ -618,6 +619,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) ~((1ull << pmu->nr_arch_gp_counters) - 1); } } else { + vcpu->arch.ia32_misc_enable_msr |= MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL; vcpu->arch.perf_capabilities &= ~PERF_CAP_PEBS_MASK; } } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2d9456b4874b..94b92381cc8b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3561,7 +3561,13 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; case MSR_IA32_MISC_ENABLE: { u64 old_val = vcpu->arch.ia32_misc_enable_msr; - u64 pmu_mask = MSR_IA32_MISC_ENABLE_EMON; + u64 pmu_mask = MSR_IA32_MISC_ENABLE_EMON | + MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL; + + /* RO bits */ + if (!msr_info->host_initiated && + ((old_val ^ data) & MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL)) + return 1; /* * For a dummy user space, the order of setting vPMU capabilities and From 63f21f326fc9e068d04c2c1d0a722e8db65588ba Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:42 +0800 Subject: [PATCH 0143/1436] KVM: x86/pmu: Move pmc_speculative_in_use() to arch/x86/kvm/pmu.h It allows this inline function to be reused by more callers in more files, such as pmu_intel.c. Signed-off-by: Like Xu Acked-by: Peter Zijlstra (Intel) Message-Id: <20220411101946.20262-14-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 11 ----------- arch/x86/kvm/pmu.h | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 162dfe23c071..6e6898ef0011 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -503,17 +503,6 @@ void kvm_pmu_init(struct kvm_vcpu *vcpu) kvm_pmu_refresh(vcpu); } -static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc) -{ - struct kvm_pmu *pmu = pmc_to_pmu(pmc); - - if (pmc_is_fixed(pmc)) - return fixed_ctrl_field(pmu->fixed_ctr_ctrl, - pmc->idx - INTEL_PMC_IDX_FIXED) & 0x3; - - return pmc->eventsel & ARCH_PERFMON_EVENTSEL_ENABLE; -} - /* Release perf_events for vPMCs that have been unused for a full time slice. */ void kvm_pmu_cleanup(struct kvm_vcpu *vcpu) { diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 5966ce18a82b..d01c883ca95c 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -152,6 +152,17 @@ static inline void pmc_update_sample_period(struct kvm_pmc *pmc) get_sample_period(pmc, pmc->counter)); } +static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc) +{ + struct kvm_pmu *pmu = pmc_to_pmu(pmc); + + if (pmc_is_fixed(pmc)) + return fixed_ctrl_field(pmu->fixed_ctr_ctrl, + pmc->idx - INTEL_PMC_IDX_FIXED) & 0x3; + + return pmc->eventsel & ARCH_PERFMON_EVENTSEL_ENABLE; +} + void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel); void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int fixed_idx); void reprogram_counter(struct kvm_pmu *pmu, int pmc_idx); From 854250329c02c0616a42532d65e81365272326d1 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:43 +0800 Subject: [PATCH 0144/1436] KVM: x86/pmu: Disable guest PEBS temporarily in two rare situations The guest PEBS will be disabled when some users try to perf KVM and its user-space through the same PEBS facility OR when the host perf doesn't schedule the guest PEBS counter in a one-to-one mapping manner (neither of these are typical scenarios). The PEBS records in the guest DS buffer are still accurate and the above two restrictions will be checked before each vm-entry only if guest PEBS is deemed to be enabled. Suggested-by: Wei Wang Signed-off-by: Like Xu Acked-by: Peter Zijlstra (Intel) Message-Id: <20220411101946.20262-15-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/intel/core.c | 11 +++++++++-- arch/x86/include/asm/kvm_host.h | 9 +++++++++ arch/x86/kvm/vmx/pmu_intel.c | 20 ++++++++++++++++++++ arch/x86/kvm/vmx/vmx.c | 4 ++++ arch/x86/kvm/vmx/vmx.h | 1 + 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 8f6189f2fbf3..39832a5e7d75 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -4048,8 +4048,15 @@ static struct perf_guest_switch_msr *intel_guest_get_msrs(int *nr, void *data) .guest = pebs_mask & ~cpuc->intel_ctrl_host_mask, }; - /* Set hw GLOBAL_CTRL bits for PEBS counter when it runs for guest */ - arr[0].guest |= arr[*nr].guest; + if (arr[pebs_enable].host) { + /* Disable guest PEBS if host PEBS is enabled. */ + arr[pebs_enable].guest = 0; + } else { + /* Disable guest PEBS for cross-mapped PEBS counters. */ + arr[pebs_enable].guest &= ~kvm_pmu->host_cross_mapped_mask; + /* Set hw GLOBAL_CTRL bits for PEBS counter when it runs for guest */ + arr[global_ctrl].guest |= arr[pebs_enable].guest; + } return arr; } diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index d99c130d0a13..032278f0ee6d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -527,6 +527,15 @@ struct kvm_pmu { u64 pebs_data_cfg; u64 pebs_data_cfg_mask; + /* + * If a guest counter is cross-mapped to host counter with different + * index, its PEBS capability will be temporarily disabled. + * + * The user should make sure that this mask is updated + * after disabling interrupts and before perf_guest_get_msrs(); + */ + u64 host_cross_mapped_mask; + /* * The gate to release perf_events not marked in * pmc_in_use only once in a vcpu time slice. diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 02cad8e08ed0..cc3d2a768320 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -786,6 +786,26 @@ static void intel_pmu_cleanup(struct kvm_vcpu *vcpu) intel_pmu_release_guest_lbr_event(vcpu); } +void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu) +{ + struct kvm_pmc *pmc = NULL; + int bit; + + for_each_set_bit(bit, (unsigned long *)&pmu->global_ctrl, + X86_PMC_IDX_MAX) { + pmc = intel_pmc_idx_to_pmc(pmu, bit); + + if (!pmc || !pmc_speculative_in_use(pmc) || + !intel_pmc_is_enabled(pmc)) + continue; + + if (pmc->perf_event && pmc->idx != pmc->perf_event->hw.idx) { + pmu->host_cross_mapped_mask |= + BIT_ULL(pmc->perf_event->hw.idx); + } + } +} + struct kvm_pmu_ops intel_pmu_ops __initdata = { .pmc_perf_hw_id = intel_pmc_perf_hw_id, .pmc_is_enabled = intel_pmc_is_enabled, diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 070b02162db6..d5ec0635ccd4 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6796,6 +6796,10 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) struct perf_guest_switch_msr *msrs; struct kvm_pmu *pmu = vcpu_to_pmu(&vmx->vcpu); + pmu->host_cross_mapped_mask = 0; + if (pmu->pebs_enable & pmu->global_ctrl) + intel_pmu_cross_mapped_check(pmu); + /* Note, nr_msrs may be garbage if perf_guest_get_msrs() returns NULL. */ msrs = perf_guest_get_msrs(&nr_msrs, (void *)pmu); if (!msrs) diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index d7baedda79e5..2d6d7870a974 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -94,6 +94,7 @@ union vmx_exit_reason { #define vcpu_to_lbr_desc(vcpu) (&to_vmx(vcpu)->lbr_desc) #define vcpu_to_lbr_records(vcpu) (&to_vmx(vcpu)->lbr_desc.records) +void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu); bool intel_pmu_lbr_is_compatible(struct kvm_vcpu *vcpu); bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu); From 968635abd5f5986f3cb6f15602d365cf1b551c5d Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:44 +0800 Subject: [PATCH 0145/1436] KVM: x86/pmu: Add kvm_pmu_cap to optimize perf_get_x86_pmu_capability The information obtained from the interface perf_get_x86_pmu_capability() doesn't change, so an exported "struct x86_pmu_capability" is introduced for all guests in the KVM, and it's initialized before hardware_setup(). Signed-off-by: Like Xu Message-Id: <20220411101946.20262-16-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/cpuid.c | 27 ++++++++------------------- arch/x86/kvm/pmu.c | 3 +++ arch/x86/kvm/pmu.h | 19 +++++++++++++++++++ arch/x86/kvm/vmx/pmu_intel.c | 17 ++++++++--------- arch/x86/kvm/x86.c | 9 ++++----- 5 files changed, 42 insertions(+), 33 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index de6d44e07e34..211f4566641e 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -868,7 +868,6 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) case 9: break; case 0xa: { /* Architectural Performance Monitoring */ - struct x86_pmu_capability cap; union cpuid10_eax eax; union cpuid10_edx edx; @@ -877,30 +876,20 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) break; } - perf_get_x86_pmu_capability(&cap); + eax.split.version_id = kvm_pmu_cap.version; + eax.split.num_counters = kvm_pmu_cap.num_counters_gp; + eax.split.bit_width = kvm_pmu_cap.bit_width_gp; + eax.split.mask_length = kvm_pmu_cap.events_mask_len; + edx.split.num_counters_fixed = kvm_pmu_cap.num_counters_fixed; + edx.split.bit_width_fixed = kvm_pmu_cap.bit_width_fixed; - /* - * The guest architecture pmu is only supported if the architecture - * pmu exists on the host and the module parameters allow it. - */ - if (!cap.version || !enable_pmu) - memset(&cap, 0, sizeof(cap)); - - eax.split.version_id = min(cap.version, 2); - eax.split.num_counters = cap.num_counters_gp; - eax.split.bit_width = cap.bit_width_gp; - eax.split.mask_length = cap.events_mask_len; - - edx.split.num_counters_fixed = - min(cap.num_counters_fixed, KVM_PMC_MAX_FIXED); - edx.split.bit_width_fixed = cap.bit_width_fixed; - if (cap.version) + if (kvm_pmu_cap.version) edx.split.anythread_deprecated = 1; edx.split.reserved1 = 0; edx.split.reserved2 = 0; entry->eax = eax.full; - entry->ebx = cap.events_mask; + entry->ebx = kvm_pmu_cap.events_mask; entry->ecx = 0; entry->edx = edx.full; break; diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 6e6898ef0011..a8f0618a5ebe 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -24,6 +24,9 @@ /* This is enough to filter the vast majority of currently defined events. */ #define KVM_PMU_EVENT_FILTER_MAX_EVENTS 300 +struct x86_pmu_capability __read_mostly kvm_pmu_cap; +EXPORT_SYMBOL_GPL(kvm_pmu_cap); + /* NOTE: * - Each perf counter is defined as "struct kvm_pmc"; * - There are two types of perf counters: general purpose (gp) and fixed. diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index d01c883ca95c..9e25cdd2bd1a 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -163,6 +163,24 @@ static inline bool pmc_speculative_in_use(struct kvm_pmc *pmc) return pmc->eventsel & ARCH_PERFMON_EVENTSEL_ENABLE; } +extern struct x86_pmu_capability kvm_pmu_cap; + +static inline void kvm_init_pmu_capability(void) +{ + perf_get_x86_pmu_capability(&kvm_pmu_cap); + + /* + * Only support guest architectural pmu on + * a host with architectural pmu. + */ + if (!kvm_pmu_cap.version) + memset(&kvm_pmu_cap, 0, sizeof(kvm_pmu_cap)); + + kvm_pmu_cap.version = min(kvm_pmu_cap.version, 2); + kvm_pmu_cap.num_counters_fixed = min(kvm_pmu_cap.num_counters_fixed, + KVM_PMC_MAX_FIXED); +} + void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel); void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int fixed_idx); void reprogram_counter(struct kvm_pmu *pmu, int pmc_idx); @@ -181,6 +199,7 @@ void kvm_pmu_cleanup(struct kvm_vcpu *vcpu); void kvm_pmu_destroy(struct kvm_vcpu *vcpu); int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp); void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id); +void kvm_init_pmu_capability(void); bool is_vmware_backdoor_pmc(u32 pmc_idx); diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index cc3d2a768320..83d1081cbd3c 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -515,8 +515,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu); - - struct x86_pmu_capability x86_pmu; struct kvm_cpuid_entry2 *entry; union cpuid10_eax eax; union cpuid10_edx edx; @@ -544,13 +542,14 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) return; vcpu->arch.ia32_misc_enable_msr |= MSR_IA32_MISC_ENABLE_EMON; - perf_get_x86_pmu_capability(&x86_pmu); pmu->nr_arch_gp_counters = min_t(int, eax.split.num_counters, - x86_pmu.num_counters_gp); - eax.split.bit_width = min_t(int, eax.split.bit_width, x86_pmu.bit_width_gp); + kvm_pmu_cap.num_counters_gp); + eax.split.bit_width = min_t(int, eax.split.bit_width, + kvm_pmu_cap.bit_width_gp); pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << eax.split.bit_width) - 1; - eax.split.mask_length = min_t(int, eax.split.mask_length, x86_pmu.events_mask_len); + eax.split.mask_length = min_t(int, eax.split.mask_length, + kvm_pmu_cap.events_mask_len); pmu->available_event_types = ~entry->ebx & ((1ull << eax.split.mask_length) - 1); @@ -560,9 +559,9 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->nr_arch_fixed_counters = min3(ARRAY_SIZE(fixed_pmc_events), (size_t) edx.split.num_counters_fixed, - (size_t) x86_pmu.num_counters_fixed); - edx.split.bit_width_fixed = min_t(int, - edx.split.bit_width_fixed, x86_pmu.bit_width_fixed); + (size_t)kvm_pmu_cap.num_counters_fixed); + edx.split.bit_width_fixed = min_t(int, edx.split.bit_width_fixed, + kvm_pmu_cap.bit_width_fixed); pmu->counter_bitmask[KVM_PMC_FIXED] = ((u64)1 << edx.split.bit_width_fixed) - 1; setup_fixed_pmc_eventsel(pmu); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 94b92381cc8b..32218fac4504 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6667,15 +6667,12 @@ out: static void kvm_init_msr_list(void) { - struct x86_pmu_capability x86_pmu; u32 dummy[2]; unsigned i; BUILD_BUG_ON_MSG(KVM_PMC_MAX_FIXED != 3, "Please update the fixed PMCs in msrs_to_saved_all[]"); - perf_get_x86_pmu_capability(&x86_pmu); - num_msrs_to_save = 0; num_emulated_msrs = 0; num_msr_based_features = 0; @@ -6727,12 +6724,12 @@ static void kvm_init_msr_list(void) break; case MSR_ARCH_PERFMON_PERFCTR0 ... MSR_ARCH_PERFMON_PERFCTR0 + 17: if (msrs_to_save_all[i] - MSR_ARCH_PERFMON_PERFCTR0 >= - min(INTEL_PMC_MAX_GENERIC, x86_pmu.num_counters_gp)) + min(INTEL_PMC_MAX_GENERIC, kvm_pmu_cap.num_counters_gp)) continue; break; case MSR_ARCH_PERFMON_EVENTSEL0 ... MSR_ARCH_PERFMON_EVENTSEL0 + 17: if (msrs_to_save_all[i] - MSR_ARCH_PERFMON_EVENTSEL0 >= - min(INTEL_PMC_MAX_GENERIC, x86_pmu.num_counters_gp)) + min(INTEL_PMC_MAX_GENERIC, kvm_pmu_cap.num_counters_gp)) continue; break; case MSR_IA32_XFD: @@ -11721,6 +11718,8 @@ int kvm_arch_hardware_setup(void *opaque) if (boot_cpu_has(X86_FEATURE_XSAVES)) rdmsrl(MSR_IA32_XSS, host_xss); + kvm_init_pmu_capability(); + r = ops->hardware_setup(); if (r != 0) return r; From 59cc99f6e971bb24b40e27f695daab98e2eff4b8 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:45 +0800 Subject: [PATCH 0146/1436] KVM: x86/cpuid: Refactor host/guest CPU model consistency check For the same purpose, the leagcy intel_pmu_lbr_is_compatible() can be renamed for reuse by more callers, and remove the comment about LBR use case can be deleted by the way. Signed-off-by: Like Xu Acked-by: Peter Zijlstra (Intel) Message-Id: <20220411101946.20262-17-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/cpuid.h | 5 +++++ arch/x86/kvm/vmx/pmu_intel.c | 12 +----------- arch/x86/kvm/vmx/vmx.c | 2 +- arch/x86/kvm/vmx/vmx.h | 1 - 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index 8a770b481d9d..ac72aabba981 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -145,6 +145,11 @@ static inline int guest_cpuid_model(struct kvm_vcpu *vcpu) return x86_model(best->eax); } +static inline bool cpuid_model_is_consistent(struct kvm_vcpu *vcpu) +{ + return boot_cpu_data.x86_model == guest_cpuid_model(vcpu); +} + static inline int guest_cpuid_stepping(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 83d1081cbd3c..ca219a54a53e 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -167,16 +167,6 @@ static inline struct kvm_pmc *get_fw_gp_pmc(struct kvm_pmu *pmu, u32 msr) return get_gp_pmc(pmu, msr, MSR_IA32_PMC0); } -bool intel_pmu_lbr_is_compatible(struct kvm_vcpu *vcpu) -{ - /* - * As a first step, a guest could only enable LBR feature if its - * cpu model is the same as the host because the LBR registers - * would be pass-through to the guest and they're model specific. - */ - return boot_cpu_data.x86_model == guest_cpuid_model(vcpu); -} - bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu) { struct x86_pmu_lbr *lbr = vcpu_to_lbr_records(vcpu); @@ -595,7 +585,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) nested_vmx_pmu_refresh(vcpu, intel_is_valid_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL)); - if (intel_pmu_lbr_is_compatible(vcpu)) + if (cpuid_model_is_consistent(vcpu)) x86_perf_get_lbr(&lbr_desc->records); else lbr_desc->records.nr = 0; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index d5ec0635ccd4..403a8834cc79 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2242,7 +2242,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if ((data & PMU_CAP_LBR_FMT) != (vmx_get_perf_capabilities() & PMU_CAP_LBR_FMT)) return 1; - if (!intel_pmu_lbr_is_compatible(vcpu)) + if (!cpuid_model_is_consistent(vcpu)) return 1; } ret = kvm_set_msr_common(vcpu, msr_info); diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 2d6d7870a974..71bcb486e73f 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -95,7 +95,6 @@ union vmx_exit_reason { #define vcpu_to_lbr_records(vcpu) (&to_vmx(vcpu)->lbr_desc.records) void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu); -bool intel_pmu_lbr_is_compatible(struct kvm_vcpu *vcpu); bool intel_pmu_lbr_is_enabled(struct kvm_vcpu *vcpu); int intel_pmu_create_guest_lbr_event(struct kvm_vcpu *vcpu); From cf8e55fe50df0c0292b389a165daa81193cd39d1 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 11 Apr 2022 18:19:46 +0800 Subject: [PATCH 0147/1436] KVM: x86/pmu: Expose CPUIDs feature bits PDCM, DS, DTES64 The CPUID features PDCM, DS and DTES64 are required for PEBS feature. KVM would expose CPUID feature PDCM, DS and DTES64 to guest when PEBS is supported in the KVM on the Ice Lake server platforms. Originally-by: Andi Kleen Co-developed-by: Kan Liang Signed-off-by: Kan Liang Co-developed-by: Luwei Kang Signed-off-by: Luwei Kang Signed-off-by: Like Xu Message-Id: <20220411101946.20262-18-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/capabilities.h | 28 +++++++++++++++++----------- arch/x86/kvm/vmx/vmx.c | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h index 5f656c9e33be..f14c4bef97e0 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -6,6 +6,7 @@ #include "lapic.h" #include "x86.h" +#include "pmu.h" extern bool __read_mostly enable_vpid; extern bool __read_mostly flexpriority_enabled; @@ -398,23 +399,28 @@ static inline bool vmx_pt_mode_is_host_guest(void) return pt_mode == PT_MODE_HOST_GUEST; } +static inline bool vmx_pebs_supported(void) +{ + return boot_cpu_has(X86_FEATURE_PEBS) && kvm_pmu_cap.pebs_ept; +} + static inline u64 vmx_get_perf_capabilities(void) { - u64 perf_cap = 0; - - if (!enable_pmu) - return perf_cap; + u64 perf_cap = PMU_CAP_FW_WRITES; + u64 host_perf_cap = 0; if (boot_cpu_has(X86_FEATURE_PDCM)) - rdmsrl(MSR_IA32_PERF_CAPABILITIES, perf_cap); + rdmsrl(MSR_IA32_PERF_CAPABILITIES, host_perf_cap); - perf_cap &= PMU_CAP_LBR_FMT; + perf_cap |= host_perf_cap & PMU_CAP_LBR_FMT; - /* - * Since counters are virtualized, KVM would support full - * width counting unconditionally, even if the host lacks it. - */ - return PMU_CAP_FW_WRITES | perf_cap; + if (vmx_pebs_supported()) { + perf_cap |= host_perf_cap & PERF_CAP_PEBS_MASK; + if ((perf_cap & PERF_CAP_PEBS_FORMAT) < 4) + perf_cap &= ~PERF_CAP_PEBS_BASELINE; + } + + return perf_cap; } static inline u64 vmx_supported_debugctl(void) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 403a8834cc79..55a8578255cb 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2245,6 +2245,17 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (!cpuid_model_is_consistent(vcpu)) return 1; } + if (data & PERF_CAP_PEBS_FORMAT) { + if ((data & PERF_CAP_PEBS_MASK) != + (vmx_get_perf_capabilities() & PERF_CAP_PEBS_MASK)) + return 1; + if (!guest_cpuid_has(vcpu, X86_FEATURE_DS)) + return 1; + if (!guest_cpuid_has(vcpu, X86_FEATURE_DTES64)) + return 1; + if (!cpuid_model_is_consistent(vcpu)) + return 1; + } ret = kvm_set_msr_common(vcpu, msr_info); break; @@ -7517,6 +7528,10 @@ static __init void vmx_set_cpu_caps(void) kvm_cpu_cap_clear(X86_FEATURE_INVPCID); if (vmx_pt_mode_is_host_guest()) kvm_cpu_cap_check_and_set(X86_FEATURE_INTEL_PT); + if (vmx_pebs_supported()) { + kvm_cpu_cap_check_and_set(X86_FEATURE_DS); + kvm_cpu_cap_check_and_set(X86_FEATURE_DTES64); + } if (!enable_sgx) { kvm_cpu_cap_clear(X86_FEATURE_SGX); From 5d9cd8b55cdc0fa2260bebab590430c8f90ce955 Mon Sep 17 00:00:00 2001 From: Guo Zhengkui Date: Wed, 11 May 2022 20:05:55 +0800 Subject: [PATCH 0148/1436] selftests: kvm: replace ternary operator with min() Fix the following coccicheck warnings: tools/testing/selftests/kvm/lib/s390x/ucall.c:25:15-17: WARNING opportunity for min() tools/testing/selftests/kvm/lib/x86_64/ucall.c:27:15-17: WARNING opportunity for min() tools/testing/selftests/kvm/lib/riscv/ucall.c:56:15-17: WARNING opportunity for min() tools/testing/selftests/kvm/lib/aarch64/ucall.c:82:15-17: WARNING opportunity for min() tools/testing/selftests/kvm/lib/aarch64/ucall.c:55:20-21: WARNING opportunity for min() min() is defined in tools/include/linux/kernel.h. Signed-off-by: Guo Zhengkui Acked-by: Claudio Imbrenda Acked-by: Anup Patel Message-Id: <20220511120621.36956-1-guozhengkui@vivo.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/aarch64/ucall.c | 4 ++-- tools/testing/selftests/kvm/lib/riscv/ucall.c | 2 +- tools/testing/selftests/kvm/lib/s390x/ucall.c | 2 +- tools/testing/selftests/kvm/lib/x86_64/ucall.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/aarch64/ucall.c b/tools/testing/selftests/kvm/lib/aarch64/ucall.c index e0b0164e9af8..00be3ef195ca 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/ucall.c +++ b/tools/testing/selftests/kvm/lib/aarch64/ucall.c @@ -52,7 +52,7 @@ void ucall_init(struct kvm_vm *vm, void *arg) * lower and won't match physical addresses. */ bits = vm->va_bits - 1; - bits = vm->pa_bits < bits ? vm->pa_bits : bits; + bits = min(vm->pa_bits, bits); end = 1ul << bits; start = end * 5 / 8; step = end / 16; @@ -79,7 +79,7 @@ void ucall(uint64_t cmd, int nargs, ...) va_list va; int i; - nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS; + nargs = min(nargs, UCALL_MAX_ARGS); va_start(va, nargs); for (i = 0; i < nargs; ++i) diff --git a/tools/testing/selftests/kvm/lib/riscv/ucall.c b/tools/testing/selftests/kvm/lib/riscv/ucall.c index 8550f424d093..c2ed59f5783d 100644 --- a/tools/testing/selftests/kvm/lib/riscv/ucall.c +++ b/tools/testing/selftests/kvm/lib/riscv/ucall.c @@ -53,7 +53,7 @@ void ucall(uint64_t cmd, int nargs, ...) va_list va; int i; - nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS; + nargs = min(nargs, UCALL_MAX_ARGS); va_start(va, nargs); for (i = 0; i < nargs; ++i) diff --git a/tools/testing/selftests/kvm/lib/s390x/ucall.c b/tools/testing/selftests/kvm/lib/s390x/ucall.c index 9d3b0f15249a..665267c1135d 100644 --- a/tools/testing/selftests/kvm/lib/s390x/ucall.c +++ b/tools/testing/selftests/kvm/lib/s390x/ucall.c @@ -22,7 +22,7 @@ void ucall(uint64_t cmd, int nargs, ...) va_list va; int i; - nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS; + nargs = min(nargs, UCALL_MAX_ARGS); va_start(va, nargs); for (i = 0; i < nargs; ++i) diff --git a/tools/testing/selftests/kvm/lib/x86_64/ucall.c b/tools/testing/selftests/kvm/lib/x86_64/ucall.c index a3489973e290..2ea31a0ebe30 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/ucall.c +++ b/tools/testing/selftests/kvm/lib/x86_64/ucall.c @@ -24,7 +24,7 @@ void ucall(uint64_t cmd, int nargs, ...) va_list va; int i; - nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS; + nargs = min(nargs, UCALL_MAX_ARGS); va_start(va, nargs); for (i = 0; i < nargs; ++i) From 43d62d108af87e683ebe41ffd76ac60594544de3 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Thu, 19 May 2022 01:01:16 +0800 Subject: [PATCH 0149/1436] KVM: x86/pmu: Move the vmx_icl_pebs_cpu[] definition out of the header file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Defining a static const array in a header file would introduce redundant definitions to the point of confusing semantics, and such a use case would only bring complaints from the compiler: arch/x86/kvm/pmu.h:20:32: warning: ‘vmx_icl_pebs_cpu’ defined but not used [-Wunused-const-variable=] 20 | static const struct x86_cpu_id vmx_icl_pebs_cpu[] = { | ^~~~~~~~~~~~~~~~ Fixes: a095df2c5f48 ("KVM: x86/pmu: Adjust precise_ip to emulate Ice Lake guest PDIR counter") Signed-off-by: Like Xu Message-Id: <20220518170118.66263-1-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 7 +++++++ arch/x86/kvm/pmu.h | 8 -------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index a8f0618a5ebe..1ed63ea19c00 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "x86.h" #include "cpuid.h" #include "lapic.h" @@ -27,6 +28,12 @@ struct x86_pmu_capability __read_mostly kvm_pmu_cap; EXPORT_SYMBOL_GPL(kvm_pmu_cap); +static const struct x86_cpu_id vmx_icl_pebs_cpu[] = { + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL), + X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL), + {} +}; + /* NOTE: * - Each perf counter is defined as "struct kvm_pmc"; * - There are two types of perf counters: general purpose (gp) and fixed. diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 9e25cdd2bd1a..796ff839493b 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -4,8 +4,6 @@ #include -#include - #define vcpu_to_pmu(vcpu) (&(vcpu)->arch.pmu) #define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu)) #define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu) @@ -17,12 +15,6 @@ #define VMWARE_BACKDOOR_PMC_REAL_TIME 0x10001 #define VMWARE_BACKDOOR_PMC_APPARENT_TIME 0x10002 -static const struct x86_cpu_id vmx_icl_pebs_cpu[] = { - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL), - X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL), - {} -}; - struct kvm_event_hw_type_mapping { u8 eventsel; u8 unit_mask; From ec4036edf924f741bc717d9afa25053cf63fa218 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 20 May 2022 08:00:05 -0400 Subject: [PATCH 0150/1436] KVM: x86/pmu: remove useless prototype Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 796ff839493b..f7bd4de14c92 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -191,7 +191,6 @@ void kvm_pmu_cleanup(struct kvm_vcpu *vcpu); void kvm_pmu_destroy(struct kvm_vcpu *vcpu); int kvm_vm_ioctl_set_pmu_event_filter(struct kvm *kvm, void __user *argp); void kvm_pmu_trigger_event(struct kvm_vcpu *vcpu, u64 perf_hw_id); -void kvm_init_pmu_capability(void); bool is_vmware_backdoor_pmc(u32 pmc_idx); From c49467a45fe013ad7a892bf1479b1438315058f3 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Tue, 10 May 2022 12:44:07 +0800 Subject: [PATCH 0151/1436] KVM: x86/pmu: Don't overwrite the pmu->global_ctrl when refreshing Assigning a value to pmu->global_ctrl just to set the value of pmu->global_ctrl_mask is more readable but does not conform to the specification. The value is reset to zero on Power up and Reset but stays unchanged on INIT, like most other MSRs. Signed-off-by: Like Xu Message-Id: <20220510044407.26445-1-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/pmu_intel.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index ca219a54a53e..1c6f2ca2beac 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -508,6 +508,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) struct kvm_cpuid_entry2 *entry; union cpuid10_eax eax; union cpuid10_edx edx; + u64 counter_mask; int i; pmu->nr_arch_gp_counters = 0; @@ -559,9 +560,9 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) for (i = 0; i < pmu->nr_arch_fixed_counters; i++) pmu->fixed_ctr_ctrl_mask &= ~(0xbull << (i * 4)); - pmu->global_ctrl = ((1ull << pmu->nr_arch_gp_counters) - 1) | - (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED); - pmu->global_ctrl_mask = ~pmu->global_ctrl; + counter_mask = ~(((1ull << pmu->nr_arch_gp_counters) - 1) | + (((1ull << pmu->nr_arch_fixed_counters) - 1) << INTEL_PMC_IDX_FIXED)); + pmu->global_ctrl_mask = counter_mask; pmu->global_ovf_ctrl_mask = pmu->global_ctrl_mask & ~(MSR_CORE_PERF_GLOBAL_OVF_CTRL_OVF_BUF | MSR_CORE_PERF_GLOBAL_OVF_CTRL_COND_CHGD); @@ -596,7 +597,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) if (vcpu->arch.perf_capabilities & PERF_CAP_PEBS_FORMAT) { vcpu->arch.ia32_misc_enable_msr &= ~MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL; if (vcpu->arch.perf_capabilities & PERF_CAP_PEBS_BASELINE) { - pmu->pebs_enable_mask = ~pmu->global_ctrl; + pmu->pebs_enable_mask = counter_mask; pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE; for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { pmu->fixed_ctr_ctrl_mask &= From 98defd2e17803263f49548fea930cfc974d505aa Mon Sep 17 00:00:00 2001 From: Like Xu Date: Mon, 9 May 2022 18:22:02 +0800 Subject: [PATCH 0152/1436] KVM: x86/pmu: Ignore pmu->global_ctrl check if vPMU doesn't support global_ctrl MSR_CORE_PERF_GLOBAL_CTRL is introduced as part of Architecture PMU V2, as indicated by Intel SDM 19.2.2 and the intel_is_valid_msr() function. So in the absence of global_ctrl support, all PMCs are enabled as AMD does. Signed-off-by: Like Xu Message-Id: <20220509102204.62389-1-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/pmu_intel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 1c6f2ca2beac..2fc90080dcce 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -98,6 +98,9 @@ static bool intel_pmc_is_enabled(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); + if (pmu->version < 2) + return true; + return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl); } From bfb088d9fb5abdd3fbf00bae9abdfee8b92265aa Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 1 Jun 2022 03:21:19 -0400 Subject: [PATCH 0153/1436] KVM: vmx, pmu: accept 0 for host-initiated write to MSR_IA32_DS_AREA Whenever an MSR is part of KVM_GET_MSR_INDEX_LIST, as is the case for MSR_IA32_DS_AREA, it has to be always settable with KVM_SET_MSR. Accept a zero value for these MSRs to obey the contract. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/pmu_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 2fc90080dcce..5bc7cfc753fc 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -443,6 +443,8 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) } break; case MSR_IA32_DS_AREA: + if (msr_info->host_initiated && data && !guest_cpuid_has(vcpu, X86_FEATURE_DS)) + return 1; if (is_noncanonical_address(data, vcpu)) return 1; pmu->ds_area = data; From d1c88a4020567ba4da52f778bcd9619d87e4ea75 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 25 May 2022 04:39:22 -0400 Subject: [PATCH 0154/1436] KVM: x86: always allow host-initiated writes to PMU MSRs Whenever an MSR is part of KVM_GET_MSR_INDEX_LIST, it has to be always retrievable and settable with KVM_GET_MSR and KVM_SET_MSR. Accept the PMU MSRs unconditionally in intel_is_valid_msr, if the access was host-initiated. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 4 ++-- arch/x86/kvm/pmu.h | 4 ++-- arch/x86/kvm/svm/pmu.c | 2 +- arch/x86/kvm/vmx/pmu_intel.c | 27 +++++++++++++++++---------- arch/x86/kvm/x86.c | 10 +++++----- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 1ed63ea19c00..d2320d1aeb9f 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -458,10 +458,10 @@ void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu) } } -bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) +bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated) { return static_call(kvm_x86_pmu_msr_idx_to_pmc)(vcpu, msr) || - static_call(kvm_x86_pmu_is_valid_msr)(vcpu, msr); + static_call(kvm_x86_pmu_is_valid_msr)(vcpu, msr, host_initiated); } static void kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u32 msr) diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index f7bd4de14c92..1398297ae6dc 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -29,7 +29,7 @@ struct kvm_pmu_ops { unsigned int idx, u64 *mask); struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, u32 msr); bool (*is_valid_rdpmc_ecx)(struct kvm_vcpu *vcpu, unsigned int idx); - bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr); + bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated); int (*get_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info); int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info); void (*refresh)(struct kvm_vcpu *vcpu); @@ -181,7 +181,7 @@ void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu); void kvm_pmu_handle_event(struct kvm_vcpu *vcpu); int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data); bool kvm_pmu_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx); -bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr); +bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated); int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); void kvm_pmu_refresh(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 136039fc6d01..0e5784371ac0 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -229,7 +229,7 @@ static struct kvm_pmc *amd_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, return &counters[idx]; } -static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) +static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated) { /* All MSRs refer to exactly one PMC, so msr_idx_to_pmc is enough. */ return false; diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 5bc7cfc753fc..8eca1321af7e 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -195,38 +195,45 @@ static bool intel_pmu_is_valid_lbr_msr(struct kvm_vcpu *vcpu, u32 index) return ret; } -static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) +static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); u64 perf_capabilities = vcpu->arch.perf_capabilities; - int ret; switch (msr) { case MSR_CORE_PERF_FIXED_CTR_CTRL: case MSR_CORE_PERF_GLOBAL_STATUS: case MSR_CORE_PERF_GLOBAL_CTRL: case MSR_CORE_PERF_GLOBAL_OVF_CTRL: - ret = pmu->version > 1; + if (host_initiated) + return true; + return pmu->version > 1; break; case MSR_IA32_PEBS_ENABLE: - ret = perf_capabilities & PERF_CAP_PEBS_FORMAT; + if (host_initiated) + return true; + return perf_capabilities & PERF_CAP_PEBS_FORMAT; break; case MSR_IA32_DS_AREA: - ret = guest_cpuid_has(vcpu, X86_FEATURE_DS); + if (host_initiated) + return true; + return guest_cpuid_has(vcpu, X86_FEATURE_DS); break; case MSR_PEBS_DATA_CFG: - ret = (perf_capabilities & PERF_CAP_PEBS_BASELINE) && + if (host_initiated) + return true; + return (perf_capabilities & PERF_CAP_PEBS_BASELINE) && ((perf_capabilities & PERF_CAP_PEBS_FORMAT) > 3); break; default: - ret = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0) || + if (host_initiated) + return true; + return get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0) || get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0) || get_fixed_pmc(pmu, msr) || get_fw_gp_pmc(pmu, msr) || intel_pmu_is_valid_lbr_msr(vcpu, msr); break; } - - return ret; } static struct kvm_pmc *intel_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr) @@ -589,7 +596,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) INTEL_PMC_MAX_GENERIC, pmu->nr_arch_fixed_counters); nested_vmx_pmu_refresh(vcpu, - intel_is_valid_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL)); + intel_is_valid_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL, false)); if (cpuid_model_is_consistent(vcpu)) x86_perf_get_lbr(&lbr_desc->records); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 32218fac4504..c8dfdef9e52f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3719,7 +3719,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) fallthrough; case MSR_K7_EVNTSEL0 ... MSR_K7_EVNTSEL3: case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL1: - if (kvm_pmu_is_valid_msr(vcpu, msr)) + if (kvm_pmu_is_valid_msr(vcpu, msr, msr_info->host_initiated)) return kvm_pmu_set_msr(vcpu, msr_info); if (pr || data != 0) @@ -3802,7 +3802,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; #endif default: - if (kvm_pmu_is_valid_msr(vcpu, msr)) + if (kvm_pmu_is_valid_msr(vcpu, msr, msr_info->host_initiated)) return kvm_pmu_set_msr(vcpu, msr_info); return KVM_MSR_RET_INVALID; } @@ -3882,7 +3882,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = 0; break; case MSR_F15H_PERF_CTL0 ... MSR_F15H_PERF_CTR5: - if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) + if (kvm_pmu_is_valid_msr(vcpu, msr_info->index, msr_info->host_initiated)) return kvm_pmu_get_msr(vcpu, msr_info); if (!msr_info->host_initiated) return 1; @@ -3892,7 +3892,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3: case MSR_P6_PERFCTR0 ... MSR_P6_PERFCTR1: case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL1: - if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) + if (kvm_pmu_is_valid_msr(vcpu, msr_info->index, msr_info->host_initiated)) return kvm_pmu_get_msr(vcpu, msr_info); msr_info->data = 0; break; @@ -4138,7 +4138,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; #endif default: - if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) + if (kvm_pmu_is_valid_msr(vcpu, msr_info->index, msr_info->host_initiated)) return kvm_pmu_get_msr(vcpu, msr_info); return KVM_MSR_RET_INVALID; } From a33095f4937b362306f8636742450cff1c4630af Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 18 May 2022 21:25:02 +0800 Subject: [PATCH 0155/1436] KVM: x86/pmu: Update comments for AMD gp counters The obsolete comment could more accurately state that AMD platforms have two base MSR addresses and two different maximum numbers for gp counters, depending on the X86_FEATURE_PERFCTR_CORE feature. Signed-off-by: Like Xu Message-Id: <20220518132512.37864-2-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index d2320d1aeb9f..72512a33a04e 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -44,7 +44,9 @@ static const struct x86_cpu_id vmx_icl_pebs_cpu[] = { * However AMD doesn't support fixed-counters; * - There are three types of index to access perf counters (PMC): * 1. MSR (named msr): For example Intel has MSR_IA32_PERFCTRn and AMD - * has MSR_K7_PERFCTRn. + * has MSR_K7_PERFCTRn and, for families 15H and later, + * MSR_F15H_PERF_CTRn, where MSR_F15H_PERF_CTR[0-3] are + * aliased to MSR_K7_PERFCTRn. * 2. MSR Index (named idx): This normally is used by RDPMC instruction. * For instance AMD RDPMC instruction uses 0000_0003h in ECX to access * C001_0007h (MSR_K7_PERCTR3). Intel has a similar mechanism, except @@ -56,7 +58,8 @@ static const struct x86_cpu_id vmx_icl_pebs_cpu[] = { * between pmc and perf counters is as the following: * * Intel: [0 .. INTEL_PMC_MAX_GENERIC-1] <=> gp counters * [INTEL_PMC_IDX_FIXED .. INTEL_PMC_IDX_FIXED + 2] <=> fixed - * * AMD: [0 .. AMD64_NUM_COUNTERS-1] <=> gp counters + * * AMD: [0 .. AMD64_NUM_COUNTERS-1] and, for families 15H + * and later, [0 .. AMD64_NUM_COUNTERS_CORE-1] <=> gp counters */ static struct kvm_pmu_ops kvm_pmu_ops __read_mostly; From 89cb454ea984d0411523dc10e70e9bf0aca1b527 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 18 May 2022 21:25:03 +0800 Subject: [PATCH 0156/1436] KVM: x86/pmu: Extract check_pmu_event_filter() handling both GP and fixed counters Checking the kvm->arch.pmu_event_filter policy in both gp and fixed code paths was somewhat redundant, so common parts can be extracted, which reduces code footprint and improves readability. Signed-off-by: Like Xu Reviewed-by: Wanpeng Li Message-Id: <20220518132512.37864-3-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 63 +++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 72512a33a04e..ee6b2895faed 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -250,14 +250,44 @@ static int cmp_u64(const void *pa, const void *pb) return (a > b) - (a < b); } +static bool check_pmu_event_filter(struct kvm_pmc *pmc) +{ + struct kvm_pmu_event_filter *filter; + struct kvm *kvm = pmc->vcpu->kvm; + bool allow_event = true; + __u64 key; + int idx; + + filter = srcu_dereference(kvm->arch.pmu_event_filter, &kvm->srcu); + if (!filter) + goto out; + + if (pmc_is_gp(pmc)) { + key = pmc->eventsel & AMD64_RAW_EVENT_MASK_NB; + if (bsearch(&key, filter->events, filter->nevents, + sizeof(__u64), cmp_u64)) + allow_event = filter->action == KVM_PMU_EVENT_ALLOW; + else + allow_event = filter->action == KVM_PMU_EVENT_DENY; + } else { + idx = pmc->idx - INTEL_PMC_IDX_FIXED; + if (filter->action == KVM_PMU_EVENT_DENY && + test_bit(idx, (ulong *)&filter->fixed_counter_bitmap)) + allow_event = false; + if (filter->action == KVM_PMU_EVENT_ALLOW && + !test_bit(idx, (ulong *)&filter->fixed_counter_bitmap)) + allow_event = false; + } + +out: + return allow_event; +} + void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel) { u64 config; u32 type = PERF_TYPE_RAW; - struct kvm *kvm = pmc->vcpu->kvm; - struct kvm_pmu_event_filter *filter; - struct kvm_pmu *pmu = vcpu_to_pmu(pmc->vcpu); - bool allow_event = true; + struct kvm_pmu *pmu = pmc_to_pmu(pmc); if (eventsel & ARCH_PERFMON_EVENTSEL_PIN_CONTROL) printk_once("kvm pmu: pin control bit is ignored\n"); @@ -269,17 +299,7 @@ void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel) if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE) || !pmc_is_enabled(pmc)) return; - filter = srcu_dereference(kvm->arch.pmu_event_filter, &kvm->srcu); - if (filter) { - __u64 key = eventsel & AMD64_RAW_EVENT_MASK_NB; - - if (bsearch(&key, filter->events, filter->nevents, - sizeof(__u64), cmp_u64)) - allow_event = filter->action == KVM_PMU_EVENT_ALLOW; - else - allow_event = filter->action == KVM_PMU_EVENT_DENY; - } - if (!allow_event) + if (!check_pmu_event_filter(pmc)) return; if (!(eventsel & (ARCH_PERFMON_EVENTSEL_EDGE | @@ -312,23 +332,14 @@ void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int idx) { unsigned en_field = ctrl & 0x3; bool pmi = ctrl & 0x8; - struct kvm_pmu_event_filter *filter; - struct kvm *kvm = pmc->vcpu->kvm; pmc_pause_counter(pmc); if (!en_field || !pmc_is_enabled(pmc)) return; - filter = srcu_dereference(kvm->arch.pmu_event_filter, &kvm->srcu); - if (filter) { - if (filter->action == KVM_PMU_EVENT_DENY && - test_bit(idx, (ulong *)&filter->fixed_counter_bitmap)) - return; - if (filter->action == KVM_PMU_EVENT_ALLOW && - !test_bit(idx, (ulong *)&filter->fixed_counter_bitmap)) - return; - } + if (!check_pmu_event_filter(pmc)) + return; if (pmc->current_config == (u64)ctrl && pmc_resume_counter(pmc)) return; From a40239b4cf33b2de872b04759c3e5ab87cc72a7f Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 18 May 2022 21:25:05 +0800 Subject: [PATCH 0157/1436] KVM: x86/pmu: Pass only "struct kvm_pmc *pmc" to reprogram_counter() Passing the reference "struct kvm_pmc *pmc" when creating pmc->perf_event is sufficient. This change helps to simplify the calling convention by replacing reprogram_{gp, fixed}_counter() with reprogram_counter() seamlessly. No functional change intended. Signed-off-by: Like Xu Message-Id: <20220518132512.37864-5-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 17 +++++------------ arch/x86/kvm/pmu.h | 2 +- arch/x86/kvm/vmx/pmu_intel.c | 32 ++++++++++++++++++-------------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index ee6b2895faed..817352d83ff4 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -355,18 +355,13 @@ void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int idx) } EXPORT_SYMBOL_GPL(reprogram_fixed_counter); -void reprogram_counter(struct kvm_pmu *pmu, int pmc_idx) +void reprogram_counter(struct kvm_pmc *pmc) { - struct kvm_pmc *pmc = static_call(kvm_x86_pmu_pmc_idx_to_pmc)(pmu, pmc_idx); - - if (!pmc) - return; - if (pmc_is_gp(pmc)) reprogram_gp_counter(pmc, pmc->eventsel); else { - int idx = pmc_idx - INTEL_PMC_IDX_FIXED; - u8 ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, idx); + int idx = pmc->idx - INTEL_PMC_IDX_FIXED; + u8 ctrl = fixed_ctrl_field(pmc_to_pmu(pmc)->fixed_ctr_ctrl, idx); reprogram_fixed_counter(pmc, ctrl, idx); } @@ -385,8 +380,7 @@ void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) clear_bit(bit, pmu->reprogram_pmi); continue; } - - reprogram_counter(pmu, bit); + reprogram_counter(pmc); } /* @@ -559,13 +553,12 @@ void kvm_pmu_destroy(struct kvm_vcpu *vcpu) static void kvm_pmu_incr_counter(struct kvm_pmc *pmc) { - struct kvm_pmu *pmu = pmc_to_pmu(pmc); u64 prev_count; prev_count = pmc->counter; pmc->counter = (pmc->counter + 1) & pmc_bitmask(pmc); - reprogram_counter(pmu, pmc->idx); + reprogram_counter(pmc); if (pmc->counter < prev_count) __kvm_perf_overflow(pmc, false); } diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 1398297ae6dc..1dd6be22cdb2 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -175,7 +175,7 @@ static inline void kvm_init_pmu_capability(void) void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel); void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int fixed_idx); -void reprogram_counter(struct kvm_pmu *pmu, int pmc_idx); +void reprogram_counter(struct kvm_pmc *pmc); void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu); void kvm_pmu_handle_event(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 8eca1321af7e..719ae6c62a5a 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -56,16 +56,32 @@ static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) pmu->fixed_ctr_ctrl = data; } +static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) +{ + if (pmc_idx < INTEL_PMC_IDX_FIXED) { + return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + pmc_idx, + MSR_P6_EVNTSEL0); + } else { + u32 idx = pmc_idx - INTEL_PMC_IDX_FIXED; + + return get_fixed_pmc(pmu, idx + MSR_CORE_PERF_FIXED_CTR0); + } +} + /* function is called when global control register has been updated. */ static void global_ctrl_changed(struct kvm_pmu *pmu, u64 data) { int bit; u64 diff = pmu->global_ctrl ^ data; + struct kvm_pmc *pmc; pmu->global_ctrl = data; - for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) - reprogram_counter(pmu, bit); + for_each_set_bit(bit, (unsigned long *)&diff, X86_PMC_IDX_MAX) { + pmc = intel_pmc_idx_to_pmc(pmu, bit); + if (pmc) + reprogram_counter(pmc); + } } static unsigned int intel_pmc_perf_hw_id(struct kvm_pmc *pmc) @@ -104,18 +120,6 @@ static bool intel_pmc_is_enabled(struct kvm_pmc *pmc) return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl); } -static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) -{ - if (pmc_idx < INTEL_PMC_IDX_FIXED) - return get_gp_pmc(pmu, MSR_P6_EVNTSEL0 + pmc_idx, - MSR_P6_EVNTSEL0); - else { - u32 idx = pmc_idx - INTEL_PMC_IDX_FIXED; - - return get_fixed_pmc(pmu, idx + MSR_CORE_PERF_FIXED_CTR0); - } -} - static bool intel_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); From fb121aaf19cd5047a01599debbb85a2c15275727 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 18 May 2022 21:25:06 +0800 Subject: [PATCH 0158/1436] KVM: x86/pmu: Drop "u64 eventsel" for reprogram_gp_counter() Because inside reprogram_gp_counter() it is bound to assign the requested eventel to pmc->eventsel, this assignment step can be moved forward, thus simplifying the passing of parameters to "struct kvm_pmc *pmc" only. No functional change intended. Signed-off-by: Like Xu Message-Id: <20220518132512.37864-6-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 7 +++---- arch/x86/kvm/pmu.h | 2 +- arch/x86/kvm/svm/pmu.c | 6 ++++-- arch/x86/kvm/vmx/pmu_intel.c | 3 ++- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 817352d83ff4..b001471fbf82 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -283,17 +283,16 @@ out: return allow_event; } -void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel) +void reprogram_gp_counter(struct kvm_pmc *pmc) { u64 config; u32 type = PERF_TYPE_RAW; struct kvm_pmu *pmu = pmc_to_pmu(pmc); + u64 eventsel = pmc->eventsel; if (eventsel & ARCH_PERFMON_EVENTSEL_PIN_CONTROL) printk_once("kvm pmu: pin control bit is ignored\n"); - pmc->eventsel = eventsel; - pmc_pause_counter(pmc); if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE) || !pmc_is_enabled(pmc)) @@ -358,7 +357,7 @@ EXPORT_SYMBOL_GPL(reprogram_fixed_counter); void reprogram_counter(struct kvm_pmc *pmc) { if (pmc_is_gp(pmc)) - reprogram_gp_counter(pmc, pmc->eventsel); + reprogram_gp_counter(pmc); else { int idx = pmc->idx - INTEL_PMC_IDX_FIXED; u8 ctrl = fixed_ctrl_field(pmc_to_pmu(pmc)->fixed_ctr_ctrl, idx); diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 1dd6be22cdb2..b9a76dd98242 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -173,7 +173,7 @@ static inline void kvm_init_pmu_capability(void) KVM_PMC_MAX_FIXED); } -void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel); +void reprogram_gp_counter(struct kvm_pmc *pmc); void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int fixed_idx); void reprogram_counter(struct kvm_pmc *pmc); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 0e5784371ac0..a1fbb72d6fbb 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -286,8 +286,10 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) pmc = get_gp_pmc_amd(pmu, msr, PMU_TYPE_EVNTSEL); if (pmc) { data &= ~pmu->reserved_bits; - if (data != pmc->eventsel) - reprogram_gp_counter(pmc, data); + if (data != pmc->eventsel) { + pmc->eventsel = data; + reprogram_gp_counter(pmc); + } return 0; } diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 719ae6c62a5a..61e14a5a247d 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -492,7 +492,8 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) (pmu->raw_event_mask & HSW_IN_TX_CHECKPOINTED)) reserved_bits ^= HSW_IN_TX_CHECKPOINTED; if (!(data & reserved_bits)) { - reprogram_gp_counter(pmc, data); + pmc->eventsel = data; + reprogram_gp_counter(pmc); return 0; } } else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, false)) From 76d287b2342e1906e399fd19d6500013aa074a50 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 18 May 2022 21:25:07 +0800 Subject: [PATCH 0159/1436] KVM: x86/pmu: Drop "u8 ctrl, int idx" for reprogram_fixed_counter() Since afrer reprogram_fixed_counter() is called, it's bound to assign the requested fixed_ctr_ctrl to pmu->fixed_ctr_ctrl, this assignment step can be moved forward (the stale value for diff is saved extra early), thus simplifying the passing of parameters. No functional change intended. Signed-off-by: Like Xu Message-Id: <20220518132512.37864-7-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 13 ++++++------- arch/x86/kvm/pmu.h | 2 +- arch/x86/kvm/vmx/pmu_intel.c | 16 ++++++++-------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index b001471fbf82..4c354298e516 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -327,8 +327,11 @@ void reprogram_gp_counter(struct kvm_pmc *pmc) } EXPORT_SYMBOL_GPL(reprogram_gp_counter); -void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int idx) +void reprogram_fixed_counter(struct kvm_pmc *pmc) { + struct kvm_pmu *pmu = pmc_to_pmu(pmc); + int idx = pmc->idx - INTEL_PMC_IDX_FIXED; + u8 ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, idx); unsigned en_field = ctrl & 0x3; bool pmi = ctrl & 0x8; @@ -358,12 +361,8 @@ void reprogram_counter(struct kvm_pmc *pmc) { if (pmc_is_gp(pmc)) reprogram_gp_counter(pmc); - else { - int idx = pmc->idx - INTEL_PMC_IDX_FIXED; - u8 ctrl = fixed_ctrl_field(pmc_to_pmu(pmc)->fixed_ctr_ctrl, idx); - - reprogram_fixed_counter(pmc, ctrl, idx); - } + else + reprogram_fixed_counter(pmc); } EXPORT_SYMBOL_GPL(reprogram_counter); diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index b9a76dd98242..fe31bbd1f906 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -174,7 +174,7 @@ static inline void kvm_init_pmu_capability(void) } void reprogram_gp_counter(struct kvm_pmc *pmc); -void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int fixed_idx); +void reprogram_fixed_counter(struct kvm_pmc *pmc); void reprogram_counter(struct kvm_pmc *pmc); void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 61e14a5a247d..13d54c5fd12b 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -37,23 +37,23 @@ static int fixed_pmc_events[] = {1, 0, 7}; static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) { + struct kvm_pmc *pmc; + u8 old_fixed_ctr_ctrl = pmu->fixed_ctr_ctrl; int i; + pmu->fixed_ctr_ctrl = data; for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { u8 new_ctrl = fixed_ctrl_field(data, i); - u8 old_ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, i); - struct kvm_pmc *pmc; - - pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i); + u8 old_ctrl = fixed_ctrl_field(old_fixed_ctr_ctrl, i); if (old_ctrl == new_ctrl) continue; - __set_bit(INTEL_PMC_IDX_FIXED + i, pmu->pmc_in_use); - reprogram_fixed_counter(pmc, new_ctrl, i); - } + pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i); - pmu->fixed_ctr_ctrl = data; + __set_bit(INTEL_PMC_IDX_FIXED + i, pmu->pmc_in_use); + reprogram_fixed_counter(pmc); + } } static struct kvm_pmc *intel_pmc_idx_to_pmc(struct kvm_pmu *pmu, int pmc_idx) From e99fae6edebcdf53658f531ee3c913ca74536355 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 25 May 2022 05:28:56 -0400 Subject: [PATCH 0160/1436] KVM: x86/pmu: Use only the uniform interface reprogram_counter() Since reprogram_counter(), reprogram_{gp, fixed}_counter() currently have the same incoming parameter "struct kvm_pmc *pmc", the callers can simplify the conetxt by using uniformly exported interface, which makes reprogram_ {gp, fixed}_counter() static and eliminates EXPORT_SYMBOL_GPL. Signed-off-by: Like Xu Message-Id: <20220518132512.37864-8-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 6 ++---- arch/x86/kvm/pmu.h | 2 -- arch/x86/kvm/svm/pmu.c | 2 +- arch/x86/kvm/vmx/pmu_intel.c | 4 ++-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 4c354298e516..d2a0581d9d4d 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -283,7 +283,7 @@ out: return allow_event; } -void reprogram_gp_counter(struct kvm_pmc *pmc) +static void reprogram_gp_counter(struct kvm_pmc *pmc) { u64 config; u32 type = PERF_TYPE_RAW; @@ -325,9 +325,8 @@ void reprogram_gp_counter(struct kvm_pmc *pmc) !(eventsel & ARCH_PERFMON_EVENTSEL_OS), eventsel & ARCH_PERFMON_EVENTSEL_INT); } -EXPORT_SYMBOL_GPL(reprogram_gp_counter); -void reprogram_fixed_counter(struct kvm_pmc *pmc) +static void reprogram_fixed_counter(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); int idx = pmc->idx - INTEL_PMC_IDX_FIXED; @@ -355,7 +354,6 @@ void reprogram_fixed_counter(struct kvm_pmc *pmc) !(en_field & 0x1), /* exclude kernel */ pmi); } -EXPORT_SYMBOL_GPL(reprogram_fixed_counter); void reprogram_counter(struct kvm_pmc *pmc) { diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index fe31bbd1f906..60faf27678d9 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -173,8 +173,6 @@ static inline void kvm_init_pmu_capability(void) KVM_PMC_MAX_FIXED); } -void reprogram_gp_counter(struct kvm_pmc *pmc); -void reprogram_fixed_counter(struct kvm_pmc *pmc); void reprogram_counter(struct kvm_pmc *pmc); void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index a1fbb72d6fbb..79346def7c96 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -288,7 +288,7 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) data &= ~pmu->reserved_bits; if (data != pmc->eventsel) { pmc->eventsel = data; - reprogram_gp_counter(pmc); + reprogram_counter(pmc); } return 0; } diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 13d54c5fd12b..0dc270e6717c 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -52,7 +52,7 @@ static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i); __set_bit(INTEL_PMC_IDX_FIXED + i, pmu->pmc_in_use); - reprogram_fixed_counter(pmc); + reprogram_counter(pmc); } } @@ -493,7 +493,7 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) reserved_bits ^= HSW_IN_TX_CHECKPOINTED; if (!(data & reserved_bits)) { pmc->eventsel = data; - reprogram_gp_counter(pmc); + reprogram_counter(pmc); return 0; } } else if (intel_pmu_handle_lbr_msrs_access(vcpu, msr_info, false)) From 02791a5c362b7d71447efb1d0131d8368bb821f2 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 18 May 2022 21:25:09 +0800 Subject: [PATCH 0161/1436] KVM: x86/pmu: Use PERF_TYPE_RAW to merge reprogram_{gp,fixed}counter() The code sketch for reprogram_{gp, fixed}_counter() is similar, while the fixed counter using the PERF_TYPE_HARDWAR type and the gp being able to use either PERF_TYPE_HARDWAR or PERF_TYPE_RAW type depending on the pmc->eventsel value. After 'commit 761875634a5e ("KVM: x86/pmu: Setup pmc->eventsel for fixed PMCs")', the pmc->eventsel of the fixed counter will also have been setup with the same semantic value and will not be changed during the guest runtime. The original story of using the PERF_TYPE_HARDWARE type is to emulate guest architecture PMU on a host without architecture PMU (the Pentium 4), for which the guest vPMC needs to be reprogrammed using the kernel generic perf_hw_id. But essentially, "the HARDWARE is just a convenience wrapper over RAW IIRC", quoated from Peterz. So it could be pretty safe to use the PERF_TYPE_RAW type only in practice to program both gp and fixed counters naturally in the reprogram_counter(). To make the gp and fixed counters more semantically symmetrical, the selection of EVENTSEL_{USER, OS, INT} bits is temporarily translated via fixed_ctr_ctrl before the pmc_reprogram_counter() call. Cc: Peter Zijlstra Suggested-by: Jim Mattson Signed-off-by: Like Xu Message-Id: <20220518132512.37864-9-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 87 +++++++++++++--------------------------------- 1 file changed, 25 insertions(+), 62 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index d2a0581d9d4d..b46a96604fe6 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -283,85 +283,48 @@ out: return allow_event; } -static void reprogram_gp_counter(struct kvm_pmc *pmc) +void reprogram_counter(struct kvm_pmc *pmc) { - u64 config; - u32 type = PERF_TYPE_RAW; struct kvm_pmu *pmu = pmc_to_pmu(pmc); u64 eventsel = pmc->eventsel; + u64 new_config = eventsel; + u8 fixed_ctr_ctrl; + + pmc_pause_counter(pmc); + + if (!pmc_speculative_in_use(pmc) || !pmc_is_enabled(pmc)) + return; + + if (!check_pmu_event_filter(pmc)) + return; if (eventsel & ARCH_PERFMON_EVENTSEL_PIN_CONTROL) printk_once("kvm pmu: pin control bit is ignored\n"); - pmc_pause_counter(pmc); - - if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE) || !pmc_is_enabled(pmc)) - return; - - if (!check_pmu_event_filter(pmc)) - return; - - if (!(eventsel & (ARCH_PERFMON_EVENTSEL_EDGE | - ARCH_PERFMON_EVENTSEL_INV | - ARCH_PERFMON_EVENTSEL_CMASK | - HSW_IN_TX | - HSW_IN_TX_CHECKPOINTED))) { - config = static_call(kvm_x86_pmu_pmc_perf_hw_id)(pmc); - if (config != PERF_COUNT_HW_MAX) - type = PERF_TYPE_HARDWARE; + if (pmc_is_fixed(pmc)) { + fixed_ctr_ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, + pmc->idx - INTEL_PMC_IDX_FIXED); + if (fixed_ctr_ctrl & 0x1) + eventsel |= ARCH_PERFMON_EVENTSEL_OS; + if (fixed_ctr_ctrl & 0x2) + eventsel |= ARCH_PERFMON_EVENTSEL_USR; + if (fixed_ctr_ctrl & 0x8) + eventsel |= ARCH_PERFMON_EVENTSEL_INT; + new_config = (u64)fixed_ctr_ctrl; } - if (type == PERF_TYPE_RAW) - config = eventsel & pmu->raw_event_mask; - - if (pmc->current_config == eventsel && pmc_resume_counter(pmc)) + if (pmc->current_config == new_config && pmc_resume_counter(pmc)) return; pmc_release_perf_event(pmc); - pmc->current_config = eventsel; - pmc_reprogram_counter(pmc, type, config, + pmc->current_config = new_config; + pmc_reprogram_counter(pmc, PERF_TYPE_RAW, + (eventsel & pmu->raw_event_mask), !(eventsel & ARCH_PERFMON_EVENTSEL_USR), !(eventsel & ARCH_PERFMON_EVENTSEL_OS), eventsel & ARCH_PERFMON_EVENTSEL_INT); } - -static void reprogram_fixed_counter(struct kvm_pmc *pmc) -{ - struct kvm_pmu *pmu = pmc_to_pmu(pmc); - int idx = pmc->idx - INTEL_PMC_IDX_FIXED; - u8 ctrl = fixed_ctrl_field(pmu->fixed_ctr_ctrl, idx); - unsigned en_field = ctrl & 0x3; - bool pmi = ctrl & 0x8; - - pmc_pause_counter(pmc); - - if (!en_field || !pmc_is_enabled(pmc)) - return; - - if (!check_pmu_event_filter(pmc)) - return; - - if (pmc->current_config == (u64)ctrl && pmc_resume_counter(pmc)) - return; - - pmc_release_perf_event(pmc); - - pmc->current_config = (u64)ctrl; - pmc_reprogram_counter(pmc, PERF_TYPE_HARDWARE, - static_call(kvm_x86_pmu_pmc_perf_hw_id)(pmc), - !(en_field & 0x2), /* exclude user */ - !(en_field & 0x1), /* exclude kernel */ - pmi); -} - -void reprogram_counter(struct kvm_pmc *pmc) -{ - if (pmc_is_gp(pmc)) - reprogram_gp_counter(pmc); - else - reprogram_fixed_counter(pmc); -} EXPORT_SYMBOL_GPL(reprogram_counter); void kvm_pmu_handle_event(struct kvm_vcpu *vcpu) From dc852ff5bb419195c7d64cfcbe26f747490fca14 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 18 May 2022 21:25:10 +0800 Subject: [PATCH 0162/1436] perf: x86/core: Add interface to query perfmon_event_map[] directly Currently, we have [intel|knc|p4|p6]_perfmon_event_map on the Intel platforms and amd_[f17h]_perfmon_event_map on the AMD platforms. Early clumsy KVM code or other potential perf_event users may have hard-coded these perfmon_maps (e.g., arch/x86/kvm/svm/pmu.c), so it would not make sense to program a common hardware event based on the generic "enum perf_hw_id" once the two tables do not match. Let's provide an interface for callers outside the perf subsystem to get the counter config based on the perfmon_event_map currently in use, and it also helps to save bytes. Cc: Peter Zijlstra Signed-off-by: Like Xu Acked-by: Peter Zijlstra (Intel) Message-Id: <20220518132512.37864-10-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/core.c | 11 +++++++++++ arch/x86/include/asm/perf_event.h | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 330825160b9a..2e16c268a005 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -3005,3 +3005,14 @@ void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) cap->pebs_ept = x86_pmu.pebs_ept; } EXPORT_SYMBOL_GPL(perf_get_x86_pmu_capability); + +u64 perf_get_hw_event_config(int hw_event) +{ + int max = x86_pmu.max_events; + + if (hw_event < max) + return x86_pmu.event_map(array_index_nospec(hw_event, max)); + + return 0; +} +EXPORT_SYMBOL_GPL(perf_get_hw_event_config); diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 58e2fcbb8bcc..cc47044401ff 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -505,6 +505,7 @@ struct x86_pmu_lbr { }; extern void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap); +extern u64 perf_get_hw_event_config(int hw_event); extern void perf_check_microcode(void); extern void perf_clear_dirty_counters(void); extern int x86_perf_rdpmc_index(struct perf_event *event); @@ -514,6 +515,11 @@ static inline void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) memset(cap, 0, sizeof(*cap)); } +static inline u64 perf_get_hw_event_config(int hw_event) +{ + return 0; +} + static inline void perf_events_lapic_init(void) { } static inline void perf_check_microcode(void) { } #endif From 08dca7a8e73abfeb3a998714272d1d1c974b0190 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 18 May 2022 21:25:11 +0800 Subject: [PATCH 0163/1436] KVM: x86/pmu: Replace pmc_perf_hw_id() with perf_get_hw_event_config() With the help of perf_get_hw_event_config(), KVM could query the correct EVENTSEL_{EVENT, UMASK} pair of a kernel-generic hw event directly from the different *_perfmon_event_map[] by the kernel's pre-defined perf_hw_id. Also extend the bit range of the comparison field to AMD64_RAW_EVENT_MASK_NB to prevent AMD from defining EventSelect[11:8] into perfmon_event_map[] one day. Signed-off-by: Like Xu Message-Id: <20220518132512.37864-11-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index b46a96604fe6..2843ce35c8d9 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -525,13 +525,8 @@ static void kvm_pmu_incr_counter(struct kvm_pmc *pmc) static inline bool eventsel_match_perf_hw_id(struct kvm_pmc *pmc, unsigned int perf_hw_id) { - u64 old_eventsel = pmc->eventsel; - unsigned int config; - - pmc->eventsel &= (ARCH_PERFMON_EVENTSEL_EVENT | ARCH_PERFMON_EVENTSEL_UMASK); - config = static_call(kvm_x86_pmu_pmc_perf_hw_id)(pmc); - pmc->eventsel = old_eventsel; - return config == perf_hw_id; + return !((pmc->eventsel ^ perf_get_hw_event_config(perf_hw_id)) & + AMD64_RAW_EVENT_MASK_NB); } static inline bool cpl_is_matched(struct kvm_pmc *pmc) From 7aadaa988c5ea0894b3bbea598e4da56f078a289 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 18 May 2022 21:25:12 +0800 Subject: [PATCH 0164/1436] KVM: x86/pmu: Drop amd_event_mapping[] in the KVM context All gp or fixed counters have been reprogrammed using PERF_TYPE_RAW, which means that the table that maps perf_hw_id to event select values is no longer useful, at least for AMD. For Intel, the logic to check if the pmu event reported by Intel cpuid is not available is still required, in which case pmc_perf_hw_id() could be renamed to hw_event_is_unavail() and a bool value is returned to replace the semantics of "PERF_COUNT_HW_MAX+1". Signed-off-by: Like Xu Message-Id: <20220518132512.37864-12-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm-x86-pmu-ops.h | 2 +- arch/x86/kvm/pmu.c | 6 +-- arch/x86/kvm/pmu.h | 2 +- arch/x86/kvm/svm/pmu.c | 56 ++------------------------ arch/x86/kvm/vmx/pmu_intel.c | 11 ++--- 5 files changed, 12 insertions(+), 65 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-pmu-ops.h b/arch/x86/include/asm/kvm-x86-pmu-ops.h index fdfd8e06fee6..c17e3e96fc1d 100644 --- a/arch/x86/include/asm/kvm-x86-pmu-ops.h +++ b/arch/x86/include/asm/kvm-x86-pmu-ops.h @@ -12,7 +12,7 @@ BUILD_BUG_ON(1) * a NULL definition, for example if "static_call_cond()" will be used * at the call sites. */ -KVM_X86_PMU_OP(pmc_perf_hw_id) +KVM_X86_PMU_OP(hw_event_available) KVM_X86_PMU_OP(pmc_is_enabled) KVM_X86_PMU_OP(pmc_idx_to_pmc) KVM_X86_PMU_OP(rdpmc_ecx_to_pmc) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 2843ce35c8d9..87483e503c46 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -158,9 +158,6 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, }; bool pebs = test_bit(pmc->idx, (unsigned long *)&pmu->pebs_enable); - if (type == PERF_TYPE_HARDWARE && config >= PERF_COUNT_HW_MAX) - return; - attr.sample_period = get_sample_period(pmc, pmc->counter); if ((attr.config & HSW_IN_TX_CHECKPOINTED) && @@ -258,6 +255,9 @@ static bool check_pmu_event_filter(struct kvm_pmc *pmc) __u64 key; int idx; + if (!static_call(kvm_x86_pmu_hw_event_available)(pmc)) + return false; + filter = srcu_dereference(kvm->arch.pmu_event_filter, &kvm->srcu); if (!filter) goto out; diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 60faf27678d9..0e719436b7b8 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -22,7 +22,7 @@ struct kvm_event_hw_type_mapping { }; struct kvm_pmu_ops { - unsigned int (*pmc_perf_hw_id)(struct kvm_pmc *pmc); + bool (*hw_event_available)(struct kvm_pmc *pmc); bool (*pmc_is_enabled)(struct kvm_pmc *pmc); struct kvm_pmc *(*pmc_idx_to_pmc)(struct kvm_pmu *pmu, int pmc_idx); struct kvm_pmc *(*rdpmc_ecx_to_pmc)(struct kvm_vcpu *vcpu, diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 79346def7c96..256244b8f89c 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -33,34 +33,6 @@ enum index { INDEX_ERROR, }; -/* duplicated from amd_perfmon_event_map, K7 and above should work. */ -static struct kvm_event_hw_type_mapping amd_event_mapping[] = { - [0] = { 0x76, 0x00, PERF_COUNT_HW_CPU_CYCLES }, - [1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS }, - [2] = { 0x7d, 0x07, PERF_COUNT_HW_CACHE_REFERENCES }, - [3] = { 0x7e, 0x07, PERF_COUNT_HW_CACHE_MISSES }, - [4] = { 0xc2, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, - [5] = { 0xc3, 0x00, PERF_COUNT_HW_BRANCH_MISSES }, - [6] = { 0xd0, 0x00, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, - [7] = { 0xd1, 0x00, PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, -}; - -/* duplicated from amd_f17h_perfmon_event_map. */ -static struct kvm_event_hw_type_mapping amd_f17h_event_mapping[] = { - [0] = { 0x76, 0x00, PERF_COUNT_HW_CPU_CYCLES }, - [1] = { 0xc0, 0x00, PERF_COUNT_HW_INSTRUCTIONS }, - [2] = { 0x60, 0xff, PERF_COUNT_HW_CACHE_REFERENCES }, - [3] = { 0x64, 0x09, PERF_COUNT_HW_CACHE_MISSES }, - [4] = { 0xc2, 0x00, PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, - [5] = { 0xc3, 0x00, PERF_COUNT_HW_BRANCH_MISSES }, - [6] = { 0x87, 0x02, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND }, - [7] = { 0x87, 0x01, PERF_COUNT_HW_STALLED_CYCLES_BACKEND }, -}; - -/* amd_pmc_perf_hw_id depends on these being the same size */ -static_assert(ARRAY_SIZE(amd_event_mapping) == - ARRAY_SIZE(amd_f17h_event_mapping)); - static unsigned int get_msr_base(struct kvm_pmu *pmu, enum pmu_type type) { struct kvm_vcpu *vcpu = pmu_to_vcpu(pmu); @@ -154,31 +126,9 @@ static inline struct kvm_pmc *get_gp_pmc_amd(struct kvm_pmu *pmu, u32 msr, return &pmu->gp_counters[msr_to_index(msr)]; } -static unsigned int amd_pmc_perf_hw_id(struct kvm_pmc *pmc) +static bool amd_hw_event_available(struct kvm_pmc *pmc) { - struct kvm_event_hw_type_mapping *event_mapping; - u8 event_select = pmc->eventsel & ARCH_PERFMON_EVENTSEL_EVENT; - u8 unit_mask = (pmc->eventsel & ARCH_PERFMON_EVENTSEL_UMASK) >> 8; - int i; - - /* return PERF_COUNT_HW_MAX as AMD doesn't have fixed events */ - if (WARN_ON(pmc_is_fixed(pmc))) - return PERF_COUNT_HW_MAX; - - if (guest_cpuid_family(pmc->vcpu) >= 0x17) - event_mapping = amd_f17h_event_mapping; - else - event_mapping = amd_event_mapping; - - for (i = 0; i < ARRAY_SIZE(amd_event_mapping); i++) - if (event_mapping[i].eventsel == event_select - && event_mapping[i].unit_mask == unit_mask) - break; - - if (i == ARRAY_SIZE(amd_event_mapping)) - return PERF_COUNT_HW_MAX; - - return event_mapping[i].event_type; + return true; } /* check if a PMC is enabled by comparing it against global_ctrl bits. Because @@ -345,7 +295,7 @@ static void amd_pmu_reset(struct kvm_vcpu *vcpu) } struct kvm_pmu_ops amd_pmu_ops __initdata = { - .pmc_perf_hw_id = amd_pmc_perf_hw_id, + .hw_event_available = amd_hw_event_available, .pmc_is_enabled = amd_pmc_is_enabled, .pmc_idx_to_pmc = amd_pmc_idx_to_pmc, .rdpmc_ecx_to_pmc = amd_rdpmc_ecx_to_pmc, diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 0dc270e6717c..5b85320fc9f1 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -84,7 +84,7 @@ static void global_ctrl_changed(struct kvm_pmu *pmu, u64 data) } } -static unsigned int intel_pmc_perf_hw_id(struct kvm_pmc *pmc) +static bool intel_hw_event_available(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); u8 event_select = pmc->eventsel & ARCH_PERFMON_EVENTSEL_EVENT; @@ -98,15 +98,12 @@ static unsigned int intel_pmc_perf_hw_id(struct kvm_pmc *pmc) /* disable event that reported as not present by cpuid */ if ((i < 7) && !(pmu->available_event_types & (1 << i))) - return PERF_COUNT_HW_MAX + 1; + return false; break; } - if (i == ARRAY_SIZE(intel_arch_events)) - return PERF_COUNT_HW_MAX; - - return intel_arch_events[i].event_type; + return true; } /* check if a PMC is enabled by comparing it with globl_ctrl bits. */ @@ -814,7 +811,7 @@ void intel_pmu_cross_mapped_check(struct kvm_pmu *pmu) } struct kvm_pmu_ops intel_pmu_ops __initdata = { - .pmc_perf_hw_id = intel_pmc_perf_hw_id, + .hw_event_available = intel_hw_event_available, .pmc_is_enabled = intel_pmc_is_enabled, .pmc_idx_to_pmc = intel_pmc_idx_to_pmc, .rdpmc_ecx_to_pmc = intel_rdpmc_ecx_to_pmc, From ed2351174e38ad4febbbc0dba802803e6cff8ae0 Mon Sep 17 00:00:00 2001 From: Chenyi Qiang Date: Tue, 24 May 2022 21:56:21 +0800 Subject: [PATCH 0165/1436] KVM: x86: Extend KVM_{G,S}ET_VCPU_EVENTS to support pending triple fault For the triple fault sythesized by KVM, e.g. the RSM path or nested_vmx_abort(), if KVM exits to userspace before the request is serviced, userspace could migrate the VM and lose the triple fault. Extend KVM_{G,S}ET_VCPU_EVENTS to support pending triple fault with a new event KVM_VCPUEVENT_VALID_FAULT_FAULT so that userspace can save and restore the triple fault event. This extension is guarded by a new KVM capability KVM_CAP_TRIPLE_FAULT_EVENT. Note that in the set_vcpu_events path, userspace is able to set/clear the triple fault request through triple_fault.pending field. Signed-off-by: Chenyi Qiang Message-Id: <20220524135624.22988-2-chenyi.qiang@intel.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 8 ++++++++ arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/include/uapi/asm/kvm.h | 6 +++++- arch/x86/kvm/x86.c | 21 ++++++++++++++++++++- include/uapi/linux/kvm.h | 1 + 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 421479a67da5..f67e367c4059 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -1150,6 +1150,10 @@ The following bits are defined in the flags field: fields contain a valid state. This bit will be set whenever KVM_CAP_EXCEPTION_PAYLOAD is enabled. +- KVM_VCPUEVENT_VALID_TRIPLE_FAULT may be set to signal that the + triple_fault_pending field contains a valid state. This bit will + be set whenever KVM_CAP_TRIPLE_FAULT_EVENT is enabled. + ARM64: ^^^^^^ @@ -1245,6 +1249,10 @@ can be set in the flags field to signal that the exception_has_payload, exception_payload, and exception.pending fields contain a valid state and shall be written into the VCPU. +If KVM_CAP_TRIPLE_FAULT_EVENT is enabled, KVM_VCPUEVENT_VALID_TRIPLE_FAULT +can be set in flags field to signal that the triple_fault field contains +a valid state and shall be written into the VCPU. + ARM64: ^^^^^^ diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 032278f0ee6d..d6c62276e131 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1174,6 +1174,8 @@ struct kvm_arch { bool guest_can_read_msr_platform_info; bool exception_payload_enabled; + bool triple_fault_event; + bool bus_lock_detection_enabled; bool enable_pmu; /* diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 21614807a2cb..24c807c8d5f7 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -325,6 +325,7 @@ struct kvm_reinject_control { #define KVM_VCPUEVENT_VALID_SHADOW 0x00000004 #define KVM_VCPUEVENT_VALID_SMM 0x00000008 #define KVM_VCPUEVENT_VALID_PAYLOAD 0x00000010 +#define KVM_VCPUEVENT_VALID_TRIPLE_FAULT 0x00000020 /* Interrupt shadow states */ #define KVM_X86_SHADOW_INT_MOV_SS 0x01 @@ -359,7 +360,10 @@ struct kvm_vcpu_events { __u8 smm_inside_nmi; __u8 latched_init; } smi; - __u8 reserved[27]; + struct { + __u8 pending; + } triple_fault; + __u8 reserved[26]; __u8 exception_has_payload; __u64 exception_payload; }; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c8dfdef9e52f..422fbb0d7518 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4296,6 +4296,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_GET_MSR_FEATURES: case KVM_CAP_MSR_PLATFORM_INFO: case KVM_CAP_EXCEPTION_PAYLOAD: + case KVM_CAP_X86_TRIPLE_FAULT_EVENT: case KVM_CAP_SET_GUEST_DEBUG: case KVM_CAP_LAST_CPU: case KVM_CAP_X86_USER_SPACE_MSR: @@ -4942,6 +4943,10 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu, | KVM_VCPUEVENT_VALID_SMM); if (vcpu->kvm->arch.exception_payload_enabled) events->flags |= KVM_VCPUEVENT_VALID_PAYLOAD; + if (vcpu->kvm->arch.triple_fault_event) { + events->triple_fault.pending = kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu); + events->flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT; + } memset(&events->reserved, 0, sizeof(events->reserved)); } @@ -4955,7 +4960,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, | KVM_VCPUEVENT_VALID_SIPI_VECTOR | KVM_VCPUEVENT_VALID_SHADOW | KVM_VCPUEVENT_VALID_SMM - | KVM_VCPUEVENT_VALID_PAYLOAD)) + | KVM_VCPUEVENT_VALID_PAYLOAD + | KVM_VCPUEVENT_VALID_TRIPLE_FAULT)) return -EINVAL; if (events->flags & KVM_VCPUEVENT_VALID_PAYLOAD) { @@ -5028,6 +5034,15 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, } } + if (events->flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT) { + if (!vcpu->kvm->arch.triple_fault_event) + return -EINVAL; + if (events->triple_fault.pending) + kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu); + else + kvm_clear_request(KVM_REQ_TRIPLE_FAULT, vcpu); + } + kvm_make_request(KVM_REQ_EVENT, vcpu); return 0; @@ -6029,6 +6044,10 @@ split_irqchip_unlock: kvm->arch.exception_payload_enabled = cap->args[0]; r = 0; break; + case KVM_CAP_X86_TRIPLE_FAULT_EVENT: + kvm->arch.triple_fault_event = cap->args[0]; + r = 0; + break; case KVM_CAP_X86_USER_SPACE_MSR: kvm->arch.user_space_msr_mask = cap->args[0]; r = 0; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index c4a32910b88a..ca799319acfd 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1158,6 +1158,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_SYSTEM_EVENT_DATA 215 #define KVM_CAP_ARM_SYSTEM_SUSPEND 216 #define KVM_CAP_S390_PROTECTED_DUMP 217 +#define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218 #ifdef KVM_CAP_IRQ_ROUTING From 30267b43c5b08260da7c76cacd28bf855b06ab93 Mon Sep 17 00:00:00 2001 From: Chenyi Qiang Date: Tue, 24 May 2022 21:56:22 +0800 Subject: [PATCH 0166/1436] KVM: selftests: Add a test to get/set triple fault event Add a selftest for triple fault event: - launch the L2 and exit to userspace via I/O. - using KVM_SET_VCPU_EVENTS to pend a triple fault event. - with the immediate_exit, check the triple fault is pending. - run for real with pending triple fault and L1 can see the triple fault. Suggested-by: Sean Christopherson Signed-off-by: Chenyi Qiang Message-Id: <20220524135624.22988-3-chenyi.qiang@intel.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../kvm/x86_64/triple_fault_event_test.c | 101 ++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 90a6dea2e84c..dd5c88c11059 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -58,6 +58,7 @@ /x86_64/xen_vmcall_test /x86_64/xss_msr_test /x86_64/vmx_pmu_caps_test +/x86_64/triple_fault_event_test /access_tracking_perf_test /demand_paging_test /dirty_log_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index a014368a2cd2..27e432273180 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -90,6 +90,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/xen_vmcall_test TEST_GEN_PROGS_x86_64 += x86_64/sev_migrate_tests TEST_GEN_PROGS_x86_64 += x86_64/amx_test TEST_GEN_PROGS_x86_64 += x86_64/max_vcpuid_cap_test +TEST_GEN_PROGS_x86_64 += x86_64/triple_fault_event_test TEST_GEN_PROGS_x86_64 += access_tracking_perf_test TEST_GEN_PROGS_x86_64 += demand_paging_test TEST_GEN_PROGS_x86_64 += dirty_log_test diff --git a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c new file mode 100644 index 000000000000..6e1de0631ce9 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" +#include "vmx.h" + +#include +#include + +#include "kselftest.h" + +#define VCPU_ID 0 +#define ARBITRARY_IO_PORT 0x2000 + +/* The virtual machine object. */ +static struct kvm_vm *vm; + +static void l2_guest_code(void) +{ + asm volatile("inb %%dx, %%al" + : : [port] "d" (ARBITRARY_IO_PORT) : "rax"); +} + +void l1_guest_code(struct vmx_pages *vmx) +{ +#define L2_GUEST_STACK_SIZE 64 + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + + GUEST_ASSERT(vmx->vmcs_gpa); + GUEST_ASSERT(prepare_for_vmx_operation(vmx)); + GUEST_ASSERT(load_vmcs(vmx)); + + prepare_vmcs(vmx, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + GUEST_ASSERT(!vmlaunch()); + /* L2 should triple fault after a triple fault event injected. */ + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_TRIPLE_FAULT); + GUEST_DONE(); +} + +int main(void) +{ + struct kvm_run *run; + struct kvm_vcpu_events events; + vm_vaddr_t vmx_pages_gva; + struct ucall uc; + + struct kvm_enable_cap cap = { + .cap = KVM_CAP_TRIPLE_FAULT_EVENT, + .args = {1} + }; + + if (!nested_vmx_supported()) { + print_skip("Nested VMX not supported"); + exit(KSFT_SKIP); + } + + if (!kvm_check_cap(KVM_CAP_TRIPLE_FAULT_EVENT)) { + print_skip("KVM_CAP_TRIPLE_FAULT_EVENT not supported"); + exit(KSFT_SKIP); + } + + vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vm_enable_cap(vm, &cap); + + run = vcpu_state(vm, VCPU_ID); + vcpu_alloc_vmx(vm, &vmx_pages_gva); + vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); + vcpu_run(vm, VCPU_ID); + + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Expected KVM_EXIT_IO, got: %u (%s)\n", + run->exit_reason, exit_reason_str(run->exit_reason)); + TEST_ASSERT(run->io.port == ARBITRARY_IO_PORT, + "Expected IN from port %d from L2, got port %d", + ARBITRARY_IO_PORT, run->io.port); + vcpu_events_get(vm, VCPU_ID, &events); + events.flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT; + events.triple_fault.pending = true; + vcpu_events_set(vm, VCPU_ID, &events); + run->immediate_exit = true; + vcpu_run_complete_io(vm, VCPU_ID); + + vcpu_events_get(vm, VCPU_ID, &events); + TEST_ASSERT(events.flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT, + "Triple fault event invalid"); + TEST_ASSERT(events.triple_fault.pending, + "No triple fault pending"); + vcpu_run(vm, VCPU_ID); + + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_DONE: + break; + case UCALL_ABORT: + TEST_FAIL("%s", (const char *)uc.args[0]); + default: + TEST_FAIL("Unexpected ucall: %lu", uc.cmd); + } + +} From 938c8745bcf2f732ee928a0b9bd592198a88cfa4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 24 May 2022 21:56:23 +0800 Subject: [PATCH 0167/1436] KVM: x86: Introduce "struct kvm_caps" to track misc caps/settings Add kvm_caps to hold a variety of capabilites and defaults that aren't handled by kvm_cpu_caps because they aren't CPUID bits in order to reduce the amount of boilerplate code required to add a new feature. The vast majority (all?) of the caps interact with vendor code and are written only during initialization, i.e. should be tagged __read_mostly, declared extern in x86.h, and exported. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220524135624.22988-4-chenyi.qiang@intel.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 15 ----- arch/x86/kvm/cpuid.c | 8 +-- arch/x86/kvm/debugfs.c | 4 +- arch/x86/kvm/lapic.c | 2 +- arch/x86/kvm/svm/nested.c | 4 +- arch/x86/kvm/svm/svm.c | 13 +++-- arch/x86/kvm/vmx/nested.c | 4 +- arch/x86/kvm/vmx/vmx.c | 22 ++++---- arch/x86/kvm/x86.c | 97 ++++++++++++++------------------- arch/x86/kvm/x86.h | 26 ++++++++- 10 files changed, 94 insertions(+), 101 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index d6c62276e131..4e00bca08cfa 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1664,21 +1664,6 @@ extern bool tdp_enabled; u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu); -/* control of guest tsc rate supported? */ -extern bool kvm_has_tsc_control; -/* maximum supported tsc_khz for guests */ -extern u32 kvm_max_guest_tsc_khz; -/* number of bits of the fractional part of the TSC scaling ratio */ -extern u8 kvm_tsc_scaling_ratio_frac_bits; -/* maximum allowed value of TSC scaling ratio */ -extern u64 kvm_max_tsc_scaling_ratio; -/* 1ull << kvm_tsc_scaling_ratio_frac_bits */ -extern u64 kvm_default_tsc_scaling_ratio; -/* bus lock detection supported? */ -extern bool kvm_has_bus_lock_exit; - -extern u64 kvm_mce_cap_supported; - /* * EMULTYPE_NO_DECODE - Set when re-emulating an instruction (after completing * userspace I/O) to indicate that the emulation context diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 211f4566641e..d47222ab8e6e 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -200,7 +200,7 @@ void kvm_update_pv_runtime(struct kvm_vcpu *vcpu) /* * Calculate guest's supported XCR0 taking into account guest CPUID data and - * supported_xcr0 (comprised of host configuration and KVM_SUPPORTED_XCR0). + * KVM's supported XCR0 (comprised of host's XCR0 and KVM_SUPPORTED_XCR0). */ static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent) { @@ -210,7 +210,7 @@ static u64 cpuid_get_supported_xcr0(struct kvm_cpuid_entry2 *entries, int nent) if (!best) return 0; - return (best->eax | ((u64)best->edx << 32)) & supported_xcr0; + return (best->eax | ((u64)best->edx << 32)) & kvm_caps.supported_xcr0; } static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *entries, @@ -912,8 +912,8 @@ static inline int __do_cpuid_func(struct kvm_cpuid_array *array, u32 function) } break; case 0xd: { - u64 permitted_xcr0 = supported_xcr0 & xstate_get_guest_group_perm(); - u64 permitted_xss = supported_xss; + u64 permitted_xcr0 = kvm_caps.supported_xcr0 & xstate_get_guest_group_perm(); + u64 permitted_xss = kvm_caps.supported_xss; entry->eax &= permitted_xcr0; entry->ebx = xstate_required_size(permitted_xcr0, false); diff --git a/arch/x86/kvm/debugfs.c b/arch/x86/kvm/debugfs.c index 9240b3b7f8dd..cfed36aba2f7 100644 --- a/arch/x86/kvm/debugfs.c +++ b/arch/x86/kvm/debugfs.c @@ -48,7 +48,7 @@ DEFINE_SIMPLE_ATTRIBUTE(vcpu_tsc_scaling_fops, vcpu_get_tsc_scaling_ratio, NULL, static int vcpu_get_tsc_scaling_frac_bits(void *data, u64 *val) { - *val = kvm_tsc_scaling_ratio_frac_bits; + *val = kvm_caps.tsc_scaling_ratio_frac_bits; return 0; } @@ -66,7 +66,7 @@ void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_ debugfs_dentry, vcpu, &vcpu_timer_advance_ns_fops); - if (kvm_has_tsc_control) { + if (kvm_caps.has_tsc_control) { debugfs_create_file("tsc-scaling-ratio", 0444, debugfs_dentry, vcpu, &vcpu_tsc_scaling_fops); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 39b805666a18..e69b83708f05 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1603,7 +1603,7 @@ static inline void __wait_lapic_expire(struct kvm_vcpu *vcpu, u64 guest_cycles) * that __delay() uses delay_tsc whenever the hardware has TSC, thus * always for VMX enabled hardware. */ - if (vcpu->arch.tsc_scaling_ratio == kvm_default_tsc_scaling_ratio) { + if (vcpu->arch.tsc_scaling_ratio == kvm_caps.default_tsc_scaling_ratio) { __delay(min(guest_cycles, nsec_to_cycles(vcpu, timer_advance_ns))); } else { diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 688f86b9202a..f958a656ff29 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -674,7 +674,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, vmcb02->control.tsc_offset = vcpu->arch.tsc_offset; - if (svm->tsc_ratio_msr != kvm_default_tsc_scaling_ratio) { + if (svm->tsc_ratio_msr != kvm_caps.default_tsc_scaling_ratio) { WARN_ON(!svm->tsc_scaling_enabled); nested_svm_update_tsc_ratio_msr(vcpu); } @@ -1031,7 +1031,7 @@ int nested_svm_vmexit(struct vcpu_svm *svm) vmcb_mark_dirty(vmcb01, VMCB_INTERCEPTS); } - if (svm->tsc_ratio_msr != kvm_default_tsc_scaling_ratio) { + if (svm->tsc_ratio_msr != kvm_caps.default_tsc_scaling_ratio) { WARN_ON(!svm->tsc_scaling_enabled); vcpu->arch.tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio; __svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 5fda7e7102f2..750933ca6b9f 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1285,7 +1285,7 @@ static void __svm_vcpu_reset(struct kvm_vcpu *vcpu) svm_init_osvw(vcpu); vcpu->arch.microcode_version = 0x01000065; - svm->tsc_ratio_msr = kvm_default_tsc_scaling_ratio; + svm->tsc_ratio_msr = kvm_caps.default_tsc_scaling_ratio; if (sev_es_guest(vcpu->kvm)) sev_es_vcpu_reset(svm); @@ -4868,7 +4868,7 @@ static __init void svm_set_cpu_caps(void) { kvm_set_cpu_caps(); - supported_xss = 0; + kvm_caps.supported_xss = 0; /* CPUID 0x80000001 and 0x8000000A (SVM features) */ if (nested) { @@ -4944,7 +4944,8 @@ static __init int svm_hardware_setup(void) init_msrpm_offsets(); - supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); + kvm_caps.supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS | + XFEATURE_MASK_BNDCSR); if (boot_cpu_has(X86_FEATURE_FXSR_OPT)) kvm_enable_efer_bits(EFER_FFXSR); @@ -4954,11 +4955,11 @@ static __init int svm_hardware_setup(void) tsc_scaling = false; } else { pr_info("TSC scaling supported\n"); - kvm_has_tsc_control = true; + kvm_caps.has_tsc_control = true; } } - kvm_max_tsc_scaling_ratio = SVM_TSC_RATIO_MAX; - kvm_tsc_scaling_ratio_frac_bits = 32; + kvm_caps.max_tsc_scaling_ratio = SVM_TSC_RATIO_MAX; + kvm_caps.tsc_scaling_ratio_frac_bits = 32; tsc_aux_uret_slot = kvm_add_user_return_msr(MSR_TSC_AUX); diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index f5cb18e00e78..5c5f4e3762f5 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -2548,7 +2548,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, vmx_get_l2_tsc_multiplier(vcpu)); vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset); - if (kvm_has_tsc_control) + if (kvm_caps.has_tsc_control) vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio); nested_vmx_transition_tlb_flush(vcpu, vmcs12, true); @@ -4610,7 +4610,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr); vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, vmx->msr_autoload.guest.nr); vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset); - if (kvm_has_tsc_control) + if (kvm_caps.has_tsc_control) vmcs_write64(TSC_MULTIPLIER, vcpu->arch.tsc_scaling_ratio); if (vmx->nested.l1_tpr_threshold != -1) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 55a8578255cb..6d631941ac1a 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -1717,7 +1717,7 @@ u64 vmx_get_l2_tsc_multiplier(struct kvm_vcpu *vcpu) nested_cpu_has2(vmcs12, SECONDARY_EXEC_TSC_SCALING)) return vmcs12->tsc_multiplier; - return kvm_default_tsc_scaling_ratio; + return kvm_caps.default_tsc_scaling_ratio; } static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) @@ -7544,7 +7544,7 @@ static __init void vmx_set_cpu_caps(void) kvm_cpu_cap_set(X86_FEATURE_UMIP); /* CPUID 0xD.1 */ - supported_xss = 0; + kvm_caps.supported_xss = 0; if (!cpu_has_vmx_xsaves()) kvm_cpu_cap_clear(X86_FEATURE_XSAVES); @@ -7685,9 +7685,9 @@ static int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc, delta_tsc = 0; /* Convert to host delta tsc if tsc scaling is enabled */ - if (vcpu->arch.l1_tsc_scaling_ratio != kvm_default_tsc_scaling_ratio && + if (vcpu->arch.l1_tsc_scaling_ratio != kvm_caps.default_tsc_scaling_ratio && delta_tsc && u64_shl_div_u64(delta_tsc, - kvm_tsc_scaling_ratio_frac_bits, + kvm_caps.tsc_scaling_ratio_frac_bits, vcpu->arch.l1_tsc_scaling_ratio, &delta_tsc)) return -ERANGE; @@ -8064,8 +8064,8 @@ static __init int hardware_setup(void) } if (!cpu_has_vmx_mpx()) - supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS | - XFEATURE_MASK_BNDCSR); + kvm_caps.supported_xcr0 &= ~(XFEATURE_MASK_BNDREGS | + XFEATURE_MASK_BNDCSR); if (!cpu_has_vmx_vpid() || !cpu_has_vmx_invvpid() || !(cpu_has_vmx_invvpid_single() || cpu_has_vmx_invvpid_global())) @@ -8132,11 +8132,11 @@ static __init int hardware_setup(void) enable_ipiv = false; if (cpu_has_vmx_tsc_scaling()) - kvm_has_tsc_control = true; + kvm_caps.has_tsc_control = true; - kvm_max_tsc_scaling_ratio = KVM_VMX_TSC_MULTIPLIER_MAX; - kvm_tsc_scaling_ratio_frac_bits = 48; - kvm_has_bus_lock_exit = cpu_has_vmx_bus_lock_detection(); + kvm_caps.max_tsc_scaling_ratio = KVM_VMX_TSC_MULTIPLIER_MAX; + kvm_caps.tsc_scaling_ratio_frac_bits = 48; + kvm_caps.has_bus_lock_exit = cpu_has_vmx_bus_lock_detection(); set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ @@ -8193,7 +8193,7 @@ static __init int hardware_setup(void) vmx_x86_ops.request_immediate_exit = __kvm_request_immediate_exit; } - kvm_mce_cap_supported |= MCG_LMCE_P; + kvm_caps.supported_mce_cap |= MCG_LMCE_P; if (pt_mode != PT_MODE_SYSTEM && pt_mode != PT_MODE_HOST_GUEST) return -EINVAL; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 422fbb0d7518..53e5f2ad2422 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -87,8 +87,11 @@ #define MAX_IO_MSRS 256 #define KVM_MAX_MCE_BANKS 32 -u64 __read_mostly kvm_mce_cap_supported = MCG_CTL_P | MCG_SER_P; -EXPORT_SYMBOL_GPL(kvm_mce_cap_supported); + +struct kvm_caps kvm_caps __read_mostly = { + .supported_mce_cap = MCG_CTL_P | MCG_SER_P, +}; +EXPORT_SYMBOL_GPL(kvm_caps); #define ERR_PTR_USR(e) ((void __user *)ERR_PTR(e)) @@ -151,19 +154,6 @@ module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR); static bool __read_mostly kvmclock_periodic_sync = true; module_param(kvmclock_periodic_sync, bool, S_IRUGO); -bool __read_mostly kvm_has_tsc_control; -EXPORT_SYMBOL_GPL(kvm_has_tsc_control); -u32 __read_mostly kvm_max_guest_tsc_khz; -EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz); -u8 __read_mostly kvm_tsc_scaling_ratio_frac_bits; -EXPORT_SYMBOL_GPL(kvm_tsc_scaling_ratio_frac_bits); -u64 __read_mostly kvm_max_tsc_scaling_ratio; -EXPORT_SYMBOL_GPL(kvm_max_tsc_scaling_ratio); -u64 __read_mostly kvm_default_tsc_scaling_ratio; -EXPORT_SYMBOL_GPL(kvm_default_tsc_scaling_ratio); -bool __read_mostly kvm_has_bus_lock_exit; -EXPORT_SYMBOL_GPL(kvm_has_bus_lock_exit); - /* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */ static u32 __read_mostly tsc_tolerance_ppm = 250; module_param(tsc_tolerance_ppm, uint, S_IRUGO | S_IWUSR); @@ -235,8 +225,6 @@ EXPORT_SYMBOL_GPL(enable_apicv); u64 __read_mostly host_xss; EXPORT_SYMBOL_GPL(host_xss); -u64 __read_mostly supported_xss; -EXPORT_SYMBOL_GPL(supported_xss); const struct _kvm_stats_desc kvm_vm_stats_desc[] = { KVM_GENERIC_VM_STATS(), @@ -309,8 +297,6 @@ const struct kvm_stats_header kvm_vcpu_stats_header = { }; u64 __read_mostly host_xcr0; -u64 __read_mostly supported_xcr0; -EXPORT_SYMBOL_GPL(supported_xcr0); static struct kmem_cache *x86_emulator_cache; @@ -2345,12 +2331,12 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale) /* Guest TSC same frequency as host TSC? */ if (!scale) { - kvm_vcpu_write_tsc_multiplier(vcpu, kvm_default_tsc_scaling_ratio); + kvm_vcpu_write_tsc_multiplier(vcpu, kvm_caps.default_tsc_scaling_ratio); return 0; } /* TSC scaling supported? */ - if (!kvm_has_tsc_control) { + if (!kvm_caps.has_tsc_control) { if (user_tsc_khz > tsc_khz) { vcpu->arch.tsc_catchup = 1; vcpu->arch.tsc_always_catchup = 1; @@ -2362,10 +2348,10 @@ static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale) } /* TSC scaling required - calculate ratio */ - ratio = mul_u64_u32_div(1ULL << kvm_tsc_scaling_ratio_frac_bits, + ratio = mul_u64_u32_div(1ULL << kvm_caps.tsc_scaling_ratio_frac_bits, user_tsc_khz, tsc_khz); - if (ratio == 0 || ratio >= kvm_max_tsc_scaling_ratio) { + if (ratio == 0 || ratio >= kvm_caps.max_tsc_scaling_ratio) { pr_warn_ratelimited("Invalid TSC scaling ratio - virtual-tsc-khz=%u\n", user_tsc_khz); return -1; @@ -2383,7 +2369,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz) /* tsc_khz can be zero if TSC calibration fails */ if (user_tsc_khz == 0) { /* set tsc_scaling_ratio to a safe value */ - kvm_vcpu_write_tsc_multiplier(vcpu, kvm_default_tsc_scaling_ratio); + kvm_vcpu_write_tsc_multiplier(vcpu, kvm_caps.default_tsc_scaling_ratio); return -1; } @@ -2460,18 +2446,18 @@ static void kvm_track_tsc_matching(struct kvm_vcpu *vcpu) * (frac) represent the fractional part, ie. ratio represents a fixed * point number (mult + frac * 2^(-N)). * - * N equals to kvm_tsc_scaling_ratio_frac_bits. + * N equals to kvm_caps.tsc_scaling_ratio_frac_bits. */ static inline u64 __scale_tsc(u64 ratio, u64 tsc) { - return mul_u64_u64_shr(tsc, ratio, kvm_tsc_scaling_ratio_frac_bits); + return mul_u64_u64_shr(tsc, ratio, kvm_caps.tsc_scaling_ratio_frac_bits); } u64 kvm_scale_tsc(u64 tsc, u64 ratio) { u64 _tsc = tsc; - if (ratio != kvm_default_tsc_scaling_ratio) + if (ratio != kvm_caps.default_tsc_scaling_ratio) _tsc = __scale_tsc(ratio, tsc); return _tsc; @@ -2498,11 +2484,11 @@ u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier) { u64 nested_offset; - if (l2_multiplier == kvm_default_tsc_scaling_ratio) + if (l2_multiplier == kvm_caps.default_tsc_scaling_ratio) nested_offset = l1_offset; else nested_offset = mul_s64_u64_shr((s64) l1_offset, l2_multiplier, - kvm_tsc_scaling_ratio_frac_bits); + kvm_caps.tsc_scaling_ratio_frac_bits); nested_offset += l2_offset; return nested_offset; @@ -2511,9 +2497,9 @@ EXPORT_SYMBOL_GPL(kvm_calc_nested_tsc_offset); u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier) { - if (l2_multiplier != kvm_default_tsc_scaling_ratio) + if (l2_multiplier != kvm_caps.default_tsc_scaling_ratio) return mul_u64_u64_shr(l1_multiplier, l2_multiplier, - kvm_tsc_scaling_ratio_frac_bits); + kvm_caps.tsc_scaling_ratio_frac_bits); return l1_multiplier; } @@ -2555,7 +2541,7 @@ static void kvm_vcpu_write_tsc_multiplier(struct kvm_vcpu *vcpu, u64 l1_multipli else vcpu->arch.tsc_scaling_ratio = l1_multiplier; - if (kvm_has_tsc_control) + if (kvm_caps.has_tsc_control) static_call(kvm_x86_write_tsc_multiplier)( vcpu, vcpu->arch.tsc_scaling_ratio); } @@ -2691,7 +2677,7 @@ static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment) { - if (vcpu->arch.l1_tsc_scaling_ratio != kvm_default_tsc_scaling_ratio) + if (vcpu->arch.l1_tsc_scaling_ratio != kvm_caps.default_tsc_scaling_ratio) WARN_ON(adjustment < 0); adjustment = kvm_scale_tsc((u64) adjustment, vcpu->arch.l1_tsc_scaling_ratio); @@ -3104,7 +3090,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v) /* With all the info we got, fill in the values */ - if (kvm_has_tsc_control) + if (kvm_caps.has_tsc_control) tgt_tsc_khz = kvm_scale_tsc(tgt_tsc_khz, v->arch.l1_tsc_scaling_ratio); @@ -3613,7 +3599,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) * IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than * XSAVES/XRSTORS to save/restore PT MSRs. */ - if (data & ~supported_xss) + if (data & ~kvm_caps.supported_xss) return 1; vcpu->arch.ia32_xss = data; kvm_update_cpuid_runtime(vcpu); @@ -4374,7 +4360,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) break; case KVM_CAP_TSC_CONTROL: case KVM_CAP_VM_TSC_CONTROL: - r = kvm_has_tsc_control; + r = kvm_caps.has_tsc_control; break; case KVM_CAP_X2APIC_API: r = KVM_X2APIC_API_VALID_FLAGS; @@ -4396,7 +4382,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = sched_info_on(); break; case KVM_CAP_X86_BUS_LOCK_EXIT: - if (kvm_has_bus_lock_exit) + if (kvm_caps.has_bus_lock_exit) r = KVM_BUS_LOCK_DETECTION_OFF | KVM_BUS_LOCK_DETECTION_EXIT; else @@ -4405,7 +4391,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_XSAVE2: { u64 guest_perm = xstate_get_guest_group_perm(); - r = xstate_required_size(supported_xcr0 & guest_perm, false); + r = xstate_required_size(kvm_caps.supported_xcr0 & guest_perm, false); if (r < sizeof(struct kvm_xsave)) r = sizeof(struct kvm_xsave); break; @@ -4443,7 +4429,7 @@ static int kvm_x86_dev_get_attr(struct kvm_device_attr *attr) switch (attr->attr) { case KVM_X86_XCOMP_GUEST_SUPP: - if (put_user(supported_xcr0, uaddr)) + if (put_user(kvm_caps.supported_xcr0, uaddr)) return -EFAULT; return 0; default: @@ -4520,8 +4506,8 @@ long kvm_arch_dev_ioctl(struct file *filp, } case KVM_X86_GET_MCE_CAP_SUPPORTED: r = -EFAULT; - if (copy_to_user(argp, &kvm_mce_cap_supported, - sizeof(kvm_mce_cap_supported))) + if (copy_to_user(argp, &kvm_caps.supported_mce_cap, + sizeof(kvm_caps.supported_mce_cap))) goto out; r = 0; break; @@ -4805,7 +4791,7 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu, r = -EINVAL; if (!bank_num || bank_num > KVM_MAX_MCE_BANKS) goto out; - if (mcg_cap & ~(kvm_mce_cap_supported | 0xff | 0xff0000)) + if (mcg_cap & ~(kvm_caps.supported_mce_cap | 0xff | 0xff0000)) goto out; r = 0; vcpu->arch.mcg_cap = mcg_cap; @@ -5111,7 +5097,8 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, return fpu_copy_uabi_to_guest_fpstate(&vcpu->arch.guest_fpu, guest_xsave->region, - supported_xcr0, &vcpu->arch.pkru); + kvm_caps.supported_xcr0, + &vcpu->arch.pkru); } static void kvm_vcpu_ioctl_x86_get_xcrs(struct kvm_vcpu *vcpu, @@ -5616,8 +5603,8 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = -EINVAL; user_tsc_khz = (u32)arg; - if (kvm_has_tsc_control && - user_tsc_khz >= kvm_max_guest_tsc_khz) + if (kvm_caps.has_tsc_control && + user_tsc_khz >= kvm_caps.max_guest_tsc_khz) goto out; if (user_tsc_khz == 0) @@ -6061,7 +6048,7 @@ split_irqchip_unlock: (cap->args[0] & KVM_BUS_LOCK_DETECTION_EXIT)) break; - if (kvm_has_bus_lock_exit && + if (kvm_caps.has_bus_lock_exit && cap->args[0] & KVM_BUS_LOCK_DETECTION_EXIT) kvm->arch.bus_lock_detection_enabled = true; r = 0; @@ -6610,8 +6597,8 @@ set_pit2_out: r = -EINVAL; user_tsc_khz = (u32)arg; - if (kvm_has_tsc_control && - user_tsc_khz >= kvm_max_guest_tsc_khz) + if (kvm_caps.has_tsc_control && + user_tsc_khz >= kvm_caps.max_guest_tsc_khz) goto out; if (user_tsc_khz == 0) @@ -8774,7 +8761,7 @@ static void kvm_hyperv_tsc_notifier(void) /* TSC frequency always matches when on Hyper-V */ for_each_present_cpu(cpu) per_cpu(cpu_tsc_khz, cpu) = tsc_khz; - kvm_max_guest_tsc_khz = tsc_khz; + kvm_caps.max_guest_tsc_khz = tsc_khz; list_for_each_entry(kvm, &vm_list, vm_list) { __kvm_start_pvclock_update(kvm); @@ -9036,7 +9023,7 @@ int kvm_arch_init(void *opaque) if (boot_cpu_has(X86_FEATURE_XSAVE)) { host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); - supported_xcr0 = host_xcr0 & KVM_SUPPORTED_XCR0; + kvm_caps.supported_xcr0 = host_xcr0 & KVM_SUPPORTED_XCR0; } if (pi_inject_timer == -1) @@ -11748,13 +11735,13 @@ int kvm_arch_hardware_setup(void *opaque) kvm_register_perf_callbacks(ops->handle_intel_pt_intr); if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES)) - supported_xss = 0; + kvm_caps.supported_xss = 0; #define __kvm_cpu_cap_has(UNUSED_, f) kvm_cpu_cap_has(f) cr4_reserved_bits = __cr4_reserved_bits(__kvm_cpu_cap_has, UNUSED_); #undef __kvm_cpu_cap_has - if (kvm_has_tsc_control) { + if (kvm_caps.has_tsc_control) { /* * Make sure the user can only configure tsc_khz values that * fit into a signed integer. @@ -11762,10 +11749,10 @@ int kvm_arch_hardware_setup(void *opaque) * be 1 on all machines. */ u64 max = min(0x7fffffffULL, - __scale_tsc(kvm_max_tsc_scaling_ratio, tsc_khz)); - kvm_max_guest_tsc_khz = max; + __scale_tsc(kvm_caps.max_tsc_scaling_ratio, tsc_khz)); + kvm_caps.max_guest_tsc_khz = max; } - kvm_default_tsc_scaling_ratio = 1ULL << kvm_tsc_scaling_ratio_frac_bits; + kvm_caps.default_tsc_scaling_ratio = 1ULL << kvm_caps.tsc_scaling_ratio_frac_bits; kvm_init_msr_list(); return 0; } diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 588792f00334..359d0454ad28 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -8,6 +8,25 @@ #include "kvm_cache_regs.h" #include "kvm_emulate.h" +struct kvm_caps { + /* control of guest tsc rate supported? */ + bool has_tsc_control; + /* maximum supported tsc_khz for guests */ + u32 max_guest_tsc_khz; + /* number of bits of the fractional part of the TSC scaling ratio */ + u8 tsc_scaling_ratio_frac_bits; + /* maximum allowed value of TSC scaling ratio */ + u64 max_tsc_scaling_ratio; + /* 1ull << kvm_caps.tsc_scaling_ratio_frac_bits */ + u64 default_tsc_scaling_ratio; + /* bus lock detection supported? */ + bool has_bus_lock_exit; + + u64 supported_mce_cap; + u64 supported_xcr0; + u64 supported_xss; +}; + void kvm_spurious_fault(void); #define KVM_NESTED_VMENTER_CONSISTENCY_CHECK(consistency_check) \ @@ -283,14 +302,15 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, fastpath_t handle_fastpath_set_msr_irqoff(struct kvm_vcpu *vcpu); extern u64 host_xcr0; -extern u64 supported_xcr0; extern u64 host_xss; -extern u64 supported_xss; + +extern struct kvm_caps kvm_caps; + extern bool enable_pmu; static inline bool kvm_mpx_supported(void) { - return (supported_xcr0 & (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR)) + return (kvm_caps.supported_xcr0 & (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR)) == (XFEATURE_MASK_BNDREGS | XFEATURE_MASK_BNDCSR); } From ded3021ef20567affdf0a08b21e9300f72cfc7c4 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 23 May 2022 14:23:23 -0700 Subject: [PATCH 0168/1436] dt-bindings: HID: i2c-hid: elan: Introduce bindings for Elan eKTH6915 Like many i2c-hid touchscreen controllers, the Elan eKTH6915 controller has a reset gpio. For the Goodix GT7375P touchscreen the decision was to add a new binding rather than trying to add a new GPIO to the existing i2c-hid binding. We'll follow the lead and do it here, too. SIDE NOTE: the Elan eKTH6915 is a touchscreen _controller_ that's included as a part on some touchscreens. The reset line isn't truly necessary for the functioning of the touchscreen, so it's possible that some designs won't have it hooked up and will just guarantee the power sequencing requirements with RLC circuits. Thus, we'll mark the reset gpio as optional. Note that if the reset GPIO isn't used there's actually no true need to use the "elan,ekth6915" compatible instead of the "hid-over-i2c" on Linux. However: - Officially using just "hid-over-i2c" for this device violates the existing "hid-over-i2c" bindings. The bindings say that you're not supposed to use "post-power-on-delay-ms" without specifying a more specific compatible. Currently the Linux driver doesn't enforce this, but it violates the bindings to just use "hid-over-i2c". ...and if you're going to add a more specific compatible anyway, might as well do it right. - Using this compatible means we don't need to specify "hid-descr-addr" since it's inferred from the compatible. - Using this compatible means that the regulator names match the names on the Elan datasheet (vcc33 / vccio) vs the generic hid-over-i2c (vdd / vddl). Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Torokhov Reviewed-by: Rob Herring Signed-off-by: Jiri Kosina --- .../bindings/input/elan,ekth6915.yaml | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/elan,ekth6915.yaml diff --git a/Documentation/devicetree/bindings/input/elan,ekth6915.yaml b/Documentation/devicetree/bindings/input/elan,ekth6915.yaml new file mode 100644 index 000000000000..05e6f2df604c --- /dev/null +++ b/Documentation/devicetree/bindings/input/elan,ekth6915.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/elan,ekth6915.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Elan eKTH6915 touchscreen controller + +maintainers: + - Douglas Anderson + +description: + Supports the Elan eKTH6915 touchscreen controller. + This touchscreen controller uses the i2c-hid protocol with a reset GPIO. + +properties: + compatible: + items: + - const: elan,ekth6915 + + reg: + const: 0x10 + + interrupts: + maxItems: 1 + + reset-gpios: + description: Reset GPIO; not all touchscreens using eKTH6915 hook this up. + + vcc33-supply: + description: The 3.3V supply to the touchscreen. + + vccio-supply: + description: + The IO supply to the touchscreen. Need not be specified if this is the + same as the 3.3V supply. + +required: + - compatible + - reg + - interrupts + - vcc33-supply + +additionalProperties: false + +examples: + - | + #include + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ap_ts: touchscreen@10 { + compatible = "elan,ekth6915"; + reg = <0x10>; + + interrupt-parent = <&tlmm>; + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; + + reset-gpios = <&tlmm 8 GPIO_ACTIVE_LOW>; + vcc33-supply = <&pp3300_ts>; + }; + }; From bd3cba00dcc639311c29eee81606707ba5fd9217 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Mon, 23 May 2022 14:23:24 -0700 Subject: [PATCH 0169/1436] HID: i2c-hid: elan: Add support for Elan eKTH6915 i2c-hid touchscreens Like many i2c-hid touchscreen controllers, the Elan eKTH6915 has a reset GPIO hooked up to it. According to the datasheet, the way we're supposed to turn the touchscreen on is: 1. Turn on the 3.3V supply. 2. Turn on the IO supply. It's OK if this is hardwired to the 3.3V supply, but if it's not then it must be turned on _after_ the 3.3V supply. 3. Wait >= 1 ms. 4. Deassert the reset GPIO (reset GPIO is active low, so there would be a leakage path if this was deasserted _before_ the IO supply). 5. Wait 300 ms. Much of the above can be handled by the generic i2c-hid-of driver, but the "reset" GPIO is not supported by that driver. Thus we'll do the same as we did for Goodix and add a new tiny driver that uses the i2c-hid core. NOTE: support for this new touchscreen could theorically fit into the Goodix driver. I've made it a separate driver because the Elan driver supports _two_ regulators and it's unclear exactly how that would fit in with commit 18eeef46d359 ("HID: i2c-hid: goodix: Tie the reset line to true state of the regulator"). Signed-off-by: Douglas Anderson Reviewed-by: Dmitry Torokhov Reviewed-by: Matthias Kaehlcke Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/Kconfig | 15 +++ drivers/hid/i2c-hid/Makefile | 1 + drivers/hid/i2c-hid/i2c-hid-of-elan.c | 130 ++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 drivers/hid/i2c-hid/i2c-hid-of-elan.c diff --git a/drivers/hid/i2c-hid/Kconfig b/drivers/hid/i2c-hid/Kconfig index a16c6a69680b..5273ee2bb134 100644 --- a/drivers/hid/i2c-hid/Kconfig +++ b/drivers/hid/i2c-hid/Kconfig @@ -32,6 +32,21 @@ config I2C_HID_OF will be called i2c-hid-of. It will also build/depend on the module i2c-hid. +config I2C_HID_OF_ELAN + tristate "Driver for Elan hid-i2c based devices on OF systems" + default n + depends on I2C && INPUT && OF + help + Say Y here if you want support for Elan i2c devices that use + the i2c-hid protocol on Open Firmware (Device Tree)-based + systems. + + If unsure, say N. + + This support is also available as a module. If so, the module + will be called i2c-hid-of-elan. It will also build/depend on + the module i2c-hid. + config I2C_HID_OF_GOODIX tristate "Driver for Goodix hid-i2c based devices on OF systems" default n diff --git a/drivers/hid/i2c-hid/Makefile b/drivers/hid/i2c-hid/Makefile index 302545a771f3..55bd5e0f35af 100644 --- a/drivers/hid/i2c-hid/Makefile +++ b/drivers/hid/i2c-hid/Makefile @@ -10,4 +10,5 @@ i2c-hid-$(CONFIG_DMI) += i2c-hid-dmi-quirks.o obj-$(CONFIG_I2C_HID_ACPI) += i2c-hid-acpi.o obj-$(CONFIG_I2C_HID_OF) += i2c-hid-of.o +obj-$(CONFIG_I2C_HID_OF_ELAN) += i2c-hid-of-elan.o obj-$(CONFIG_I2C_HID_OF_GOODIX) += i2c-hid-of-goodix.o diff --git a/drivers/hid/i2c-hid/i2c-hid-of-elan.c b/drivers/hid/i2c-hid/i2c-hid-of-elan.c new file mode 100644 index 000000000000..2d991325e734 --- /dev/null +++ b/drivers/hid/i2c-hid/i2c-hid-of-elan.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Elan touchscreens that use the i2c-hid protocol. + * + * Copyright 2020 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-hid.h" + +struct elan_i2c_hid_chip_data { + unsigned int post_gpio_reset_delay_ms; + unsigned int post_power_delay_ms; + u16 hid_descriptor_address; +}; + +struct i2c_hid_of_elan { + struct i2chid_ops ops; + + struct regulator *vcc33; + struct regulator *vccio; + struct gpio_desc *reset_gpio; + const struct elan_i2c_hid_chip_data *chip_data; +}; + +static int elan_i2c_hid_power_up(struct i2chid_ops *ops) +{ + struct i2c_hid_of_elan *ihid_elan = + container_of(ops, struct i2c_hid_of_elan, ops); + int ret; + + ret = regulator_enable(ihid_elan->vcc33); + if (ret) + return ret; + + ret = regulator_enable(ihid_elan->vccio); + if (ret) { + regulator_disable(ihid_elan->vcc33); + return ret; + } + + if (ihid_elan->chip_data->post_power_delay_ms) + msleep(ihid_elan->chip_data->post_power_delay_ms); + + gpiod_set_value_cansleep(ihid_elan->reset_gpio, 0); + if (ihid_elan->chip_data->post_gpio_reset_delay_ms) + msleep(ihid_elan->chip_data->post_gpio_reset_delay_ms); + + return 0; +} + +static void elan_i2c_hid_power_down(struct i2chid_ops *ops) +{ + struct i2c_hid_of_elan *ihid_elan = + container_of(ops, struct i2c_hid_of_elan, ops); + + gpiod_set_value_cansleep(ihid_elan->reset_gpio, 1); + regulator_disable(ihid_elan->vccio); + regulator_disable(ihid_elan->vcc33); +} + +static int i2c_hid_of_elan_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_hid_of_elan *ihid_elan; + + ihid_elan = devm_kzalloc(&client->dev, sizeof(*ihid_elan), GFP_KERNEL); + if (!ihid_elan) + return -ENOMEM; + + ihid_elan->ops.power_up = elan_i2c_hid_power_up; + ihid_elan->ops.power_down = elan_i2c_hid_power_down; + + /* Start out with reset asserted */ + ihid_elan->reset_gpio = + devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ihid_elan->reset_gpio)) + return PTR_ERR(ihid_elan->reset_gpio); + + ihid_elan->vccio = devm_regulator_get(&client->dev, "vccio"); + if (IS_ERR(ihid_elan->vccio)) + return PTR_ERR(ihid_elan->vccio); + + ihid_elan->vcc33 = devm_regulator_get(&client->dev, "vcc33"); + if (IS_ERR(ihid_elan->vcc33)) + return PTR_ERR(ihid_elan->vcc33); + + ihid_elan->chip_data = device_get_match_data(&client->dev); + + return i2c_hid_core_probe(client, &ihid_elan->ops, + ihid_elan->chip_data->hid_descriptor_address, 0); +} + +static const struct elan_i2c_hid_chip_data elan_ekth6915_chip_data = { + .post_power_delay_ms = 1, + .post_gpio_reset_delay_ms = 300, + .hid_descriptor_address = 0x0001, +}; + +static const struct of_device_id elan_i2c_hid_of_match[] = { + { .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data }, + { } +}; +MODULE_DEVICE_TABLE(of, elan_i2c_hid_of_match); + +static struct i2c_driver elan_i2c_hid_ts_driver = { + .driver = { + .name = "i2c_hid_of_elan", + .pm = &i2c_hid_core_pm, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .of_match_table = of_match_ptr(elan_i2c_hid_of_match), + }, + .probe = i2c_hid_of_elan_probe, + .remove = i2c_hid_core_remove, + .shutdown = i2c_hid_core_shutdown, +}; +module_i2c_driver(elan_i2c_hid_ts_driver); + +MODULE_AUTHOR("Douglas Anderson "); +MODULE_DESCRIPTION("Elan i2c-hid touchscreen driver"); +MODULE_LICENSE("GPL"); From 92cdfba40155aab313d307eecbaef331b447fe54 Mon Sep 17 00:00:00 2001 From: "Daniel J. Ogorchock" Date: Sat, 28 May 2022 17:23:31 -0400 Subject: [PATCH 0170/1436] HID: nintendo: fix unused const warning JC_RUMBLE_ZERO_AMP_PKT_CNT is only used when force feedback support in the driver is enabled. Place the declaration in the CONFIG_NINTENDO_FF ifdef to avoid a warning when compiling without rumble support. Signed-off-by: Daniel J. Ogorchock Reviewed-by: Silvan Jegen Signed-off-by: Jiri Kosina --- drivers/hid/hid-nintendo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index 2204de889739..dcd0f16de7b5 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -292,6 +292,7 @@ static const struct joycon_rumble_amp_data joycon_rumble_amplitudes[] = { }; static const u16 JC_RUMBLE_DFLT_LOW_FREQ = 160; static const u16 JC_RUMBLE_DFLT_HIGH_FREQ = 320; +static const unsigned short JC_RUMBLE_ZERO_AMP_PKT_CNT = 5; #endif /* IS_ENABLED(CONFIG_NINTENDO_FF) */ static const u16 JC_RUMBLE_PERIOD_MS = 50; @@ -402,8 +403,6 @@ struct joycon_input_report { #define JC_RUMBLE_DATA_SIZE 8 #define JC_RUMBLE_QUEUE_SIZE 8 -static const unsigned short JC_RUMBLE_ZERO_AMP_PKT_CNT = 5; - static const char * const joycon_player_led_names[] = { LED_FUNCTION_PLAYER1, LED_FUNCTION_PLAYER2, From a0a05054583fed17f522172e101594f1ff265463 Mon Sep 17 00:00:00 2001 From: Hilton Chain Date: Thu, 2 Jun 2022 16:12:19 +0800 Subject: [PATCH 0171/1436] HID: apple: Properly handle function keys on non-Apple keyboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit extends fa33382c7f74 ("HID: apple: Properly handle function keys on Keychron keyboards") by adding an array of known non-Apple keyboards' device names, and the function apple_is_non_apple_keyboard() to identify and create exception for them. Signed-off-by: Hilton Chain Reviewed-by: Bryan Cain Tested-by: Bryan Cain Reviewed-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 42a568902f49..7fbde58e1219 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -36,7 +36,7 @@ #define APPLE_NUMLOCK_EMULATION BIT(8) #define APPLE_RDESC_BATTERY BIT(9) #define APPLE_BACKLIGHT_CTL BIT(10) -#define APPLE_IS_KEYCHRON BIT(11) +#define APPLE_IS_NON_APPLE BIT(11) #define APPLE_FLAG_FKEY 0x01 @@ -65,6 +65,10 @@ MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. " "(For people who want to keep PC keyboard muscle memory. " "[0] = as-is, Mac layout, 1 = swapped, PC layout)"); +struct apple_non_apple_keyboard { + char *name; +}; + struct apple_sc_backlight { struct led_classdev cdev; struct hid_device *hdev; @@ -313,6 +317,26 @@ static const struct apple_key_translation swapped_fn_leftctrl_keys[] = { { } }; +static const struct apple_non_apple_keyboard non_apple_keyboards[] = { + { "SONiX USB DEVICE" }, + { "Keychron" }, + { "AONE" } +}; + +static bool apple_is_non_apple_keyboard(struct hid_device *hdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(non_apple_keyboards); i++) { + char *non_apple = non_apple_keyboards[i].name; + + if (strncmp(hdev->name, non_apple, strlen(non_apple)) == 0) + return true; + } + + return false; +} + static inline void apple_setup_key_translation(struct input_dev *input, const struct apple_key_translation *table) { @@ -363,7 +387,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, } if (fnmode == 3) { - real_fnmode = (asc->quirks & APPLE_IS_KEYCHRON) ? 2 : 1; + real_fnmode = (asc->quirks & APPLE_IS_NON_APPLE) ? 2 : 1; } else { real_fnmode = fnmode; } @@ -669,9 +693,9 @@ static int apple_input_configured(struct hid_device *hdev, asc->quirks &= ~APPLE_HAS_FN; } - if (strncmp(hdev->name, "Keychron", 8) == 0) { - hid_info(hdev, "Keychron keyboard detected; function keys will default to fnmode=2 behavior\n"); - asc->quirks |= APPLE_IS_KEYCHRON; + if (apple_is_non_apple_keyboard(hdev)) { + hid_info(hdev, "Non-apple keyboard detected; function keys will default to fnmode=2 behavior\n"); + asc->quirks |= APPLE_IS_NON_APPLE; } return 0; From 2f4073e08f4cc5a41e35d777c240aaadd0257051 Mon Sep 17 00:00:00 2001 From: Tao Xu Date: Tue, 24 May 2022 21:56:24 +0800 Subject: [PATCH 0172/1436] KVM: VMX: Enable Notify VM exit There are cases that malicious virtual machines can cause CPU stuck (due to event windows don't open up), e.g., infinite loop in microcode when nested #AC (CVE-2015-5307). No event window means no event (NMI, SMI and IRQ) can be delivered. It leads the CPU to be unavailable to host or other VMs. VMM can enable notify VM exit that a VM exit generated if no event window occurs in VM non-root mode for a specified amount of time (notify window). Feature enabling: - The new vmcs field SECONDARY_EXEC_NOTIFY_VM_EXITING is introduced to enable this feature. VMM can set NOTIFY_WINDOW vmcs field to adjust the expected notify window. - Add a new KVM capability KVM_CAP_X86_NOTIFY_VMEXIT so that user space can query and enable this feature in per-VM scope. The argument is a 64bit value: bits 63:32 are used for notify window, and bits 31:0 are for flags. Current supported flags: - KVM_X86_NOTIFY_VMEXIT_ENABLED: enable the feature with the notify window provided. - KVM_X86_NOTIFY_VMEXIT_USER: exit to userspace once the exits happen. - It's safe to even set notify window to zero since an internal hardware threshold is added to vmcs.notify_window. VM exit handling: - Introduce a vcpu state notify_window_exits to records the count of notify VM exits and expose it through the debugfs. - Notify VM exit can happen incident to delivery of a vector event. Allow it in KVM. - Exit to userspace unconditionally for handling when VM_CONTEXT_INVALID bit is set. Nested handling - Nested notify VM exits are not supported yet. Keep the same notify window control in vmcs02 as vmcs01, so that L1 can't escape the restriction of notify VM exits through launching L2 VM. Notify VM exit is defined in latest Intel Architecture Instruction Set Extensions Programming Reference, chapter 9.2. Co-developed-by: Xiaoyao Li Signed-off-by: Xiaoyao Li Signed-off-by: Tao Xu Co-developed-by: Chenyi Qiang Signed-off-by: Chenyi Qiang Message-Id: <20220524135624.22988-5-chenyi.qiang@intel.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 49 ++++++++++++++++++++++++++++++ arch/x86/include/asm/kvm_host.h | 7 +++++ arch/x86/include/asm/vmx.h | 7 +++++ arch/x86/include/asm/vmxfeatures.h | 1 + arch/x86/include/uapi/asm/vmx.h | 4 ++- arch/x86/kvm/vmx/capabilities.h | 6 ++++ arch/x86/kvm/vmx/nested.c | 8 +++++ arch/x86/kvm/vmx/vmx.c | 40 ++++++++++++++++++++++-- arch/x86/kvm/x86.c | 22 +++++++++++++- arch/x86/kvm/x86.h | 7 +++++ include/uapi/linux/kvm.h | 11 +++++++ 11 files changed, 158 insertions(+), 4 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index f67e367c4059..30e31a886422 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6557,6 +6557,26 @@ array field represents return values. The userspace should update the return values of SBI call before resuming the VCPU. For more details on RISC-V SBI spec refer, https://github.com/riscv/riscv-sbi-doc. +:: + + /* KVM_EXIT_NOTIFY */ + struct { + #define KVM_NOTIFY_CONTEXT_INVALID (1 << 0) + __u32 flags; + } notify; + +Used on x86 systems. When the VM capability KVM_CAP_X86_NOTIFY_VMEXIT is +enabled, a VM exit generated if no event window occurs in VM non-root mode +for a specified amount of time. Once KVM_X86_NOTIFY_VMEXIT_USER is set when +enabling the cap, it would exit to userspace with the exit reason +KVM_EXIT_NOTIFY for further handling. The "flags" field contains more +detailed info. + +The valid value for 'flags' is: + + - KVM_NOTIFY_CONTEXT_INVALID -- the VM context is corrupted and not valid + in VMCS. It would run into unknown result if resume the target VM. + :: /* Fix the size of the union. */ @@ -7523,6 +7543,35 @@ if the value was set to zero or KVM_ENABLE_CAP was not invoked, KVM uses the return value of KVM_CHECK_EXTENSION(KVM_CAP_MAX_VCPU_ID) as the maximum APIC ID. +7.33 KVM_CAP_X86_NOTIFY_VMEXIT +------------------------------ + +:Architectures: x86 +:Target: VM +:Parameters: args[0] is the value of notify window as well as some flags +:Returns: 0 on success, -EINVAL if args[0] contains invalid flags or notify + VM exit is unsupported. + +Bits 63:32 of args[0] are used for notify window. +Bits 31:0 of args[0] are for some flags. Valid bits are:: + + #define KVM_X86_NOTIFY_VMEXIT_ENABLED (1 << 0) + #define KVM_X86_NOTIFY_VMEXIT_USER (1 << 1) + +This capability allows userspace to configure the notify VM exit on/off +in per-VM scope during VM creation. Notify VM exit is disabled by default. +When userspace sets KVM_X86_NOTIFY_VMEXIT_ENABLED bit in args[0], VMM will +enable this feature with the notify window provided, which will generate +a VM exit if no event window occurs in VM non-root mode for a specified of +time (notify window). + +If KVM_X86_NOTIFY_VMEXIT_USER is set in args[0], upon notify VM exits happen, +KVM would exit to userspace for handling. + +This capability is aimed to mitigate the threat that malicious VMs can +cause CPU stuck (due to event windows don't open up) and make the CPU +unavailable to host or other VMs. + 8. Other capabilities. ====================== diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 4e00bca08cfa..6cf5d77d7896 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -65,6 +65,9 @@ #define KVM_BUS_LOCK_DETECTION_VALID_MODE (KVM_BUS_LOCK_DETECTION_OFF | \ KVM_BUS_LOCK_DETECTION_EXIT) +#define KVM_X86_NOTIFY_VMEXIT_VALID_BITS (KVM_X86_NOTIFY_VMEXIT_ENABLED | \ + KVM_X86_NOTIFY_VMEXIT_USER) + /* x86-specific vcpu->requests bit members */ #define KVM_REQ_MIGRATE_TIMER KVM_ARCH_REQ(0) #define KVM_REQ_REPORT_TPR_ACCESS KVM_ARCH_REQ(1) @@ -1178,6 +1181,9 @@ struct kvm_arch { bool bus_lock_detection_enabled; bool enable_pmu; + + u32 notify_window; + u32 notify_vmexit_flags; /* * If exit_on_emulation_error is set, and the in-kernel instruction * emulator fails to emulate an instruction, allow userspace @@ -1325,6 +1331,7 @@ struct kvm_vcpu_stat { u64 directed_yield_attempted; u64 directed_yield_successful; u64 guest_mode; + u64 notify_window_exits; }; struct x86_instruction_info; diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 89d2172787c5..c371ef695fcc 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -75,6 +75,7 @@ #define SECONDARY_EXEC_TSC_SCALING VMCS_CONTROL_BIT(TSC_SCALING) #define SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE VMCS_CONTROL_BIT(USR_WAIT_PAUSE) #define SECONDARY_EXEC_BUS_LOCK_DETECTION VMCS_CONTROL_BIT(BUS_LOCK_DETECTION) +#define SECONDARY_EXEC_NOTIFY_VM_EXITING VMCS_CONTROL_BIT(NOTIFY_VM_EXITING) /* * Definitions of Tertiary Processor-Based VM-Execution Controls. @@ -280,6 +281,7 @@ enum vmcs_field { SECONDARY_VM_EXEC_CONTROL = 0x0000401e, PLE_GAP = 0x00004020, PLE_WINDOW = 0x00004022, + NOTIFY_WINDOW = 0x00004024, VM_INSTRUCTION_ERROR = 0x00004400, VM_EXIT_REASON = 0x00004402, VM_EXIT_INTR_INFO = 0x00004404, @@ -564,6 +566,11 @@ enum vm_entry_failure_code { #define EPT_VIOLATION_GVA_IS_VALID (1 << EPT_VIOLATION_GVA_IS_VALID_BIT) #define EPT_VIOLATION_GVA_TRANSLATED (1 << EPT_VIOLATION_GVA_TRANSLATED_BIT) +/* + * Exit Qualifications for NOTIFY VM EXIT + */ +#define NOTIFY_VM_CONTEXT_INVALID BIT(0) + /* * VM-instruction error numbers */ diff --git a/arch/x86/include/asm/vmxfeatures.h b/arch/x86/include/asm/vmxfeatures.h index 589608c157bf..c6a7eed03914 100644 --- a/arch/x86/include/asm/vmxfeatures.h +++ b/arch/x86/include/asm/vmxfeatures.h @@ -85,6 +85,7 @@ #define VMX_FEATURE_USR_WAIT_PAUSE ( 2*32+ 26) /* Enable TPAUSE, UMONITOR, UMWAIT in guest */ #define VMX_FEATURE_ENCLV_EXITING ( 2*32+ 28) /* "" VM-Exit on ENCLV (leaf dependent) */ #define VMX_FEATURE_BUS_LOCK_DETECTION ( 2*32+ 30) /* "" VM-Exit when bus lock caused */ +#define VMX_FEATURE_NOTIFY_VM_EXITING ( 2*32+ 31) /* VM-Exit when no event windows after notify window */ /* Tertiary Processor-Based VM-Execution Controls, word 3 */ #define VMX_FEATURE_IPI_VIRT ( 3*32+ 4) /* Enable IPI virtualization */ diff --git a/arch/x86/include/uapi/asm/vmx.h b/arch/x86/include/uapi/asm/vmx.h index 946d761adbd3..a5faf6d88f1b 100644 --- a/arch/x86/include/uapi/asm/vmx.h +++ b/arch/x86/include/uapi/asm/vmx.h @@ -91,6 +91,7 @@ #define EXIT_REASON_UMWAIT 67 #define EXIT_REASON_TPAUSE 68 #define EXIT_REASON_BUS_LOCK 74 +#define EXIT_REASON_NOTIFY 75 #define VMX_EXIT_REASONS \ { EXIT_REASON_EXCEPTION_NMI, "EXCEPTION_NMI" }, \ @@ -153,7 +154,8 @@ { EXIT_REASON_XRSTORS, "XRSTORS" }, \ { EXIT_REASON_UMWAIT, "UMWAIT" }, \ { EXIT_REASON_TPAUSE, "TPAUSE" }, \ - { EXIT_REASON_BUS_LOCK, "BUS_LOCK" } + { EXIT_REASON_BUS_LOCK, "BUS_LOCK" }, \ + { EXIT_REASON_NOTIFY, "NOTIFY" } #define VMX_EXIT_REASON_FLAGS \ { VMX_EXIT_REASONS_FAILED_VMENTRY, "FAILED_VMENTRY" } diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h index f14c4bef97e0..2d3f13b18714 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -436,4 +436,10 @@ static inline u64 vmx_supported_debugctl(void) return debugctl; } +static inline bool cpu_has_notify_vmexit(void) +{ + return vmcs_config.cpu_based_2nd_exec_ctrl & + SECONDARY_EXEC_NOTIFY_VM_EXITING; +} + #endif /* __KVM_X86_VMX_CAPS_H */ diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 5c5f4e3762f5..7d8cd0ebcc75 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -2133,6 +2133,8 @@ static u64 nested_vmx_calc_efer(struct vcpu_vmx *vmx, struct vmcs12 *vmcs12) static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx) { + struct kvm *kvm = vmx->vcpu.kvm; + /* * If vmcs02 hasn't been initialized, set the constant vmcs02 state * according to L0's settings (vmcs12 is irrelevant here). Host @@ -2175,6 +2177,9 @@ static void prepare_vmcs02_constant_state(struct vcpu_vmx *vmx) if (cpu_has_vmx_encls_vmexit()) vmcs_write64(ENCLS_EXITING_BITMAP, INVALID_GPA); + if (kvm_notify_vmexit_enabled(kvm)) + vmcs_write32(NOTIFY_WINDOW, kvm->arch.notify_window); + /* * Set the MSR load/store lists to match L0's settings. Only the * addresses are constant (for vmcs02), the counts can change based @@ -6112,6 +6117,9 @@ static bool nested_vmx_l1_wants_exit(struct kvm_vcpu *vcpu, SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE); case EXIT_REASON_ENCLS: return nested_vmx_exit_handled_encls(vcpu, vmcs12); + case EXIT_REASON_NOTIFY: + /* Notify VM exit is not exposed to L1 */ + return false; default: return true; } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 6d631941ac1a..2e00890d752a 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2499,7 +2499,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, SECONDARY_EXEC_PT_USE_GPA | SECONDARY_EXEC_PT_CONCEAL_VMX | SECONDARY_EXEC_ENABLE_VMFUNC | - SECONDARY_EXEC_BUS_LOCK_DETECTION; + SECONDARY_EXEC_BUS_LOCK_DETECTION | + SECONDARY_EXEC_NOTIFY_VM_EXITING; if (cpu_has_sgx()) opt2 |= SECONDARY_EXEC_ENCLS_EXITING; if (adjust_vmx_controls(min2, opt2, @@ -4417,6 +4418,9 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx) if (!vcpu->kvm->arch.bus_lock_detection_enabled) exec_control &= ~SECONDARY_EXEC_BUS_LOCK_DETECTION; + if (!kvm_notify_vmexit_enabled(vcpu->kvm)) + exec_control &= ~SECONDARY_EXEC_NOTIFY_VM_EXITING; + return exec_control; } @@ -4498,6 +4502,9 @@ static void init_vmcs(struct vcpu_vmx *vmx) vmx->ple_window_dirty = true; } + if (kvm_notify_vmexit_enabled(kvm)) + vmcs_write32(NOTIFY_WINDOW, kvm->arch.notify_window); + vmcs_write32(PAGE_FAULT_ERROR_CODE_MASK, 0); vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, 0); vmcs_write32(CR3_TARGET_COUNT, 0); /* 22.2.1 */ @@ -5784,6 +5791,32 @@ static int handle_bus_lock_vmexit(struct kvm_vcpu *vcpu) return 1; } +static int handle_notify(struct kvm_vcpu *vcpu) +{ + unsigned long exit_qual = vmx_get_exit_qual(vcpu); + bool context_invalid = exit_qual & NOTIFY_VM_CONTEXT_INVALID; + + ++vcpu->stat.notify_window_exits; + + /* + * Notify VM exit happened while executing iret from NMI, + * "blocked by NMI" bit has to be set before next VM entry. + */ + if (enable_vnmi && (exit_qual & INTR_INFO_UNBLOCK_NMI)) + vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, + GUEST_INTR_STATE_NMI); + + if (vcpu->kvm->arch.notify_vmexit_flags & KVM_X86_NOTIFY_VMEXIT_USER || + context_invalid) { + vcpu->run->exit_reason = KVM_EXIT_NOTIFY; + vcpu->run->notify.flags = context_invalid ? + KVM_NOTIFY_CONTEXT_INVALID : 0; + return 0; + } + + return 1; +} + /* * The exit handlers return 1 if the exit was handled fully and guest execution * may resume. Otherwise they set the kvm_run parameter to indicate what needs @@ -5841,6 +5874,7 @@ static int (*kvm_vmx_exit_handlers[])(struct kvm_vcpu *vcpu) = { [EXIT_REASON_PREEMPTION_TIMER] = handle_preemption_timer, [EXIT_REASON_ENCLS] = handle_encls, [EXIT_REASON_BUS_LOCK] = handle_bus_lock_vmexit, + [EXIT_REASON_NOTIFY] = handle_notify, }; static const int kvm_vmx_max_exit_handlers = @@ -6214,7 +6248,8 @@ static int __vmx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath) exit_reason.basic != EXIT_REASON_EPT_VIOLATION && exit_reason.basic != EXIT_REASON_PML_FULL && exit_reason.basic != EXIT_REASON_APIC_ACCESS && - exit_reason.basic != EXIT_REASON_TASK_SWITCH)) { + exit_reason.basic != EXIT_REASON_TASK_SWITCH && + exit_reason.basic != EXIT_REASON_NOTIFY)) { int ndata = 3; vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; @@ -8137,6 +8172,7 @@ static __init int hardware_setup(void) kvm_caps.max_tsc_scaling_ratio = KVM_VMX_TSC_MULTIPLIER_MAX; kvm_caps.tsc_scaling_ratio_frac_bits = 48; kvm_caps.has_bus_lock_exit = cpu_has_vmx_bus_lock_detection(); + kvm_caps.has_notify_vmexit = cpu_has_notify_vmexit(); set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 53e5f2ad2422..a8014233fd57 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -284,7 +284,8 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { STATS_DESC_COUNTER(VCPU, nested_run), STATS_DESC_COUNTER(VCPU, directed_yield_attempted), STATS_DESC_COUNTER(VCPU, directed_yield_successful), - STATS_DESC_ICOUNTER(VCPU, guest_mode) + STATS_DESC_ICOUNTER(VCPU, guest_mode), + STATS_DESC_COUNTER(VCPU, notify_window_exits), }; const struct kvm_stats_header kvm_vcpu_stats_header = { @@ -4402,6 +4403,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_DISABLE_QUIRKS2: r = KVM_X86_VALID_QUIRKS; break; + case KVM_CAP_X86_NOTIFY_VMEXIT: + r = kvm_caps.has_notify_vmexit; + break; default: break; } @@ -6125,6 +6129,22 @@ split_irqchip_unlock: } mutex_unlock(&kvm->lock); break; + case KVM_CAP_X86_NOTIFY_VMEXIT: + r = -EINVAL; + if ((u32)cap->args[0] & ~KVM_X86_NOTIFY_VMEXIT_VALID_BITS) + break; + if (!kvm_caps.has_notify_vmexit) + break; + if (!((u32)cap->args[0] & KVM_X86_NOTIFY_VMEXIT_ENABLED)) + break; + mutex_lock(&kvm->lock); + if (!kvm->created_vcpus) { + kvm->arch.notify_window = cap->args[0] >> 32; + kvm->arch.notify_vmexit_flags = (u32)cap->args[0]; + r = 0; + } + mutex_unlock(&kvm->lock); + break; default: r = -EINVAL; break; diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 359d0454ad28..501b884b8cc4 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -21,6 +21,8 @@ struct kvm_caps { u64 default_tsc_scaling_ratio; /* bus lock detection supported? */ bool has_bus_lock_exit; + /* notify VM exit supported? */ + bool has_notify_vmexit; u64 supported_mce_cap; u64 supported_xcr0; @@ -364,6 +366,11 @@ static inline bool kvm_cstate_in_guest(struct kvm *kvm) return kvm->arch.cstate_in_guest; } +static inline bool kvm_notify_vmexit_enabled(struct kvm *kvm) +{ + return kvm->arch.notify_vmexit_flags & KVM_X86_NOTIFY_VMEXIT_ENABLED; +} + enum kvm_intr_type { /* Values are arbitrary, but must be non-zero. */ KVM_HANDLING_IRQ = 1, diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index ca799319acfd..7569b4ec199c 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -270,6 +270,7 @@ struct kvm_xen_exit { #define KVM_EXIT_X86_BUS_LOCK 33 #define KVM_EXIT_XEN 34 #define KVM_EXIT_RISCV_SBI 35 +#define KVM_EXIT_NOTIFY 36 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -496,6 +497,11 @@ struct kvm_run { unsigned long args[6]; unsigned long ret[2]; } riscv_sbi; + /* KVM_EXIT_NOTIFY */ + struct { +#define KVM_NOTIFY_CONTEXT_INVALID (1 << 0) + __u32 flags; + } notify; /* Fix the size of the union. */ char padding[256]; }; @@ -1159,6 +1165,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_ARM_SYSTEM_SUSPEND 216 #define KVM_CAP_S390_PROTECTED_DUMP 217 #define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218 +#define KVM_CAP_X86_NOTIFY_VMEXIT 219 #ifdef KVM_CAP_IRQ_ROUTING @@ -2174,4 +2181,8 @@ struct kvm_stats_desc { /* Available with KVM_CAP_S390_PROTECTED_DUMP */ #define KVM_S390_PV_CPU_COMMAND _IOWR(KVMIO, 0xd0, struct kvm_pv_cmd) +/* Available with KVM_CAP_X86_NOTIFY_VMEXIT */ +#define KVM_X86_NOTIFY_VMEXIT_ENABLED (1ULL << 0) +#define KVM_X86_NOTIFY_VMEXIT_USER (1ULL << 1) + #endif /* __LINUX_KVM_H */ From d5e649a5a53767d48c244ca009168941adf3bb9a Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Sat, 4 Jun 2022 09:07:11 +0700 Subject: [PATCH 0173/1436] HID: uclogic: properly format kernel-doc comment for hid_dbg() wrappers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running kernel-doc script on drivers/hid/hid-uclogic-params.c, it found 6 warnings for hid_dbg() wrapper functions below: drivers/hid/hid-uclogic-params.c:48: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Dump tablet interface pen parameters with hid_dbg(), indented with one tab. drivers/hid/hid-uclogic-params.c:48: warning: missing initial short description on line: * Dump tablet interface pen parameters with hid_dbg(), indented with one tab. drivers/hid/hid-uclogic-params.c:48: info: Scanning doc for function Dump drivers/hid/hid-uclogic-params.c:80: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Dump tablet interface frame parameters with hid_dbg(), indented with two drivers/hid/hid-uclogic-params.c:80: warning: missing initial short description on line: * Dump tablet interface frame parameters with hid_dbg(), indented with two drivers/hid/hid-uclogic-params.c:80: info: Scanning doc for function Dump drivers/hid/hid-uclogic-params.c:105: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Dump tablet interface parameters with hid_dbg(). drivers/hid/hid-uclogic-params.c:105: warning: missing initial short description on line: * Dump tablet interface parameters with hid_dbg(). One of them is reported by kernel test robot. Fix these warnings by properly format kernel-doc comment for these functions. Link: https://lore.kernel.org/linux-doc/202205272033.XFYlYj8k-lkp@intel.com/ Fixes: a228809fa6f39c ("HID: uclogic: Move param printing to a function") Reported-by: kernel test robot Tested-by: Randy Dunlap Tested-by: José Expósito Acked-by: Randy Dunlap Cc: Nikolai Kondrashov Cc: Jiri Kosina Cc: Benjamin Tissoires Cc: llvm@lists.linux.dev Cc: linux-input@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Bagas Sanjaya Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index db838f16282d..e5e65d849faa 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -23,11 +23,11 @@ /** * uclogic_params_pen_inrange_to_str() - Convert a pen in-range reporting type * to a string. - * * @inrange: The in-range reporting type to convert. * - * Returns: - * The string representing the type, or NULL if the type is unknown. + * Return: + * * The string representing the type, or + * * %NULL if the type is unknown. */ static const char *uclogic_params_pen_inrange_to_str( enum uclogic_params_pen_inrange inrange) @@ -45,10 +45,12 @@ static const char *uclogic_params_pen_inrange_to_str( } /** - * Dump tablet interface pen parameters with hid_dbg(), indented with one tab. - * + * uclogic_params_pen_hid_dbg() - Dump tablet interface pen parameters * @hdev: The HID device the pen parameters describe. * @pen: The pen parameters to dump. + * + * Dump tablet interface pen parameters with hid_dbg(). The dump is indented + * with a tab. */ static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev, const struct uclogic_params_pen *pen) @@ -77,11 +79,12 @@ static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev, } /** - * Dump tablet interface frame parameters with hid_dbg(), indented with two - * tabs. - * + * uclogic_params_frame_hid_dbg() - Dump tablet interface frame parameters * @hdev: The HID device the pen parameters describe. * @frame: The frame parameters to dump. + * + * Dump tablet interface frame parameters with hid_dbg(). The dump is + * indented with two tabs. */ static void uclogic_params_frame_hid_dbg( const struct hid_device *hdev, @@ -102,10 +105,11 @@ static void uclogic_params_frame_hid_dbg( } /** - * Dump tablet interface parameters with hid_dbg(). - * + * uclogic_params_hid_dbg() - Dump tablet interface parameters * @hdev: The HID device the parameters describe. * @params: The parameters to dump. + * + * Dump tablet interface parameters with hid_dbg(). */ void uclogic_params_hid_dbg(const struct hid_device *hdev, const struct uclogic_params *params) From 6431fd0151eca63d4c62c4e6bcc1913b5e26d028 Mon Sep 17 00:00:00 2001 From: Xiang wangx Date: Sun, 5 Jun 2022 16:43:43 +0800 Subject: [PATCH 0174/1436] HID: logitech-hidpp: Fix syntax errors in comments Delete the redundant word 'in'. Signed-off-by: Xiang wangx Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-hidpp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 81de88ab2ecc..68f9e9d207f4 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -1694,7 +1694,7 @@ static int hidpp_battery_get_property(struct power_supply *psy, val->strval = hidpp->hid_dev->uniq; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - /* hardware reports voltage in in mV. sysfs expects uV */ + /* hardware reports voltage in mV. sysfs expects uV */ val->intval = hidpp->battery.voltage * 1000; break; case POWER_SUPPLY_PROP_CHARGE_TYPE: From 15b28156029465e594b462e6dad459a737028697 Mon Sep 17 00:00:00 2001 From: Li Qiong Date: Mon, 6 Jun 2022 21:47:50 +0800 Subject: [PATCH 0175/1436] HID: intel-ish-hid: ipc: use time_before to replace "jiffies < a" time_before deals with timer wrapping correctly. Signed-off-by: Li Qiong Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/ipc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c index 8ccb246b0114..15e14239af82 100644 --- a/drivers/hid/intel-ish-hid/ipc/ipc.c +++ b/drivers/hid/intel-ish-hid/ipc/ipc.c @@ -578,7 +578,7 @@ static void _ish_sync_fw_clock(struct ishtp_device *dev) static unsigned long prev_sync; uint64_t usec; - if (prev_sync && jiffies - prev_sync < 20 * HZ) + if (prev_sync && time_before(jiffies, prev_sync + 20 * HZ)) return; prev_sync = jiffies; From db925d809011c37b246434fdce71209fc2e6c0c2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 26 May 2022 01:08:27 +0200 Subject: [PATCH 0176/1436] HID: hid-input: add Surface Go battery quirk Similar to the Surface Go (1), the (Elantech) touchscreen/digitizer in the Surface Go 2 mistakenly reports the battery of the stylus. Instead of over the touchscreen device, battery information is provided via bluetooth and the touchscreen device reports an empty battery. Apply the HID_BATTERY_QUIRK_IGNORE quirk to ignore this battery and prevent the erroneous low battery warnings. Cc: stable@vger.kernel.org Signed-off-by: Maximilian Luz Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-input.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d9eb676abe96..9c4e92a9c646 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -413,6 +413,7 @@ #define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN 0x2544 #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706 #define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN 0x261A +#define I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN 0x2A1C #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index c6b27aab9041..48c1c02c69f4 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -381,6 +381,8 @@ static const struct hid_device_id hid_battery_quirks[] = { HID_BATTERY_QUIRK_IGNORE }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN), HID_BATTERY_QUIRK_IGNORE }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN), + HID_BATTERY_QUIRK_IGNORE }, {} }; From 92d80178a35b1ab04c4a8250a06399150dbf0b6a Mon Sep 17 00:00:00 2001 From: Like Xu Date: Tue, 17 May 2022 11:40:45 -0400 Subject: [PATCH 0177/1436] perf/x86/intel: Fix the comment about guest LBR support on KVM Starting from v5.12, KVM reports guest LBR and extra_regs support when the host has relevant support. Just delete this part of the comment and fix a typo incidentally. Cc: Peter Zijlstra Reviewed-by: Kan Liang Reviewed-by: Andi Kleen Signed-off-by: Like Xu Signed-off-by: Yang Weijiang Message-Id: <20220517154100.29983-2-weijiang.yang@intel.com> Signed-off-by: Paolo Bonzini --- arch/x86/events/intel/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 39832a5e7d75..4e9b7af9cc45 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -6501,8 +6501,7 @@ __init int intel_pmu_init(void) x86_pmu.intel_ctrl); /* * Access LBR MSR may cause #GP under certain circumstances. - * E.g. KVM doesn't support LBR MSR - * Check all LBT MSR here. + * Check all LBR MSR here. * Disable LBR access if any LBR MSRs can not be accessed. */ if (x86_pmu.lbr_tos && !check_msr(x86_pmu.lbr_tos, 0x3UL)) From 916e3a4f950eac92c28cc138c10d86514ffebf98 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 1 Jun 2022 05:45:17 -0400 Subject: [PATCH 0178/1436] x86: events: Do not return bogus capabilities if PMU is broken If the PMU is broken due to firmware issues, check_hw_exists() will return false but perf_get_x86_pmu_capability() will still return data from x86_pmu. Likewise if some of the hotplug callbacks cannot be installed the contents of x86_pmu will not be reverted. Handle the failure in both cases by clearing x86_pmu if init_hw_perf_events() or reverts to software events only. Co-developed-by: Like Xu Signed-off-by: Like Xu Signed-off-by: Paolo Bonzini --- arch/x86/events/core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 2e16c268a005..f969410d0c90 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -2103,14 +2103,15 @@ static int __init init_hw_perf_events(void) } if (err != 0) { pr_cont("no PMU driver, software events only.\n"); - return 0; + err = 0; + goto out_bad_pmu; } pmu_check_apic(); /* sanity check that the hardware exists or is emulated */ if (!check_hw_exists(&pmu, x86_pmu.num_counters, x86_pmu.num_counters_fixed)) - return 0; + goto out_bad_pmu; pr_cont("%s PMU driver.\n", x86_pmu.name); @@ -2219,6 +2220,8 @@ out1: cpuhp_remove_state(CPUHP_AP_PERF_X86_STARTING); out: cpuhp_remove_state(CPUHP_PERF_X86_PREPARE); +out_bad_pmu: + memset(&x86_pmu, 0, sizeof(x86_pmu)); return err; } early_initcall(init_hw_perf_events); @@ -2990,6 +2993,11 @@ unsigned long perf_misc_flags(struct pt_regs *regs) void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) { + if (!x86_pmu_initialized()) { + memset(cap, 0, sizeof(*cap)); + return; + } + cap->version = x86_pmu.version; /* * KVM doesn't support the hybrid PMU yet. From d7808f739162c003d249168bfe4c571aba18fb8a Mon Sep 17 00:00:00 2001 From: Like Xu Date: Thu, 19 May 2022 01:01:18 +0800 Subject: [PATCH 0179/1436] KVM: x86/pmu: Update global enable_pmu when PMU is undetected On some virt platforms (L1 guest w/o PMU), the value of module parameter 'enable_pmu' for nested L2 guests should be updated at initialisation. Considering that there is no concept of "architecture pmu" in AMD or Hygon and that the versions (prior to Zen 4) are all 0, but that the theoretical available counters are at least AMD64_NUM_COUNTERS, the utility check_hw_exists() is reused in the initialisation call path. Opportunistically update Intel specific comments. Fixes: 8eeac7e999e8 ("KVM: x86/pmu: Add kvm_pmu_cap to optimize perf_get_x86_pmu_capability") Signed-off-by: Like Xu Message-Id: <20220518170118.66263-3-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 0e719436b7b8..d59e1cb3b5dc 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -159,14 +159,19 @@ extern struct x86_pmu_capability kvm_pmu_cap; static inline void kvm_init_pmu_capability(void) { + bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL; + perf_get_x86_pmu_capability(&kvm_pmu_cap); - /* - * Only support guest architectural pmu on - * a host with architectural pmu. - */ - if (!kvm_pmu_cap.version) + /* + * For Intel, only support guest architectural pmu + * on a host with architectural pmu. + */ + if ((is_intel && !kvm_pmu_cap.version) || !kvm_pmu_cap.num_counters_gp) { memset(&kvm_pmu_cap, 0, sizeof(kvm_pmu_cap)); + enable_pmu = false; + return; + } kvm_pmu_cap.version = min(kvm_pmu_cap.version, 2); kvm_pmu_cap.num_counters_fixed = min(kvm_pmu_cap.num_counters_fixed, From b9181c8ef35636152facc72f801f27b4264df8c0 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 1 Jun 2022 11:19:25 +0800 Subject: [PATCH 0180/1436] KVM: x86/pmu: Avoid exposing Intel BTS feature The BTS feature (including the ability to set the BTS and BTINT bits in the DEBUGCTL MSR) is currently unsupported on KVM. But we may try using the BTS facility on a PEBS enabled guest like this: perf record -e branches:u -c 1 -d ls and then we would encounter the following call trace: [] unchecked MSR access error: WRMSR to 0x1d9 (tried to write 0x00000000000003c0) at rIP: 0xffffffff810745e4 (native_write_msr+0x4/0x20) [] Call Trace: [] intel_pmu_enable_bts+0x5d/0x70 [] bts_event_add+0x54/0x70 [] event_sched_in+0xee/0x290 As it lacks any CPUID indicator or perf_capabilities valid bit fields to prompt for this information, the platform would hint the Intel BTS feature unavailable to guest by setting the BTS_UNAVAIL bit in the IA32_MISC_ENABLE. Signed-off-by: Like Xu Message-Id: <20220601031925.59693-3-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.h | 3 +++ arch/x86/kvm/vmx/pmu_intel.c | 3 ++- arch/x86/kvm/x86.c | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index d59e1cb3b5dc..2c5b3c9f5531 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -8,6 +8,9 @@ #define pmu_to_vcpu(pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu)) #define pmc_to_pmu(pmc) (&(pmc)->vcpu->arch.pmu) +#define MSR_IA32_MISC_ENABLE_PMU_RO_MASK (MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL | \ + MSR_IA32_MISC_ENABLE_BTS_UNAVAIL) + /* retrieve the 4 bits for EN and PMI out of IA32_FIXED_CTR_CTRL */ #define fixed_ctrl_field(ctrl_reg, idx) (((ctrl_reg) >> ((idx)*4)) & 0xf) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 5b85320fc9f1..422f0a6562ac 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -536,6 +536,8 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->pebs_enable_mask = ~0ull; pmu->pebs_data_cfg_mask = ~0ull; + vcpu->arch.ia32_misc_enable_msr |= MSR_IA32_MISC_ENABLE_PMU_RO_MASK; + entry = kvm_find_cpuid_entry(vcpu, 0xa, 0); if (!entry || !vcpu->kvm->arch.enable_pmu) return; @@ -623,7 +625,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) ~((1ull << pmu->nr_arch_gp_counters) - 1); } } else { - vcpu->arch.ia32_misc_enable_msr |= MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL; vcpu->arch.perf_capabilities &= ~PERF_CAP_PEBS_MASK; } } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a8014233fd57..79efdc19b4c8 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3548,12 +3548,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; case MSR_IA32_MISC_ENABLE: { u64 old_val = vcpu->arch.ia32_misc_enable_msr; - u64 pmu_mask = MSR_IA32_MISC_ENABLE_EMON | - MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL; + u64 pmu_mask = MSR_IA32_MISC_ENABLE_PMU_RO_MASK | + MSR_IA32_MISC_ENABLE_EMON; /* RO bits */ if (!msr_info->host_initiated && - ((old_val ^ data) & MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL)) + ((old_val ^ data) & MSR_IA32_MISC_ENABLE_PMU_RO_MASK)) return 1; /* From 6ef25aa0a961298278301ae1d88106c701eb73fa Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 1 Jun 2022 11:19:24 +0800 Subject: [PATCH 0181/1436] KVM: x86/pmu: Restrict advanced features based on module enable_pmu Once vPMU is disabled, the KVM would not expose features like: PEBS (via clear kvm_pmu_cap.pebs_ept), legacy LBR and ARCH_LBR, CPUID 0xA leaf, PDCM bit and MSR_IA32_PERF_CAPABILITIES, plus PT_MODE_HOST_GUEST mode. What this group of features has in common is that their use relies on the underlying PMU counter and the host perf_event as a back-end resource requester or sharing part of the irq delivery path. Signed-off-by: Like Xu Message-Id: <20220601031925.59693-2-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.h | 6 ++++-- arch/x86/kvm/vmx/capabilities.h | 4 ++++ arch/x86/kvm/vmx/vmx.c | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index 2c5b3c9f5531..c1b61671ba1e 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -170,9 +170,11 @@ static inline void kvm_init_pmu_capability(void) * For Intel, only support guest architectural pmu * on a host with architectural pmu. */ - if ((is_intel && !kvm_pmu_cap.version) || !kvm_pmu_cap.num_counters_gp) { - memset(&kvm_pmu_cap, 0, sizeof(kvm_pmu_cap)); + if ((is_intel && !kvm_pmu_cap.version) || !kvm_pmu_cap.num_counters_gp) enable_pmu = false; + + if (!enable_pmu) { + memset(&kvm_pmu_cap, 0, sizeof(kvm_pmu_cap)); return; } diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h index 2d3f13b18714..292e58679d95 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -7,6 +7,7 @@ #include "lapic.h" #include "x86.h" #include "pmu.h" +#include "cpuid.h" extern bool __read_mostly enable_vpid; extern bool __read_mostly flexpriority_enabled; @@ -409,6 +410,9 @@ static inline u64 vmx_get_perf_capabilities(void) u64 perf_cap = PMU_CAP_FW_WRITES; u64 host_perf_cap = 0; + if (!enable_pmu) + return 0; + if (boot_cpu_has(X86_FEATURE_PDCM)) rdmsrl(MSR_IA32_PERF_CAPABILITIES, host_perf_cap); diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 2e00890d752a..83eeecb4c7f7 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7568,6 +7568,9 @@ static __init void vmx_set_cpu_caps(void) kvm_cpu_cap_check_and_set(X86_FEATURE_DTES64); } + if (!enable_pmu) + kvm_cpu_cap_clear(X86_FEATURE_PDCM); + if (!enable_sgx) { kvm_cpu_cap_clear(X86_FEATURE_SGX); kvm_cpu_cap_clear(X86_FEATURE_SGX_LC); @@ -8233,7 +8236,7 @@ static __init int hardware_setup(void) if (pt_mode != PT_MODE_SYSTEM && pt_mode != PT_MODE_HOST_GUEST) return -EINVAL; - if (!enable_ept || !cpu_has_vmx_intel_pt()) + if (!enable_ept || !enable_pmu || !cpu_has_vmx_intel_pt()) pt_mode = PT_MODE_SYSTEM; if (pt_mode == PT_MODE_HOST_GUEST) vmx_init_ops.handle_intel_pt_intr = vmx_handle_intel_pt_intr; From 8e6a58e28b34e8d247e772159b8fa8f6bae39192 Mon Sep 17 00:00:00 2001 From: Like Xu Date: Wed, 1 Jun 2022 11:19:23 +0800 Subject: [PATCH 0182/1436] KVM: x86/pmu: Accept 0 for absent PMU MSRs when host-initiated if !enable_pmu Whenever an MSR is part of KVM_GET_MSR_INDEX_LIST, as is the case for MSR_K7_EVNTSEL0 or MSR_F15H_PERF_CTL0, it has to be always retrievable and settable with KVM_GET_MSR and KVM_SET_MSR. Accept a zero value for these MSRs to obey the contract. Signed-off-by: Like Xu Message-Id: <20220601031925.59693-1-likexu@tencent.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 8 ++++++++ arch/x86/kvm/svm/pmu.c | 11 ++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 87483e503c46..6a32092460d3 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -442,11 +442,19 @@ static void kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u32 msr) int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { + if (msr_info->host_initiated && !vcpu->kvm->arch.enable_pmu) { + msr_info->data = 0; + return 0; + } + return static_call(kvm_x86_pmu_get_msr)(vcpu, msr_info); } int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { + if (msr_info->host_initiated && !vcpu->kvm->arch.enable_pmu) + return !!msr_info->data; + kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index); return static_call(kvm_x86_pmu_set_msr)(vcpu, msr_info); } diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 256244b8f89c..fe520b2649b5 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -182,7 +182,16 @@ static struct kvm_pmc *amd_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated) { /* All MSRs refer to exactly one PMC, so msr_idx_to_pmc is enough. */ - return false; + if (!host_initiated) + return false; + + switch (msr) { + case MSR_K7_EVNTSEL0 ... MSR_K7_PERFCTR3: + case MSR_F15H_PERF_CTL0 ... MSR_F15H_PERF_CTR5: + return true; + default: + return false; + } } static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr) From f5a81d0eb01e0dfebd175edffa7d0a1bdb74d026 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 27 May 2022 17:06:57 +0000 Subject: [PATCH 0183/1436] KVM: VMX: Sanitize VM-Entry/VM-Exit control pairs at kvm_intel load time Sanitize the VM-Entry/VM-Exit control pairs (load+load or load+clear) during setup instead of checking both controls in a pair at runtime. If only one control is supported, KVM will report the associated feature as not available, but will leave the supported control bit set in the VMCS config, which could lead to corruption of host state. E.g. if only the VM-Entry control is supported and the feature is not dynamically toggled, KVM will set the control in all VMCSes and load zeros without restoring host state. Note, while this is technically a bug fix, practically speaking no sane CPU or VMM would support only one control. KVM's behavior of checking both controls is mostly pedantry. Cc: Chenyi Qiang Cc: Lei Wang Signed-off-by: Sean Christopherson Message-Id: <20220527170658.3571367-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/capabilities.h | 10 +++------- arch/x86/kvm/vmx/vmx.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/vmx/capabilities.h b/arch/x86/kvm/vmx/capabilities.h index 292e58679d95..069d8d298e1d 100644 --- a/arch/x86/kvm/vmx/capabilities.h +++ b/arch/x86/kvm/vmx/capabilities.h @@ -98,20 +98,17 @@ static inline bool cpu_has_vmx_posted_intr(void) static inline bool cpu_has_load_ia32_efer(void) { - return (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_EFER) && - (vmcs_config.vmexit_ctrl & VM_EXIT_LOAD_IA32_EFER); + return vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_EFER; } static inline bool cpu_has_load_perf_global_ctrl(void) { - return (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL) && - (vmcs_config.vmexit_ctrl & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL); + return vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; } static inline bool cpu_has_vmx_mpx(void) { - return (vmcs_config.vmexit_ctrl & VM_EXIT_CLEAR_BNDCFGS) && - (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_BNDCFGS); + return vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_BNDCFGS; } static inline bool cpu_has_vmx_tpr_shadow(void) @@ -378,7 +375,6 @@ static inline bool cpu_has_vmx_intel_pt(void) rdmsrl(MSR_IA32_VMX_MISC, vmx_msr); return (vmx_msr & MSR_IA32_VMX_MISC_INTEL_PT) && (vmcs_config.cpu_based_2nd_exec_ctrl & SECONDARY_EXEC_PT_USE_GPA) && - (vmcs_config.vmexit_ctrl & VM_EXIT_CLEAR_IA32_RTIT_CTL) && (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_RTIT_CTL); } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 83eeecb4c7f7..bc1a0baa5f60 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2446,6 +2446,23 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, u64 _cpu_based_3rd_exec_control = 0; u32 _vmexit_control = 0; u32 _vmentry_control = 0; + int i; + + /* + * LOAD/SAVE_DEBUG_CONTROLS are absent because both are mandatory. + * SAVE_IA32_PAT and SAVE_IA32_EFER are absent because KVM always + * intercepts writes to PAT and EFER, i.e. never enables those controls. + */ + struct { + u32 entry_control; + u32 exit_control; + } const vmcs_entry_exit_pairs[] = { + { VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL, VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL }, + { VM_ENTRY_LOAD_IA32_PAT, VM_EXIT_LOAD_IA32_PAT }, + { VM_ENTRY_LOAD_IA32_EFER, VM_EXIT_LOAD_IA32_EFER }, + { VM_ENTRY_LOAD_BNDCFGS, VM_EXIT_CLEAR_BNDCFGS }, + { VM_ENTRY_LOAD_IA32_RTIT_CTL, VM_EXIT_CLEAR_IA32_RTIT_CTL }, + }; memset(vmcs_conf, 0, sizeof(*vmcs_conf)); min = CPU_BASED_HLT_EXITING | @@ -2586,6 +2603,20 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, &_vmentry_control) < 0) return -EIO; + for (i = 0; i < ARRAY_SIZE(vmcs_entry_exit_pairs); i++) { + u32 n_ctrl = vmcs_entry_exit_pairs[i].entry_control; + u32 x_ctrl = vmcs_entry_exit_pairs[i].exit_control; + + if (!(_vmentry_control & n_ctrl) == !(_vmexit_control & x_ctrl)) + continue; + + pr_warn_once("Inconsistent VM-Entry/VM-Exit pair, entry = %x, exit = %x\n", + _vmentry_control & n_ctrl, _vmexit_control & x_ctrl); + + _vmentry_control &= ~n_ctrl; + _vmexit_control &= ~x_ctrl; + } + /* * Some cpus support VM_{ENTRY,EXIT}_IA32_PERF_GLOBAL_CTRL but they * can't be used due to an errata where VM Exit may incorrectly clear From 3dbec44d9c94d8350a39326561ac40f969c63d16 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 27 May 2022 17:06:58 +0000 Subject: [PATCH 0184/1436] KVM: VMX: Reject kvm_intel if an inconsistent VMCS config is detected Add an on-by-default module param, error_on_inconsistent_vmcs_config, to allow rejecting the load of kvm_intel if an inconsistent VMCS config is detected. Continuing on with an inconsistent, degraded config is undesirable in the vast majority of use cases, e.g. may result in a misconfigured VM, poor performance due to lack of fast MSR switching, or even security issues in the unlikely event the guest is relying on MPX. Practically speaking, an inconsistent VMCS config should never be encountered in a production quality environment, e.g. on bare metal it indicates a silicon defect (or a disturbing lack of validation by the hardware vendor), and in a virtualized machine (KVM as L1) it indicates a buggy/misconfigured L0 VMM/hypervisor. Provide a module param to override the behavior for testing purposes, or in the unlikely scenario that KVM is deployed on a flawed-but-usable CPU or virtual machine. Note, what is or isn't an inconsistency is somewhat subjective, e.g. one might argue that LOAD_EFER without SAVE_EFER is an inconsistency. KVM's unofficial guideline for an "inconsistency" is either scenarios that are completely nonsensical, e.g. the existing checks on having EPT/VPID knobs without EPT/VPID, and/or scenarios that prevent KVM from virtualizing or utilizing a feature, e.g. the unpaired entry/exit controls checks. Other checks that fall into one or both of the covered scenarios could be added in the future, e.g. asserting that a VMCS control exists available if and only if the associated feature is supported in bare metal. Signed-off-by: Sean Christopherson Message-Id: <20220527170658.3571367-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index bc1a0baa5f60..b959fe24c13b 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -119,6 +119,9 @@ module_param(nested, bool, S_IRUGO); bool __read_mostly enable_pml = 1; module_param_named(pml, enable_pml, bool, S_IRUGO); +static bool __read_mostly error_on_inconsistent_vmcs_config = true; +module_param(error_on_inconsistent_vmcs_config, bool, 0444); + static bool __read_mostly dump_invalid_vmcs = 0; module_param(dump_invalid_vmcs, bool, 0644); @@ -2547,15 +2550,23 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, CPU_BASED_CR3_STORE_EXITING | CPU_BASED_INVLPG_EXITING); } else if (vmx_cap->ept) { - vmx_cap->ept = 0; pr_warn_once("EPT CAP should not exist if not support " "1-setting enable EPT VM-execution control\n"); + + if (error_on_inconsistent_vmcs_config) + return -EIO; + + vmx_cap->ept = 0; } if (!(_cpu_based_2nd_exec_control & SECONDARY_EXEC_ENABLE_VPID) && - vmx_cap->vpid) { - vmx_cap->vpid = 0; + vmx_cap->vpid) { pr_warn_once("VPID CAP should not exist if not support " "1-setting enable VPID VM-execution control\n"); + + if (error_on_inconsistent_vmcs_config) + return -EIO; + + vmx_cap->vpid = 0; } if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) { @@ -2613,6 +2624,9 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, pr_warn_once("Inconsistent VM-Entry/VM-Exit pair, entry = %x, exit = %x\n", _vmentry_control & n_ctrl, _vmexit_control & x_ctrl); + if (error_on_inconsistent_vmcs_config) + return -EIO; + _vmentry_control &= ~n_ctrl; _vmexit_control &= ~x_ctrl; } From b172862241b4849985c3e0e86cfb05d61e4a841d Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Tue, 31 May 2022 13:44:21 +0100 Subject: [PATCH 0185/1436] KVM: x86: PIT: Preserve state of speaker port data bit Currently the state of the speaker port (0x61) data bit (bit 1) is not saved in the exported state (kvm_pit_state2) and hence is lost when re-constructing guest state. This patch removes the 'speaker_data_port' field from kvm_kpit_state and instead tracks the state using a new KVM_PIT_FLAGS_SPEAKER_DATA_ON flag defined in the API. Signed-off-by: Paul Durrant Message-Id: <20220531124421.1427-1-pdurrant@amazon.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 4 +++- arch/x86/include/uapi/asm/kvm.h | 3 ++- arch/x86/kvm/i8254.c | 10 +++++++--- arch/x86/kvm/i8254.h | 1 - 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 30e31a886422..9cbbfdb663b6 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -3006,7 +3006,9 @@ KVM_CREATE_PIT2. The state is returned in the following structure:: Valid flags are:: /* disable PIT in HPET legacy mode */ - #define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001 + #define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001 + /* speaker port data bit enabled */ + #define KVM_PIT_FLAGS_SPEAKER_DATA_ON 0x00000002 This IOCTL replaces the obsolete KVM_GET_PIT. diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 24c807c8d5f7..50a4e787d5e6 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -306,7 +306,8 @@ struct kvm_pit_state { struct kvm_pit_channel_state channels[3]; }; -#define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001 +#define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001 +#define KVM_PIT_FLAGS_SPEAKER_DATA_ON 0x00000002 struct kvm_pit_state2 { struct kvm_pit_channel_state channels[3]; diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 1c83076091af..e0a7a0e7a73c 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -591,7 +591,10 @@ static int speaker_ioport_write(struct kvm_vcpu *vcpu, return -EOPNOTSUPP; mutex_lock(&pit_state->lock); - pit_state->speaker_data_on = (val >> 1) & 1; + if (val & (1 << 1)) + pit_state->flags |= KVM_PIT_FLAGS_SPEAKER_DATA_ON; + else + pit_state->flags &= ~KVM_PIT_FLAGS_SPEAKER_DATA_ON; pit_set_gate(pit, 2, val & 1); mutex_unlock(&pit_state->lock); return 0; @@ -612,8 +615,9 @@ static int speaker_ioport_read(struct kvm_vcpu *vcpu, refresh_clock = ((unsigned int)ktime_to_ns(ktime_get()) >> 14) & 1; mutex_lock(&pit_state->lock); - ret = ((pit_state->speaker_data_on << 1) | pit_get_gate(pit, 2) | - (pit_get_out(pit, 2) << 5) | (refresh_clock << 4)); + ret = (!!(pit_state->flags & KVM_PIT_FLAGS_SPEAKER_DATA_ON) << 1) | + pit_get_gate(pit, 2) | (pit_get_out(pit, 2) << 5) | + (refresh_clock << 4); if (len > sizeof(ret)) len = sizeof(ret); memcpy(data, (char *)&ret, len); diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h index 394d9527da7e..a768212ba821 100644 --- a/arch/x86/kvm/i8254.h +++ b/arch/x86/kvm/i8254.h @@ -29,7 +29,6 @@ struct kvm_kpit_state { bool is_periodic; s64 period; /* unit: ns */ struct hrtimer timer; - u32 speaker_data_on; struct mutex lock; atomic_t reinject; From 381583845d19cb4bd21c8193449385f3fefa9caf Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Wed, 8 Jun 2022 05:26:09 -0700 Subject: [PATCH 0186/1436] HID: cp2112: prevent a buffer overflow in cp2112_xfer() Smatch warnings: drivers/hid/hid-cp2112.c:793 cp2112_xfer() error: __memcpy() 'data->block[1]' too small (33 vs 255) drivers/hid/hid-cp2112.c:793 cp2112_xfer() error: __memcpy() 'buf' too small (64 vs 255) The 'read_length' variable is provided by 'data->block[0]' which comes from user and it(read_length) can take a value between 0-255. Add an upper bound to 'read_length' variable to prevent a buffer overflow in memcpy(). Fixes: 542134c0375b ("HID: cp2112: Fix I2C_BLOCK_DATA transactions") Signed-off-by: Harshit Mogalapalli Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index ece147d1a278..1e16b0fa310d 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -790,6 +790,11 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, data->word = le16_to_cpup((__le16 *)buf); break; case I2C_SMBUS_I2C_BLOCK_DATA: + if (read_length > I2C_SMBUS_BLOCK_MAX) { + ret = -EINVAL; + goto power_normal; + } + memcpy(data->block + 1, buf, read_length); break; case I2C_SMBUS_BLOCK_DATA: From 54eed5c7b938dc4ef6b14d4ee048bbdafdbce352 Mon Sep 17 00:00:00 2001 From: Tao Jin Date: Thu, 19 May 2022 23:51:32 -0400 Subject: [PATCH 0187/1436] HID: multitouch: new device class fix Lenovo X12 trackpad sticky The trackpad of the given device sends continuous report of pointers status as per wxn8 spec. However, the spec did not clarify when the fingers are lifted so fast that between the interval of two report frames fingers on pad reduced from >=2 to 0. The second last report contains >=2 fingers with tip state 1 and the last report contains only 1 finger with tip state 0. Although this can happen unfrequently, a quick fix will be improve the consistency to 100%. A quick fix is to disable MT_QUIRK_ALWAYS_VALID and enable MT_QUIRK_NOT_SEEN_MEANS_UP. Test for hid-tools is added in [1] In addition to this, I2C device 04CA:00B1 may also need similar class but with MT_QUIRK_FORCE_MULTI_INPUT disabled (but it does not harm to enable it on non-multi-input device either). The respective owner has been notified and a patch may coming soon after test. [1]: https://gitlab.freedesktop.org/libevdev/hid-tools/-/merge_requests/130 Signed-off-by: Tao Jin Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 6bb3890b0f2c..2e72922e36f5 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -194,6 +194,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app); #define MT_CLS_WIN_8_FORCE_MULTI_INPUT 0x0015 #define MT_CLS_WIN_8_DISABLE_WAKEUP 0x0016 #define MT_CLS_WIN_8_NO_STICKY_FINGERS 0x0017 +#define MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU 0x0018 /* vendor specific classes */ #define MT_CLS_3M 0x0101 @@ -286,6 +287,15 @@ static const struct mt_class mt_classes[] = { MT_QUIRK_WIN8_PTP_BUTTONS | MT_QUIRK_FORCE_MULTI_INPUT, .export_all_inputs = true }, + { .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU, + .quirks = MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | + MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_STICKY_FINGERS | + MT_QUIRK_WIN8_PTP_BUTTONS | + MT_QUIRK_FORCE_MULTI_INPUT | + MT_QUIRK_NOT_SEEN_MEANS_UP, + .export_all_inputs = true }, { .name = MT_CLS_WIN_8_DISABLE_WAKEUP, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | @@ -783,6 +793,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, case HID_DG_CONFIDENCE: if ((cls->name == MT_CLS_WIN_8 || cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT || + cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU || cls->name == MT_CLS_WIN_8_DISABLE_WAKEUP) && (field->application == HID_DG_TOUCHPAD || field->application == HID_DG_TOUCHSCREEN)) @@ -2035,7 +2046,7 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_LENOVO_X1_TAB3) }, /* Lenovo X12 TAB Gen 1 */ - { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, + { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU, HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X12_TAB) }, From e9ada6c208c15c907afe5afb1aa82e23e81eb8ba Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:13 +0100 Subject: [PATCH 0188/1436] KVM: arm64: Drop FP_FOREIGN_STATE from the hypervisor code The vcpu KVM_ARM64_FP_FOREIGN_FPSTATE flag tracks the thread's own TIF_FOREIGN_FPSTATE so that we can evaluate just before running the vcpu whether it the FP regs contain something that is owned by the vcpu or not by updating the rest of the FP flags. We do this in the hypervisor code in order to make sure we're in a context where we are not interruptible. But we already have a hook in the run loop to generate this flag. We may as well update the FP flags directly and save the pointless flag tracking. Whilst we're at it, rename update_fp_enabled() to guest_owns_fp_regs() to indicate what the leftover of this helper actually do. Signed-off-by: Marc Zyngier Reviewed-by: Reiji Watanabe Reviewed-by: Mark Brown --- arch/arm64/include/asm/kvm_host.h | 1 - arch/arm64/kvm/fpsimd.c | 17 ++++++++++------- arch/arm64/kvm/hyp/include/hyp/switch.h | 16 ++-------------- arch/arm64/kvm/hyp/nvhe/switch.c | 2 +- arch/arm64/kvm/hyp/vhe/switch.c | 2 +- 5 files changed, 14 insertions(+), 24 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 47a1e25e25bb..63103cc1bdc4 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -462,7 +462,6 @@ struct kvm_vcpu_arch { #define KVM_ARM64_DEBUG_STATE_SAVE_SPE (1 << 12) /* Save SPE context if active */ #define KVM_ARM64_DEBUG_STATE_SAVE_TRBE (1 << 13) /* Save TRBE context if active */ -#define KVM_ARM64_FP_FOREIGN_FPSTATE (1 << 14) #define KVM_ARM64_ON_UNSUPPORTED_CPU (1 << 15) /* Physical CPU not in supported_cpus */ #define KVM_ARM64_HOST_SME_ENABLED (1 << 16) /* SME enabled for EL0 */ #define KVM_ARM64_WFIT (1 << 17) /* WFIT instruction trapped */ diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c index 6012b08ecb14..edbc0183c89b 100644 --- a/arch/arm64/kvm/fpsimd.c +++ b/arch/arm64/kvm/fpsimd.c @@ -107,16 +107,19 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) } /* - * Called just before entering the guest once we are no longer - * preemptable. Syncs the host's TIF_FOREIGN_FPSTATE with the KVM - * mirror of the flag used by the hypervisor. + * Called just before entering the guest once we are no longer preemptable + * and interrupts are disabled. If we have managed to run anything using + * FP while we were preemptible (such as off the back of an interrupt), + * then neither the host nor the guest own the FP hardware (and it was the + * responsibility of the code that used FP to save the existing state). + * + * Note that not supporting FP is basically the same thing as far as the + * hypervisor is concerned (nothing to save). */ void kvm_arch_vcpu_ctxflush_fp(struct kvm_vcpu *vcpu) { - if (test_thread_flag(TIF_FOREIGN_FPSTATE)) - vcpu->arch.flags |= KVM_ARM64_FP_FOREIGN_FPSTATE; - else - vcpu->arch.flags &= ~KVM_ARM64_FP_FOREIGN_FPSTATE; + if (!system_supports_fpsimd() || test_thread_flag(TIF_FOREIGN_FPSTATE)) + vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED | KVM_ARM64_FP_HOST); } /* diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index 37d9f211c200..e54320384943 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -37,21 +37,9 @@ struct kvm_exception_table_entry { extern struct kvm_exception_table_entry __start___kvm_ex_table; extern struct kvm_exception_table_entry __stop___kvm_ex_table; -/* Check whether the FP regs were dirtied while in the host-side run loop: */ -static inline bool update_fp_enabled(struct kvm_vcpu *vcpu) +/* Check whether the FP regs are owned by the guest */ +static inline bool guest_owns_fp_regs(struct kvm_vcpu *vcpu) { - /* - * When the system doesn't support FP/SIMD, we cannot rely on - * the _TIF_FOREIGN_FPSTATE flag. However, we always inject an - * abort on the very first access to FP and thus we should never - * see KVM_ARM64_FP_ENABLED. For added safety, make sure we always - * trap the accesses. - */ - if (!system_supports_fpsimd() || - vcpu->arch.flags & KVM_ARM64_FP_FOREIGN_FPSTATE) - vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED | - KVM_ARM64_FP_HOST); - return !!(vcpu->arch.flags & KVM_ARM64_FP_ENABLED); } diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c index 6db801db8f27..a6b9f1186577 100644 --- a/arch/arm64/kvm/hyp/nvhe/switch.c +++ b/arch/arm64/kvm/hyp/nvhe/switch.c @@ -43,7 +43,7 @@ static void __activate_traps(struct kvm_vcpu *vcpu) val = vcpu->arch.cptr_el2; val |= CPTR_EL2_TTA | CPTR_EL2_TAM; - if (!update_fp_enabled(vcpu)) { + if (!guest_owns_fp_regs(vcpu)) { val |= CPTR_EL2_TFP | CPTR_EL2_TZ; __activate_traps_fpsimd32(vcpu); } diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c index 969f20daf97a..46f365254e9f 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -55,7 +55,7 @@ static void __activate_traps(struct kvm_vcpu *vcpu) val |= CPTR_EL2_TAM; - if (update_fp_enabled(vcpu)) { + if (guest_owns_fp_regs(vcpu)) { if (vcpu_has_sve(vcpu)) val |= CPACR_EL1_ZEN_EL0EN | CPACR_EL1_ZEN_EL1EN; } else { From f8077b0d59230cbb58e0b98839e04b564529a5ac Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:14 +0100 Subject: [PATCH 0189/1436] KVM: arm64: Move FP state ownership from flag to a tristate The KVM FP code uses a pair of flags to denote three states: - FP_ENABLED set: the guest owns the FP state - FP_HOST set: the host owns the FP state - FP_ENABLED and FP_HOST clear: nobody owns the FP state at all and both flags set is an illegal state, which nothing ever checks for... As it turns out, this isn't really a good match for flags, and we'd be better off if this was a simpler tristate, each state having a name that actually reflect the state: - FP_STATE_FREE - FP_STATE_HOST_OWNED - FP_STATE_GUEST_OWNED Kill the two flags, and move over to an enum encoding these three states. This results in less confusing code, and less risk of ending up in the uncharted territory of a 4th state if we forget to clear one of the two flags. Signed-off-by: Marc Zyngier Reviewed-by: Mark Brown Reviewed-by: Reiji Watanabe --- arch/arm64/include/asm/kvm_host.h | 9 +++++++-- arch/arm64/kvm/fpsimd.c | 14 ++++++-------- arch/arm64/kvm/hyp/include/hyp/switch.h | 8 +++----- arch/arm64/kvm/hyp/nvhe/switch.c | 4 ++-- arch/arm64/kvm/hyp/vhe/switch.c | 2 +- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 63103cc1bdc4..372c5642cfab 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -325,6 +325,13 @@ struct kvm_vcpu_arch { /* Exception Information */ struct kvm_vcpu_fault_info fault; + /* Ownership of the FP regs */ + enum { + FP_STATE_FREE, + FP_STATE_HOST_OWNED, + FP_STATE_GUEST_OWNED, + } fp_state; + /* Miscellaneous vcpu state flags */ u64 flags; @@ -430,8 +437,6 @@ struct kvm_vcpu_arch { /* vcpu_arch flags field values: */ #define KVM_ARM64_DEBUG_DIRTY (1 << 0) -#define KVM_ARM64_FP_ENABLED (1 << 1) /* guest FP regs loaded */ -#define KVM_ARM64_FP_HOST (1 << 2) /* host FP regs loaded */ #define KVM_ARM64_HOST_SVE_ENABLED (1 << 4) /* SVE enabled for EL0 */ #define KVM_ARM64_GUEST_HAS_SVE (1 << 5) /* SVE exposed to guest */ #define KVM_ARM64_VCPU_SVE_FINALIZED (1 << 6) /* SVE config completed */ diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c index edbc0183c89b..d397efe1a378 100644 --- a/arch/arm64/kvm/fpsimd.c +++ b/arch/arm64/kvm/fpsimd.c @@ -77,8 +77,7 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) BUG_ON(!current->mm); BUG_ON(test_thread_flag(TIF_SVE)); - vcpu->arch.flags &= ~KVM_ARM64_FP_ENABLED; - vcpu->arch.flags |= KVM_ARM64_FP_HOST; + vcpu->arch.fp_state = FP_STATE_HOST_OWNED; vcpu->arch.flags &= ~KVM_ARM64_HOST_SVE_ENABLED; if (read_sysreg(cpacr_el1) & CPACR_EL1_ZEN_EL0EN) @@ -98,9 +97,8 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) if (read_sysreg(cpacr_el1) & CPACR_EL1_SMEN_EL0EN) vcpu->arch.flags |= KVM_ARM64_HOST_SME_ENABLED; - if (read_sysreg_s(SYS_SVCR) & - (SVCR_SM_MASK | SVCR_ZA_MASK)) { - vcpu->arch.flags &= ~KVM_ARM64_FP_HOST; + if (read_sysreg_s(SYS_SVCR) & (SVCR_SM_MASK | SVCR_ZA_MASK)) { + vcpu->arch.fp_state = FP_STATE_FREE; fpsimd_save_and_flush_cpu_state(); } } @@ -119,7 +117,7 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) void kvm_arch_vcpu_ctxflush_fp(struct kvm_vcpu *vcpu) { if (!system_supports_fpsimd() || test_thread_flag(TIF_FOREIGN_FPSTATE)) - vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED | KVM_ARM64_FP_HOST); + vcpu->arch.fp_state = FP_STATE_FREE; } /* @@ -133,7 +131,7 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu) { WARN_ON_ONCE(!irqs_disabled()); - if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) { + if (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED) { /* * Currently we do not support SME guests so SVCR is * always 0 and we just need a variable to point to. @@ -176,7 +174,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu) CPACR_EL1_SMEN_EL1EN); } - if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) { + if (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED) { if (vcpu_has_sve(vcpu)) { __vcpu_sys_reg(vcpu, ZCR_EL1) = read_sysreg_el1(SYS_ZCR); diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h index e54320384943..6cbbb6c02f66 100644 --- a/arch/arm64/kvm/hyp/include/hyp/switch.h +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h @@ -40,7 +40,7 @@ extern struct kvm_exception_table_entry __stop___kvm_ex_table; /* Check whether the FP regs are owned by the guest */ static inline bool guest_owns_fp_regs(struct kvm_vcpu *vcpu) { - return !!(vcpu->arch.flags & KVM_ARM64_FP_ENABLED); + return vcpu->arch.fp_state == FP_STATE_GUEST_OWNED; } /* Save the 32-bit only FPSIMD system register state */ @@ -179,10 +179,8 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code) isb(); /* Write out the host state if it's in the registers */ - if (vcpu->arch.flags & KVM_ARM64_FP_HOST) { + if (vcpu->arch.fp_state == FP_STATE_HOST_OWNED) __fpsimd_save_state(vcpu->arch.host_fpsimd_state); - vcpu->arch.flags &= ~KVM_ARM64_FP_HOST; - } /* Restore the guest state */ if (sve_guest) @@ -194,7 +192,7 @@ static bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code) if (!(read_sysreg(hcr_el2) & HCR_RW)) write_sysreg(__vcpu_sys_reg(vcpu, FPEXC32_EL2), fpexc32_el2); - vcpu->arch.flags |= KVM_ARM64_FP_ENABLED; + vcpu->arch.fp_state = FP_STATE_GUEST_OWNED; return true; } diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c index a6b9f1186577..764bdc423cb8 100644 --- a/arch/arm64/kvm/hyp/nvhe/switch.c +++ b/arch/arm64/kvm/hyp/nvhe/switch.c @@ -123,7 +123,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu) } cptr = CPTR_EL2_DEFAULT; - if (vcpu_has_sve(vcpu) && (vcpu->arch.flags & KVM_ARM64_FP_ENABLED)) + if (vcpu_has_sve(vcpu) && (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED)) cptr |= CPTR_EL2_TZ; if (cpus_have_final_cap(ARM64_SME)) cptr &= ~CPTR_EL2_TSM; @@ -335,7 +335,7 @@ int __kvm_vcpu_run(struct kvm_vcpu *vcpu) __sysreg_restore_state_nvhe(host_ctxt); - if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) + if (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED) __fpsimd_save_fpexc32(vcpu); __debug_switch_to_host(vcpu); diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c index 46f365254e9f..bce7fc51f9a1 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -175,7 +175,7 @@ static int __kvm_vcpu_run_vhe(struct kvm_vcpu *vcpu) sysreg_restore_host_state_vhe(host_ctxt); - if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) + if (vcpu->arch.fp_state == FP_STATE_GUEST_OWNED) __fpsimd_save_fpexc32(vcpu); __debug_switch_to_host(vcpu); From e87abb73e5946379896cf49b10f6b57e02937a4c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:15 +0100 Subject: [PATCH 0190/1436] KVM: arm64: Add helpers to manipulate vcpu flags among a set Careful analysis of the vcpu flags show that this is a mix of configuration, communication between the host and the hypervisor, as well as anciliary state that has no consistency. It'd be a lot better if we could split these flags into consistent categories. However, even if we split these flags apart, we want to make sure that each flag can only be applied to its own set, and not across sets. To achieve this, use a preprocessor hack so that each flag is always associated with: - the set that contains it, - a mask that describe all the bits that contain it (for a simple flag, this is the same thing as the flag itself, but we will eventually have values that cover multiple bits at once). Each flag is thus a triplet that is not directly usable as a value, but used by three helpers that allow the flag to be set, cleared, and fetched. By mandating the use of such helper, we can easily enforce that a flag can only be used with the set it belongs to. Finally, one last helper "unpacks" the raw value from the triplet that represents a flag, which is useful for multi-bit values that need to be enumerated (in a switch statement, for example). Further patches will start making use of this infrastructure. Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 44 +++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 372c5642cfab..6d30ac7e3164 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -415,6 +415,50 @@ struct kvm_vcpu_arch { } steal; }; +/* + * Each 'flag' is composed of a comma-separated triplet: + * + * - the flag-set it belongs to in the vcpu->arch structure + * - the value for that flag + * - the mask for that flag + * + * __vcpu_single_flag() builds such a triplet for a single-bit flag. + * unpack_vcpu_flag() extract the flag value from the triplet for + * direct use outside of the flag accessors. + */ +#define __vcpu_single_flag(_set, _f) _set, (_f), (_f) + +#define __unpack_flag(_set, _f, _m) _f +#define unpack_vcpu_flag(...) __unpack_flag(__VA_ARGS__) + +#define __vcpu_get_flag(v, flagset, f, m) \ + ({ \ + v->arch.flagset & (m); \ + }) + +#define __vcpu_set_flag(v, flagset, f, m) \ + do { \ + typeof(v->arch.flagset) *fset; \ + \ + fset = &v->arch.flagset; \ + if (HWEIGHT(m) > 1) \ + *fset &= ~(m); \ + *fset |= (f); \ + } while (0) + +#define __vcpu_clear_flag(v, flagset, f, m) \ + do { \ + typeof(v->arch.flagset) *fset; \ + \ + fset = &v->arch.flagset; \ + *fset &= ~(m); \ + } while (0) + +#define vcpu_get_flag(v, ...) __vcpu_get_flag((v), __VA_ARGS__) +#define vcpu_set_flag(v, ...) __vcpu_set_flag((v), __VA_ARGS__) +#define vcpu_clear_flag(v, ...) __vcpu_clear_flag((v), __VA_ARGS__) + + /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */ #define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \ sve_ffr_offset((vcpu)->arch.sve_max_vl)) From 690bacb83bc30d14821bd32cac1c5839b4a9ac6c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:16 +0100 Subject: [PATCH 0191/1436] KVM: arm64: Add three sets of flags to the vcpu state It so appears that each of the vcpu flags is really belonging to one of three categories: - a configuration flag, set once and for all - an input flag generated by the kernel for the hypervisor to use - a state flag that is only for the kernel's own bookkeeping As we are going to split all the existing flags into these three sets, introduce all three in one go. No functional change other than a bit of bloat... Reviewed-by: Fuad Tabba Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 6d30ac7e3164..af45320f247f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -335,6 +335,15 @@ struct kvm_vcpu_arch { /* Miscellaneous vcpu state flags */ u64 flags; + /* Configuration flags, set once and for all before the vcpu can run */ + u64 cflags; + + /* Input flags to the hypervisor code, potentially cleared after use */ + u64 iflags; + + /* State flags for kernel bookkeeping, unused by the hypervisor code */ + u64 sflags; + /* * We maintain more than a single set of debug registers to support * debugging the guest from the host and to maintain separate host and From 4c0680d394d8a77868049931101e4a59372346b5 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:17 +0100 Subject: [PATCH 0192/1436] KVM: arm64: Move vcpu configuration flags into their own set The KVM_ARM64_{GUEST_HAS_SVE,VCPU_SVE_FINALIZED,GUEST_HAS_PTRAUTH} flags are purely configuration flags. Once set, they are never cleared, but evaluated all over the code base. Move these three flags into the configuration set in one go, using the new accessors, and take this opportunity to drop the KVM_ARM64_ prefix which doesn't provide any help. Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 17 ++++++++++------- arch/arm64/kvm/reset.c | 6 +++--- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index af45320f247f..66a08b0e12a8 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -467,6 +467,13 @@ struct kvm_vcpu_arch { #define vcpu_set_flag(v, ...) __vcpu_set_flag((v), __VA_ARGS__) #define vcpu_clear_flag(v, ...) __vcpu_clear_flag((v), __VA_ARGS__) +/* SVE exposed to guest */ +#define GUEST_HAS_SVE __vcpu_single_flag(cflags, BIT(0)) +/* SVE config completed */ +#define VCPU_SVE_FINALIZED __vcpu_single_flag(cflags, BIT(1)) +/* PTRAUTH exposed to guest */ +#define GUEST_HAS_PTRAUTH __vcpu_single_flag(cflags, BIT(2)) + /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */ #define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \ @@ -491,9 +498,6 @@ struct kvm_vcpu_arch { /* vcpu_arch flags field values: */ #define KVM_ARM64_DEBUG_DIRTY (1 << 0) #define KVM_ARM64_HOST_SVE_ENABLED (1 << 4) /* SVE enabled for EL0 */ -#define KVM_ARM64_GUEST_HAS_SVE (1 << 5) /* SVE exposed to guest */ -#define KVM_ARM64_VCPU_SVE_FINALIZED (1 << 6) /* SVE config completed */ -#define KVM_ARM64_GUEST_HAS_PTRAUTH (1 << 7) /* PTRAUTH exposed to guest */ #define KVM_ARM64_PENDING_EXCEPTION (1 << 8) /* Exception pending */ /* * Overlaps with KVM_ARM64_EXCEPT_MASK on purpose so that it can't be @@ -530,13 +534,13 @@ struct kvm_vcpu_arch { KVM_GUESTDBG_SINGLESTEP) #define vcpu_has_sve(vcpu) (system_supports_sve() && \ - ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE)) + vcpu_get_flag(vcpu, GUEST_HAS_SVE)) #ifdef CONFIG_ARM64_PTR_AUTH #define vcpu_has_ptrauth(vcpu) \ ((cpus_have_final_cap(ARM64_HAS_ADDRESS_AUTH) || \ cpus_have_final_cap(ARM64_HAS_GENERIC_AUTH)) && \ - (vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_PTRAUTH) + vcpu_get_flag(vcpu, GUEST_HAS_PTRAUTH)) #else #define vcpu_has_ptrauth(vcpu) false #endif @@ -893,8 +897,7 @@ void kvm_init_protected_traps(struct kvm_vcpu *vcpu); int kvm_arm_vcpu_finalize(struct kvm_vcpu *vcpu, int feature); bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu); -#define kvm_arm_vcpu_sve_finalized(vcpu) \ - ((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED) +#define kvm_arm_vcpu_sve_finalized(vcpu) vcpu_get_flag(vcpu, VCPU_SVE_FINALIZED) #define kvm_has_mte(kvm) \ (system_supports_mte() && \ diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 6c70c6f61c70..0e08fbe68715 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -81,7 +81,7 @@ static int kvm_vcpu_enable_sve(struct kvm_vcpu *vcpu) * KVM_REG_ARM64_SVE_VLS. Allocation is deferred until * kvm_arm_vcpu_finalize(), which freezes the configuration. */ - vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_SVE; + vcpu_set_flag(vcpu, GUEST_HAS_SVE); return 0; } @@ -120,7 +120,7 @@ static int kvm_vcpu_finalize_sve(struct kvm_vcpu *vcpu) } vcpu->arch.sve_state = buf; - vcpu->arch.flags |= KVM_ARM64_VCPU_SVE_FINALIZED; + vcpu_set_flag(vcpu, VCPU_SVE_FINALIZED); return 0; } @@ -177,7 +177,7 @@ static int kvm_vcpu_enable_ptrauth(struct kvm_vcpu *vcpu) !system_has_full_ptr_auth()) return -EINVAL; - vcpu->arch.flags |= KVM_ARM64_GUEST_HAS_PTRAUTH; + vcpu_set_flag(vcpu, GUEST_HAS_PTRAUTH); return 0; } From ae5a8983414ae67db27bc9f1c38919db70c26b0e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Jun 2022 19:18:35 +0200 Subject: [PATCH 0193/1436] dt-bindings: sram: qcom,ocmem: cleanup example coding style Fix the indentation in the OCMEM example and use generic node name - sram - to reflect the type of the device. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220607171848.535128-1-krzysztof.kozlowski@linaro.org --- Documentation/devicetree/bindings/sram/qcom,ocmem.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/sram/qcom,ocmem.yaml b/Documentation/devicetree/bindings/sram/qcom,ocmem.yaml index 930188bc5e6a..071f2d676196 100644 --- a/Documentation/devicetree/bindings/sram/qcom,ocmem.yaml +++ b/Documentation/devicetree/bindings/sram/qcom,ocmem.yaml @@ -72,10 +72,10 @@ patternProperties: examples: - | - #include - #include + #include + #include - ocmem: ocmem@fdd00000 { + sram@fdd00000 { compatible = "qcom,msm8974-ocmem"; reg = <0xfdd00000 0x2000>, @@ -93,6 +93,6 @@ examples: ranges = <0 0xfec00000 0x100000>; gmu-sram@0 { - reg = <0x0 0x100000>; + reg = <0x0 0x100000>; }; - }; + }; From 38a85b9d95c7a7c2bf12a0e73ef974136318f15f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Jun 2022 19:18:36 +0200 Subject: [PATCH 0194/1436] dt-bindings: sram: qcom,imem: add IMEM memory region Add bindings for IMEM memory region (like SRAM) used on several Qualcomm SoCs. In the downstream (vendor) tree, it comes with several children used for debugging purposes. The upstreamed parts are much smaller - just image loader and syscon reboot. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220607171848.535128-2-krzysztof.kozlowski@linaro.org --- .../devicetree/bindings/sram/qcom,imem.yaml | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Documentation/devicetree/bindings/sram/qcom,imem.yaml diff --git a/Documentation/devicetree/bindings/sram/qcom,imem.yaml b/Documentation/devicetree/bindings/sram/qcom,imem.yaml new file mode 100644 index 000000000000..e9199190198d --- /dev/null +++ b/Documentation/devicetree/bindings/sram/qcom,imem.yaml @@ -0,0 +1,75 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/sram/qcom,imem.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm IMEM memory region + +maintainers: + - Bjorn Andersson + +description: + Qualcomm IMEM is dedicated memory region for various debug features and DMA + transactions. + +properties: + compatible: + items: + - enum: + - qcom,apq8064-imem + - qcom,msm8974-imem + - qcom,qcs404-imem + - qcom,sc7180-imem + - qcom,sc7280-imem + - qcom,sdm630-imem + - qcom,sdm845-imem + - qcom,sdx55-imem + - const: syscon + - const: simple-mfd + + reg: + maxItems: 1 + + ranges: true + + '#address-cells': + const: 1 + + '#size-cells': + const: 1 + + reboot-mode: + $ref: /schemas/power/reset/syscon-reboot-mode.yaml# + +patternProperties: + "^pil-reloc@[0-9a-f]+$": + $ref: /schemas/remoteproc/qcom,pil-info.yaml# + description: Peripheral image loader relocation region + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + soc { + #address-cells = <2>; + #size-cells = <2>; + + sram@146bf000 { + compatible = "qcom,sdm845-imem", "syscon", "simple-mfd"; + reg = <0 0x146bf000 0 0x1000>; + ranges = <0 0 0x146bf000 0x1000>; + + #address-cells = <1>; + #size-cells = <1>; + + pil-reloc@94c { + compatible = "qcom,pil-reloc-info"; + reg = <0x94c 0xc8>; + }; + }; + }; From 337eac8f8499df7aa5a15e53c92d7242e97b4212 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 23 May 2022 17:08:18 +0800 Subject: [PATCH 0195/1436] platform/chrome: cros_kbd_led_backlight: sort headers alphabetically To be neat and reduce conflict possibility, sort the headers alphabetically. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220523090822.3035189-2-tzungbi@kernel.org --- drivers/platform/chrome/cros_kbd_led_backlight.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/chrome/cros_kbd_led_backlight.c b/drivers/platform/chrome/cros_kbd_led_backlight.c index aa409f0201fb..f9587a562bb7 100644 --- a/drivers/platform/chrome/cros_kbd_led_backlight.c +++ b/drivers/platform/chrome/cros_kbd_led_backlight.c @@ -4,12 +4,12 @@ // Copyright (C) 2012 Google, Inc. #include -#include #include #include -#include #include #include +#include +#include #include #include From 6b1e5ba39c44442c5ca115d89056823e064f1796 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 23 May 2022 17:08:19 +0800 Subject: [PATCH 0196/1436] platform/chrome: cros_kbd_led_backlight: separate ACPI backend cros_kbd_led_backlight uses ACPI_KEYBOARD_BACKLIGHT_WRITE and ACPI_KEYBOARD_BACKLIGHT_READ for setting and getting the brightness respectively. Separate ACPI operations for preparing the driver to support other backends. Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220523090822.3035189-3-tzungbi@kernel.org --- .../platform/chrome/cros_kbd_led_backlight.c | 82 ++++++++++++++++--- 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/drivers/platform/chrome/cros_kbd_led_backlight.c b/drivers/platform/chrome/cros_kbd_led_backlight.c index f9587a562bb7..a86d664854ae 100644 --- a/drivers/platform/chrome/cros_kbd_led_backlight.c +++ b/drivers/platform/chrome/cros_kbd_led_backlight.c @@ -13,6 +13,33 @@ #include #include +/** + * struct keyboard_led_drvdata - keyboard LED driver data. + * @init: Init function. + * @brightness_get: Get LED brightness level. + * @brightness_set: Set LED brightness level. Must not sleep. + * @brightness_set_blocking: Set LED brightness level. It can block the + * caller for the time required for accessing a + * LED device register + * @max_brightness: Maximum brightness. + * + * See struct led_classdev in include/linux/leds.h for more details. + */ +struct keyboard_led_drvdata { + int (*init)(struct platform_device *pdev); + + enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); + + void (*brightness_set)(struct led_classdev *led_cdev, + enum led_brightness brightness); + int (*brightness_set_blocking)(struct led_classdev *led_cdev, + enum led_brightness brightness); + + enum led_brightness max_brightness; +}; + +#ifdef CONFIG_ACPI + /* Keyboard LED ACPI Device must be defined in firmware */ #define ACPI_KEYBOARD_BACKLIGHT_DEVICE "\\_SB.KBLT" #define ACPI_KEYBOARD_BACKLIGHT_READ ACPI_KEYBOARD_BACKLIGHT_DEVICE ".KBQC" @@ -20,8 +47,8 @@ #define ACPI_KEYBOARD_BACKLIGHT_MAX 100 -static void keyboard_led_set_brightness(struct led_classdev *cdev, - enum led_brightness brightness) +static void keyboard_led_set_brightness_acpi(struct led_classdev *cdev, + enum led_brightness brightness) { union acpi_object param; struct acpi_object_list input; @@ -40,7 +67,7 @@ static void keyboard_led_set_brightness(struct led_classdev *cdev, } static enum led_brightness -keyboard_led_get_brightness(struct led_classdev *cdev) +keyboard_led_get_brightness_acpi(struct led_classdev *cdev) { unsigned long long brightness; acpi_status status; @@ -56,12 +83,10 @@ keyboard_led_get_brightness(struct led_classdev *cdev) return brightness; } -static int keyboard_led_probe(struct platform_device *pdev) +static int keyboard_led_init_acpi(struct platform_device *pdev) { - struct led_classdev *cdev; acpi_handle handle; acpi_status status; - int error; /* Look for the keyboard LED ACPI Device */ status = acpi_get_handle(ACPI_ROOT_OBJECT, @@ -73,15 +98,44 @@ static int keyboard_led_probe(struct platform_device *pdev) return -ENXIO; } + return 0; +} + +static const struct keyboard_led_drvdata keyboard_led_drvdata_acpi = { + .init = keyboard_led_init_acpi, + .brightness_set = keyboard_led_set_brightness_acpi, + .brightness_get = keyboard_led_get_brightness_acpi, + .max_brightness = ACPI_KEYBOARD_BACKLIGHT_MAX, +}; + +#endif /* CONFIG_ACPI */ + +static int keyboard_led_probe(struct platform_device *pdev) +{ + struct led_classdev *cdev; + const struct keyboard_led_drvdata *drvdata; + int error; + + drvdata = acpi_device_get_match_data(&pdev->dev); + if (!drvdata) + return -EINVAL; + + if (drvdata->init) { + error = drvdata->init(pdev); + if (error) + return error; + } + cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL); if (!cdev) return -ENOMEM; cdev->name = "chromeos::kbd_backlight"; - cdev->max_brightness = ACPI_KEYBOARD_BACKLIGHT_MAX; cdev->flags |= LED_CORE_SUSPENDRESUME; - cdev->brightness_set = keyboard_led_set_brightness; - cdev->brightness_get = keyboard_led_get_brightness; + cdev->max_brightness = drvdata->max_brightness; + cdev->brightness_set = drvdata->brightness_set; + cdev->brightness_set_blocking = drvdata->brightness_set_blocking; + cdev->brightness_get = drvdata->brightness_get; error = devm_led_classdev_register(&pdev->dev, cdev); if (error) @@ -90,16 +144,18 @@ static int keyboard_led_probe(struct platform_device *pdev) return 0; } -static const struct acpi_device_id keyboard_led_id[] = { - { "GOOG0002", 0 }, +#ifdef CONFIG_ACPI +static const struct acpi_device_id keyboard_led_acpi_match[] = { + { "GOOG0002", (kernel_ulong_t)&keyboard_led_drvdata_acpi }, { } }; -MODULE_DEVICE_TABLE(acpi, keyboard_led_id); +MODULE_DEVICE_TABLE(acpi, keyboard_led_acpi_match); +#endif static struct platform_driver keyboard_led_driver = { .driver = { .name = "chromeos-keyboard-leds", - .acpi_match_table = ACPI_PTR(keyboard_led_id), + .acpi_match_table = ACPI_PTR(keyboard_led_acpi_match), }, .probe = keyboard_led_probe, }; From 20f370efddb58c497588a51df889dc784055733f Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 23 May 2022 17:08:20 +0800 Subject: [PATCH 0197/1436] dt-bindings: add google,cros-kbd-led-backlight Acked-by: Rob Herring Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220523090822.3035189-4-tzungbi@kernel.org --- .../chrome/google,cros-kbd-led-backlight.yaml | 35 +++++++++++++++++++ .../bindings/mfd/google,cros-ec.yaml | 3 ++ 2 files changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/chrome/google,cros-kbd-led-backlight.yaml diff --git a/Documentation/devicetree/bindings/chrome/google,cros-kbd-led-backlight.yaml b/Documentation/devicetree/bindings/chrome/google,cros-kbd-led-backlight.yaml new file mode 100644 index 000000000000..5b875af6a95a --- /dev/null +++ b/Documentation/devicetree/bindings/chrome/google,cros-kbd-led-backlight.yaml @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/chrome/google,cros-kbd-led-backlight.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ChromeOS keyboard backlight LED driver. + +maintainers: + - Tzung-Bi Shih + +properties: + compatible: + const: google,cros-kbd-led-backlight + +required: + - compatible + +additionalProperties: false + +examples: + - | + spi0 { + #address-cells = <1>; + #size-cells = <0>; + + cros_ec: ec@0 { + compatible = "google,cros-ec-spi"; + reg = <0>; + + kbd-led-backlight { + compatible = "google,cros-kbd-led-backlight"; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml index e25caf8ef9f4..04962bb29576 100644 --- a/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml +++ b/Documentation/devicetree/bindings/mfd/google,cros-ec.yaml @@ -90,6 +90,9 @@ properties: pwm: $ref: "/schemas/pwm/google,cros-ec-pwm.yaml#" + kbd-led-backlight: + $ref: "/schemas/chrome/google,cros-kbd-led-backlight.yaml#" + keyboard-controller: $ref: "/schemas/input/google,cros-ec-keyb.yaml#" From fd1e8054ff6985cfcbdf66a6de88cf1c47a14f46 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 23 May 2022 17:08:21 +0800 Subject: [PATCH 0198/1436] platform/chrome: cros_kbd_led_backlight: support OF match For letting device tree based machines to use the driver, support OF match. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Reviewed-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/20220523090822.3035189-5-tzungbi@kernel.org --- drivers/platform/chrome/cros_kbd_led_backlight.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/platform/chrome/cros_kbd_led_backlight.c b/drivers/platform/chrome/cros_kbd_led_backlight.c index a86d664854ae..4bca880d7721 100644 --- a/drivers/platform/chrome/cros_kbd_led_backlight.c +++ b/drivers/platform/chrome/cros_kbd_led_backlight.c @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include /** @@ -116,7 +118,7 @@ static int keyboard_led_probe(struct platform_device *pdev) const struct keyboard_led_drvdata *drvdata; int error; - drvdata = acpi_device_get_match_data(&pdev->dev); + drvdata = device_get_match_data(&pdev->dev); if (!drvdata) return -EINVAL; @@ -152,10 +154,21 @@ static const struct acpi_device_id keyboard_led_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, keyboard_led_acpi_match); #endif +#ifdef CONFIG_OF +static const struct of_device_id keyboard_led_of_match[] = { + { + .compatible = "google,cros-kbd-led-backlight", + }, + {} +}; +MODULE_DEVICE_TABLE(of, keyboard_led_of_match); +#endif + static struct platform_driver keyboard_led_driver = { .driver = { .name = "chromeos-keyboard-leds", .acpi_match_table = ACPI_PTR(keyboard_led_acpi_match), + .of_match_table = of_match_ptr(keyboard_led_of_match), }, .probe = keyboard_led_probe, }; From 40f58143745eaabc68ef44b068642ca3b38d23a6 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 23 May 2022 17:08:22 +0800 Subject: [PATCH 0199/1436] platform/chrome: cros_kbd_led_backlight: support EC PWM backend EC PWM backend uses EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT and EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT for setting and getting the brightness respectively. Signed-off-by: Tzung-Bi Shih Reviewed-by: Matthias Kaehlcke Tested-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/20220523090822.3035189-6-tzungbi@kernel.org --- drivers/platform/chrome/Kconfig | 2 +- .../platform/chrome/cros_kbd_led_backlight.c | 113 +++++++++++++++--- 2 files changed, 99 insertions(+), 16 deletions(-) diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 4b3d2427e8dd..08fef209090d 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -139,7 +139,7 @@ config CROS_EC_PROTO config CROS_KBD_LED_BACKLIGHT tristate "Backlight LED support for Chrome OS keyboards" - depends on LEDS_CLASS && ACPI + depends on LEDS_CLASS && (ACPI || CROS_EC) help This option enables support for the keyboard backlight LEDs on select Chrome OS systems. diff --git a/drivers/platform/chrome/cros_kbd_led_backlight.c b/drivers/platform/chrome/cros_kbd_led_backlight.c index 4bca880d7721..5ad41c10412d 100644 --- a/drivers/platform/chrome/cros_kbd_led_backlight.c +++ b/drivers/platform/chrome/cros_kbd_led_backlight.c @@ -11,10 +11,17 @@ #include #include #include +#include +#include #include #include #include +struct keyboard_led { + struct led_classdev cdev; + struct cros_ec_device *ec; +}; + /** * struct keyboard_led_drvdata - keyboard LED driver data. * @init: Init function. @@ -40,6 +47,8 @@ struct keyboard_led_drvdata { enum led_brightness max_brightness; }; +#define KEYBOARD_BACKLIGHT_MAX 100 + #ifdef CONFIG_ACPI /* Keyboard LED ACPI Device must be defined in firmware */ @@ -47,8 +56,6 @@ struct keyboard_led_drvdata { #define ACPI_KEYBOARD_BACKLIGHT_READ ACPI_KEYBOARD_BACKLIGHT_DEVICE ".KBQC" #define ACPI_KEYBOARD_BACKLIGHT_WRITE ACPI_KEYBOARD_BACKLIGHT_DEVICE ".KBCM" -#define ACPI_KEYBOARD_BACKLIGHT_MAX 100 - static void keyboard_led_set_brightness_acpi(struct led_classdev *cdev, enum led_brightness brightness) { @@ -107,39 +114,114 @@ static const struct keyboard_led_drvdata keyboard_led_drvdata_acpi = { .init = keyboard_led_init_acpi, .brightness_set = keyboard_led_set_brightness_acpi, .brightness_get = keyboard_led_get_brightness_acpi, - .max_brightness = ACPI_KEYBOARD_BACKLIGHT_MAX, + .max_brightness = KEYBOARD_BACKLIGHT_MAX, }; #endif /* CONFIG_ACPI */ +#ifdef CONFIG_CROS_EC + +static int +keyboard_led_set_brightness_ec_pwm(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct { + struct cros_ec_command msg; + struct ec_params_pwm_set_keyboard_backlight params; + } __packed buf; + struct ec_params_pwm_set_keyboard_backlight *params = &buf.params; + struct cros_ec_command *msg = &buf.msg; + struct keyboard_led *keyboard_led = container_of(cdev, struct keyboard_led, cdev); + + memset(&buf, 0, sizeof(buf)); + + msg->command = EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT; + msg->outsize = sizeof(*params); + + params->percent = brightness; + + return cros_ec_cmd_xfer_status(keyboard_led->ec, msg); +} + +static enum led_brightness +keyboard_led_get_brightness_ec_pwm(struct led_classdev *cdev) +{ + struct { + struct cros_ec_command msg; + struct ec_response_pwm_get_keyboard_backlight resp; + } __packed buf; + struct ec_response_pwm_get_keyboard_backlight *resp = &buf.resp; + struct cros_ec_command *msg = &buf.msg; + struct keyboard_led *keyboard_led = container_of(cdev, struct keyboard_led, cdev); + int ret; + + memset(&buf, 0, sizeof(buf)); + + msg->command = EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT; + msg->insize = sizeof(*resp); + + ret = cros_ec_cmd_xfer_status(keyboard_led->ec, msg); + if (ret < 0) + return ret; + + return resp->percent; +} + +static int keyboard_led_init_ec_pwm(struct platform_device *pdev) +{ + struct keyboard_led *keyboard_led = platform_get_drvdata(pdev); + + keyboard_led->ec = dev_get_drvdata(pdev->dev.parent); + if (!keyboard_led->ec) { + dev_err(&pdev->dev, "no parent EC device\n"); + return -EINVAL; + } + + return 0; +} + +static const struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = { + .init = keyboard_led_init_ec_pwm, + .brightness_set_blocking = keyboard_led_set_brightness_ec_pwm, + .brightness_get = keyboard_led_get_brightness_ec_pwm, + .max_brightness = KEYBOARD_BACKLIGHT_MAX, +}; + +#else /* CONFIG_CROS_EC */ + +static const struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = {}; + +#endif /* CONFIG_CROS_EC */ + static int keyboard_led_probe(struct platform_device *pdev) { - struct led_classdev *cdev; const struct keyboard_led_drvdata *drvdata; + struct keyboard_led *keyboard_led; int error; drvdata = device_get_match_data(&pdev->dev); if (!drvdata) return -EINVAL; + keyboard_led = devm_kzalloc(&pdev->dev, sizeof(*keyboard_led), GFP_KERNEL); + if (!keyboard_led) + return -ENOMEM; + platform_set_drvdata(pdev, keyboard_led); + if (drvdata->init) { error = drvdata->init(pdev); if (error) return error; } - cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL); - if (!cdev) - return -ENOMEM; + keyboard_led->cdev.name = "chromeos::kbd_backlight"; + keyboard_led->cdev.flags |= LED_CORE_SUSPENDRESUME; + keyboard_led->cdev.max_brightness = drvdata->max_brightness; + keyboard_led->cdev.brightness_set = drvdata->brightness_set; + keyboard_led->cdev.brightness_set_blocking = drvdata->brightness_set_blocking; + keyboard_led->cdev.brightness_get = drvdata->brightness_get; - cdev->name = "chromeos::kbd_backlight"; - cdev->flags |= LED_CORE_SUSPENDRESUME; - cdev->max_brightness = drvdata->max_brightness; - cdev->brightness_set = drvdata->brightness_set; - cdev->brightness_set_blocking = drvdata->brightness_set_blocking; - cdev->brightness_get = drvdata->brightness_get; - - error = devm_led_classdev_register(&pdev->dev, cdev); + error = devm_led_classdev_register(&pdev->dev, &keyboard_led->cdev); if (error) return error; @@ -158,6 +240,7 @@ MODULE_DEVICE_TABLE(acpi, keyboard_led_acpi_match); static const struct of_device_id keyboard_led_of_match[] = { { .compatible = "google,cros-kbd-led-backlight", + .data = &keyboard_led_drvdata_ec_pwm, }, {} }; From ea7f0f777d28db6e500a05836f2a9d467c7012de Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:37 +0000 Subject: [PATCH 0200/1436] platform/chrome: cros_ec_commands: fix compile errors Fix compile errors when including cros_ec_commands.h solely. 1. cros_ec_commands.h:587:9: error: unknown type name 'uint8_t' 587 | uint8_t flags; | ^~~~~~~ 2. cros_ec_commands.h:1105:43: error: implicit declaration of function 'BIT' 1105 | EC_COMMS_STATUS_PROCESSING = BIT(0), | ^~~ Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-2-tzungbi@kernel.org --- include/linux/platform_data/cros_ec_commands.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index e59f51c41a1c..f13568b3e247 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -13,8 +13,8 @@ #ifndef __CROS_EC_COMMANDS_H #define __CROS_EC_COMMANDS_H - - +#include +#include #define BUILD_ASSERT(_cond) From b99eb596efbd2aa138dad3dd5b6705b2e8c42c36 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:38 +0000 Subject: [PATCH 0201/1436] platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_query_all() cros_ec_query_all() sends multiple host commands to EC for querying supported protocols and settings. Add required mock for interacting with cros_ec_query_all() and Kunit tests. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-3-tzungbi@kernel.org --- drivers/platform/chrome/Kconfig | 6 + drivers/platform/chrome/Makefile | 1 + drivers/platform/chrome/cros_ec_proto_test.c | 802 +++++++++++++++++++ drivers/platform/chrome/cros_kunit_util.c | 98 +++ drivers/platform/chrome/cros_kunit_util.h | 36 + 5 files changed, 943 insertions(+) create mode 100644 drivers/platform/chrome/cros_kunit_util.c create mode 100644 drivers/platform/chrome/cros_kunit_util.h diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 08fef209090d..cae859f0bc06 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -268,11 +268,17 @@ config CHROMEOS_PRIVACY_SCREEN source "drivers/platform/chrome/wilco_ec/Kconfig" # Kunit test cases +config CROS_KUNIT + tristate + help + ChromeOS Kunit. + config CROS_EC_PROTO_KUNIT_TEST tristate "Kunit tests for ChromeOS EC protocol" if !KUNIT_ALL_TESTS depends on KUNIT && CROS_EC default KUNIT_ALL_TESTS select CROS_EC_PROTO + select CROS_KUNIT help Kunit tests for the ChromeOS Embedded Controller protocol. diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 3c380066c6b6..a06bc56d12a8 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -32,4 +32,5 @@ obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o obj-$(CONFIG_WILCO_EC) += wilco_ec/ # Kunit test cases +obj-$(CONFIG_CROS_KUNIT) += cros_kunit_util.o obj-$(CONFIG_CROS_EC_PROTO_KUNIT_TEST) += cros_ec_proto_test.o diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 25c4fca5c165..675306c16d47 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -9,6 +9,7 @@ #include #include "cros_ec.h" +#include "cros_kunit_util.h" #define BUFSIZE 512 @@ -172,6 +173,779 @@ static void cros_ec_proto_test_check_result(struct kunit *test) KUNIT_EXPECT_EQ(test, ret, -EAGAIN); } +static void cros_ec_proto_test_query_all_pretest(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + + /* + * cros_ec_query_all() will free din and dout and allocate them again to fit the usage by + * calling devm_kfree() and devm_kzalloc(). Set them to NULL as they aren't managed by + * ec_dev->dev but allocated statically in struct cros_ec_proto_test_priv + * (see cros_ec_proto_test_init()). + */ + ec_dev->din = NULL; + ec_dev->dout = NULL; +} + +static void cros_ec_proto_test_query_all_normal(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->protocol_versions = BIT(3) | BIT(2); + data->max_request_packet_size = 0xbe; + data->max_response_packet_size = 0xef; + } + + /* For cros_ec_host_command_proto_query() with passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->max_request_packet_size = 0xbf; + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + struct ec_response_get_cmd_versions *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_cmd_versions *)mock->o_data; + data->version_mask = BIT(6) | BIT(5); + } + + /* For cros_ec_get_host_command_version_mask() for host sleep v1. */ + { + struct ec_response_get_cmd_versions *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_cmd_versions *)mock->o_data; + data->version_mask = BIT(1); + } + + /* For cros_ec_get_host_event_wake_mask(). */ + { + struct ec_response_host_event_mask *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_host_event_mask *)mock->o_data; + data->mask = 0xbeef; + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + + KUNIT_EXPECT_EQ(test, ec_dev->max_request, 0xbe - sizeof(struct ec_host_request)); + KUNIT_EXPECT_EQ(test, ec_dev->max_response, 0xef - sizeof(struct ec_host_response)); + KUNIT_EXPECT_EQ(test, ec_dev->proto_version, 3); + KUNIT_EXPECT_EQ(test, ec_dev->din_size, 0xef + EC_MAX_RESPONSE_OVERHEAD); + KUNIT_EXPECT_EQ(test, ec_dev->dout_size, 0xbe + EC_MAX_REQUEST_OVERHEAD); + } + + /* For cros_ec_host_command_proto_query() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, + EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + + KUNIT_EXPECT_EQ(test, ec_dev->max_passthru, 0xbf - sizeof(struct ec_host_request)); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + struct ec_params_get_cmd_versions *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data)); + + data = (struct ec_params_get_cmd_versions *)mock->i_data; + KUNIT_EXPECT_EQ(test, data->cmd, EC_CMD_GET_NEXT_EVENT); + + KUNIT_EXPECT_EQ(test, ec_dev->mkbp_event_supported, 7); + } + + /* For cros_ec_get_host_command_version_mask() for host sleep v1. */ + { + struct ec_params_get_cmd_versions *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data)); + + data = (struct ec_params_get_cmd_versions *)mock->i_data; + KUNIT_EXPECT_EQ(test, data->cmd, EC_CMD_HOST_SLEEP_EVENT); + + KUNIT_EXPECT_TRUE(test, ec_dev->host_sleep_v1); + } + + /* For cros_ec_get_host_event_wake_mask(). */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HOST_EVENT_GET_WAKE_MASK); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_host_event_mask)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + + KUNIT_EXPECT_EQ(test, ec_dev->host_event_wake_mask, 0xbeef); + } +} + +static void cros_ec_proto_test_query_all_no_pd_return_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* Set some garbage bytes. */ + ec_dev->max_passthru = 0xbf; + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + /* + * Although it doesn't check the value, provides valid sizes so that + * cros_ec_query_all() allocates din and dout correctly. + */ + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->max_request_packet_size = 0xbe; + data->max_response_packet_size = 0xef; + } + + /* For cros_ec_host_command_proto_query() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_host_command_proto_query() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, + EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + + KUNIT_EXPECT_EQ(test, ec_dev->max_passthru, 0); + } +} + +static void cros_ec_proto_test_query_all_legacy_normal_v3_return_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_host_command_proto_query_v2(). */ + { + struct ec_response_hello *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_hello *)mock->o_data; + data->out_data = 0xa1b2c3d4; + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_host_command_proto_query_v2(). */ + { + struct ec_params_hello *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data)); + + data = (struct ec_params_hello *)mock->i_data; + KUNIT_EXPECT_EQ(test, data->in_data, 0xa0b0c0d0); + + KUNIT_EXPECT_EQ(test, ec_dev->proto_version, 2); + KUNIT_EXPECT_EQ(test, ec_dev->max_request, EC_PROTO2_MAX_PARAM_SIZE); + KUNIT_EXPECT_EQ(test, ec_dev->max_response, EC_PROTO2_MAX_PARAM_SIZE); + KUNIT_EXPECT_EQ(test, ec_dev->max_passthru, 0); + KUNIT_EXPECT_PTR_EQ(test, ec_dev->pkt_xfer, NULL); + KUNIT_EXPECT_EQ(test, ec_dev->din_size, EC_PROTO2_MSG_BYTES); + KUNIT_EXPECT_EQ(test, ec_dev->dout_size, EC_PROTO2_MSG_BYTES); + } +} + +static void cros_ec_proto_test_query_all_legacy_xfer_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_host_command_proto_query_v2(). */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, -EIO, EC_RES_SUCCESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, -EIO); + KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN); + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_host_command_proto_query_v2(). */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_hello)); + } +} + +static void cros_ec_proto_test_query_all_legacy_return_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_host_command_proto_query_v2(). */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, EC_RES_INVALID_COMMAND); + KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN); + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_host_command_proto_query_v2(). */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_hello)); + } +} + +static void cros_ec_proto_test_query_all_legacy_data_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_host_command_proto_query_v2(). */ + { + struct ec_response_hello *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_hello *)mock->o_data; + data->out_data = 0xbeefbfbf; + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, -EBADMSG); + KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN); + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_host_command_proto_query_v2(). */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_hello)); + } +} + +static void cros_ec_proto_test_query_all_no_mkbp(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* Set some garbage bytes. */ + ec_dev->mkbp_event_supported = 0xbf; + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + /* + * Although it doesn't check the value, provides valid sizes so that + * cros_ec_query_all() allocates din and dout correctly. + */ + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->max_request_packet_size = 0xbe; + data->max_response_packet_size = 0xef; + } + + /* For cros_ec_host_command_proto_query() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + struct ec_response_get_cmd_versions *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_cmd_versions *)mock->o_data; + data->version_mask = 0; + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_host_command_proto_query() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, + EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + struct ec_params_get_cmd_versions *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data)); + + data = (struct ec_params_get_cmd_versions *)mock->i_data; + KUNIT_EXPECT_EQ(test, data->cmd, EC_CMD_GET_NEXT_EVENT); + + KUNIT_EXPECT_EQ(test, ec_dev->mkbp_event_supported, 0); + } +} + +static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* Set some garbage bytes. */ + ec_dev->host_sleep_v1 = true; + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + /* + * Although it doesn't check the value, provides valid sizes so that + * cros_ec_query_all() allocates din and dout correctly. + */ + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->max_request_packet_size = 0xbe; + data->max_response_packet_size = 0xef; + } + + /* For cros_ec_host_command_proto_query() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_command_version_mask() for host sleep v1. */ + { + struct ec_response_get_cmd_versions *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_cmd_versions *)mock->o_data; + data->version_mask = 0; + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_host_command_proto_query() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, + EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions)); + } + + /* For cros_ec_get_host_command_version_mask() for host sleep v1. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions)); + + KUNIT_EXPECT_FALSE(test, ec_dev->host_sleep_v1); + } +} + +static void cros_ec_proto_test_query_all_default_wake_mask_return_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* Set some garbage bytes. */ + ec_dev->host_event_wake_mask = U32_MAX; + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + /* + * Although it doesn't check the value, provides valid sizes so that + * cros_ec_query_all() allocates din and dout correctly. + */ + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->max_request_packet_size = 0xbe; + data->max_response_packet_size = 0xef; + } + + /* For cros_ec_host_command_proto_query() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_command_version_mask() for host sleep v1. */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_event_wake_mask(). */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_host_command_proto_query() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_host_command_proto_query() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, + EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions)); + } + + /* For cros_ec_get_host_command_version_mask() for host sleep v1. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions)); + } + + /* For cros_ec_get_host_event_wake_mask(). */ + { + u32 mask; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HOST_EVENT_GET_WAKE_MASK); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_host_event_mask)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + + mask = ec_dev->host_event_wake_mask; + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_AC_DISCONNECTED), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_LOW), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_CRITICAL), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_STATUS), 0); + } +} + +static void cros_ec_proto_test_release(struct device *dev) +{ +} + static int cros_ec_proto_test_init(struct kunit *test) { struct cros_ec_proto_test_priv *priv; @@ -188,24 +962,52 @@ static int cros_ec_proto_test_init(struct kunit *test) ec_dev->din = (u8 *)priv->din; ec_dev->din_size = ARRAY_SIZE(priv->din); ec_dev->proto_version = EC_HOST_REQUEST_VERSION; + ec_dev->dev = kunit_kzalloc(test, sizeof(*ec_dev->dev), GFP_KERNEL); + if (!ec_dev->dev) + return -ENOMEM; + device_initialize(ec_dev->dev); + dev_set_name(ec_dev->dev, "cros_ec_proto_test"); + ec_dev->dev->release = cros_ec_proto_test_release; + ec_dev->cmd_xfer = cros_kunit_ec_xfer_mock; + ec_dev->pkt_xfer = cros_kunit_ec_xfer_mock; priv->msg = (struct cros_ec_command *)priv->_msg; + cros_kunit_mock_reset(); + return 0; } +static void cros_ec_proto_test_exit(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + + put_device(ec_dev->dev); +} + static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_prepare_tx_legacy_normal), KUNIT_CASE(cros_ec_proto_test_prepare_tx_legacy_bad_msg_outsize), KUNIT_CASE(cros_ec_proto_test_prepare_tx_normal), KUNIT_CASE(cros_ec_proto_test_prepare_tx_bad_msg_outsize), KUNIT_CASE(cros_ec_proto_test_check_result), + KUNIT_CASE(cros_ec_proto_test_query_all_normal), + KUNIT_CASE(cros_ec_proto_test_query_all_no_pd_return_error), + KUNIT_CASE(cros_ec_proto_test_query_all_legacy_normal_v3_return_error), + KUNIT_CASE(cros_ec_proto_test_query_all_legacy_xfer_error), + KUNIT_CASE(cros_ec_proto_test_query_all_legacy_return_error), + KUNIT_CASE(cros_ec_proto_test_query_all_legacy_data_error), + KUNIT_CASE(cros_ec_proto_test_query_all_no_mkbp), + KUNIT_CASE(cros_ec_proto_test_query_all_no_host_sleep), + KUNIT_CASE(cros_ec_proto_test_query_all_default_wake_mask_return_error), {} }; static struct kunit_suite cros_ec_proto_test_suite = { .name = "cros_ec_proto_test", .init = cros_ec_proto_test_init, + .exit = cros_ec_proto_test_exit, .test_cases = cros_ec_proto_test_cases, }; diff --git a/drivers/platform/chrome/cros_kunit_util.c b/drivers/platform/chrome/cros_kunit_util.c new file mode 100644 index 000000000000..e031777dea87 --- /dev/null +++ b/drivers/platform/chrome/cros_kunit_util.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CrOS Kunit tests utilities. + */ + +#include + +#include +#include +#include +#include + +#include "cros_ec.h" +#include "cros_kunit_util.h" + +int cros_kunit_ec_xfer_mock_default_ret; +EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_default_ret); + +static struct list_head cros_kunit_ec_xfer_mock_in; +static struct list_head cros_kunit_ec_xfer_mock_out; + +int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) +{ + struct ec_xfer_mock *mock; + + mock = list_first_entry_or_null(&cros_kunit_ec_xfer_mock_in, struct ec_xfer_mock, list); + if (!mock) + return cros_kunit_ec_xfer_mock_default_ret; + + list_del(&mock->list); + + memcpy(&mock->msg, msg, sizeof(*msg)); + if (msg->outsize) { + mock->i_data = kunit_kzalloc(mock->test, msg->outsize, GFP_KERNEL); + if (mock->i_data) + memcpy(mock->i_data, msg->data, msg->outsize); + } + + msg->result = mock->result; + if (msg->insize) + memcpy(msg->data, mock->o_data, min(msg->insize, mock->o_data_len)); + + list_add_tail(&mock->list, &cros_kunit_ec_xfer_mock_out); + + return mock->ret; +} +EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock); + +struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size) +{ + return cros_kunit_ec_xfer_mock_addx(test, size, EC_RES_SUCCESS, size); +} +EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_add); + +struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test, + int ret, int result, size_t size) +{ + struct ec_xfer_mock *mock; + + mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL); + if (!mock) + return NULL; + + list_add_tail(&mock->list, &cros_kunit_ec_xfer_mock_in); + mock->test = test; + + mock->ret = ret; + mock->result = result; + mock->o_data = kunit_kzalloc(test, size, GFP_KERNEL); + if (!mock->o_data) + return NULL; + mock->o_data_len = size; + + return mock; +} +EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_addx); + +struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void) +{ + struct ec_xfer_mock *mock; + + mock = list_first_entry_or_null(&cros_kunit_ec_xfer_mock_out, struct ec_xfer_mock, list); + if (mock) + list_del(&mock->list); + + return mock; +} +EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_next); + +void cros_kunit_mock_reset(void) +{ + cros_kunit_ec_xfer_mock_default_ret = 0; + INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_in); + INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_out); +} +EXPORT_SYMBOL_GPL(cros_kunit_mock_reset); + +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/chrome/cros_kunit_util.h b/drivers/platform/chrome/cros_kunit_util.h new file mode 100644 index 000000000000..79c4525f873c --- /dev/null +++ b/drivers/platform/chrome/cros_kunit_util.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * CrOS Kunit tests utilities. + */ + +#ifndef _CROS_KUNIT_UTIL_H_ +#define _CROS_KUNIT_UTIL_H_ + +#include + +struct ec_xfer_mock { + struct list_head list; + struct kunit *test; + + /* input */ + struct cros_ec_command msg; + void *i_data; + + /* output */ + int ret; + int result; + void *o_data; + u32 o_data_len; +}; + +extern int cros_kunit_ec_xfer_mock_default_ret; + +int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg); +struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size); +struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test, + int ret, int result, size_t size); +struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void); + +void cros_kunit_mock_reset(void); + +#endif From 3db0c9e5de7bd9dbe52580eb9752b2b3049e38da Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:39 +0000 Subject: [PATCH 0202/1436] platform/chrome: use macros for passthru indexes Move passthru indexes for EC and PD devices to common header. Also use them instead of literal constants. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-4-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec.c | 3 --- drivers/platform/chrome/cros_ec_proto.c | 6 +++--- drivers/platform/chrome/cros_ec_proto_test.c | 15 ++++++++++----- drivers/platform/chrome/cros_ec_trace.h | 8 ++++---- include/linux/platform_data/cros_ec_proto.h | 3 +++ 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c index b3e94cdf7d1a..e51a3f2176c7 100644 --- a/drivers/platform/chrome/cros_ec.c +++ b/drivers/platform/chrome/cros_ec.c @@ -19,9 +19,6 @@ #include "cros_ec.h" -#define CROS_EC_DEV_EC_INDEX 0 -#define CROS_EC_DEV_PD_INDEX 1 - static struct cros_ec_platform ec_p = { .ec_name = CROS_EC_DEV_NAME, .cmd_offset = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_EC_INDEX), diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index cefabfe45551..cfa3dacce4e5 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -433,7 +433,7 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) /* First try sending with proto v3. */ ec_dev->proto_version = 3; - ret = cros_ec_host_command_proto_query(ec_dev, 0, proto_msg); + ret = cros_ec_host_command_proto_query(ec_dev, CROS_EC_DEV_EC_INDEX, proto_msg); if (ret == 0) { proto_info = (struct ec_response_get_protocol_info *) @@ -459,7 +459,7 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) /* * Check for PD */ - ret = cros_ec_host_command_proto_query(ec_dev, 1, proto_msg); + ret = cros_ec_host_command_proto_query(ec_dev, CROS_EC_DEV_PD_INDEX, proto_msg); if (ret) { dev_dbg(ec_dev->dev, "no PD chip found: %d\n", ret); @@ -609,7 +609,7 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) msg->insize = ec_dev->max_response; } - if (msg->command < EC_CMD_PASSTHRU_OFFSET(1)) { + if (msg->command < EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX)) { if (msg->outsize > ec_dev->max_request) { dev_err(ec_dev->dev, "request of size %u is too big (max: %u)\n", diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 675306c16d47..f8dbfb0d8dc8 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -281,7 +281,8 @@ static void cros_ec_proto_test_query_all_normal(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.version, 0); KUNIT_EXPECT_EQ(test, mock->msg.command, - EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_protocol_info)); KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); @@ -396,7 +397,8 @@ static void cros_ec_proto_test_query_all_no_pd_return_error(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.version, 0); KUNIT_EXPECT_EQ(test, mock->msg.command, - EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_protocol_info)); KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); @@ -685,7 +687,8 @@ static void cros_ec_proto_test_query_all_no_mkbp(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.version, 0); KUNIT_EXPECT_EQ(test, mock->msg.command, - EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_protocol_info)); KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); @@ -783,7 +786,8 @@ static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.version, 0); KUNIT_EXPECT_EQ(test, mock->msg.command, - EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_protocol_info)); KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); @@ -889,7 +893,8 @@ static void cros_ec_proto_test_query_all_default_wake_mask_return_error(struct k KUNIT_EXPECT_EQ(test, mock->msg.version, 0); KUNIT_EXPECT_EQ(test, mock->msg.command, - EC_CMD_PASSTHRU_OFFSET(1) | EC_CMD_GET_PROTOCOL_INFO); + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_protocol_info)); KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); diff --git a/drivers/platform/chrome/cros_ec_trace.h b/drivers/platform/chrome/cros_ec_trace.h index 9bb5cd2c98b8..d7e407de88df 100644 --- a/drivers/platform/chrome/cros_ec_trace.h +++ b/drivers/platform/chrome/cros_ec_trace.h @@ -30,8 +30,8 @@ TRACE_EVENT(cros_ec_request_start, ), TP_fast_assign( __entry->version = cmd->version; - __entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1); - __entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1); + __entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX); + __entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX); __entry->outsize = cmd->outsize; __entry->insize = cmd->insize; ), @@ -55,8 +55,8 @@ TRACE_EVENT(cros_ec_request_done, ), TP_fast_assign( __entry->version = cmd->version; - __entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(1); - __entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(1); + __entry->offset = cmd->command / EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX); + __entry->command = cmd->command % EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX); __entry->outsize = cmd->outsize; __entry->insize = cmd->insize; __entry->result = cmd->result; diff --git a/include/linux/platform_data/cros_ec_proto.h b/include/linux/platform_data/cros_ec_proto.h index 85e29300f63d..c82a8285d936 100644 --- a/include/linux/platform_data/cros_ec_proto.h +++ b/include/linux/platform_data/cros_ec_proto.h @@ -21,6 +21,9 @@ #define CROS_EC_DEV_SCP_NAME "cros_scp" #define CROS_EC_DEV_TP_NAME "cros_tp" +#define CROS_EC_DEV_EC_INDEX 0 +#define CROS_EC_DEV_PD_INDEX 1 + /* * The EC is unresponsive for a time after a reboot command. Add a * simple delay to make sure that the bus stays locked. From e796c0c4b1ada2e038b22215d38ddc97153de053 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:40 +0000 Subject: [PATCH 0203/1436] platform/chrome: cros_ec_proto: assign buffer size from protocol info `din_size` is calculated from `ec_dev->max_response`. `ec_dev->max_response` is further calculated from the protocol info. To make it clear, assign `din_size` and `dout_size` from protocol info directly. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-5-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index cfa3dacce4e5..4977c8deb3ec 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -449,12 +449,8 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) "using proto v%u\n", ec_dev->proto_version); - ec_dev->din_size = ec_dev->max_response + - sizeof(struct ec_host_response) + - EC_MAX_RESPONSE_OVERHEAD; - ec_dev->dout_size = ec_dev->max_request + - sizeof(struct ec_host_request) + - EC_MAX_REQUEST_OVERHEAD; + ec_dev->din_size = proto_info->max_response_packet_size + EC_MAX_RESPONSE_OVERHEAD; + ec_dev->dout_size = proto_info->max_request_packet_size + EC_MAX_REQUEST_OVERHEAD; /* * Check for PD From 8e3991610ba5c11003d8c228b280cc007c2a6177 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:41 +0000 Subject: [PATCH 0204/1436] platform/chrome: cros_ec_proto: remove redundant NULL check send_command() already checks if `ec_dev->pkt_xfer` is NULL. Remove the redundant check. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-6-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 4977c8deb3ec..1e01eb94fbee 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -281,9 +281,6 @@ static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev, */ int ret; - if (!ec_dev->pkt_xfer) - return -EPROTONOSUPPORT; - memset(msg, 0, sizeof(*msg)); msg->command = EC_CMD_PASSTHRU_OFFSET(devidx) | EC_CMD_GET_PROTOCOL_INFO; msg->insize = sizeof(struct ec_response_get_protocol_info); From 93bea2faed630bd014916fd2e7ab16a79ee1b46a Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:42 +0000 Subject: [PATCH 0205/1436] platform/chrome: cros_ec_proto: use cros_ec_map_error() Use cros_ec_map_error() in cros_ec_get_host_event_wake_mask(). The behavior of cros_ec_get_host_event_wake_mask() slightly changed. It is acceptable because the caller only needs it returns negative integers for indicating errors. Especially, the EC_RES_INVALID_COMMAND still maps to -EOPNOTSUPP. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-7-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 1e01eb94fbee..b3e6096e027c 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -247,7 +247,7 @@ static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, uint32_t *mask) { struct ec_response_host_event_mask *r; - int ret; + int ret, mapped; msg->command = EC_CMD_HOST_EVENT_GET_WAKE_MASK; msg->version = 0; @@ -256,10 +256,9 @@ static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, ret = send_command(ec_dev, msg); if (ret >= 0) { - if (msg->result == EC_RES_INVALID_COMMAND) - return -EOPNOTSUPP; - if (msg->result != EC_RES_SUCCESS) - return -EPROTO; + mapped = cros_ec_map_error(msg->result); + if (mapped) + return mapped; } if (ret > 0) { r = (struct ec_response_host_event_mask *)msg->data; From b4d0836e81603600a8db7777b588fe020abf4cf8 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:43 +0000 Subject: [PATCH 0206/1436] platform/chrome: cros_ec_proto: separate cros_ec_get_proto_info() Rename cros_ec_host_command_proto_query() to cros_ec_get_proto_info() and make it responsible for setting `ec_dev` fields according to the response protocol info. Also make cros_ec_get_host_event_wake_mask() allocate its own message buffer. It was lucky that size of `struct ec_response_host_event_mask` is less than `struct ec_response_get_protocol_info`. Thus, the buffer wasn't overflow. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-8-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 134 +++++++++---------- drivers/platform/chrome/cros_ec_proto_test.c | 56 ++++---- 2 files changed, 93 insertions(+), 97 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index b3e6096e027c..1009b8ee0f86 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -242,47 +242,53 @@ EXPORT_SYMBOL(cros_ec_check_result); * the caller has ec_dev->lock mutex, or the caller knows there is * no other command in progress. */ -static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, - struct cros_ec_command *msg, - uint32_t *mask) +static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, uint32_t *mask) { + struct cros_ec_command *msg; struct ec_response_host_event_mask *r; int ret, mapped; + msg = kzalloc(sizeof(*msg) + sizeof(*r), GFP_KERNEL); + if (!msg) + return -ENOMEM; + msg->command = EC_CMD_HOST_EVENT_GET_WAKE_MASK; - msg->version = 0; - msg->outsize = 0; msg->insize = sizeof(*r); ret = send_command(ec_dev, msg); if (ret >= 0) { mapped = cros_ec_map_error(msg->result); - if (mapped) - return mapped; + if (mapped) { + ret = mapped; + goto exit; + } } if (ret > 0) { r = (struct ec_response_host_event_mask *)msg->data; *mask = r->mask; } +exit: + kfree(msg); return ret; } -static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev, - int devidx, - struct cros_ec_command *msg) +static int cros_ec_get_proto_info(struct cros_ec_device *ec_dev, int devidx) { - /* - * Try using v3+ to query for supported protocols. If this - * command fails, fall back to v2. Returns the highest protocol - * supported by the EC. - * Also sets the max request/response/passthru size. - */ - int ret; + struct cros_ec_command *msg; + struct ec_response_get_protocol_info *info; + int ret, mapped; + + ec_dev->proto_version = 3; + if (devidx > 0) + ec_dev->max_passthru = 0; + + msg = kzalloc(sizeof(*msg) + sizeof(*info), GFP_KERNEL); + if (!msg) + return -ENOMEM; - memset(msg, 0, sizeof(*msg)); msg->command = EC_CMD_PASSTHRU_OFFSET(devidx) | EC_CMD_GET_PROTOCOL_INFO; - msg->insize = sizeof(struct ec_response_get_protocol_info); + msg->insize = sizeof(*info); ret = send_command(ec_dev, msg); /* @@ -299,15 +305,45 @@ static int cros_ec_host_command_proto_query(struct cros_ec_device *ec_dev, dev_dbg(ec_dev->dev, "failed to check for EC[%d] protocol version: %d\n", devidx, ret); - return ret; + goto exit; } - if (devidx > 0 && msg->result == EC_RES_INVALID_COMMAND) - return -ENODEV; - else if (msg->result != EC_RES_SUCCESS) - return msg->result; + mapped = cros_ec_map_error(msg->result); + if (mapped) { + ret = mapped; + goto exit; + } - return 0; + info = (struct ec_response_get_protocol_info *)msg->data; + + switch (devidx) { + case CROS_EC_DEV_EC_INDEX: + ec_dev->max_request = info->max_request_packet_size - + sizeof(struct ec_host_request); + ec_dev->max_response = info->max_response_packet_size - + sizeof(struct ec_host_response); + ec_dev->proto_version = min(EC_HOST_REQUEST_VERSION, + fls(info->protocol_versions) - 1); + ec_dev->din_size = info->max_response_packet_size + EC_MAX_RESPONSE_OVERHEAD; + ec_dev->dout_size = info->max_request_packet_size + EC_MAX_REQUEST_OVERHEAD; + + dev_dbg(ec_dev->dev, "using proto v%u\n", ec_dev->proto_version); + break; + case CROS_EC_DEV_PD_INDEX: + ec_dev->max_passthru = info->max_request_packet_size - + sizeof(struct ec_host_request); + + dev_dbg(ec_dev->dev, "found PD chip\n"); + break; + default: + dev_dbg(ec_dev->dev, "unknwon passthru index: %d\n", devidx); + break; + } + + ret = 0; +exit: + kfree(msg); + return ret; } static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev) @@ -417,51 +453,13 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, int cros_ec_query_all(struct cros_ec_device *ec_dev) { struct device *dev = ec_dev->dev; - struct cros_ec_command *proto_msg; - struct ec_response_get_protocol_info *proto_info; u32 ver_mask = 0; int ret; - proto_msg = kzalloc(sizeof(*proto_msg) + sizeof(*proto_info), - GFP_KERNEL); - if (!proto_msg) - return -ENOMEM; - /* First try sending with proto v3. */ - ec_dev->proto_version = 3; - ret = cros_ec_host_command_proto_query(ec_dev, CROS_EC_DEV_EC_INDEX, proto_msg); - - if (ret == 0) { - proto_info = (struct ec_response_get_protocol_info *) - proto_msg->data; - ec_dev->max_request = proto_info->max_request_packet_size - - sizeof(struct ec_host_request); - ec_dev->max_response = proto_info->max_response_packet_size - - sizeof(struct ec_host_response); - ec_dev->proto_version = - min(EC_HOST_REQUEST_VERSION, - fls(proto_info->protocol_versions) - 1); - dev_dbg(ec_dev->dev, - "using proto v%u\n", - ec_dev->proto_version); - - ec_dev->din_size = proto_info->max_response_packet_size + EC_MAX_RESPONSE_OVERHEAD; - ec_dev->dout_size = proto_info->max_request_packet_size + EC_MAX_REQUEST_OVERHEAD; - - /* - * Check for PD - */ - ret = cros_ec_host_command_proto_query(ec_dev, CROS_EC_DEV_PD_INDEX, proto_msg); - - if (ret) { - dev_dbg(ec_dev->dev, "no PD chip found: %d\n", ret); - ec_dev->max_passthru = 0; - } else { - dev_dbg(ec_dev->dev, "found PD chip\n"); - ec_dev->max_passthru = - proto_info->max_request_packet_size - - sizeof(struct ec_host_request); - } + if (!cros_ec_get_proto_info(ec_dev, CROS_EC_DEV_EC_INDEX)) { + /* Check for PD. */ + cros_ec_get_proto_info(ec_dev, CROS_EC_DEV_PD_INDEX); } else { /* Try querying with a v2 hello message. */ ec_dev->proto_version = 2; @@ -524,8 +522,7 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) ec_dev->host_sleep_v1 = (ret >= 0 && (ver_mask & EC_VER_MASK(1))); /* Get host event wake mask. */ - ret = cros_ec_get_host_event_wake_mask(ec_dev, proto_msg, - &ec_dev->host_event_wake_mask); + ret = cros_ec_get_host_event_wake_mask(ec_dev, &ec_dev->host_event_wake_mask); if (ret < 0) { /* * If the EC doesn't support EC_CMD_HOST_EVENT_GET_WAKE_MASK, @@ -556,7 +553,6 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) ret = 0; exit: - kfree(proto_msg); return ret; } EXPORT_SYMBOL(cros_ec_query_all); diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index f8dbfb0d8dc8..8b16666c1657 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -195,7 +195,7 @@ static void cros_ec_proto_test_query_all_normal(struct kunit *test) struct ec_xfer_mock *mock; int ret; - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { struct ec_response_get_protocol_info *data; @@ -208,7 +208,7 @@ static void cros_ec_proto_test_query_all_normal(struct kunit *test) data->max_response_packet_size = 0xef; } - /* For cros_ec_host_command_proto_query() with passthru. */ + /* For cros_ec_get_proto_info() with passthru. */ { struct ec_response_get_protocol_info *data; @@ -256,7 +256,7 @@ static void cros_ec_proto_test_query_all_normal(struct kunit *test) ret = cros_ec_query_all(ec_dev); KUNIT_EXPECT_EQ(test, ret, 0); - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -274,7 +274,7 @@ static void cros_ec_proto_test_query_all_normal(struct kunit *test) KUNIT_EXPECT_EQ(test, ec_dev->dout_size, 0xbe + EC_MAX_REQUEST_OVERHEAD); } - /* For cros_ec_host_command_proto_query() with passthru. */ + /* For cros_ec_get_proto_info() with passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -352,7 +352,7 @@ static void cros_ec_proto_test_query_all_no_pd_return_error(struct kunit *test) /* Set some garbage bytes. */ ec_dev->max_passthru = 0xbf; - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { struct ec_response_get_protocol_info *data; @@ -368,7 +368,7 @@ static void cros_ec_proto_test_query_all_no_pd_return_error(struct kunit *test) data->max_response_packet_size = 0xef; } - /* For cros_ec_host_command_proto_query() with passthru. */ + /* For cros_ec_get_proto_info() with passthru. */ { mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); KUNIT_ASSERT_PTR_NE(test, mock, NULL); @@ -378,7 +378,7 @@ static void cros_ec_proto_test_query_all_no_pd_return_error(struct kunit *test) ret = cros_ec_query_all(ec_dev); KUNIT_EXPECT_EQ(test, ret, 0); - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -390,7 +390,7 @@ static void cros_ec_proto_test_query_all_no_pd_return_error(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); } - /* For cros_ec_host_command_proto_query() with passthru. */ + /* For cros_ec_get_proto_info() with passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -414,7 +414,7 @@ static void cros_ec_proto_test_query_all_legacy_normal_v3_return_error(struct ku struct ec_xfer_mock *mock; int ret; - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); KUNIT_ASSERT_PTR_NE(test, mock, NULL); @@ -435,7 +435,7 @@ static void cros_ec_proto_test_query_all_legacy_normal_v3_return_error(struct ku ret = cros_ec_query_all(ec_dev); KUNIT_EXPECT_EQ(test, ret, 0); - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -479,7 +479,7 @@ static void cros_ec_proto_test_query_all_legacy_xfer_error(struct kunit *test) struct ec_xfer_mock *mock; int ret; - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); KUNIT_ASSERT_PTR_NE(test, mock, NULL); @@ -496,7 +496,7 @@ static void cros_ec_proto_test_query_all_legacy_xfer_error(struct kunit *test) KUNIT_EXPECT_EQ(test, ret, -EIO); KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN); - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -527,7 +527,7 @@ static void cros_ec_proto_test_query_all_legacy_return_error(struct kunit *test) struct ec_xfer_mock *mock; int ret; - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); KUNIT_ASSERT_PTR_NE(test, mock, NULL); @@ -544,7 +544,7 @@ static void cros_ec_proto_test_query_all_legacy_return_error(struct kunit *test) KUNIT_EXPECT_EQ(test, ret, EC_RES_INVALID_COMMAND); KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN); - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -575,7 +575,7 @@ static void cros_ec_proto_test_query_all_legacy_data_error(struct kunit *test) struct ec_xfer_mock *mock; int ret; - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); KUNIT_ASSERT_PTR_NE(test, mock, NULL); @@ -597,7 +597,7 @@ static void cros_ec_proto_test_query_all_legacy_data_error(struct kunit *test) KUNIT_EXPECT_EQ(test, ret, -EBADMSG); KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN); - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -631,7 +631,7 @@ static void cros_ec_proto_test_query_all_no_mkbp(struct kunit *test) /* Set some garbage bytes. */ ec_dev->mkbp_event_supported = 0xbf; - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { struct ec_response_get_protocol_info *data; @@ -647,7 +647,7 @@ static void cros_ec_proto_test_query_all_no_mkbp(struct kunit *test) data->max_response_packet_size = 0xef; } - /* For cros_ec_host_command_proto_query() with passthru. */ + /* For cros_ec_get_proto_info() with passthru. */ { mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); KUNIT_ASSERT_PTR_NE(test, mock, NULL); @@ -668,7 +668,7 @@ static void cros_ec_proto_test_query_all_no_mkbp(struct kunit *test) ret = cros_ec_query_all(ec_dev); KUNIT_EXPECT_EQ(test, ret, 0); - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -680,7 +680,7 @@ static void cros_ec_proto_test_query_all_no_mkbp(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); } - /* For cros_ec_host_command_proto_query() with passthru. */ + /* For cros_ec_get_proto_info() with passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -724,7 +724,7 @@ static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test) /* Set some garbage bytes. */ ec_dev->host_sleep_v1 = true; - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { struct ec_response_get_protocol_info *data; @@ -740,7 +740,7 @@ static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test) data->max_response_packet_size = 0xef; } - /* For cros_ec_host_command_proto_query() with passthru. */ + /* For cros_ec_get_proto_info() with passthru. */ { mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); KUNIT_ASSERT_PTR_NE(test, mock, NULL); @@ -767,7 +767,7 @@ static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test) ret = cros_ec_query_all(ec_dev); KUNIT_EXPECT_EQ(test, ret, 0); - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -779,7 +779,7 @@ static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); } - /* For cros_ec_host_command_proto_query() with passthru. */ + /* For cros_ec_get_proto_info() with passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -830,7 +830,7 @@ static void cros_ec_proto_test_query_all_default_wake_mask_return_error(struct k /* Set some garbage bytes. */ ec_dev->host_event_wake_mask = U32_MAX; - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { struct ec_response_get_protocol_info *data; @@ -846,7 +846,7 @@ static void cros_ec_proto_test_query_all_default_wake_mask_return_error(struct k data->max_response_packet_size = 0xef; } - /* For cros_ec_host_command_proto_query() with passthru. */ + /* For cros_ec_get_proto_info() with passthru. */ { mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); KUNIT_ASSERT_PTR_NE(test, mock, NULL); @@ -874,7 +874,7 @@ static void cros_ec_proto_test_query_all_default_wake_mask_return_error(struct k ret = cros_ec_query_all(ec_dev); KUNIT_EXPECT_EQ(test, ret, 0); - /* For cros_ec_host_command_proto_query() without passthru. */ + /* For cros_ec_get_proto_info() without passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -886,7 +886,7 @@ static void cros_ec_proto_test_query_all_default_wake_mask_return_error(struct k KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); } - /* For cros_ec_host_command_proto_query() with passthru. */ + /* For cros_ec_get_proto_info() with passthru. */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); From 3e97581ed9a24657cbfabaab215c9a646d94b351 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:44 +0000 Subject: [PATCH 0207/1436] platform/chrome: cros_ec_proto: add Kunit tests for getting proto info cros_ec_get_proto_info() expects to receive sizeof(struct ec_response_get_protocol_info) from send_command(). The payload is valid only if the return value is positive. Add Kunit tests for returning 0 from send_command() in cros_ec_get_proto_info(). Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-9-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 132 +++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 8b16666c1657..1378ac90e1cb 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -407,6 +407,71 @@ static void cros_ec_proto_test_query_all_no_pd_return_error(struct kunit *test) } } +static void cros_ec_proto_test_query_all_no_pd_return0(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* Set some garbage bytes. */ + ec_dev->max_passthru = 0xbf; + + /* For cros_ec_get_proto_info() without passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + /* + * Although it doesn't check the value, provides valid sizes so that + * cros_ec_query_all() allocates din and dout correctly. + */ + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->max_request_packet_size = 0xbe; + data->max_response_packet_size = 0xef; + } + + /* For cros_ec_get_proto_info() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_get_proto_info() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_proto_info() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + + KUNIT_EXPECT_EQ(test, ec_dev->max_passthru, 0); + } +} + static void cros_ec_proto_test_query_all_legacy_normal_v3_return_error(struct kunit *test) { struct cros_ec_proto_test_priv *priv = test->priv; @@ -472,6 +537,71 @@ static void cros_ec_proto_test_query_all_legacy_normal_v3_return_error(struct ku } } +static void cros_ec_proto_test_query_all_legacy_normal_v3_return0(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* For cros_ec_get_proto_info() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_host_command_proto_query_v2(). */ + { + struct ec_response_hello *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_hello *)mock->o_data; + data->out_data = 0xa1b2c3d4; + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_get_proto_info() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_host_command_proto_query_v2(). */ + { + struct ec_params_hello *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data)); + + data = (struct ec_params_hello *)mock->i_data; + KUNIT_EXPECT_EQ(test, data->in_data, 0xa0b0c0d0); + + KUNIT_EXPECT_EQ(test, ec_dev->proto_version, 2); + KUNIT_EXPECT_EQ(test, ec_dev->max_request, EC_PROTO2_MAX_PARAM_SIZE); + KUNIT_EXPECT_EQ(test, ec_dev->max_response, EC_PROTO2_MAX_PARAM_SIZE); + KUNIT_EXPECT_EQ(test, ec_dev->max_passthru, 0); + KUNIT_EXPECT_PTR_EQ(test, ec_dev->pkt_xfer, NULL); + KUNIT_EXPECT_EQ(test, ec_dev->din_size, EC_PROTO2_MSG_BYTES); + KUNIT_EXPECT_EQ(test, ec_dev->dout_size, EC_PROTO2_MSG_BYTES); + } +} + static void cros_ec_proto_test_query_all_legacy_xfer_error(struct kunit *test) { struct cros_ec_proto_test_priv *priv = test->priv; @@ -999,7 +1129,9 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_check_result), KUNIT_CASE(cros_ec_proto_test_query_all_normal), KUNIT_CASE(cros_ec_proto_test_query_all_no_pd_return_error), + KUNIT_CASE(cros_ec_proto_test_query_all_no_pd_return0), KUNIT_CASE(cros_ec_proto_test_query_all_legacy_normal_v3_return_error), + KUNIT_CASE(cros_ec_proto_test_query_all_legacy_normal_v3_return0), KUNIT_CASE(cros_ec_proto_test_query_all_legacy_xfer_error), KUNIT_CASE(cros_ec_proto_test_query_all_legacy_return_error), KUNIT_CASE(cros_ec_proto_test_query_all_legacy_data_error), From 878c36f6caa45d6a6234465fb16da07fc639f51d Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:45 +0000 Subject: [PATCH 0208/1436] platform/chrome: cros_ec_proto: handle empty payload in getting proto info cros_ec_get_proto_info() expects to receive sizeof(struct ec_response_get_protocol_info) from send_command(). The payload is valid only if the return value is positive. Return -EPROTO if send_command() returns 0 in cros_ec_get_proto_info(). Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-10-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 1009b8ee0f86..a34ef2b796b0 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -314,6 +314,11 @@ static int cros_ec_get_proto_info(struct cros_ec_device *ec_dev, int devidx) goto exit; } + if (ret == 0) { + ret = -EPROTO; + goto exit; + } + info = (struct ec_response_get_protocol_info *)msg->data; switch (devidx) { From a88f79666d14836215058f38e2ac4f1fea61a53e Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:46 +0000 Subject: [PATCH 0209/1436] platform/chrome: cros_ec_proto: separate cros_ec_get_proto_info_legacy() Rename cros_ec_host_command_proto_query_v2() to cros_ec_get_proto_info_legacy() and make it responsible for setting `ec_dev` fields for EC protocol v2. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-11-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 72 +++++++++----------- drivers/platform/chrome/cros_ec_proto_test.c | 22 +++--- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index a34ef2b796b0..24b8bc30d453 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -351,51 +351,57 @@ exit: return ret; } -static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev) +static int cros_ec_get_proto_info_legacy(struct cros_ec_device *ec_dev) { struct cros_ec_command *msg; - struct ec_params_hello *hello_params; - struct ec_response_hello *hello_response; + struct ec_params_hello *params; + struct ec_response_hello *response; int ret; - int len = max(sizeof(*hello_params), sizeof(*hello_response)); - msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL); + ec_dev->proto_version = 2; + + msg = kzalloc(sizeof(*msg) + max(sizeof(*params), sizeof(*response)), GFP_KERNEL); if (!msg) return -ENOMEM; - msg->version = 0; msg->command = EC_CMD_HELLO; - hello_params = (struct ec_params_hello *)msg->data; - msg->outsize = sizeof(*hello_params); - hello_response = (struct ec_response_hello *)msg->data; - msg->insize = sizeof(*hello_response); + msg->insize = sizeof(*response); + msg->outsize = sizeof(*params); - hello_params->in_data = 0xa0b0c0d0; + params = (struct ec_params_hello *)msg->data; + params->in_data = 0xa0b0c0d0; ret = send_command(ec_dev, msg); - if (ret < 0) { - dev_dbg(ec_dev->dev, - "EC failed to respond to v2 hello: %d\n", - ret); + dev_dbg(ec_dev->dev, "EC failed to respond to v2 hello: %d\n", ret); goto exit; - } else if (msg->result != EC_RES_SUCCESS) { - dev_err(ec_dev->dev, - "EC responded to v2 hello with error: %d\n", - msg->result); - ret = msg->result; + } + + ret = cros_ec_map_error(msg->result); + if (ret) { + dev_err(ec_dev->dev, "EC responded to v2 hello with error: %d\n", msg->result); goto exit; - } else if (hello_response->out_data != 0xa1b2c3d4) { + } + + response = (struct ec_response_hello *)msg->data; + if (response->out_data != 0xa1b2c3d4) { dev_err(ec_dev->dev, "EC responded to v2 hello with bad result: %u\n", - hello_response->out_data); + response->out_data); ret = -EBADMSG; goto exit; } - ret = 0; + ec_dev->max_request = EC_PROTO2_MAX_PARAM_SIZE; + ec_dev->max_response = EC_PROTO2_MAX_PARAM_SIZE; + ec_dev->max_passthru = 0; + ec_dev->pkt_xfer = NULL; + ec_dev->din_size = EC_PROTO2_MSG_BYTES; + ec_dev->dout_size = EC_PROTO2_MSG_BYTES; - exit: + dev_dbg(ec_dev->dev, "falling back to proto v2\n"); + ret = 0; +exit: kfree(msg); return ret; } @@ -467,20 +473,8 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) cros_ec_get_proto_info(ec_dev, CROS_EC_DEV_PD_INDEX); } else { /* Try querying with a v2 hello message. */ - ec_dev->proto_version = 2; - ret = cros_ec_host_command_proto_query_v2(ec_dev); - - if (ret == 0) { - /* V2 hello succeeded. */ - dev_dbg(ec_dev->dev, "falling back to proto v2\n"); - - ec_dev->max_request = EC_PROTO2_MAX_PARAM_SIZE; - ec_dev->max_response = EC_PROTO2_MAX_PARAM_SIZE; - ec_dev->max_passthru = 0; - ec_dev->pkt_xfer = NULL; - ec_dev->din_size = EC_PROTO2_MSG_BYTES; - ec_dev->dout_size = EC_PROTO2_MSG_BYTES; - } else { + ret = cros_ec_get_proto_info_legacy(ec_dev); + if (ret) { /* * It's possible for a test to occur too early when * the EC isn't listening. If this happens, we'll @@ -488,7 +482,7 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) */ ec_dev->proto_version = EC_PROTO_VERSION_UNKNOWN; dev_dbg(ec_dev->dev, "EC query failed: %d\n", ret); - goto exit; + return ret; } } diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 1378ac90e1cb..8e47cb70dc8b 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -485,7 +485,7 @@ static void cros_ec_proto_test_query_all_legacy_normal_v3_return_error(struct ku KUNIT_ASSERT_PTR_NE(test, mock, NULL); } - /* For cros_ec_host_command_proto_query_v2(). */ + /* For cros_ec_get_proto_info_legacy(). */ { struct ec_response_hello *data; @@ -512,7 +512,7 @@ static void cros_ec_proto_test_query_all_legacy_normal_v3_return_error(struct ku KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); } - /* For cros_ec_host_command_proto_query_v2(). */ + /* For cros_ec_get_proto_info_legacy(). */ { struct ec_params_hello *data; @@ -550,7 +550,7 @@ static void cros_ec_proto_test_query_all_legacy_normal_v3_return0(struct kunit * KUNIT_ASSERT_PTR_NE(test, mock, NULL); } - /* For cros_ec_host_command_proto_query_v2(). */ + /* For cros_ec_get_proto_info_legacy(). */ { struct ec_response_hello *data; @@ -577,7 +577,7 @@ static void cros_ec_proto_test_query_all_legacy_normal_v3_return0(struct kunit * KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); } - /* For cros_ec_host_command_proto_query_v2(). */ + /* For cros_ec_get_proto_info_legacy(). */ { struct ec_params_hello *data; @@ -615,7 +615,7 @@ static void cros_ec_proto_test_query_all_legacy_xfer_error(struct kunit *test) KUNIT_ASSERT_PTR_NE(test, mock, NULL); } - /* For cros_ec_host_command_proto_query_v2(). */ + /* For cros_ec_get_proto_info_legacy(). */ { mock = cros_kunit_ec_xfer_mock_addx(test, -EIO, EC_RES_SUCCESS, 0); KUNIT_ASSERT_PTR_NE(test, mock, NULL); @@ -638,7 +638,7 @@ static void cros_ec_proto_test_query_all_legacy_xfer_error(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); } - /* For cros_ec_host_command_proto_query_v2(). */ + /* For cros_ec_get_proto_info_legacy(). */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -663,7 +663,7 @@ static void cros_ec_proto_test_query_all_legacy_return_error(struct kunit *test) KUNIT_ASSERT_PTR_NE(test, mock, NULL); } - /* For cros_ec_host_command_proto_query_v2(). */ + /* For cros_ec_get_proto_info_legacy(). */ { mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); KUNIT_ASSERT_PTR_NE(test, mock, NULL); @@ -671,7 +671,7 @@ static void cros_ec_proto_test_query_all_legacy_return_error(struct kunit *test) cros_ec_proto_test_query_all_pretest(test); ret = cros_ec_query_all(ec_dev); - KUNIT_EXPECT_EQ(test, ret, EC_RES_INVALID_COMMAND); + KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP); KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN); /* For cros_ec_get_proto_info() without passthru. */ @@ -686,7 +686,7 @@ static void cros_ec_proto_test_query_all_legacy_return_error(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); } - /* For cros_ec_host_command_proto_query_v2(). */ + /* For cros_ec_get_proto_info_legacy(). */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); @@ -711,7 +711,7 @@ static void cros_ec_proto_test_query_all_legacy_data_error(struct kunit *test) KUNIT_ASSERT_PTR_NE(test, mock, NULL); } - /* For cros_ec_host_command_proto_query_v2(). */ + /* For cros_ec_get_proto_info_legacy(). */ { struct ec_response_hello *data; @@ -739,7 +739,7 @@ static void cros_ec_proto_test_query_all_legacy_data_error(struct kunit *test) KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); } - /* For cros_ec_host_command_proto_query_v2(). */ + /* For cros_ec_get_proto_info_legacy(). */ { mock = cros_kunit_ec_xfer_mock_next(); KUNIT_EXPECT_PTR_NE(test, mock, NULL); From cce5d551809c54e4067933e900239f58281390aa Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:47 +0000 Subject: [PATCH 0210/1436] platform/chrome: cros_ec_proto: add Kunit test for getting legacy info cros_ec_get_proto_info_legacy() expects to receive sizeof(struct ec_response_hello) from send_command(). The payload is valid only if the return value is positive. Add a Kunit test for returning 0 from send_command() in cros_ec_get_proto_info_legacy(). Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-12-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 49 ++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 8e47cb70dc8b..63071af81c94 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -751,6 +751,54 @@ static void cros_ec_proto_test_query_all_legacy_data_error(struct kunit *test) } } +static void cros_ec_proto_test_query_all_legacy_return0(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* For cros_ec_get_proto_info() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_proto_info_legacy(). */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, -EPROTO); + KUNIT_EXPECT_EQ(test, ec_dev->proto_version, EC_PROTO_VERSION_UNKNOWN); + + /* For cros_ec_get_proto_info() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_proto_info_legacy(). */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_hello)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_hello)); + } +} + static void cros_ec_proto_test_query_all_no_mkbp(struct kunit *test) { struct cros_ec_proto_test_priv *priv = test->priv; @@ -1135,6 +1183,7 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_query_all_legacy_xfer_error), KUNIT_CASE(cros_ec_proto_test_query_all_legacy_return_error), KUNIT_CASE(cros_ec_proto_test_query_all_legacy_data_error), + KUNIT_CASE(cros_ec_proto_test_query_all_legacy_return0), KUNIT_CASE(cros_ec_proto_test_query_all_no_mkbp), KUNIT_CASE(cros_ec_proto_test_query_all_no_host_sleep), KUNIT_CASE(cros_ec_proto_test_query_all_default_wake_mask_return_error), From d394ab5c062a7701b9af04e012d3a4c1e1447f47 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:48 +0000 Subject: [PATCH 0211/1436] platform/chrome: cros_ec_proto: handle empty payload in getting info legacy cros_ec_get_proto_info_legacy() expects to receive sizeof(struct ec_response_hello) from send_command(). The payload is valid only if the return value is positive. Return -EPROTO if send_command() returns 0 in cros_ec_get_proto_info_legacy(). Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-13-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 24b8bc30d453..60b8ef980b8a 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -356,7 +356,7 @@ static int cros_ec_get_proto_info_legacy(struct cros_ec_device *ec_dev) struct cros_ec_command *msg; struct ec_params_hello *params; struct ec_response_hello *response; - int ret; + int ret, mapped; ec_dev->proto_version = 2; @@ -377,12 +377,18 @@ static int cros_ec_get_proto_info_legacy(struct cros_ec_device *ec_dev) goto exit; } - ret = cros_ec_map_error(msg->result); - if (ret) { + mapped = cros_ec_map_error(msg->result); + if (mapped) { + ret = mapped; dev_err(ec_dev->dev, "EC responded to v2 hello with error: %d\n", msg->result); goto exit; } + if (ret == 0) { + ret = -EPROTO; + goto exit; + } + response = (struct ec_response_hello *)msg->data; if (response->out_data != 0xa1b2c3d4) { dev_err(ec_dev->dev, From b36f0643ff14a2fb281b105418e4e73c9d7c11d0 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:49 +0000 Subject: [PATCH 0212/1436] platform/chrome: cros_ec_proto: don't show MKBP version if unsupported It wrongly showed the following message when it doesn't support MKBP: "MKBP support version 4294967295". Fix it. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-14-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 60b8ef980b8a..630d7ee5392a 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -512,13 +512,13 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) ret = cros_ec_get_host_command_version_mask(ec_dev, EC_CMD_GET_NEXT_EVENT, &ver_mask); - if (ret < 0 || ver_mask == 0) + if (ret < 0 || ver_mask == 0) { ec_dev->mkbp_event_supported = 0; - else + } else { ec_dev->mkbp_event_supported = fls(ver_mask); - dev_dbg(ec_dev->dev, "MKBP support version %u\n", - ec_dev->mkbp_event_supported - 1); + dev_dbg(ec_dev->dev, "MKBP support version %u\n", ec_dev->mkbp_event_supported - 1); + } /* Probe if host sleep v1 is supported for S0ix failure detection. */ ret = cros_ec_get_host_command_version_mask(ec_dev, From f91183aa459a9a06eae6843cde2fbe2d97db4f96 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:50 +0000 Subject: [PATCH 0213/1436] platform/chrome: cros_ec_proto: return 0 on getting cmd mask success cros_ec_get_host_command_version_mask() used to return value from send_command() which is number of available bytes for input payload on success (i.e. sizeof(struct ec_response_get_cmd_versions)). However, the callers don't need to know how many bytes are available. Don't return number of available bytes. Instead, return 0 on success; otherwise, negative integers on error. Also remove the unneeded `ver_mask` initialization as the callers should take it only if cros_ec_get_host_command_version_mask() returns 0. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-15-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 630d7ee5392a..1df22eb29e95 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -453,6 +453,7 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, if (ret > 0) { rver = (struct ec_response_get_cmd_versions *)msg->data; *mask = rver->version_mask; + ret = 0; } kfree(msg); @@ -470,7 +471,7 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, int cros_ec_query_all(struct cros_ec_device *ec_dev) { struct device *dev = ec_dev->dev; - u32 ver_mask = 0; + u32 ver_mask; int ret; /* First try sending with proto v3. */ @@ -509,9 +510,7 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) } /* Probe if MKBP event is supported */ - ret = cros_ec_get_host_command_version_mask(ec_dev, - EC_CMD_GET_NEXT_EVENT, - &ver_mask); + ret = cros_ec_get_host_command_version_mask(ec_dev, EC_CMD_GET_NEXT_EVENT, &ver_mask); if (ret < 0 || ver_mask == 0) { ec_dev->mkbp_event_supported = 0; } else { @@ -521,10 +520,8 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) } /* Probe if host sleep v1 is supported for S0ix failure detection. */ - ret = cros_ec_get_host_command_version_mask(ec_dev, - EC_CMD_HOST_SLEEP_EVENT, - &ver_mask); - ec_dev->host_sleep_v1 = (ret >= 0 && (ver_mask & EC_VER_MASK(1))); + ret = cros_ec_get_host_command_version_mask(ec_dev, EC_CMD_HOST_SLEEP_EVENT, &ver_mask); + ec_dev->host_sleep_v1 = (ret == 0 && (ver_mask & EC_VER_MASK(1))); /* Get host event wake mask. */ ret = cros_ec_get_host_event_wake_mask(ec_dev, &ec_dev->host_event_wake_mask); From a8f77c63baece8c47599bc418d3c2c138ca7efaf Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:51 +0000 Subject: [PATCH 0214/1436] platform/chrome: cros_ec_proto: add Kunit test for getting cmd mask error cros_ec_query_all() uses cros_ec_get_host_command_version_mask() to query the supported MKBP version; cros_ec_get_host_command_version_mask() uses send_command() for transferring the host command. Returning >=0 from send_command() only denotes the transfer was success. cros_ec_get_host_command_version_mask() should check if EC wasn't happy by checking `msg->result`. Add a Kunit test for returning error in `msg->result` in cros_ec_get_host_command_version_mask(). For the case, cros_ec_query_all() should find the EC device doesn't support MKBP. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-16-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 89 ++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 63071af81c94..ce7a2f64f01b 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -892,6 +892,94 @@ static void cros_ec_proto_test_query_all_no_mkbp(struct kunit *test) } } +static void cros_ec_proto_test_query_all_no_mkbp_return_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* Set some garbage bytes. */ + ec_dev->mkbp_event_supported = 0xbf; + + /* For cros_ec_get_proto_info() without passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + /* + * Although it doesn't check the value, provides valid sizes so that + * cros_ec_query_all() allocates din and dout correctly. + */ + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->max_request_packet_size = 0xbe; + data->max_response_packet_size = 0xef; + } + + /* For cros_ec_get_proto_info() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_get_proto_info() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_proto_info() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + struct ec_params_get_cmd_versions *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data)); + + data = (struct ec_params_get_cmd_versions *)mock->i_data; + KUNIT_EXPECT_EQ(test, data->cmd, EC_CMD_GET_NEXT_EVENT); + + KUNIT_EXPECT_EQ(test, ec_dev->mkbp_event_supported, 0); + } +} + static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test) { struct cros_ec_proto_test_priv *priv = test->priv; @@ -1185,6 +1273,7 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_query_all_legacy_data_error), KUNIT_CASE(cros_ec_proto_test_query_all_legacy_return0), KUNIT_CASE(cros_ec_proto_test_query_all_no_mkbp), + KUNIT_CASE(cros_ec_proto_test_query_all_no_mkbp_return_error), KUNIT_CASE(cros_ec_proto_test_query_all_no_host_sleep), KUNIT_CASE(cros_ec_proto_test_query_all_default_wake_mask_return_error), {} From ec513489933528e179bc6f98d47e6ea86c271a22 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:52 +0000 Subject: [PATCH 0215/1436] platform/chrome: cros_ec_proto: check `msg->result` in getting cmd mask cros_ec_get_host_command_version_mask() should check if EC wasn't happy by checking `msg->result`. Use cros_ec_map_error() and return the error code if any. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-17-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 1df22eb29e95..b152f2902b32 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -428,13 +428,12 @@ exit: * the caller has ec_dev->lock mutex or the caller knows there is * no other command in progress. */ -static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, - u16 cmd, u32 *mask) +static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, u16 cmd, u32 *mask) { struct ec_params_get_cmd_versions *pver; struct ec_response_get_cmd_versions *rver; struct cros_ec_command *msg; - int ret; + int ret, mapped; msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)), GFP_KERNEL); @@ -450,14 +449,20 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, pver->cmd = cmd; ret = send_command(ec_dev, msg); - if (ret > 0) { - rver = (struct ec_response_get_cmd_versions *)msg->data; - *mask = rver->version_mask; - ret = 0; + if (ret < 0) + goto exit; + + mapped = cros_ec_map_error(msg->result); + if (mapped) { + ret = mapped; + goto exit; } + rver = (struct ec_response_get_cmd_versions *)msg->data; + *mask = rver->version_mask; + ret = 0; +exit: kfree(msg); - return ret; } From 8120febafccb01eeea8c077130be6f6c1e46bb2f Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:53 +0000 Subject: [PATCH 0216/1436] platform/chrome: cros_ec_proto: add Kunit tests for getting cmd mask cros_ec_get_host_command_version_mask() expects to receive sizeof(struct ec_response_get_cmd_versions) from send_command(). The payload is valid only if the return value is positive. Add Kunit tests for returning 0 from send_command() in cros_ec_get_host_command_version_mask(). Note that because the 2 cros_ec_get_host_command_version_mask() use the same `ver_mask`. cros_ec_proto_test_query_all_no_host_sleep_return0() polluates the `ver_mask` and returns 0 on the second send_command() to make sure the second cros_ec_get_host_command_version_mask() doesn't take the garbage from the previous call. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-18-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 197 +++++++++++++++++++ 1 file changed, 197 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index ce7a2f64f01b..757d601f4aee 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -980,6 +980,94 @@ static void cros_ec_proto_test_query_all_no_mkbp_return_error(struct kunit *test } } +static void cros_ec_proto_test_query_all_no_mkbp_return0(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* Set some garbage bytes. */ + ec_dev->mkbp_event_supported = 0xbf; + + /* For cros_ec_get_proto_info() without passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + /* + * Although it doesn't check the value, provides valid sizes so that + * cros_ec_query_all() allocates din and dout correctly. + */ + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->max_request_packet_size = 0xbe; + data->max_response_packet_size = 0xef; + } + + /* For cros_ec_get_proto_info() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_get_proto_info() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_proto_info() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + struct ec_params_get_cmd_versions *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data)); + + data = (struct ec_params_get_cmd_versions *)mock->i_data; + KUNIT_EXPECT_EQ(test, data->cmd, EC_CMD_GET_NEXT_EVENT); + + KUNIT_EXPECT_EQ(test, ec_dev->mkbp_event_supported, 0); + } +} + static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test) { struct cros_ec_proto_test_priv *priv = test->priv; @@ -1086,6 +1174,113 @@ static void cros_ec_proto_test_query_all_no_host_sleep(struct kunit *test) } } +static void cros_ec_proto_test_query_all_no_host_sleep_return0(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* Set some garbage bytes. */ + ec_dev->host_sleep_v1 = true; + + /* For cros_ec_get_proto_info() without passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + /* + * Although it doesn't check the value, provides valid sizes so that + * cros_ec_query_all() allocates din and dout correctly. + */ + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->max_request_packet_size = 0xbe; + data->max_response_packet_size = 0xef; + } + + /* For cros_ec_get_proto_info() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + struct ec_response_get_cmd_versions *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + /* In order to pollute next cros_ec_get_host_command_version_mask(). */ + data = (struct ec_response_get_cmd_versions *)mock->o_data; + data->version_mask = 0xbeef; + } + + /* For cros_ec_get_host_command_version_mask() for host sleep v1. */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_get_proto_info() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_proto_info() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions)); + } + + /* For cros_ec_get_host_command_version_mask() for host sleep v1. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions)); + + KUNIT_EXPECT_FALSE(test, ec_dev->host_sleep_v1); + } +} + static void cros_ec_proto_test_query_all_default_wake_mask_return_error(struct kunit *test) { struct cros_ec_proto_test_priv *priv = test->priv; @@ -1274,7 +1469,9 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_query_all_legacy_return0), KUNIT_CASE(cros_ec_proto_test_query_all_no_mkbp), KUNIT_CASE(cros_ec_proto_test_query_all_no_mkbp_return_error), + KUNIT_CASE(cros_ec_proto_test_query_all_no_mkbp_return0), KUNIT_CASE(cros_ec_proto_test_query_all_no_host_sleep), + KUNIT_CASE(cros_ec_proto_test_query_all_no_host_sleep_return0), KUNIT_CASE(cros_ec_proto_test_query_all_default_wake_mask_return_error), {} }; From aac29b04dc3fdc5b95bca31413d90dbe8c1ae33d Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:54 +0000 Subject: [PATCH 0217/1436] platform/chrome: cros_ec_proto: handle empty payload in getting cmd mask cros_ec_get_host_command_version_mask() expects to receive sizeof(struct ec_response_get_cmd_versions) from send_command(). The payload is valid only if the return value is positive. Return -EPROTO if send_command() returns 0 in cros_ec_get_host_command_version_mask(). Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-19-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index b152f2902b32..0b0bc3717cbb 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -458,6 +458,11 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, goto exit; } + if (ret == 0) { + ret = -EPROTO; + goto exit; + } + rver = (struct ec_response_get_cmd_versions *)msg->data; *mask = rver->version_mask; ret = 0; From d65da5f9bb0a5b6f2115bc0e5fcf65c0867fef17 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:55 +0000 Subject: [PATCH 0218/1436] platform/chrome: cros_ec_proto: return 0 on getting wake mask success cros_ec_get_host_event_wake_mask() used to return value from send_command() which is number of bytes for input payload on success (i.e. sizeof(struct ec_response_host_event_mask)). However, the callers don't need to know how many bytes are available. Don't return number of available bytes. Instead, return 0 on success; otherwise, negative integers on error. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-20-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 0b0bc3717cbb..a7d807c9b3bd 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -236,7 +236,7 @@ EXPORT_SYMBOL(cros_ec_check_result); * * @ec_dev: EC device to call * @msg: message structure to use - * @mask: result when function returns >=0. + * @mask: result when function returns 0. * * LOCKING: * the caller has ec_dev->lock mutex, or the caller knows there is @@ -266,6 +266,7 @@ static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, uint3 if (ret > 0) { r = (struct ec_response_host_event_mask *)msg->data; *mask = r->mask; + ret = 0; } exit: From e43772294246d9c96ba31446d3dc27e3573a5473 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:56 +0000 Subject: [PATCH 0219/1436] platform/chrome: cros_ec_proto: add Kunit test for getting wake mask cros_ec_get_host_event_wake_mask() expects to receive sizeof(struct ec_response_host_event_mask) from send_command(). The payload is valid only if the return value is positive. Add Kunit tests for returning 0 from send_command() in cros_ec_get_host_event_wake_mask(). Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-21-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 128 +++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 757d601f4aee..1e2a1522c288 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -1408,6 +1408,133 @@ static void cros_ec_proto_test_query_all_default_wake_mask_return_error(struct k } } +static void cros_ec_proto_test_query_all_default_wake_mask_return0(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + + /* Set some garbage bytes. */ + ec_dev->host_event_wake_mask = U32_MAX; + + /* For cros_ec_get_proto_info() without passthru. */ + { + struct ec_response_get_protocol_info *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + /* + * Although it doesn't check the value, provides valid sizes so that + * cros_ec_query_all() allocates din and dout correctly. + */ + data = (struct ec_response_get_protocol_info *)mock->o_data; + data->max_request_packet_size = 0xbe; + data->max_response_packet_size = 0xef; + } + + /* For cros_ec_get_proto_info() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For cros_ec_get_host_command_version_mask() for host sleep v1. */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For get_host_event_wake_mask(). */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + cros_ec_proto_test_query_all_pretest(test); + ret = cros_ec_query_all(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* For cros_ec_get_proto_info() without passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_proto_info() with passthru. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, + EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) | + EC_CMD_GET_PROTOCOL_INFO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_protocol_info)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + /* For cros_ec_get_host_command_version_mask() for MKBP. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions)); + } + + /* For cros_ec_get_host_command_version_mask() for host sleep v1. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_CMD_VERSIONS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_cmd_versions)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(struct ec_params_get_cmd_versions)); + } + + /* For get_host_event_wake_mask(). */ + { + u32 mask; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HOST_EVENT_GET_WAKE_MASK); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_host_event_mask)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + + mask = ec_dev->host_event_wake_mask; + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_AC_DISCONNECTED), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_LOW), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_CRITICAL), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU), 0); + KUNIT_EXPECT_EQ(test, mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_STATUS), 0); + } +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -1473,6 +1600,7 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_query_all_no_host_sleep), KUNIT_CASE(cros_ec_proto_test_query_all_no_host_sleep_return0), KUNIT_CASE(cros_ec_proto_test_query_all_default_wake_mask_return_error), + KUNIT_CASE(cros_ec_proto_test_query_all_default_wake_mask_return0), {} }; From cfed691b80dce32b62634b1d7f92a661a3b03e4f Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Thu, 9 Jun 2022 08:49:57 +0000 Subject: [PATCH 0220/1436] platform/chrome: cros_ec_proto: handle empty payload in getting wake mask cros_ec_get_host_event_wake_mask() expects to receive sizeof(struct ec_response_host_event_mask) from send_command(). The payload is valid only if the return value is positive. Return -EPROTO if send_command() returns 0 in cros_ec_get_host_event_wake_mask(). Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220609084957.3684698-22-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 26 ++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index a7d807c9b3bd..1bd567244f8e 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -256,19 +256,23 @@ static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, uint3 msg->insize = sizeof(*r); ret = send_command(ec_dev, msg); - if (ret >= 0) { - mapped = cros_ec_map_error(msg->result); - if (mapped) { - ret = mapped; - goto exit; - } - } - if (ret > 0) { - r = (struct ec_response_host_event_mask *)msg->data; - *mask = r->mask; - ret = 0; + if (ret < 0) + goto exit; + + mapped = cros_ec_map_error(msg->result); + if (mapped) { + ret = mapped; + goto exit; } + if (ret == 0) { + ret = -EPROTO; + goto exit; + } + + r = (struct ec_response_host_event_mask *)msg->data; + *mask = r->mask; + ret = 0; exit: kfree(msg); return ret; From 72aef4f60ff90984fe7aa8b09698120a73373d7f Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Tue, 7 Jun 2022 21:00:49 +0200 Subject: [PATCH 0221/1436] staging: olpc_dcon: Use backlight helper Instead of retrieving the backlight brightness in struct backlight_properties manually, and then checking whether the backlight should be on at all, use backlight_get_brightness() which does all this and insulates this from future changes. Cc: Jens Frederich Cc: Jon Nettleton Cc: Greg Kroah-Hartman Cc: linux-staging@lists.linux.dev Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20220607190049.1132154-1-steve@sk2.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/olpc_dcon/olpc_dcon.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index 7284cb4ac395..b9d570e9ad3b 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -517,10 +517,7 @@ static struct device_attribute dcon_device_files[] = { static int dcon_bl_update(struct backlight_device *dev) { struct dcon_priv *dcon = bl_get_data(dev); - u8 level = dev->props.brightness & 0x0F; - - if (dev->props.power != FB_BLANK_UNBLANK) - level = 0; + u8 level = backlight_get_brightness(dev) & 0x0F; if (level != dcon->bl_val) dcon_set_backlight(dcon, level); From 455c5de922236dee1c008621c0401718a4657619 Mon Sep 17 00:00:00 2001 From: Rommel Rodriguez Perez Date: Tue, 7 Jun 2022 21:38:43 -0500 Subject: [PATCH 0222/1436] staging: r8188eu: Add blank line after declarations This patch adds a blank line after the variable declarations, it should remove a checkpatch.pl warning and improve readability. checkpatch output: WARNING: Missing a blank line after declarations Signed-off-by: Rommel Rodriguez Perez Link: https://lore.kernel.org/r/YqALs/7VkGsYUngw@debianmain.debian.pc.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_ieee80211.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/r8188eu/core/rtw_ieee80211.c b/drivers/staging/r8188eu/core/rtw_ieee80211.c index 385a9ed8eff7..bc8543ea2e66 100644 --- a/drivers/staging/r8188eu/core/rtw_ieee80211.c +++ b/drivers/staging/r8188eu/core/rtw_ieee80211.c @@ -1048,6 +1048,7 @@ static int rtw_get_cipher_info(struct wlan_network *pnetwork) unsigned char *pbuf; int group_cipher = 0, pairwise_cipher = 0, is8021x = 0; int ret = _FAIL; + pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12); if (pbuf && (wpa_ielen > 0)) { From 66d653c37228cb328e9e7ecfa87e6b6b7650e56f Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Tue, 7 Jun 2022 20:55:16 +0200 Subject: [PATCH 0223/1436] staging: ftbft: Use backlight helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit backlight_properties.fb_blank is deprecated. The states it represents are handled by other properties; but instead of accessing those properties directly, drivers should use the helpers provided by backlight.h. Instead of manually checking the power state in struct backlight_properties, use backlight_is_blank(). Cc: Greg Kroah-Hartman Cc: "Noralf Trønnes" Cc: Thomas Zimmermann Cc: Andy Shevchenko Cc: Javier Martinez Canillas Cc: Len Baker Cc: dri-devel@lists.freedesktop.org Cc: linux-fbdev@vger.kernel.org Cc: linux-staging@lists.linux.dev Reviewed-by: Daniel Thompson Reviewed-by: Andy Shevchenko Signed-off-by: Stephen Kitt Link: https://lore.kernel.org/r/20220607185516.1129900-1-steve@sk2.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/fb_ssd1351.c | 3 +-- drivers/staging/fbtft/fbtft-core.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/fbtft/fb_ssd1351.c b/drivers/staging/fbtft/fb_ssd1351.c index 6fd549a424d5..b8d55aa8c5c7 100644 --- a/drivers/staging/fbtft/fb_ssd1351.c +++ b/drivers/staging/fbtft/fb_ssd1351.c @@ -196,8 +196,7 @@ static int update_onboard_backlight(struct backlight_device *bd) "%s: power=%d, fb_blank=%d\n", __func__, bd->props.power, bd->props.fb_blank); - on = (bd->props.power == FB_BLANK_UNBLANK) && - (bd->props.fb_blank == FB_BLANK_UNBLANK); + on = !backlight_is_blank(bd); /* Onboard backlight connected to GPIO0 on SSD1351, GPIO1 unused */ write_reg(par, 0xB5, on ? 0x03 : 0x02); diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 60b2278d8b16..9b3eaed80cdd 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -137,8 +137,7 @@ static int fbtft_backlight_update_status(struct backlight_device *bd) "%s: polarity=%d, power=%d, fb_blank=%d\n", __func__, polarity, bd->props.power, bd->props.fb_blank); - if ((bd->props.power == FB_BLANK_UNBLANK) && - (bd->props.fb_blank == FB_BLANK_UNBLANK)) + if (!backlight_is_blank(bd)) gpiod_set_value(par->gpio.led[0], polarity); else gpiod_set_value(par->gpio.led[0], !polarity); From da30e351882965df99455904c3c020d138899d9f Mon Sep 17 00:00:00 2001 From: Srivathsan Sivakumar Date: Thu, 9 Jun 2022 16:46:39 -0400 Subject: [PATCH 0224/1436] staging: qlge: qlge_main.c: rewrite do-while loops into more compact for loops simplify do-while loops into for loops Reviewed-by: Dan Carpenter Signed-off-by: Srivathsan Sivakumar Link: https://lore.kernel.org/r/YqJcLwUQorZQOrkd@Sassy Signed-off-by: Greg Kroah-Hartman --- drivers/staging/qlge/qlge_main.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c index 8c35d4c4b851..689a87d58f27 100644 --- a/drivers/staging/qlge/qlge_main.c +++ b/drivers/staging/qlge/qlge_main.c @@ -3006,13 +3006,11 @@ static int qlge_start_rx_ring(struct qlge_adapter *qdev, struct rx_ring *rx_ring cqicb->flags |= FLAGS_LL; /* Load lbq values */ tmp = (u64)rx_ring->lbq.base_dma; base_indirect_ptr = rx_ring->lbq.base_indirect; - page_entries = 0; - do { - *base_indirect_ptr = cpu_to_le64(tmp); - tmp += DB_PAGE_SIZE; - base_indirect_ptr++; - page_entries++; - } while (page_entries < MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN)); + + for (page_entries = 0; page_entries < + MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN); page_entries++) + base_indirect_ptr[page_entries] = + cpu_to_le64(tmp + (page_entries * DB_PAGE_SIZE)); cqicb->lbq_addr = cpu_to_le64(rx_ring->lbq.base_indirect_dma); cqicb->lbq_buf_size = cpu_to_le16(QLGE_FIT16(qdev->lbq_buf_size)); @@ -3023,13 +3021,11 @@ static int qlge_start_rx_ring(struct qlge_adapter *qdev, struct rx_ring *rx_ring cqicb->flags |= FLAGS_LS; /* Load sbq values */ tmp = (u64)rx_ring->sbq.base_dma; base_indirect_ptr = rx_ring->sbq.base_indirect; - page_entries = 0; - do { - *base_indirect_ptr = cpu_to_le64(tmp); - tmp += DB_PAGE_SIZE; - base_indirect_ptr++; - page_entries++; - } while (page_entries < MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN)); + + for (page_entries = 0; page_entries < + MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN); page_entries++) + base_indirect_ptr[page_entries] = + cpu_to_le64(tmp + (page_entries * DB_PAGE_SIZE)); cqicb->sbq_addr = cpu_to_le64(rx_ring->sbq.base_indirect_dma); cqicb->sbq_buf_size = cpu_to_le16(SMALL_BUFFER_SIZE); From 857fe9e5efc09833fe1110e99d8baba954a86abb Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Tue, 7 Jun 2022 22:26:05 +0300 Subject: [PATCH 0225/1436] staging: r8188eu: add error handling of rtw_read8 rtw_read8() reads data from device via USB API which may fail. In case of any failure previous code returned stack data to callers, which is wrong. Fix it by changing rtw_read8() prototype and prevent caller from touching random stack data Signed-off-by: Pavel Skripkin Link: https://lore.kernel.org/r/c8f8ef4f14db3ba2478a87d5be6eb768a093dfaf.1654629778.git.paskripkin@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_efuse.c | 13 +- drivers/staging/r8188eu/core/rtw_fw.c | 56 ++++-- drivers/staging/r8188eu/core/rtw_led.c | 16 +- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 48 ++++- drivers/staging/r8188eu/core/rtw_wlan_util.c | 20 +- drivers/staging/r8188eu/hal/HalPhyRf_8188e.c | 18 +- drivers/staging/r8188eu/hal/HalPwrSeqCmd.c | 9 +- drivers/staging/r8188eu/hal/hal_com.c | 27 ++- drivers/staging/r8188eu/hal/rtl8188e_cmd.c | 37 +++- drivers/staging/r8188eu/hal/rtl8188e_dm.c | 6 +- .../staging/r8188eu/hal/rtl8188e_hal_init.c | 69 +++++-- drivers/staging/r8188eu/hal/rtl8188e_phycfg.c | 10 +- drivers/staging/r8188eu/hal/usb_halinit.c | 171 +++++++++++++++--- drivers/staging/r8188eu/hal/usb_ops_linux.c | 7 +- drivers/staging/r8188eu/include/rtw_io.h | 2 +- drivers/staging/r8188eu/os_dep/ioctl_linux.c | 11 +- 16 files changed, 418 insertions(+), 102 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_efuse.c b/drivers/staging/r8188eu/core/rtw_efuse.c index 0e0e60638880..a2691c7f96f6 100644 --- a/drivers/staging/r8188eu/core/rtw_efuse.c +++ b/drivers/staging/r8188eu/core/rtw_efuse.c @@ -28,14 +28,21 @@ ReadEFuseByte( u32 value32; u8 readbyte; u16 retry; + int res; /* Write Address */ rtw_write8(Adapter, EFUSE_CTRL + 1, (_offset & 0xff)); - readbyte = rtw_read8(Adapter, EFUSE_CTRL + 2); + res = rtw_read8(Adapter, EFUSE_CTRL + 2, &readbyte); + if (res) + return; + rtw_write8(Adapter, EFUSE_CTRL + 2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc)); /* Write bit 32 0 */ - readbyte = rtw_read8(Adapter, EFUSE_CTRL + 3); + res = rtw_read8(Adapter, EFUSE_CTRL + 3, &readbyte); + if (res) + return; + rtw_write8(Adapter, EFUSE_CTRL + 3, (readbyte & 0x7f)); /* Check bit 32 read-ready */ @@ -54,6 +61,8 @@ ReadEFuseByte( value32 = rtw_read32(Adapter, EFUSE_CTRL); *pbuf = (u8)(value32 & 0xff); + + /* FIXME: return an error to caller */ } /*----------------------------------------------------------------------------- diff --git a/drivers/staging/r8188eu/core/rtw_fw.c b/drivers/staging/r8188eu/core/rtw_fw.c index 87dc0e97652a..e1fc883a5f7e 100644 --- a/drivers/staging/r8188eu/core/rtw_fw.c +++ b/drivers/staging/r8188eu/core/rtw_fw.c @@ -44,18 +44,28 @@ static_assert(sizeof(struct rt_firmware_hdr) == 32); static void fw_download_enable(struct adapter *padapter, bool enable) { u8 tmp; + int res; if (enable) { /* MCU firmware download enable. */ - tmp = rtw_read8(padapter, REG_MCUFWDL); + res = rtw_read8(padapter, REG_MCUFWDL, &tmp); + if (res) + return; + rtw_write8(padapter, REG_MCUFWDL, tmp | 0x01); /* 8051 reset */ - tmp = rtw_read8(padapter, REG_MCUFWDL + 2); + res = rtw_read8(padapter, REG_MCUFWDL + 2, &tmp); + if (res) + return; + rtw_write8(padapter, REG_MCUFWDL + 2, tmp & 0xf7); } else { /* MCU firmware download disable. */ - tmp = rtw_read8(padapter, REG_MCUFWDL); + res = rtw_read8(padapter, REG_MCUFWDL, &tmp); + if (res) + return; + rtw_write8(padapter, REG_MCUFWDL, tmp & 0xfe); /* Reserved for fw extension. */ @@ -125,8 +135,13 @@ static int page_write(struct adapter *padapter, u32 page, u8 *buffer, u32 size) { u8 value8; u8 u8Page = (u8)(page & 0x07); + int res; - value8 = (rtw_read8(padapter, REG_MCUFWDL + 2) & 0xF8) | u8Page; + res = rtw_read8(padapter, REG_MCUFWDL + 2, &value8); + if (res) + return _FAIL; + + value8 = (value8 & 0xF8) | u8Page; rtw_write8(padapter, REG_MCUFWDL + 2, value8); return block_write(padapter, buffer, size); @@ -165,8 +180,12 @@ exit: void rtw_reset_8051(struct adapter *padapter) { u8 val8; + int res; + + res = rtw_read8(padapter, REG_SYS_FUNC_EN + 1, &val8); + if (res) + return; - val8 = rtw_read8(padapter, REG_SYS_FUNC_EN + 1); rtw_write8(padapter, REG_SYS_FUNC_EN + 1, val8 & (~BIT(2))); rtw_write8(padapter, REG_SYS_FUNC_EN + 1, val8 | (BIT(2))); } @@ -239,7 +258,7 @@ exit: int rtl8188e_firmware_download(struct adapter *padapter) { int ret = _SUCCESS; - u8 write_fw_retry = 0; + u8 reg; unsigned long fwdl_timeout; struct dvobj_priv *dvobj = adapter_to_dvobj(padapter); struct device *device = dvobj_to_dev(dvobj); @@ -269,23 +288,34 @@ int rtl8188e_firmware_download(struct adapter *padapter) /* Suggested by Filen. If 8051 is running in RAM code, driver should inform Fw to reset by itself, */ /* or it will cause download Fw fail. 2010.02.01. by tynli. */ - if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) { /* 8051 RAM code */ + ret = rtw_read8(padapter, REG_MCUFWDL, ®); + if (ret) { + ret = _FAIL; + goto exit; + } + + if (reg & RAM_DL_SEL) { /* 8051 RAM code */ rtw_write8(padapter, REG_MCUFWDL, 0x00); rtw_reset_8051(padapter); } fw_download_enable(padapter, true); fwdl_timeout = jiffies + msecs_to_jiffies(500); - while (1) { + do { /* reset the FWDL chksum */ - rtw_write8(padapter, REG_MCUFWDL, rtw_read8(padapter, REG_MCUFWDL) | FWDL_CHKSUM_RPT); + ret = rtw_read8(padapter, REG_MCUFWDL, ®); + if (ret) { + ret = _FAIL; + continue; + } + + rtw_write8(padapter, REG_MCUFWDL, reg | FWDL_CHKSUM_RPT); ret = write_fw(padapter, fw_data, fw_size); - - if (ret == _SUCCESS || - (time_after(jiffies, fwdl_timeout) && write_fw_retry++ >= 3)) + if (ret == _SUCCESS) break; - } + } while (!time_after(jiffies, fwdl_timeout)); + fw_download_enable(padapter, false); if (ret != _SUCCESS) goto exit; diff --git a/drivers/staging/r8188eu/core/rtw_led.c b/drivers/staging/r8188eu/core/rtw_led.c index 2f3000428af7..25989acf5259 100644 --- a/drivers/staging/r8188eu/core/rtw_led.c +++ b/drivers/staging/r8188eu/core/rtw_led.c @@ -35,11 +35,15 @@ static void ResetLedStatus(struct LED_871x *pLed) static void SwLedOn(struct adapter *padapter, struct LED_871x *pLed) { u8 LedCfg; + int res; if (padapter->bSurpriseRemoved || padapter->bDriverStopped) return; - LedCfg = rtw_read8(padapter, REG_LEDCFG2); + res = rtw_read8(padapter, REG_LEDCFG2, &LedCfg); + if (res) + return; + rtw_write8(padapter, REG_LEDCFG2, (LedCfg & 0xf0) | BIT(5) | BIT(6)); /* SW control led0 on. */ pLed->bLedOn = true; } @@ -47,15 +51,21 @@ static void SwLedOn(struct adapter *padapter, struct LED_871x *pLed) static void SwLedOff(struct adapter *padapter, struct LED_871x *pLed) { u8 LedCfg; + int res; if (padapter->bSurpriseRemoved || padapter->bDriverStopped) goto exit; - LedCfg = rtw_read8(padapter, REG_LEDCFG2);/* 0x4E */ + res = rtw_read8(padapter, REG_LEDCFG2, &LedCfg);/* 0x4E */ + if (res) + goto exit; LedCfg &= 0x90; /* Set to software control. */ rtw_write8(padapter, REG_LEDCFG2, (LedCfg | BIT(3))); - LedCfg = rtw_read8(padapter, REG_MAC_PINMUX_CFG); + res = rtw_read8(padapter, REG_MAC_PINMUX_CFG, &LedCfg); + if (res) + goto exit; + LedCfg &= 0xFE; rtw_write8(padapter, REG_MAC_PINMUX_CFG, LedCfg); exit: diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 87bf37f33606..2eb9d85e5553 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5650,14 +5650,28 @@ unsigned int send_beacon(struct adapter *padapter) bool get_beacon_valid_bit(struct adapter *adapter) { + int res; + u8 reg; + + res = rtw_read8(adapter, REG_TDECTRL + 2, ®); + if (res) + return false; + /* BIT(16) of REG_TDECTRL = BIT(0) of REG_TDECTRL+2 */ - return BIT(0) & rtw_read8(adapter, REG_TDECTRL + 2); + return BIT(0) & reg; } void clear_beacon_valid_bit(struct adapter *adapter) { + int res; + u8 reg; + + res = rtw_read8(adapter, REG_TDECTRL + 2, ®); + if (res) + return; + /* BIT(16) of REG_TDECTRL = BIT(0) of REG_TDECTRL+2, write 1 to clear, Clear by sw */ - rtw_write8(adapter, REG_TDECTRL + 2, rtw_read8(adapter, REG_TDECTRL + 2) | BIT(0)); + rtw_write8(adapter, REG_TDECTRL + 2, reg | BIT(0)); } /**************************************************************************** @@ -5985,7 +5999,8 @@ static void rtw_set_bssid(struct adapter *adapter, u8 *bssid) static void mlme_join(struct adapter *adapter, int type) { struct mlme_priv *mlmepriv = &adapter->mlmepriv; - u8 retry_limit = 0x30; + u8 retry_limit = 0x30, reg; + int res; switch (type) { case 0: @@ -6010,7 +6025,11 @@ static void mlme_join(struct adapter *adapter, int type) case 2: /* sta add event call back */ /* enable update TSF */ - rtw_write8(adapter, REG_BCN_CTRL, rtw_read8(adapter, REG_BCN_CTRL) & (~BIT(4))); + res = rtw_read8(adapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(adapter, REG_BCN_CTRL, reg & (~BIT(4))); if (check_fwstate(mlmepriv, WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) retry_limit = 0x7; @@ -6731,6 +6750,9 @@ void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *p static void mlme_disconnect(struct adapter *adapter) { + int res; + u8 reg; + /* Set RCR to not to receive data frame when NO LINK state */ /* reject all data frames */ rtw_write16(adapter, REG_RXFLTMAP2, 0x00); @@ -6739,7 +6761,12 @@ static void mlme_disconnect(struct adapter *adapter) rtw_write8(adapter, REG_DUAL_TSF_RST, (BIT(0) | BIT(1))); /* disable update TSF */ - rtw_write8(adapter, REG_BCN_CTRL, rtw_read8(adapter, REG_BCN_CTRL) | BIT(4)); + + res = rtw_read8(adapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(adapter, REG_BCN_CTRL, reg | BIT(4)); } void mlmeext_sta_del_event_callback(struct adapter *padapter) @@ -6793,14 +6820,15 @@ static u8 chk_ap_is_alive(struct sta_info *psta) return ret; } -static void rtl8188e_sreset_linked_status_check(struct adapter *padapter) +static int rtl8188e_sreset_linked_status_check(struct adapter *padapter) { u32 rx_dma_status = rtw_read32(padapter, REG_RXDMA_STATUS); + u8 reg; if (rx_dma_status != 0x00) rtw_write32(padapter, REG_RXDMA_STATUS, rx_dma_status); - rtw_read8(padapter, REG_FMETHR); + return rtw_read8(padapter, REG_FMETHR, ®); } void linked_status_chk(struct adapter *padapter) @@ -7202,6 +7230,7 @@ u8 disconnect_hdl(struct adapter *padapter, unsigned char *pbuf) struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&pmlmeinfo->network); u8 val8; + int res; if (is_client_associated_to_ap(padapter)) issue_deauth_ex(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms / 100, 100); @@ -7214,7 +7243,10 @@ u8 disconnect_hdl(struct adapter *padapter, unsigned char *pbuf) if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) { /* Stop BCN */ - val8 = rtw_read8(padapter, REG_BCN_CTRL); + res = rtw_read8(padapter, REG_BCN_CTRL, &val8); + if (res) + return H2C_DROPPED; + rtw_write8(padapter, REG_BCN_CTRL, val8 & (~(EN_BCN_FUNCTION | EN_TXBCN_RPT))); } diff --git a/drivers/staging/r8188eu/core/rtw_wlan_util.c b/drivers/staging/r8188eu/core/rtw_wlan_util.c index 9f0a823b6e52..2d5fd654ead9 100644 --- a/drivers/staging/r8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/r8188eu/core/rtw_wlan_util.c @@ -279,8 +279,13 @@ void Restore_DM_Func_Flag(struct adapter *padapter) void Set_MSR(struct adapter *padapter, u8 type) { u8 val8; + int res; - val8 = rtw_read8(padapter, MSR) & 0x0c; + res = rtw_read8(padapter, MSR, &val8); + if (res) + return; + + val8 &= 0x0c; val8 |= type; rtw_write8(padapter, MSR, val8); } @@ -505,7 +510,11 @@ int WMM_param_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) static void set_acm_ctrl(struct adapter *adapter, u8 acm_mask) { - u8 acmctrl = rtw_read8(adapter, REG_ACMHWCTRL); + u8 acmctrl; + int res = rtw_read8(adapter, REG_ACMHWCTRL, &acmctrl); + + if (res) + return; if (acm_mask > 1) acmctrl = acmctrl | 0x1; @@ -765,6 +774,7 @@ void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) static void set_min_ampdu_spacing(struct adapter *adapter, u8 spacing) { u8 sec_spacing; + int res; if (spacing <= 7) { switch (adapter->securitypriv.dot11PrivacyAlgrthm) { @@ -786,8 +796,12 @@ static void set_min_ampdu_spacing(struct adapter *adapter, u8 spacing) if (spacing < sec_spacing) spacing = sec_spacing; + res = rtw_read8(adapter, REG_AMPDU_MIN_SPACE, &sec_spacing); + if (res) + return; + rtw_write8(adapter, REG_AMPDU_MIN_SPACE, - (rtw_read8(adapter, REG_AMPDU_MIN_SPACE) & 0xf8) | spacing); + (sec_spacing & 0xf8) | spacing); } } diff --git a/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c b/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c index b944c8071a3b..a5b7980dfcee 100644 --- a/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c +++ b/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c @@ -463,6 +463,7 @@ void _PHY_SaveADDARegisters(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup } } +/* FIXME: return an error to caller */ static void _PHY_SaveMACRegisters( struct adapter *adapt, u32 *MACReg, @@ -470,9 +471,17 @@ static void _PHY_SaveMACRegisters( ) { u32 i; + int res; - for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) - MACBackup[i] = rtw_read8(adapt, MACReg[i]); + for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++) { + u8 reg; + + res = rtw_read8(adapt, MACReg[i], ®); + if (res) + return; + + MACBackup[i] = reg; + } MACBackup[i] = rtw_read32(adapt, MACReg[i]); } @@ -739,9 +748,12 @@ static void phy_LCCalibrate_8188E(struct adapter *adapt) { u8 tmpreg; u32 RF_Amode = 0, LC_Cal; + int res; /* Check continuous TX and Packet TX */ - tmpreg = rtw_read8(adapt, 0xd03); + res = rtw_read8(adapt, 0xd03, &tmpreg); + if (res) + return; if ((tmpreg & 0x70) != 0) /* Deal with contisuous TX case */ rtw_write8(adapt, 0xd03, tmpreg & 0x8F); /* disable all continuous TX */ diff --git a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c index 150ea380c39e..4a4563b900b3 100644 --- a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c +++ b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c @@ -12,6 +12,7 @@ u8 HalPwrSeqCmdParsing(struct adapter *padapter, struct wl_pwr_cfg pwrseqcmd[]) u32 offset = 0; u32 poll_count = 0; /* polling autoload done. */ u32 max_poll_count = 5000; + int res; do { pwrcfgcmd = pwrseqcmd[aryidx]; @@ -21,7 +22,9 @@ u8 HalPwrSeqCmdParsing(struct adapter *padapter, struct wl_pwr_cfg pwrseqcmd[]) offset = GET_PWR_CFG_OFFSET(pwrcfgcmd); /* Read the value from system register */ - value = rtw_read8(padapter, offset); + res = rtw_read8(padapter, offset, &value); + if (res) + return false; value &= ~(GET_PWR_CFG_MASK(pwrcfgcmd)); value |= (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd)); @@ -33,7 +36,9 @@ u8 HalPwrSeqCmdParsing(struct adapter *padapter, struct wl_pwr_cfg pwrseqcmd[]) poll_bit = false; offset = GET_PWR_CFG_OFFSET(pwrcfgcmd); do { - value = rtw_read8(padapter, offset); + res = rtw_read8(padapter, offset, &value); + if (res) + return false; value &= GET_PWR_CFG_MASK(pwrcfgcmd); if (value == (GET_PWR_CFG_VALUE(pwrcfgcmd) & GET_PWR_CFG_MASK(pwrcfgcmd))) diff --git a/drivers/staging/r8188eu/hal/hal_com.c b/drivers/staging/r8188eu/hal/hal_com.c index 910cc07f656c..e9a32dd84a8e 100644 --- a/drivers/staging/r8188eu/hal/hal_com.c +++ b/drivers/staging/r8188eu/hal/hal_com.c @@ -303,7 +303,9 @@ s32 c2h_evt_read(struct adapter *adapter, u8 *buf) if (!buf) goto exit; - trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR); + ret = rtw_read8(adapter, REG_C2HEVT_CLEAR, &trigger); + if (ret) + return _FAIL; if (trigger == C2H_EVT_HOST_CLOSE) goto exit; /* Not ready */ @@ -314,13 +316,26 @@ s32 c2h_evt_read(struct adapter *adapter, u8 *buf) memset(c2h_evt, 0, 16); - *buf = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL); - *(buf + 1) = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1); + ret = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL, buf); + if (ret) { + ret = _FAIL; + goto clear_evt; + } + ret = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1, buf + 1); + if (ret) { + ret = _FAIL; + goto clear_evt; + } /* Read the content */ - for (i = 0; i < c2h_evt->plen; i++) - c2h_evt->payload[i] = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + - sizeof(*c2h_evt) + i); + for (i = 0; i < c2h_evt->plen; i++) { + ret = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + + sizeof(*c2h_evt) + i, c2h_evt->payload + i); + if (ret) { + ret = _FAIL; + goto clear_evt; + } + } ret = _SUCCESS; diff --git a/drivers/staging/r8188eu/hal/rtl8188e_cmd.c b/drivers/staging/r8188eu/hal/rtl8188e_cmd.c index 475650dc7301..b01ee1695fee 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_cmd.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_cmd.c @@ -18,13 +18,18 @@ static u8 _is_fw_read_cmd_down(struct adapter *adapt, u8 msgbox_num) { - u8 read_down = false; + u8 read_down = false, reg; int retry_cnts = 100; + int res; u8 valid; do { - valid = rtw_read8(adapt, REG_HMETFR) & BIT(msgbox_num); + res = rtw_read8(adapt, REG_HMETFR, ®); + if (res) + continue; + + valid = reg & BIT(msgbox_num); if (0 == valid) read_down = true; } while ((!read_down) && (retry_cnts--)); @@ -533,6 +538,8 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus) bool bcn_valid = false; u8 DLBcnCount = 0; u32 poll = 0; + u8 reg; + int res; if (mstatus == 1) { /* We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */ @@ -547,8 +554,17 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus) /* Disable Hw protection for a time which revserd for Hw sending beacon. */ /* Fix download reserved page packet fail that access collision with the protection time. */ /* 2010.05.11. Added by tynli. */ - rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) & (~BIT(3))); - rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) | BIT(4)); + res = rtw_read8(adapt, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(adapt, REG_BCN_CTRL, reg & (~BIT(3))); + + res = rtw_read8(adapt, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(adapt, REG_BCN_CTRL, reg | BIT(4)); if (haldata->RegFwHwTxQCtrl & BIT(6)) bSendBeacon = true; @@ -581,8 +597,17 @@ void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *adapt, u8 mstatus) /* */ /* Enable Bcn */ - rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) | BIT(3)); - rtw_write8(adapt, REG_BCN_CTRL, rtw_read8(adapt, REG_BCN_CTRL) & (~BIT(4))); + res = rtw_read8(adapt, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(adapt, REG_BCN_CTRL, reg | BIT(3)); + + res = rtw_read8(adapt, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(adapt, REG_BCN_CTRL, reg & (~BIT(4))); /* To make sure that if there exists an adapter which would like to send beacon. */ /* If exists, the origianl value of 0x422[6] will be 1, we should check this to */ diff --git a/drivers/staging/r8188eu/hal/rtl8188e_dm.c b/drivers/staging/r8188eu/hal/rtl8188e_dm.c index 6d28e3dc0d26..0399872c4546 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_dm.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_dm.c @@ -12,8 +12,12 @@ static void dm_InitGPIOSetting(struct adapter *Adapter) { u8 tmp1byte; + int res; + + res = rtw_read8(Adapter, REG_GPIO_MUXCFG, &tmp1byte); + if (res) + return; - tmp1byte = rtw_read8(Adapter, REG_GPIO_MUXCFG); tmp1byte &= (GPIOSEL_GPIO | ~GPIOSEL_ENBT); rtw_write8(Adapter, REG_GPIO_MUXCFG, tmp1byte); diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index e17375a74f17..e67ecbd1ba79 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -13,10 +13,14 @@ static void iol_mode_enable(struct adapter *padapter, u8 enable) { u8 reg_0xf0 = 0; + int res; if (enable) { /* Enable initial offload */ - reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG); + res = rtw_read8(padapter, REG_SYS_CFG, ®_0xf0); + if (res) + return; + rtw_write8(padapter, REG_SYS_CFG, reg_0xf0 | SW_OFFLOAD_EN); if (!padapter->bFWReady) @@ -24,7 +28,10 @@ static void iol_mode_enable(struct adapter *padapter, u8 enable) } else { /* disable initial offload */ - reg_0xf0 = rtw_read8(padapter, REG_SYS_CFG); + res = rtw_read8(padapter, REG_SYS_CFG, ®_0xf0); + if (res) + return; + rtw_write8(padapter, REG_SYS_CFG, reg_0xf0 & ~SW_OFFLOAD_EN); } } @@ -34,17 +41,31 @@ static s32 iol_execute(struct adapter *padapter, u8 control) s32 status = _FAIL; u8 reg_0x88 = 0; unsigned long timeout; + int res; control = control & 0x0f; - reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0); + res = rtw_read8(padapter, REG_HMEBOX_E0, ®_0x88); + if (res) + return _FAIL; + rtw_write8(padapter, REG_HMEBOX_E0, reg_0x88 | control); timeout = jiffies + msecs_to_jiffies(1000); - while ((reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0)) & control && - time_before(jiffies, timeout)) - ; - reg_0x88 = rtw_read8(padapter, REG_HMEBOX_E0); + do { + res = rtw_read8(padapter, REG_HMEBOX_E0, ®_0x88); + if (res) + continue; + + if (!(reg_0x88 & control)) + break; + + } while (time_before(jiffies, timeout)); + + res = rtw_read8(padapter, REG_HMEBOX_E0, ®_0x88); + if (res) + return _FAIL; + status = (reg_0x88 & control) ? _FAIL : _SUCCESS; if (reg_0x88 & control << 4) status = _FAIL; @@ -190,13 +211,18 @@ static void efuse_read_phymap_from_txpktbuf( u16 dbg_addr = 0; __le32 lo32 = 0, hi32 = 0; u16 len = 0, count = 0; - int i = 0; + int i = 0, res; u16 limit = *size; - + u8 reg; u8 *pos = content; - if (bcnhead < 0) /* if not valid */ - bcnhead = rtw_read8(adapter, REG_TDECTRL + 1); + if (bcnhead < 0) { /* if not valid */ + res = rtw_read8(adapter, REG_TDECTRL + 1, ®); + if (res) + return; + + bcnhead = reg; + } rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); @@ -207,8 +233,16 @@ static void efuse_read_phymap_from_txpktbuf( rtw_write8(adapter, REG_TXPKTBUF_DBG, 0); timeout = jiffies + msecs_to_jiffies(1000); - while (!rtw_read8(adapter, REG_TXPKTBUF_DBG) && time_before(jiffies, timeout)) + do { + res = rtw_read8(adapter, REG_TXPKTBUF_DBG, ®); + if (res) + continue; + + if (reg) + break; + rtw_usleep_os(100); + } while (time_before(jiffies, timeout)); /* data from EEPROM needs to be in LE */ lo32 = cpu_to_le32(rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L)); @@ -525,10 +559,17 @@ void rtl8188e_SetHalODMVar(struct adapter *Adapter, void *pValue1, bool bSet) void hal_notch_filter_8188e(struct adapter *adapter, bool enable) { + int res; + u8 reg; + + res = rtw_read8(adapter, rOFDM0_RxDSP + 1, ®); + if (res) + return; + if (enable) - rtw_write8(adapter, rOFDM0_RxDSP + 1, rtw_read8(adapter, rOFDM0_RxDSP + 1) | BIT(1)); + rtw_write8(adapter, rOFDM0_RxDSP + 1, reg | BIT(1)); else - rtw_write8(adapter, rOFDM0_RxDSP + 1, rtw_read8(adapter, rOFDM0_RxDSP + 1) & ~BIT(1)); + rtw_write8(adapter, rOFDM0_RxDSP + 1, reg & ~BIT(1)); } /* */ diff --git a/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c b/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c index 4864dafd887b..985339a974fc 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c @@ -594,6 +594,7 @@ _PHY_SetBWMode92C( struct hal_data_8188e *pHalData = &Adapter->haldata; u8 regBwOpMode; u8 regRRSR_RSC; + int res; if (Adapter->bDriverStopped) return; @@ -602,8 +603,13 @@ _PHY_SetBWMode92C( /* 3<1>Set MAC register */ /* 3 */ - regBwOpMode = rtw_read8(Adapter, REG_BWOPMODE); - regRRSR_RSC = rtw_read8(Adapter, REG_RRSR + 2); + res = rtw_read8(Adapter, REG_BWOPMODE, ®BwOpMode); + if (res) + return; + + res = rtw_read8(Adapter, REG_RRSR + 2, ®RRSR_RSC); + if (res) + return; switch (pHalData->CurrentChannelBW) { case HT_CHANNEL_WIDTH_20: diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 895619fea501..5540d5ad07d3 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -81,6 +81,7 @@ static void _InitInterrupt(struct adapter *Adapter) { u32 imr, imr_ex; u8 usb_opt; + int res; /* HISR write one to clear */ rtw_write32(Adapter, REG_HISR_88E, 0xFFFFFFFF); @@ -94,7 +95,9 @@ static void _InitInterrupt(struct adapter *Adapter) /* REG_USB_SPECIAL_OPTION - BIT(4) */ /* 0; Use interrupt endpoint to upload interrupt pkt */ /* 1; Use bulk endpoint to upload interrupt pkt, */ - usb_opt = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION); + res = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION, &usb_opt); + if (res) + return; if (adapter_to_dvobj(Adapter)->pusbdev->speed == USB_SPEED_HIGH) usb_opt = usb_opt | (INT_BULK_SEL); @@ -363,8 +366,12 @@ static void _InitEDCA(struct adapter *Adapter) static void _InitRetryFunction(struct adapter *Adapter) { u8 value8; + int res; + + res = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL, &value8); + if (res) + return; - value8 = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL); value8 |= EN_AMPDU_RTY_NEW; rtw_write8(Adapter, REG_FWHW_TXQ_CTRL, value8); @@ -423,9 +430,15 @@ usb_AggSettingRxUpdate( { u8 valueDMA; u8 valueUSB; + int res; - valueDMA = rtw_read8(Adapter, REG_TRXDMA_CTRL); - valueUSB = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION); + res = rtw_read8(Adapter, REG_TRXDMA_CTRL, &valueDMA); + if (res) + return; + + res = rtw_read8(Adapter, REG_USB_SPECIAL_OPTION, &valueUSB); + if (res) + return; valueDMA |= RXDMA_AGG_EN; valueUSB &= ~USB_AGG_EN; @@ -446,9 +459,11 @@ static void InitUsbAggregationSetting(struct adapter *Adapter) usb_AggSettingRxUpdate(Adapter); } -static void _InitBeaconParameters(struct adapter *Adapter) +/* FIXME: add error handling in callers */ +static int _InitBeaconParameters(struct adapter *Adapter) { struct hal_data_8188e *haldata = &Adapter->haldata; + int res; rtw_write16(Adapter, REG_BCN_CTRL, 0x1010); @@ -461,9 +476,19 @@ static void _InitBeaconParameters(struct adapter *Adapter) /* beacause test chip does not contension before sending beacon. by tynli. 2009.11.03 */ rtw_write16(Adapter, REG_BCNTCFG, 0x660F); - haldata->RegFwHwTxQCtrl = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL + 2); - haldata->RegReg542 = rtw_read8(Adapter, REG_TBTT_PROHIBIT + 2); - haldata->RegCR_1 = rtw_read8(Adapter, REG_CR + 1); + res = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL + 2, &haldata->RegFwHwTxQCtrl); + if (res) + return res; + + res = rtw_read8(Adapter, REG_TBTT_PROHIBIT + 2, &haldata->RegReg542); + if (res) + return res; + + res = rtw_read8(Adapter, REG_CR + 1, &haldata->RegCR_1); + if (res) + return res; + + return 0; } static void _BeaconFunctionEnable(struct adapter *Adapter, @@ -514,6 +539,7 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter) u16 value16; u8 txpktbuf_bndy; u32 status = _SUCCESS; + int res; struct hal_data_8188e *haldata = &Adapter->haldata; struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; struct registry_priv *pregistrypriv = &Adapter->registrypriv; @@ -620,7 +646,10 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter) /* Enable TX Report */ /* Enable Tx Report Timer */ - value8 = rtw_read8(Adapter, REG_TX_RPT_CTRL); + res = rtw_read8(Adapter, REG_TX_RPT_CTRL, &value8); + if (res) + return _FAIL; + rtw_write8(Adapter, REG_TX_RPT_CTRL, (value8 | BIT(1) | BIT(0))); /* Set MAX RPT MACID */ rtw_write8(Adapter, REG_TX_RPT_CTRL + 1, 2);/* FOR sta mode ,0: bc/mc ,1:AP */ @@ -714,9 +743,13 @@ static void CardDisableRTL8188EU(struct adapter *Adapter) { u8 val8; struct hal_data_8188e *haldata = &Adapter->haldata; + int res; /* Stop Tx Report Timer. 0x4EC[Bit1]=b'0 */ - val8 = rtw_read8(Adapter, REG_TX_RPT_CTRL); + res = rtw_read8(Adapter, REG_TX_RPT_CTRL, &val8); + if (res) + return; + rtw_write8(Adapter, REG_TX_RPT_CTRL, val8 & (~BIT(1))); /* stop rx */ @@ -727,10 +760,16 @@ static void CardDisableRTL8188EU(struct adapter *Adapter) /* 2. 0x1F[7:0] = 0 turn off RF */ - val8 = rtw_read8(Adapter, REG_MCUFWDL); + res = rtw_read8(Adapter, REG_MCUFWDL, &val8); + if (res) + return; + if ((val8 & RAM_DL_SEL) && Adapter->bFWReady) { /* 8051 RAM code */ /* Reset MCU 0x2[10]=0. */ - val8 = rtw_read8(Adapter, REG_SYS_FUNC_EN + 1); + res = rtw_read8(Adapter, REG_SYS_FUNC_EN + 1, &val8); + if (res) + return; + val8 &= ~BIT(2); /* 0x2[10], FEN_CPUEN */ rtw_write8(Adapter, REG_SYS_FUNC_EN + 1, val8); } @@ -740,26 +779,45 @@ static void CardDisableRTL8188EU(struct adapter *Adapter) /* YJ,add,111212 */ /* Disable 32k */ - val8 = rtw_read8(Adapter, REG_32K_CTRL); + res = rtw_read8(Adapter, REG_32K_CTRL, &val8); + if (res) + return; + rtw_write8(Adapter, REG_32K_CTRL, val8 & (~BIT(0))); /* Card disable power action flow */ HalPwrSeqCmdParsing(Adapter, Rtl8188E_NIC_DISABLE_FLOW); /* Reset MCU IO Wrapper */ - val8 = rtw_read8(Adapter, REG_RSV_CTRL + 1); + res = rtw_read8(Adapter, REG_RSV_CTRL + 1, &val8); + if (res) + return; + rtw_write8(Adapter, REG_RSV_CTRL + 1, (val8 & (~BIT(3)))); - val8 = rtw_read8(Adapter, REG_RSV_CTRL + 1); + + res = rtw_read8(Adapter, REG_RSV_CTRL + 1, &val8); + if (res) + return; + rtw_write8(Adapter, REG_RSV_CTRL + 1, val8 | BIT(3)); /* YJ,test add, 111207. For Power Consumption. */ - val8 = rtw_read8(Adapter, GPIO_IN); + res = rtw_read8(Adapter, GPIO_IN, &val8); + if (res) + return; + rtw_write8(Adapter, GPIO_OUT, val8); rtw_write8(Adapter, GPIO_IO_SEL, 0xFF);/* Reg0x46 */ - val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL); + res = rtw_read8(Adapter, REG_GPIO_IO_SEL, &val8); + if (res) + return; + rtw_write8(Adapter, REG_GPIO_IO_SEL, (val8 << 4)); - val8 = rtw_read8(Adapter, REG_GPIO_IO_SEL + 1); + res = rtw_read8(Adapter, REG_GPIO_IO_SEL + 1, &val8); + if (res) + return; + rtw_write8(Adapter, REG_GPIO_IO_SEL + 1, val8 | 0x0F);/* Reg0x43 */ rtw_write32(Adapter, REG_BB_PAD_CTRL, 0x00080808);/* set LNA ,TRSW,EX_PA Pin to output mode */ haldata->bMacPwrCtrlOn = false; @@ -830,9 +888,13 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) struct eeprom_priv *eeprom = &Adapter->eeprompriv; struct led_priv *ledpriv = &Adapter->ledpriv; u8 eeValue; + int res; /* check system boot selection */ - eeValue = rtw_read8(Adapter, REG_9346CR); + res = rtw_read8(Adapter, REG_9346CR, &eeValue); + if (res) + return; + eeprom->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM); eeprom->bautoload_fail_flag = !(eeValue & EEPROM_EN); @@ -887,12 +949,21 @@ static void hw_var_set_opmode(struct adapter *Adapter, u8 *val) { u8 val8; u8 mode = *((u8 *)val); + int res; /* disable Port0 TSF update */ - rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) | BIT(4)); + res = rtw_read8(Adapter, REG_BCN_CTRL, &val8); + if (res) + return; + + rtw_write8(Adapter, REG_BCN_CTRL, val8 | BIT(4)); /* set net_type */ - val8 = rtw_read8(Adapter, MSR) & 0x0c; + res = rtw_read8(Adapter, MSR, &val8); + if (res) + return; + + val8 &= 0x0c; val8 |= mode; rtw_write8(Adapter, MSR, val8); @@ -927,14 +998,22 @@ static void hw_var_set_opmode(struct adapter *Adapter, u8 *val) rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0)); /* BIT(3) - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 */ - rtw_write8(Adapter, REG_MBID_NUM, rtw_read8(Adapter, REG_MBID_NUM) | BIT(3) | BIT(4)); + res = rtw_read8(Adapter, REG_MBID_NUM, &val8); + if (res) + return; + + rtw_write8(Adapter, REG_MBID_NUM, val8 | BIT(3) | BIT(4)); /* enable BCN0 Function for if1 */ /* don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) */ rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP | EN_BCN_FUNCTION | BIT(1))); /* dis BCN1 ATIM WND if if2 is station */ - rtw_write8(Adapter, REG_BCN_CTRL_1, rtw_read8(Adapter, REG_BCN_CTRL_1) | BIT(0)); + res = rtw_read8(Adapter, REG_BCN_CTRL_1, &val8); + if (res) + return; + + rtw_write8(Adapter, REG_BCN_CTRL_1, val8 | BIT(0)); } } @@ -943,6 +1022,8 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) struct hal_data_8188e *haldata = &Adapter->haldata; struct dm_priv *pdmpriv = &haldata->dmpriv; struct odm_dm_struct *podmpriv = &haldata->odmpriv; + u8 reg; + int res; switch (variable) { case HW_VAR_SET_OPMODE: @@ -970,7 +1051,11 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) /* Set RRSR rate table. */ rtw_write8(Adapter, REG_RRSR, BrateCfg & 0xff); rtw_write8(Adapter, REG_RRSR + 1, (BrateCfg >> 8) & 0xff); - rtw_write8(Adapter, REG_RRSR + 2, rtw_read8(Adapter, REG_RRSR + 2) & 0xf0); + res = rtw_read8(Adapter, REG_RRSR + 2, ®); + if (res) + return; + + rtw_write8(Adapter, REG_RRSR + 2, reg & 0xf0); /* Set RTS initial rate */ while (BrateCfg > 0x1) { @@ -994,13 +1079,21 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) StopTxBeacon(Adapter); /* disable related TSF function */ - rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) & (~BIT(3))); + res = rtw_read8(Adapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(Adapter, REG_BCN_CTRL, reg & (~BIT(3))); rtw_write32(Adapter, REG_TSFTR, tsf); rtw_write32(Adapter, REG_TSFTR + 4, tsf >> 32); /* enable related TSF function */ - rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) | BIT(3)); + res = rtw_read8(Adapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(Adapter, REG_BCN_CTRL, reg | BIT(3)); if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) ResumeTxBeacon(Adapter); @@ -1016,7 +1109,11 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) rtw_write16(Adapter, REG_RXFLTMAP2, 0x00); /* disable update TSF */ - rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) | BIT(4)); + res = rtw_read8(Adapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(Adapter, REG_BCN_CTRL, reg | BIT(4)); } else { /* sitesurvey done */ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -1027,11 +1124,19 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); /* enable update TSF */ - rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) & (~BIT(4))); + res = rtw_read8(Adapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(Adapter, REG_BCN_CTRL, reg & (~BIT(4))); } else if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); /* enable update TSF */ - rtw_write8(Adapter, REG_BCN_CTRL, rtw_read8(Adapter, REG_BCN_CTRL) & (~BIT(4))); + res = rtw_read8(Adapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(Adapter, REG_BCN_CTRL, reg & (~BIT(4))); } rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR) | RCR_CBSSID_BCN); } @@ -1166,6 +1271,8 @@ void SetBeaconRelatedRegisters8188EUsb(struct adapter *adapt) struct mlme_ext_priv *pmlmeext = &adapt->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; u32 bcn_ctrl_reg = REG_BCN_CTRL; + int res; + u8 reg; /* reset TSF, enable update TSF, correcting TSF On Beacon */ /* BCN interval */ @@ -1191,7 +1298,11 @@ void SetBeaconRelatedRegisters8188EUsb(struct adapter *adapt) ResumeTxBeacon(adapt); - rtw_write8(adapt, bcn_ctrl_reg, rtw_read8(adapt, bcn_ctrl_reg) | BIT(1)); + res = rtw_read8(adapt, bcn_ctrl_reg, ®); + if (res) + return; + + rtw_write8(adapt, bcn_ctrl_reg, reg | BIT(1)); } void rtl8188eu_init_default_value(struct adapter *adapt) diff --git a/drivers/staging/r8188eu/hal/usb_ops_linux.c b/drivers/staging/r8188eu/hal/usb_ops_linux.c index d5e674542a78..f399a7fd8b97 100644 --- a/drivers/staging/r8188eu/hal/usb_ops_linux.c +++ b/drivers/staging/r8188eu/hal/usb_ops_linux.c @@ -94,16 +94,13 @@ static int usb_write(struct intf_hdl *intf, u16 value, void *data, u8 size) return status; } -u8 rtw_read8(struct adapter *adapter, u32 addr) +int __must_check rtw_read8(struct adapter *adapter, u32 addr, u8 *data) { struct io_priv *io_priv = &adapter->iopriv; struct intf_hdl *intf = &io_priv->intf; u16 value = addr & 0xffff; - u8 data; - usb_read(intf, value, &data, 1); - - return data; + return usb_read(intf, value, data, 1); } u16 rtw_read16(struct adapter *adapter, u32 addr) diff --git a/drivers/staging/r8188eu/include/rtw_io.h b/drivers/staging/r8188eu/include/rtw_io.h index 0e390eda5b4d..c03646e9658d 100644 --- a/drivers/staging/r8188eu/include/rtw_io.h +++ b/drivers/staging/r8188eu/include/rtw_io.h @@ -220,7 +220,7 @@ void unregister_intf_hdl(struct intf_hdl *pintfhdl); void _rtw_attrib_read(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); void _rtw_attrib_write(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); -u8 rtw_read8(struct adapter *adapter, u32 addr); +int __must_check rtw_read8(struct adapter *adapter, u32 addr, u8 *data); u16 rtw_read16(struct adapter *adapter, u32 addr); u32 rtw_read32(struct adapter *adapter, u32 addr); void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); diff --git a/drivers/staging/r8188eu/os_dep/ioctl_linux.c b/drivers/staging/r8188eu/os_dep/ioctl_linux.c index 1b09462ca908..168f4ec99a03 100644 --- a/drivers/staging/r8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/r8188eu/os_dep/ioctl_linux.c @@ -3178,6 +3178,7 @@ static void rtw_set_dynamic_functions(struct adapter *adapter, u8 dm_func) { struct hal_data_8188e *haldata = &adapter->haldata; struct odm_dm_struct *odmpriv = &haldata->odmpriv; + int res; switch (dm_func) { case 0: @@ -3193,7 +3194,9 @@ static void rtw_set_dynamic_functions(struct adapter *adapter, u8 dm_func) if (!(odmpriv->SupportAbility & DYNAMIC_BB_DIG)) { struct rtw_dig *digtable = &odmpriv->DM_DigTable; - digtable->CurIGValue = rtw_read8(adapter, 0xc50); + res = rtw_read8(adapter, 0xc50, &digtable->CurIGValue); + (void)res; + /* FIXME: return an error to caller */ } odmpriv->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE; break; @@ -3329,8 +3332,9 @@ static int rtw_dbg_port(struct net_device *dev, u16 reg = arg; u16 start_value = 0; u32 write_num = extra_arg; - int i; + int i, res; struct xmit_frame *xmit_frame; + u8 val8; xmit_frame = rtw_IOL_accquire_xmit_frame(padapter); if (!xmit_frame) { @@ -3343,7 +3347,8 @@ static int rtw_dbg_port(struct net_device *dev, if (rtl8188e_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0) != _SUCCESS) ret = -EPERM; - rtw_read8(padapter, reg); + /* FIXME: is this read necessary? */ + res = rtw_read8(padapter, reg, &val8); } break; From fed9e604eeb6150847d9757f6b056c12912d468b Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Tue, 7 Jun 2022 22:26:12 +0300 Subject: [PATCH 0226/1436] staging: r8188eu: add error handling of rtw_read16 rtw_read16() reads data from device via USB API which may fail. In case of any failure previous code returned stack data to callers, which is wrong. Fix it by changing rtw_read16() prototype and prevent caller from touching random stack data Signed-off-by: Pavel Skripkin Link: https://lore.kernel.org/r/06b45afda048d0aeddeed983c2318680fe6265f5.1654629778.git.paskripkin@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../staging/r8188eu/hal/rtl8188e_hal_init.c | 29 +++++++++++++++---- drivers/staging/r8188eu/hal/rtl8188e_phycfg.c | 8 +++-- drivers/staging/r8188eu/hal/usb_halinit.c | 27 ++++++++++++++--- drivers/staging/r8188eu/hal/usb_ops_linux.c | 13 ++++++--- drivers/staging/r8188eu/include/rtw_io.h | 2 +- drivers/staging/r8188eu/os_dep/ioctl_linux.c | 9 ++++-- drivers/staging/r8188eu/os_dep/os_intfs.c | 6 +++- 7 files changed, 73 insertions(+), 21 deletions(-) diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index e67ecbd1ba79..8215ed8b506d 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -200,7 +200,8 @@ exit: kfree(eFuseWord); } -static void efuse_read_phymap_from_txpktbuf( +/* FIXME: add error handling in callers */ +static int efuse_read_phymap_from_txpktbuf( struct adapter *adapter, int bcnhead, /* beacon head, where FW store len(2-byte) and efuse physical map. */ u8 *content, /* buffer to store efuse physical map */ @@ -219,7 +220,7 @@ static void efuse_read_phymap_from_txpktbuf( if (bcnhead < 0) { /* if not valid */ res = rtw_read8(adapter, REG_TDECTRL + 1, ®); if (res) - return; + return res; bcnhead = reg; } @@ -249,11 +250,15 @@ static void efuse_read_phymap_from_txpktbuf( hi32 = cpu_to_le32(rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H)); if (i == 0) { + u16 reg; + /* Although lenc is only used in a debug statement, * do not remove it as the rtw_read16() call consumes * 2 bytes from the EEPROM source. */ - rtw_read16(adapter, REG_PKTBUF_DBG_DATA_L); + res = rtw_read16(adapter, REG_PKTBUF_DBG_DATA_L, ®); + if (res) + return res; len = le32_to_cpu(lo32) & 0x0000ffff; @@ -280,6 +285,8 @@ static void efuse_read_phymap_from_txpktbuf( } rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, DISABLE_TRXPKT_BUF_ACCESS); *size = count; + + return 0; } static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset, u16 size_byte, u8 *logical_map) @@ -355,25 +362,35 @@ exit: void rtl8188e_EfusePowerSwitch(struct adapter *pAdapter, u8 PwrState) { u16 tmpV16; + int res; if (PwrState) { rtw_write8(pAdapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON); /* 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid */ - tmpV16 = rtw_read16(pAdapter, REG_SYS_ISO_CTRL); + res = rtw_read16(pAdapter, REG_SYS_ISO_CTRL, &tmpV16); + if (res) + return; + if (!(tmpV16 & PWC_EV12V)) { tmpV16 |= PWC_EV12V; rtw_write16(pAdapter, REG_SYS_ISO_CTRL, tmpV16); } /* Reset: 0x0000h[28], default valid */ - tmpV16 = rtw_read16(pAdapter, REG_SYS_FUNC_EN); + res = rtw_read16(pAdapter, REG_SYS_FUNC_EN, &tmpV16); + if (res) + return; + if (!(tmpV16 & FEN_ELDR)) { tmpV16 |= FEN_ELDR; rtw_write16(pAdapter, REG_SYS_FUNC_EN, tmpV16); } /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */ - tmpV16 = rtw_read16(pAdapter, REG_SYS_CLKR); + res = rtw_read16(pAdapter, REG_SYS_CLKR, &tmpV16); + if (res) + return; + if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) { tmpV16 |= (LOADER_CLK_EN | ANA8M); rtw_write16(pAdapter, REG_SYS_CLKR, tmpV16); diff --git a/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c b/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c index 985339a974fc..298c3d9bc7be 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c @@ -484,13 +484,17 @@ PHY_BBConfig8188E( { int rtStatus = _SUCCESS; struct hal_data_8188e *pHalData = &Adapter->haldata; - u32 RegVal; + u16 RegVal; u8 CrystalCap; + int res; phy_InitBBRFRegisterDefinition(Adapter); /* Enable BB and RF */ - RegVal = rtw_read16(Adapter, REG_SYS_FUNC_EN); + res = rtw_read16(Adapter, REG_SYS_FUNC_EN, &RegVal); + if (res) + return _FAIL; + rtw_write16(Adapter, REG_SYS_FUNC_EN, (u16)(RegVal | BIT(13) | BIT(0) | BIT(1))); /* 20090923 Joseph: Advised by Steven and Jenyu. Power sequence before init RF. */ diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 5540d5ad07d3..9a7d22960be8 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -52,6 +52,8 @@ void rtl8188eu_interface_configure(struct adapter *adapt) u32 rtl8188eu_InitPowerOn(struct adapter *adapt) { u16 value16; + int res; + /* HW Power on sequence */ struct hal_data_8188e *haldata = &adapt->haldata; if (haldata->bMacPwrCtrlOn) @@ -65,7 +67,10 @@ u32 rtl8188eu_InitPowerOn(struct adapter *adapt) rtw_write16(adapt, REG_CR, 0x00); /* suggseted by zhouzhou, by page, 20111230 */ /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */ - value16 = rtw_read16(adapt, REG_CR); + res = rtw_read16(adapt, REG_CR, &value16); + if (res) + return _FAIL; + value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN | PROTOCOL_EN | SCHEDULE_EN | ENSEC | CALTMR_EN); /* for SDIO - Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy. Added by tynli. 2011.08.31. */ @@ -166,7 +171,14 @@ static void _InitNormalChipRegPriority(struct adapter *Adapter, u16 beQ, u16 bkQ, u16 viQ, u16 voQ, u16 mgtQ, u16 hiQ) { - u16 value16 = (rtw_read16(Adapter, REG_TRXDMA_CTRL) & 0x7); + u16 value16; + int res; + + res = rtw_read16(Adapter, REG_TRXDMA_CTRL, &value16); + if (res) + return; + + value16 &= 0x7; value16 |= _TXDMA_BEQ_MAP(beQ) | _TXDMA_BKQ_MAP(bkQ) | _TXDMA_VIQ_MAP(viQ) | _TXDMA_VOQ_MAP(voQ) | @@ -640,7 +652,10 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter) /* Hw bug which Hw initials RxFF boundary size to a value which is larger than the real Rx buffer size in 88E. */ /* */ /* Enable MACTXEN/MACRXEN block */ - value16 = rtw_read16(Adapter, REG_CR); + res = rtw_read16(Adapter, REG_CR, &value16); + if (res) + return _FAIL; + value16 |= (MACTXEN | MACRXEN); rtw_write8(Adapter, REG_CR, value16); @@ -713,7 +728,11 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter) rtw_write16(Adapter, REG_TX_RPT_TIME, 0x3DF0); /* enable tx DMA to drop the redundate data of packet */ - rtw_write16(Adapter, REG_TXDMA_OFFSET_CHK, (rtw_read16(Adapter, REG_TXDMA_OFFSET_CHK) | DROP_DATA_EN)); + res = rtw_read16(Adapter, REG_TXDMA_OFFSET_CHK, &value16); + if (res) + return _FAIL; + + rtw_write16(Adapter, REG_TXDMA_OFFSET_CHK, (value16 | DROP_DATA_EN)); /* 2010/08/26 MH Merge from 8192CE. */ if (pwrctrlpriv->rf_pwrstate == rf_on) { diff --git a/drivers/staging/r8188eu/hal/usb_ops_linux.c b/drivers/staging/r8188eu/hal/usb_ops_linux.c index f399a7fd8b97..7d62f1f3d26e 100644 --- a/drivers/staging/r8188eu/hal/usb_ops_linux.c +++ b/drivers/staging/r8188eu/hal/usb_ops_linux.c @@ -103,16 +103,21 @@ int __must_check rtw_read8(struct adapter *adapter, u32 addr, u8 *data) return usb_read(intf, value, data, 1); } -u16 rtw_read16(struct adapter *adapter, u32 addr) +int __must_check rtw_read16(struct adapter *adapter, u32 addr, u16 *data) { struct io_priv *io_priv = &adapter->iopriv; struct intf_hdl *intf = &io_priv->intf; u16 value = addr & 0xffff; - __le16 data; + __le16 le_data; + int res; - usb_read(intf, value, &data, 2); + res = usb_read(intf, value, &le_data, 2); + if (res) + return res; - return le16_to_cpu(data); + *data = le16_to_cpu(le_data); + + return 0; } u32 rtw_read32(struct adapter *adapter, u32 addr) diff --git a/drivers/staging/r8188eu/include/rtw_io.h b/drivers/staging/r8188eu/include/rtw_io.h index c03646e9658d..d9db2c1c7a67 100644 --- a/drivers/staging/r8188eu/include/rtw_io.h +++ b/drivers/staging/r8188eu/include/rtw_io.h @@ -221,7 +221,7 @@ void _rtw_attrib_read(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); void _rtw_attrib_write(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); int __must_check rtw_read8(struct adapter *adapter, u32 addr, u8 *data); -u16 rtw_read16(struct adapter *adapter, u32 addr); +int __must_check rtw_read16(struct adapter *adapter, u32 addr, u16 *data); u32 rtw_read32(struct adapter *adapter, u32 addr); void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); u32 rtw_read_port(struct adapter *adapter, u8 *pmem); diff --git a/drivers/staging/r8188eu/os_dep/ioctl_linux.c b/drivers/staging/r8188eu/os_dep/ioctl_linux.c index 168f4ec99a03..30aa2a2c0ade 100644 --- a/drivers/staging/r8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/r8188eu/os_dep/ioctl_linux.c @@ -3349,6 +3349,7 @@ static int rtw_dbg_port(struct net_device *dev, /* FIXME: is this read necessary? */ res = rtw_read8(padapter, reg, &val8); + (void)res; } break; @@ -3357,8 +3358,8 @@ static int rtw_dbg_port(struct net_device *dev, u16 reg = arg; u16 start_value = 200; u32 write_num = extra_arg; - - int i; + u16 val16; + int i, res; struct xmit_frame *xmit_frame; xmit_frame = rtw_IOL_accquire_xmit_frame(padapter); @@ -3372,7 +3373,9 @@ static int rtw_dbg_port(struct net_device *dev, if (rtl8188e_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0) != _SUCCESS) ret = -EPERM; - rtw_read16(padapter, reg); + /* FIXME: is this read necessary? */ + res = rtw_read16(padapter, reg, &val16); + (void)res; } break; case 0x08: /* continuous write dword test */ diff --git a/drivers/staging/r8188eu/os_dep/os_intfs.c b/drivers/staging/r8188eu/os_dep/os_intfs.c index 891c85b088ca..d9325ef6ac28 100644 --- a/drivers/staging/r8188eu/os_dep/os_intfs.c +++ b/drivers/staging/r8188eu/os_dep/os_intfs.c @@ -740,12 +740,16 @@ static void rtw_fifo_cleanup(struct adapter *adapter) { struct pwrctrl_priv *pwrpriv = &adapter->pwrctrlpriv; u8 trycnt = 100; + int res; /* pause tx */ rtw_write8(adapter, REG_TXPAUSE, 0xff); /* keep sn */ - adapter->xmitpriv.nqos_ssn = rtw_read16(adapter, REG_NQOS_SEQ); + /* FIXME: return an error to caller */ + res = rtw_read16(adapter, REG_NQOS_SEQ, &adapter->xmitpriv.nqos_ssn); + if (res) + return; if (!pwrpriv->bkeepfwalive) { /* RX DMA stop */ From b9c5e272062708680d47df433bfbfe5299ad1a63 Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Tue, 7 Jun 2022 22:26:21 +0300 Subject: [PATCH 0227/1436] staging: r8188eu: add error handling of rtw_read32 rtw_read32() reads data from device via USB API which may fail. In case of any failure previous code returned stack data to callers, which is wrong. Fix it by changing rtw_read32() prototype and prevent caller from touching random stack data Signed-off-by: Pavel Skripkin Link: https://lore.kernel.org/r/583c3d21c46066275e4fc8da5ba4fd0e3679335b.1654629778.git.paskripkin@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_cmd.c | 15 +++++- drivers/staging/r8188eu/core/rtw_efuse.c | 20 ++++--- drivers/staging/r8188eu/core/rtw_fw.c | 16 ++++-- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 14 ++++- drivers/staging/r8188eu/core/rtw_pwrctrl.c | 9 +++- .../r8188eu/hal/Hal8188ERateAdaptive.c | 21 ++++++-- drivers/staging/r8188eu/hal/HalPhyRf_8188e.c | 3 +- .../staging/r8188eu/hal/rtl8188e_hal_init.c | 40 +++++++++----- drivers/staging/r8188eu/hal/rtl8188e_phycfg.c | 12 ++++- drivers/staging/r8188eu/hal/usb_halinit.c | 53 ++++++++++++++++--- drivers/staging/r8188eu/hal/usb_ops_linux.c | 13 +++-- drivers/staging/r8188eu/include/rtw_io.h | 2 +- drivers/staging/r8188eu/os_dep/ioctl_linux.c | 27 ++++++++-- drivers/staging/r8188eu/os_dep/os_intfs.c | 13 ++++- 14 files changed, 202 insertions(+), 56 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_cmd.c b/drivers/staging/r8188eu/core/rtw_cmd.c index 06523d91939a..5b6a891b5d67 100644 --- a/drivers/staging/r8188eu/core/rtw_cmd.c +++ b/drivers/staging/r8188eu/core/rtw_cmd.c @@ -898,8 +898,12 @@ static void traffic_status_watchdog(struct adapter *padapter) static void rtl8188e_sreset_xmit_status_check(struct adapter *padapter) { u32 txdma_status; + int res; + + res = rtw_read32(padapter, REG_TXDMA_STATUS, &txdma_status); + if (res) + return; - txdma_status = rtw_read32(padapter, REG_TXDMA_STATUS); if (txdma_status != 0x00) rtw_write32(padapter, REG_TXDMA_STATUS, txdma_status); /* total xmit irp = 4 */ @@ -1177,7 +1181,14 @@ exit: static bool rtw_is_hi_queue_empty(struct adapter *adapter) { - return (rtw_read32(adapter, REG_HGQ_INFORMATION) & 0x0000ff00) == 0; + int res; + u32 reg; + + res = rtw_read32(adapter, REG_HGQ_INFORMATION, ®); + if (res) + return false; + + return (reg & 0x0000ff00) == 0; } static void rtw_chk_hi_queue_hdl(struct adapter *padapter) diff --git a/drivers/staging/r8188eu/core/rtw_efuse.c b/drivers/staging/r8188eu/core/rtw_efuse.c index a2691c7f96f6..8005ed8d3a20 100644 --- a/drivers/staging/r8188eu/core/rtw_efuse.c +++ b/drivers/staging/r8188eu/core/rtw_efuse.c @@ -46,11 +46,17 @@ ReadEFuseByte( rtw_write8(Adapter, EFUSE_CTRL + 3, (readbyte & 0x7f)); /* Check bit 32 read-ready */ - retry = 0; - value32 = rtw_read32(Adapter, EFUSE_CTRL); - while (!(((value32 >> 24) & 0xff) & 0x80) && (retry < 10000)) { - value32 = rtw_read32(Adapter, EFUSE_CTRL); - retry++; + res = rtw_read32(Adapter, EFUSE_CTRL, &value32); + if (res) + return; + + for (retry = 0; retry < 10000; retry++) { + res = rtw_read32(Adapter, EFUSE_CTRL, &value32); + if (res) + continue; + + if (((value32 >> 24) & 0xff) & 0x80) + break; } /* 20100205 Joseph: Add delay suggested by SD1 Victor. */ @@ -58,7 +64,9 @@ ReadEFuseByte( /* Designer says that there shall be some delay after ready bit is set, or the */ /* result will always stay on last data we read. */ udelay(50); - value32 = rtw_read32(Adapter, EFUSE_CTRL); + res = rtw_read32(Adapter, EFUSE_CTRL, &value32); + if (res) + return; *pbuf = (u8)(value32 & 0xff); diff --git a/drivers/staging/r8188eu/core/rtw_fw.c b/drivers/staging/r8188eu/core/rtw_fw.c index e1fc883a5f7e..95534f9c7a0f 100644 --- a/drivers/staging/r8188eu/core/rtw_fw.c +++ b/drivers/staging/r8188eu/core/rtw_fw.c @@ -194,10 +194,14 @@ static int fw_free_to_go(struct adapter *padapter) { u32 counter = 0; u32 value32; + int res; /* polling CheckSum report */ do { - value32 = rtw_read32(padapter, REG_MCUFWDL); + res = rtw_read32(padapter, REG_MCUFWDL, &value32); + if (res) + continue; + if (value32 & FWDL_CHKSUM_RPT) break; } while (counter++ < POLLING_READY_TIMEOUT_COUNT); @@ -205,7 +209,10 @@ static int fw_free_to_go(struct adapter *padapter) if (counter >= POLLING_READY_TIMEOUT_COUNT) return _FAIL; - value32 = rtw_read32(padapter, REG_MCUFWDL); + res = rtw_read32(padapter, REG_MCUFWDL, &value32); + if (res) + return _FAIL; + value32 |= MCUFWDL_RDY; value32 &= ~WINTINI_RDY; rtw_write32(padapter, REG_MCUFWDL, value32); @@ -215,9 +222,10 @@ static int fw_free_to_go(struct adapter *padapter) /* polling for FW ready */ counter = 0; do { - value32 = rtw_read32(padapter, REG_MCUFWDL); - if (value32 & WINTINI_RDY) + res = rtw_read32(padapter, REG_MCUFWDL, &value32); + if (!res && value32 & WINTINI_RDY) return _SUCCESS; + udelay(5); } while (counter++ < POLLING_READY_TIMEOUT_COUNT); diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 2eb9d85e5553..37b1608ed2d1 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -6000,6 +6000,7 @@ static void mlme_join(struct adapter *adapter, int type) { struct mlme_priv *mlmepriv = &adapter->mlmepriv; u8 retry_limit = 0x30, reg; + u32 reg32; int res; switch (type) { @@ -6008,8 +6009,12 @@ static void mlme_join(struct adapter *adapter, int type) /* enable to rx data frame, accept all data frame */ rtw_write16(adapter, REG_RXFLTMAP2, 0xFFFF); + res = rtw_read32(adapter, REG_RCR, ®32); + if (res) + return; + rtw_write32(adapter, REG_RCR, - rtw_read32(adapter, REG_RCR) | RCR_CBSSID_DATA | RCR_CBSSID_BCN); + reg32 | RCR_CBSSID_DATA | RCR_CBSSID_BCN); if (check_fwstate(mlmepriv, WIFI_STATION_STATE)) { retry_limit = 48; @@ -6822,9 +6827,14 @@ static u8 chk_ap_is_alive(struct sta_info *psta) static int rtl8188e_sreset_linked_status_check(struct adapter *padapter) { - u32 rx_dma_status = rtw_read32(padapter, REG_RXDMA_STATUS); + u32 rx_dma_status; + int res; u8 reg; + res = rtw_read32(padapter, REG_RXDMA_STATUS, &rx_dma_status); + if (res) + return res; + if (rx_dma_status != 0x00) rtw_write32(padapter, REG_RXDMA_STATUS, rx_dma_status); diff --git a/drivers/staging/r8188eu/core/rtw_pwrctrl.c b/drivers/staging/r8188eu/core/rtw_pwrctrl.c index 7b816b824947..45e85b593665 100644 --- a/drivers/staging/r8188eu/core/rtw_pwrctrl.c +++ b/drivers/staging/r8188eu/core/rtw_pwrctrl.c @@ -229,6 +229,9 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a static bool lps_rf_on(struct adapter *adapter) { + int res; + u32 reg; + /* When we halt NIC, we should check if FW LPS is leave. */ if (adapter->pwrctrlpriv.rf_pwrstate == rf_off) { /* If it is in HW/SW Radio OFF or IPS state, we do not check Fw LPS Leave, */ @@ -236,7 +239,11 @@ static bool lps_rf_on(struct adapter *adapter) return true; } - if (rtw_read32(adapter, REG_RCR) & 0x00070000) + res = rtw_read32(adapter, REG_RCR, ®); + if (res) + return false; + + if (reg & 0x00070000) return false; return true; diff --git a/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c b/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c index 57e8f5573846..3cefdf90d6e0 100644 --- a/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c +++ b/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c @@ -279,6 +279,7 @@ static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_inf { /* Wilson 2011/10/26 */ u32 MaskFromReg; s8 i; + int res; switch (pRaInfo->RateID) { case RATR_INX_WIRELESS_NGB: @@ -303,19 +304,31 @@ static int odm_ARFBRefresh_8188E(struct odm_dm_struct *dm_odm, struct odm_ra_inf pRaInfo->RAUseRate = (pRaInfo->RateMask) & 0x0000000d; break; case 12: - MaskFromReg = rtw_read32(dm_odm->Adapter, REG_ARFR0); + res = rtw_read32(dm_odm->Adapter, REG_ARFR0, &MaskFromReg); + if (res) + return res; + pRaInfo->RAUseRate = (pRaInfo->RateMask) & MaskFromReg; break; case 13: - MaskFromReg = rtw_read32(dm_odm->Adapter, REG_ARFR1); + res = rtw_read32(dm_odm->Adapter, REG_ARFR1, &MaskFromReg); + if (res) + return res; + pRaInfo->RAUseRate = (pRaInfo->RateMask) & MaskFromReg; break; case 14: - MaskFromReg = rtw_read32(dm_odm->Adapter, REG_ARFR2); + res = rtw_read32(dm_odm->Adapter, REG_ARFR2, &MaskFromReg); + if (res) + return res; + pRaInfo->RAUseRate = (pRaInfo->RateMask) & MaskFromReg; break; case 15: - MaskFromReg = rtw_read32(dm_odm->Adapter, REG_ARFR3); + res = rtw_read32(dm_odm->Adapter, REG_ARFR3, &MaskFromReg); + if (res) + return res; + pRaInfo->RAUseRate = (pRaInfo->RateMask) & MaskFromReg; break; default: diff --git a/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c b/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c index a5b7980dfcee..525deab10820 100644 --- a/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c +++ b/drivers/staging/r8188eu/hal/HalPhyRf_8188e.c @@ -483,7 +483,8 @@ static void _PHY_SaveMACRegisters( MACBackup[i] = reg; } - MACBackup[i] = rtw_read32(adapt, MACReg[i]); + res = rtw_read32(adapt, MACReg[i], MACBackup + i); + (void)res; } static void reload_adda_reg(struct adapter *adapt, u32 *ADDAReg, u32 *ADDABackup, u32 RegiesterNum) diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index 8215ed8b506d..5549e7be334a 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -216,6 +216,7 @@ static int efuse_read_phymap_from_txpktbuf( u16 limit = *size; u8 reg; u8 *pos = content; + u32 reg32; if (bcnhead < 0) { /* if not valid */ res = rtw_read8(adapter, REG_TDECTRL + 1, ®); @@ -246,8 +247,17 @@ static int efuse_read_phymap_from_txpktbuf( } while (time_before(jiffies, timeout)); /* data from EEPROM needs to be in LE */ - lo32 = cpu_to_le32(rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L)); - hi32 = cpu_to_le32(rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H)); + res = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_L, ®32); + if (res) + return res; + + lo32 = cpu_to_le32(reg32); + + res = rtw_read32(adapter, REG_PKTBUF_DBG_DATA_H, ®32); + if (res) + return res; + + hi32 = cpu_to_le32(reg32); if (i == 0) { u16 reg; @@ -548,8 +558,12 @@ void rtl8188e_read_chip_version(struct adapter *padapter) u32 value32; struct HAL_VERSION ChipVersion; struct hal_data_8188e *pHalData = &padapter->haldata; + int res; + + res = rtw_read32(padapter, REG_SYS_CFG, &value32); + if (res) + return; - value32 = rtw_read32(padapter, REG_SYS_CFG); ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP); ChipVersion.VendorType = ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC); @@ -596,26 +610,24 @@ void hal_notch_filter_8188e(struct adapter *adapter, bool enable) /* */ static s32 _LLTWrite(struct adapter *padapter, u32 address, u32 data) { - s32 status = _SUCCESS; - s32 count = 0; + s32 count; u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS); u16 LLTReg = REG_LLT_INIT; + int res; rtw_write32(padapter, LLTReg, value); /* polling */ - do { - value = rtw_read32(padapter, LLTReg); + for (count = 0; count <= POLLING_LLT_THRESHOLD; count++) { + res = rtw_read32(padapter, LLTReg, &value); + if (res) + continue; + if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) break; + } - if (count > POLLING_LLT_THRESHOLD) { - status = _FAIL; - break; - } - } while (count++); - - return status; + return count > POLLING_LLT_THRESHOLD ? _FAIL : _SUCCESS; } s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy) diff --git a/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c b/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c index 298c3d9bc7be..dea6d915a1f4 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_phycfg.c @@ -56,8 +56,12 @@ rtl8188e_PHY_QueryBBReg( ) { u32 ReturnValue = 0, OriginalValue, BitShift; + int res; + + res = rtw_read32(Adapter, RegAddr, &OriginalValue); + if (res) + return 0; - OriginalValue = rtw_read32(Adapter, RegAddr); BitShift = phy_CalculateBitShift(BitMask); ReturnValue = (OriginalValue & BitMask) >> BitShift; return ReturnValue; @@ -84,9 +88,13 @@ rtl8188e_PHY_QueryBBReg( void rtl8188e_PHY_SetBBReg(struct adapter *Adapter, u32 RegAddr, u32 BitMask, u32 Data) { u32 OriginalValue, BitShift; + int res; if (BitMask != bMaskDWord) { /* if not "double word" write */ - OriginalValue = rtw_read32(Adapter, RegAddr); + res = rtw_read32(Adapter, RegAddr, &OriginalValue); + if (res) + return; + BitShift = phy_CalculateBitShift(BitMask); Data = ((OriginalValue & (~BitMask)) | (Data << BitShift)); } diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 9a7d22960be8..cb9b4bcc536a 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -297,8 +297,12 @@ static void _InitQueuePriority(struct adapter *Adapter) static void _InitNetworkType(struct adapter *Adapter) { u32 value32; + int res; + + res = rtw_read32(Adapter, REG_CR, &value32); + if (res) + return; - value32 = rtw_read32(Adapter, REG_CR); /* TODO: use the other function to set network type */ value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AP); @@ -338,9 +342,13 @@ static void _InitAdaptiveCtrl(struct adapter *Adapter) { u16 value16; u32 value32; + int res; /* Response Rate Set */ - value32 = rtw_read32(Adapter, REG_RRSR); + res = rtw_read32(Adapter, REG_RRSR, &value32); + if (res) + return; + value32 &= ~RATE_BITMAP_ALL; value32 |= RATE_RRSR_CCK_ONLY_1M; rtw_write32(Adapter, REG_RRSR, value32); @@ -409,11 +417,15 @@ static void _InitRetryFunction(struct adapter *Adapter) static void usb_AggSettingTxUpdate(struct adapter *Adapter) { u32 value32; + int res; if (Adapter->registrypriv.wifi_spec) return; - value32 = rtw_read32(Adapter, REG_TDECTRL); + res = rtw_read32(Adapter, REG_TDECTRL, &value32); + if (res) + return; + value32 = value32 & ~(BLK_DESC_NUM_MASK << BLK_DESC_NUM_SHIFT); value32 |= ((USB_TXAGG_DESC_NUM & BLK_DESC_NUM_MASK) << BLK_DESC_NUM_SHIFT); @@ -521,11 +533,17 @@ static void _BBTurnOnBlock(struct adapter *Adapter) static void _InitAntenna_Selection(struct adapter *Adapter) { struct hal_data_8188e *haldata = &Adapter->haldata; + int res; + u32 reg; if (haldata->AntDivCfg == 0) return; - rtw_write32(Adapter, REG_LEDCFG0, rtw_read32(Adapter, REG_LEDCFG0) | BIT(23)); + res = rtw_read32(Adapter, REG_LEDCFG0, ®); + if (res) + return; + + rtw_write32(Adapter, REG_LEDCFG0, reg | BIT(23)); rtl8188e_PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter, BIT(13), 0x01); if (rtl8188e_PHY_QueryBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, 0x300) == Antenna_A) @@ -555,6 +573,7 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter) struct hal_data_8188e *haldata = &Adapter->haldata; struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv; struct registry_priv *pregistrypriv = &Adapter->registrypriv; + u32 reg; if (Adapter->pwrctrlpriv.bkeepfwalive) { if (haldata->odmpriv.RFCalibrateInfo.bIQKInitialized) { @@ -752,7 +771,11 @@ u32 rtl8188eu_hal_init(struct adapter *Adapter) rtw_write8(Adapter, REG_USB_HRPWM, 0); /* ack for xmit mgmt frames. */ - rtw_write32(Adapter, REG_FWHW_TXQ_CTRL, rtw_read32(Adapter, REG_FWHW_TXQ_CTRL) | BIT(12)); + res = rtw_read32(Adapter, REG_FWHW_TXQ_CTRL, ®); + if (res) + return _FAIL; + + rtw_write32(Adapter, REG_FWHW_TXQ_CTRL, reg | BIT(12)); exit: return status; @@ -1121,7 +1144,12 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) case HW_VAR_MLME_SITESURVEY: if (*((u8 *)val)) { /* under sitesurvey */ /* config RCR to receive different BSSID & not to receive data frame */ - u32 v = rtw_read32(Adapter, REG_RCR); + u32 v; + + res = rtw_read32(Adapter, REG_RCR, &v); + if (res) + return; + v &= ~(RCR_CBSSID_BCN); rtw_write32(Adapter, REG_RCR, v); /* reject all data frame */ @@ -1136,6 +1164,7 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) } else { /* sitesurvey done */ struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u32 reg32; if ((is_client_associated_to_ap(Adapter)) || ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) { @@ -1157,7 +1186,12 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) rtw_write8(Adapter, REG_BCN_CTRL, reg & (~BIT(4))); } - rtw_write32(Adapter, REG_RCR, rtw_read32(Adapter, REG_RCR) | RCR_CBSSID_BCN); + + res = rtw_read32(Adapter, REG_RCR, ®32); + if (res) + return; + + rtw_write32(Adapter, REG_RCR, reg32 | RCR_CBSSID_BCN); } break; case HW_VAR_DM_FLAG: @@ -1302,7 +1336,10 @@ void SetBeaconRelatedRegisters8188EUsb(struct adapter *adapt) rtw_write8(adapt, REG_SLOT, 0x09); - value32 = rtw_read32(adapt, REG_TCR); + res = rtw_read32(adapt, REG_TCR, &value32); + if (res) + return; + value32 &= ~TSFRST; rtw_write32(adapt, REG_TCR, value32); diff --git a/drivers/staging/r8188eu/hal/usb_ops_linux.c b/drivers/staging/r8188eu/hal/usb_ops_linux.c index 7d62f1f3d26e..c1a4d023f627 100644 --- a/drivers/staging/r8188eu/hal/usb_ops_linux.c +++ b/drivers/staging/r8188eu/hal/usb_ops_linux.c @@ -120,16 +120,21 @@ int __must_check rtw_read16(struct adapter *adapter, u32 addr, u16 *data) return 0; } -u32 rtw_read32(struct adapter *adapter, u32 addr) +int __must_check rtw_read32(struct adapter *adapter, u32 addr, u32 *data) { struct io_priv *io_priv = &adapter->iopriv; struct intf_hdl *intf = &io_priv->intf; u16 value = addr & 0xffff; - __le32 data; + __le32 le_data; + int res; - usb_read(intf, value, &data, 4); + res = usb_read(intf, value, &le_data, 4); + if (res) + return res; - return le32_to_cpu(data); + *data = le32_to_cpu(le_data); + + return 0; } int rtw_write8(struct adapter *adapter, u32 addr, u8 val) diff --git a/drivers/staging/r8188eu/include/rtw_io.h b/drivers/staging/r8188eu/include/rtw_io.h index d9db2c1c7a67..925c7967ac04 100644 --- a/drivers/staging/r8188eu/include/rtw_io.h +++ b/drivers/staging/r8188eu/include/rtw_io.h @@ -222,7 +222,7 @@ void _rtw_attrib_write(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); int __must_check rtw_read8(struct adapter *adapter, u32 addr, u8 *data); int __must_check rtw_read16(struct adapter *adapter, u32 addr, u16 *data); -u32 rtw_read32(struct adapter *adapter, u32 addr); +int __must_check rtw_read32(struct adapter *adapter, u32 addr, u32 *data); void _rtw_read_mem(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem); u32 rtw_read_port(struct adapter *adapter, u8 *pmem); void rtw_read_port_cancel(struct adapter *adapter); diff --git a/drivers/staging/r8188eu/os_dep/ioctl_linux.c b/drivers/staging/r8188eu/os_dep/ioctl_linux.c index 30aa2a2c0ade..e95cf35949d0 100644 --- a/drivers/staging/r8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/r8188eu/os_dep/ioctl_linux.c @@ -3126,18 +3126,29 @@ exit: static void mac_reg_dump(struct adapter *padapter) { int i, j = 1; + u32 reg; + int res; + pr_info("\n ======= MAC REG =======\n"); for (i = 0x0; i < 0x300; i += 4) { if (j % 4 == 1) pr_info("0x%02x", i); - pr_info(" 0x%08x ", rtw_read32(padapter, i)); + + res = rtw_read32(padapter, i, ®); + if (!res) + pr_info(" 0x%08x ", reg); + if ((j++) % 4 == 0) pr_info("\n"); } for (i = 0x400; i < 0x800; i += 4) { if (j % 4 == 1) pr_info("0x%02x", i); - pr_info(" 0x%08x ", rtw_read32(padapter, i)); + + res = rtw_read32(padapter, i, ®); + if (!res) + pr_info(" 0x%08x ", reg); + if ((j++) % 4 == 0) pr_info("\n"); } @@ -3145,13 +3156,18 @@ static void mac_reg_dump(struct adapter *padapter) static void bb_reg_dump(struct adapter *padapter) { - int i, j = 1; + int i, j = 1, res; + u32 reg; + pr_info("\n ======= BB REG =======\n"); for (i = 0x800; i < 0x1000; i += 4) { if (j % 4 == 1) pr_info("0x%02x", i); - pr_info(" 0x%08x ", rtw_read32(padapter, i)); + res = rtw_read32(padapter, i, ®); + if (!res) + pr_info(" 0x%08x ", reg); + if ((j++) % 4 == 0) pr_info("\n"); } @@ -3398,7 +3414,8 @@ static int rtw_dbg_port(struct net_device *dev, if (rtl8188e_IOL_exec_cmds_sync(padapter, xmit_frame, 5000, 0) != _SUCCESS) ret = -EPERM; - rtw_read32(padapter, reg); + /* FIXME: is this read necessary? */ + ret = rtw_read32(padapter, reg, &write_num); } break; } diff --git a/drivers/staging/r8188eu/os_dep/os_intfs.c b/drivers/staging/r8188eu/os_dep/os_intfs.c index d9325ef6ac28..cac9553666e6 100644 --- a/drivers/staging/r8188eu/os_dep/os_intfs.c +++ b/drivers/staging/r8188eu/os_dep/os_intfs.c @@ -741,6 +741,7 @@ static void rtw_fifo_cleanup(struct adapter *adapter) struct pwrctrl_priv *pwrpriv = &adapter->pwrctrlpriv; u8 trycnt = 100; int res; + u32 reg; /* pause tx */ rtw_write8(adapter, REG_TXPAUSE, 0xff); @@ -753,10 +754,18 @@ static void rtw_fifo_cleanup(struct adapter *adapter) if (!pwrpriv->bkeepfwalive) { /* RX DMA stop */ + res = rtw_read32(adapter, REG_RXPKT_NUM, ®); + if (res) + return; + rtw_write32(adapter, REG_RXPKT_NUM, - (rtw_read32(adapter, REG_RXPKT_NUM) | RW_RELEASE_EN)); + (reg | RW_RELEASE_EN)); do { - if (!(rtw_read32(adapter, REG_RXPKT_NUM) & RXDMA_IDLE)) + res = rtw_read32(adapter, REG_RXPKT_NUM, ®); + if (res) + continue; + + if (!(reg & RXDMA_IDLE)) break; } while (trycnt--); From 991ebc730369c10f6ac36a62c8174276b3811de8 Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Tue, 7 Jun 2022 22:26:31 +0300 Subject: [PATCH 0228/1436] MAINTAINERS: add myself as r8188eu reviewer I was reviewing r8188eu patches for a while, but I am missing some of them, since I am not in CC list. I want to be CC'ed to help reviewing and testing more patches. Acked-by: Dan Carpenter Signed-off-by: Pavel Skripkin Acked-by: Phillip Potter Acked-by: Larry Finger Link: https://lore.kernel.org/r/d6f6420a0d5ceff6bb50d268023f7d2e117027c5.1654629778.git.paskripkin@gmail.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index a6d3bd9d2a8d..60e5e4007844 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18920,6 +18920,7 @@ F: drivers/staging/olpc_dcon/ STAGING - REALTEK RTL8188EU DRIVERS M: Larry Finger M: Phillip Potter +R: Pavel Skripkin S: Supported F: drivers/staging/r8188eu/ From 699bb2e0c6f3796549dabac329501df7ffd99439 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:18 +0100 Subject: [PATCH 0229/1436] KVM: arm64: Move vcpu PC/Exception flags to the input flag set The PC update flags (which also deal with exception injection) is one of the most complicated use of the flag we have. Make it more fool prof by: - moving it over to the new accessors and assign it to the input flag set - turn the combination of generic ELx flags with another flag indicating the target EL itself into an explicit set of flags for each EL and vector combination - add a new accessor to pend the exception This is otherwise a pretty straightformward conversion. Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_emulate.h | 9 ++++- arch/arm64/include/asm/kvm_host.h | 58 ++++++++++++++++------------ arch/arm64/kvm/arm.c | 4 +- arch/arm64/kvm/hyp/exception.c | 23 ++++++----- arch/arm64/kvm/hyp/nvhe/sys_regs.c | 4 +- arch/arm64/kvm/inject_fault.c | 17 +++----- 6 files changed, 61 insertions(+), 54 deletions(-) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 0e66edd3aff2..6ec58080ece8 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -473,9 +473,16 @@ static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu, static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu) { - vcpu->arch.flags |= KVM_ARM64_INCREMENT_PC; + vcpu_set_flag(vcpu, INCREMENT_PC); } +#define kvm_pend_exception(v, e) \ + do { \ + vcpu_set_flag((v), PENDING_EXCEPTION); \ + vcpu_set_flag((v), e); \ + } while (0) + + static inline bool vcpu_has_feature(struct kvm_vcpu *vcpu, int feature) { return test_bit(feature, vcpu->arch.features); diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 66a08b0e12a8..db42b4c06449 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -474,6 +474,40 @@ struct kvm_vcpu_arch { /* PTRAUTH exposed to guest */ #define GUEST_HAS_PTRAUTH __vcpu_single_flag(cflags, BIT(2)) +/* Exception pending */ +#define PENDING_EXCEPTION __vcpu_single_flag(iflags, BIT(0)) +/* + * PC increment. Overlaps with EXCEPT_MASK on purpose so that it can't + * be set together with an exception... + */ +#define INCREMENT_PC __vcpu_single_flag(iflags, BIT(1)) +/* Target EL/MODE (not a single flag, but let's abuse the macro) */ +#define EXCEPT_MASK __vcpu_single_flag(iflags, GENMASK(3, 1)) + +/* Helpers to encode exceptions with minimum fuss */ +#define __EXCEPT_MASK_VAL unpack_vcpu_flag(EXCEPT_MASK) +#define __EXCEPT_SHIFT __builtin_ctzl(__EXCEPT_MASK_VAL) +#define __vcpu_except_flags(_f) iflags, (_f << __EXCEPT_SHIFT), __EXCEPT_MASK_VAL + +/* + * When PENDING_EXCEPTION is set, EXCEPT_MASK can take the following + * values: + * + * For AArch32 EL1: + */ +#define EXCEPT_AA32_UND __vcpu_except_flags(0) +#define EXCEPT_AA32_IABT __vcpu_except_flags(1) +#define EXCEPT_AA32_DABT __vcpu_except_flags(2) +/* For AArch64: */ +#define EXCEPT_AA64_EL1_SYNC __vcpu_except_flags(0) +#define EXCEPT_AA64_EL1_IRQ __vcpu_except_flags(1) +#define EXCEPT_AA64_EL1_FIQ __vcpu_except_flags(2) +#define EXCEPT_AA64_EL1_SERR __vcpu_except_flags(3) +/* For AArch64 with NV (one day): */ +#define EXCEPT_AA64_EL2_SYNC __vcpu_except_flags(4) +#define EXCEPT_AA64_EL2_IRQ __vcpu_except_flags(5) +#define EXCEPT_AA64_EL2_FIQ __vcpu_except_flags(6) +#define EXCEPT_AA64_EL2_SERR __vcpu_except_flags(7) /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */ #define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \ @@ -498,30 +532,6 @@ struct kvm_vcpu_arch { /* vcpu_arch flags field values: */ #define KVM_ARM64_DEBUG_DIRTY (1 << 0) #define KVM_ARM64_HOST_SVE_ENABLED (1 << 4) /* SVE enabled for EL0 */ -#define KVM_ARM64_PENDING_EXCEPTION (1 << 8) /* Exception pending */ -/* - * Overlaps with KVM_ARM64_EXCEPT_MASK on purpose so that it can't be - * set together with an exception... - */ -#define KVM_ARM64_INCREMENT_PC (1 << 9) /* Increment PC */ -#define KVM_ARM64_EXCEPT_MASK (7 << 9) /* Target EL/MODE */ -/* - * When KVM_ARM64_PENDING_EXCEPTION is set, KVM_ARM64_EXCEPT_MASK can - * take the following values: - * - * For AArch32 EL1: - */ -#define KVM_ARM64_EXCEPT_AA32_UND (0 << 9) -#define KVM_ARM64_EXCEPT_AA32_IABT (1 << 9) -#define KVM_ARM64_EXCEPT_AA32_DABT (2 << 9) -/* For AArch64: */ -#define KVM_ARM64_EXCEPT_AA64_ELx_SYNC (0 << 9) -#define KVM_ARM64_EXCEPT_AA64_ELx_IRQ (1 << 9) -#define KVM_ARM64_EXCEPT_AA64_ELx_FIQ (2 << 9) -#define KVM_ARM64_EXCEPT_AA64_ELx_SERR (3 << 9) -#define KVM_ARM64_EXCEPT_AA64_EL1 (0 << 11) -#define KVM_ARM64_EXCEPT_AA64_EL2 (1 << 11) - #define KVM_ARM64_DEBUG_STATE_SAVE_SPE (1 << 12) /* Save SPE context if active */ #define KVM_ARM64_DEBUG_STATE_SAVE_TRBE (1 << 13) /* Save TRBE context if active */ #define KVM_ARM64_ON_UNSUPPORTED_CPU (1 << 15) /* Physical CPU not in supported_cpus */ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 400bb0fe2745..5beabbe69585 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1013,8 +1013,8 @@ out: * the vcpu state. Note that this relies on __kvm_adjust_pc() * being preempt-safe on VHE. */ - if (unlikely(vcpu->arch.flags & (KVM_ARM64_PENDING_EXCEPTION | - KVM_ARM64_INCREMENT_PC))) + if (unlikely(vcpu_get_flag(vcpu, PENDING_EXCEPTION) || + vcpu_get_flag(vcpu, INCREMENT_PC))) kvm_call_hyp(__kvm_adjust_pc, vcpu); vcpu_put(vcpu); diff --git a/arch/arm64/kvm/hyp/exception.c b/arch/arm64/kvm/hyp/exception.c index c5d009715402..b7557b25ed56 100644 --- a/arch/arm64/kvm/hyp/exception.c +++ b/arch/arm64/kvm/hyp/exception.c @@ -303,14 +303,14 @@ static void enter_exception32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset) static void kvm_inject_exception(struct kvm_vcpu *vcpu) { if (vcpu_el1_is_32bit(vcpu)) { - switch (vcpu->arch.flags & KVM_ARM64_EXCEPT_MASK) { - case KVM_ARM64_EXCEPT_AA32_UND: + switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) { + case unpack_vcpu_flag(EXCEPT_AA32_UND): enter_exception32(vcpu, PSR_AA32_MODE_UND, 4); break; - case KVM_ARM64_EXCEPT_AA32_IABT: + case unpack_vcpu_flag(EXCEPT_AA32_IABT): enter_exception32(vcpu, PSR_AA32_MODE_ABT, 12); break; - case KVM_ARM64_EXCEPT_AA32_DABT: + case unpack_vcpu_flag(EXCEPT_AA32_DABT): enter_exception32(vcpu, PSR_AA32_MODE_ABT, 16); break; default: @@ -318,9 +318,8 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu) break; } } else { - switch (vcpu->arch.flags & KVM_ARM64_EXCEPT_MASK) { - case (KVM_ARM64_EXCEPT_AA64_ELx_SYNC | - KVM_ARM64_EXCEPT_AA64_EL1): + switch (vcpu_get_flag(vcpu, EXCEPT_MASK)) { + case unpack_vcpu_flag(EXCEPT_AA64_EL1_SYNC): enter_exception64(vcpu, PSR_MODE_EL1h, except_type_sync); break; default: @@ -340,12 +339,12 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu) */ void __kvm_adjust_pc(struct kvm_vcpu *vcpu) { - if (vcpu->arch.flags & KVM_ARM64_PENDING_EXCEPTION) { + if (vcpu_get_flag(vcpu, PENDING_EXCEPTION)) { kvm_inject_exception(vcpu); - vcpu->arch.flags &= ~(KVM_ARM64_PENDING_EXCEPTION | - KVM_ARM64_EXCEPT_MASK); - } else if (vcpu->arch.flags & KVM_ARM64_INCREMENT_PC) { + vcpu_clear_flag(vcpu, PENDING_EXCEPTION); + vcpu_clear_flag(vcpu, EXCEPT_MASK); + } else if (vcpu_get_flag(vcpu, INCREMENT_PC)) { kvm_skip_instr(vcpu); - vcpu->arch.flags &= ~KVM_ARM64_INCREMENT_PC; + vcpu_clear_flag(vcpu, INCREMENT_PC); } } diff --git a/arch/arm64/kvm/hyp/nvhe/sys_regs.c b/arch/arm64/kvm/hyp/nvhe/sys_regs.c index b6d86e423319..edd3eabf520f 100644 --- a/arch/arm64/kvm/hyp/nvhe/sys_regs.c +++ b/arch/arm64/kvm/hyp/nvhe/sys_regs.c @@ -38,9 +38,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu) *vcpu_pc(vcpu) = read_sysreg_el2(SYS_ELR); *vcpu_cpsr(vcpu) = read_sysreg_el2(SYS_SPSR); - vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA64_EL1 | - KVM_ARM64_EXCEPT_AA64_ELx_SYNC | - KVM_ARM64_PENDING_EXCEPTION); + kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC); __kvm_adjust_pc(vcpu); diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c index 55a5dbe957e0..f32f4a2a347f 100644 --- a/arch/arm64/kvm/inject_fault.c +++ b/arch/arm64/kvm/inject_fault.c @@ -20,9 +20,7 @@ static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr bool is_aarch32 = vcpu_mode_is_32bit(vcpu); u64 esr = 0; - vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA64_EL1 | - KVM_ARM64_EXCEPT_AA64_ELx_SYNC | - KVM_ARM64_PENDING_EXCEPTION); + kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC); vcpu_write_sys_reg(vcpu, addr, FAR_EL1); @@ -52,9 +50,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu) { u64 esr = (ESR_ELx_EC_UNKNOWN << ESR_ELx_EC_SHIFT); - vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA64_EL1 | - KVM_ARM64_EXCEPT_AA64_ELx_SYNC | - KVM_ARM64_PENDING_EXCEPTION); + kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SYNC); /* * Build an unknown exception, depending on the instruction @@ -73,8 +69,7 @@ static void inject_undef64(struct kvm_vcpu *vcpu) static void inject_undef32(struct kvm_vcpu *vcpu) { - vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_UND | - KVM_ARM64_PENDING_EXCEPTION); + kvm_pend_exception(vcpu, EXCEPT_AA32_UND); } /* @@ -97,14 +92,12 @@ static void inject_abt32(struct kvm_vcpu *vcpu, bool is_pabt, u32 addr) far = vcpu_read_sys_reg(vcpu, FAR_EL1); if (is_pabt) { - vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_IABT | - KVM_ARM64_PENDING_EXCEPTION); + kvm_pend_exception(vcpu, EXCEPT_AA32_IABT); far &= GENMASK(31, 0); far |= (u64)addr << 32; vcpu_write_sys_reg(vcpu, fsr, IFSR32_EL2); } else { /* !iabt */ - vcpu->arch.flags |= (KVM_ARM64_EXCEPT_AA32_DABT | - KVM_ARM64_PENDING_EXCEPTION); + kvm_pend_exception(vcpu, EXCEPT_AA32_DABT); far &= GENMASK(63, 32); far |= addr; vcpu_write_sys_reg(vcpu, fsr, ESR_EL1); From c5d337a358b3e41bb4f7abd99a79b68a28eafaa2 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 8 Jun 2022 20:49:18 +0300 Subject: [PATCH 0230/1436] usb: gadget: uvc: Fix comment blocks style The UVC gadget driver historically uses the /* Comment * style */ for multi-line block comments, which is frowned upon. Patches for the driver are required to use the more standard /* * Comment * style */ style. This result in inconsistencies. Fix it by converting all remaining instances of the old style. Reviewed-by: Kieran Bingham Signed-off-by: Laurent Pinchart Link: https://lore.kernel.org/r/20220608174918.14656-1-laurent.pinchart@ideasonboard.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_uvc.c | 30 ++++++++++++++++--------- drivers/usb/gadget/function/uvc_queue.c | 6 +++-- drivers/usb/gadget/function/uvc_video.c | 12 ++++++---- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index d3feeeb50841..71669e0e4d00 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -141,7 +141,8 @@ static struct usb_endpoint_descriptor uvc_fs_streaming_ep = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_SYNC_ASYNC | USB_ENDPOINT_XFER_ISOC, - /* The wMaxPacketSize and bInterval values will be initialized from + /* + * The wMaxPacketSize and bInterval values will be initialized from * module parameters. */ }; @@ -152,7 +153,8 @@ static struct usb_endpoint_descriptor uvc_hs_streaming_ep = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_SYNC_ASYNC | USB_ENDPOINT_XFER_ISOC, - /* The wMaxPacketSize and bInterval values will be initialized from + /* + * The wMaxPacketSize and bInterval values will be initialized from * module parameters. */ }; @@ -164,7 +166,8 @@ static struct usb_endpoint_descriptor uvc_ss_streaming_ep = { .bEndpointAddress = USB_DIR_IN, .bmAttributes = USB_ENDPOINT_SYNC_ASYNC | USB_ENDPOINT_XFER_ISOC, - /* The wMaxPacketSize and bInterval values will be initialized from + /* + * The wMaxPacketSize and bInterval values will be initialized from * module parameters. */ }; @@ -172,7 +175,8 @@ static struct usb_endpoint_descriptor uvc_ss_streaming_ep = { static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = { .bLength = sizeof(uvc_ss_streaming_comp), .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, - /* The bMaxBurst, bmAttributes and wBytesPerInterval values will be + /* + * The bMaxBurst, bmAttributes and wBytesPerInterval values will be * initialized from module parameters. */ }; @@ -234,7 +238,8 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) if (le16_to_cpu(ctrl->wLength) > UVC_MAX_REQUEST_SIZE) return -EINVAL; - /* Tell the complete callback to generate an event for the next request + /* + * Tell the complete callback to generate an event for the next request * that will be enqueued by UVCIOC_SEND_RESPONSE. */ uvc->event_setup_out = !(ctrl->bRequestType & USB_DIR_IN); @@ -500,7 +505,8 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) if (!uvc_control_desc || !uvc_streaming_cls) return ERR_PTR(-ENODEV); - /* Descriptors layout + /* + * Descriptors layout * * uvc_iad * uvc_control_intf @@ -597,8 +603,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) uvcg_info(f, "%s()\n", __func__); opts = fi_to_f_uvc_opts(f->fi); - /* Sanity check the streaming endpoint module parameters. - */ + /* Sanity check the streaming endpoint module parameters. */ opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U); opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U); opts->streaming_maxburst = min(opts->streaming_maxburst, 15U); @@ -611,7 +616,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) opts->streaming_maxpacket); } - /* Fill in the FS/HS/SS Video Streaming specific descriptors from the + /* + * Fill in the FS/HS/SS Video Streaming specific descriptors from the * module parameters. * * NOTE: We assume that the user knows what they are doing and won't @@ -895,7 +901,8 @@ static void uvc_function_unbind(struct usb_configuration *c, uvcg_info(f, "%s()\n", __func__); - /* If we know we're connected via v4l2, then there should be a cleanup + /* + * If we know we're connected via v4l2, then there should be a cleanup * of the device from userspace either via UVC_EVENT_DISCONNECT or * though the video device removal uevent. Allow some time for the * application to close out before things get deleted. @@ -912,7 +919,8 @@ static void uvc_function_unbind(struct usb_configuration *c, v4l2_device_unregister(&uvc->v4l2_dev); if (uvc->func_connected) { - /* Wait for the release to occur to ensure there are no longer any + /* + * Wait for the release to occur to ensure there are no longer any * pending operations that may cause panics when resources are cleaned * up. */ diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index d25edc3d2174..951934aa4454 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -104,7 +104,8 @@ static void uvc_buffer_queue(struct vb2_buffer *vb) if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) { list_add_tail(&buf->queue, &queue->irqqueue); } else { - /* If the device is disconnected return the buffer to userspace + /* + * If the device is disconnected return the buffer to userspace * directly. The next QBUF call will fail with -ENODEV. */ buf->state = UVC_BUF_STATE_ERROR; @@ -255,7 +256,8 @@ void uvcg_queue_cancel(struct uvc_video_queue *queue, int disconnect) } queue->buf_used = 0; - /* This must be protected by the irqlock spinlock to avoid race + /* + * This must be protected by the irqlock spinlock to avoid race * conditions between uvc_queue_buffer and the disconnection event that * could result in an interruptible wait in uvc_dequeue_buffer. Do not * blindly replace this logic by checking for the UVC_DEV_DISCONNECTED diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index a9bb4553db84..5876bc73f929 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -378,7 +378,8 @@ static void uvcg_video_pump(struct work_struct *work) int ret; while (video->ep->enabled) { - /* Retrieve the first available USB request, protected by the + /* + * Retrieve the first available USB request, protected by the * request lock. */ spin_lock_irqsave(&video->req_lock, flags); @@ -391,7 +392,8 @@ static void uvcg_video_pump(struct work_struct *work) list_del(&req->list); spin_unlock_irqrestore(&video->req_lock, flags); - /* Retrieve the first available video buffer and fill the + /* + * Retrieve the first available video buffer and fill the * request, protected by the video queue irqlock. */ spin_lock_irqsave(&queue->irqlock, flags); @@ -403,9 +405,11 @@ static void uvcg_video_pump(struct work_struct *work) video->encode(req, video, buf); - /* With usb3 we have more requests. This will decrease the + /* + * With usb3 we have more requests. This will decrease the * interrupt load to a quarter but also catches the corner - * cases, which needs to be handled */ + * cases, which needs to be handled. + */ if (list_empty(&video->req_free) || buf->state == UVC_BUF_STATE_DONE || !(video->req_int_count % From 7d602f30149a117eea260208b1661bc404c21dfd Mon Sep 17 00:00:00 2001 From: Frank Li Date: Wed, 8 Jun 2022 14:04:30 -0500 Subject: [PATCH 0231/1436] usb: cdns3 fix use-after-free at workaround 2 BUG: KFENCE: use-after-free read in __list_del_entry_valid+0x10/0xac cdns3_wa2_remove_old_request() { ... kfree(priv_req->request.buf); cdns3_gadget_ep_free_request(&priv_ep->endpoint, &priv_req->request); list_del_init(&priv_req->list); ^^^ use after free ... } cdns3_gadget_ep_free_request() free the space pointed by priv_req, but priv_req is used in the following list_del_init(). This patch move list_del_init() before cdns3_gadget_ep_free_request(). Signed-off-by: Frank Li Signed-off-by: Faqiang Zhu Link: https://lore.kernel.org/r/20220608190430.2814358-1-Frank.Li@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdns3-gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index 5c15c48952a6..29662c8ac024 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -625,9 +625,9 @@ static void cdns3_wa2_remove_old_request(struct cdns3_endpoint *priv_ep) trace_cdns3_wa2(priv_ep, "removes eldest request"); kfree(priv_req->request.buf); + list_del_init(&priv_req->list); cdns3_gadget_ep_free_request(&priv_ep->endpoint, &priv_req->request); - list_del_init(&priv_req->list); --priv_ep->wa2_counter; if (!chain) From 8659ab3d936fcf0084676f98b75b317017aa8f82 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 9 Jun 2022 10:44:56 -0500 Subject: [PATCH 0232/1436] usb: cdns3: fix random warning message when driver load Warning log: [ 4.141392] Unexpected gfp: 0x4 (GFP_DMA32). Fixing up to gfp: 0xa20 (GFP_ATOMIC). Fix your code! [ 4.150340] CPU: 1 PID: 175 Comm: 1-0050 Not tainted 5.15.5-00039-g2fd9ae1b568c #20 [ 4.158010] Hardware name: Freescale i.MX8QXP MEK (DT) [ 4.163155] Call trace: [ 4.165600] dump_backtrace+0x0/0x1b0 [ 4.169286] show_stack+0x18/0x68 [ 4.172611] dump_stack_lvl+0x68/0x84 [ 4.176286] dump_stack+0x18/0x34 [ 4.179613] kmalloc_fix_flags+0x60/0x88 [ 4.183550] new_slab+0x334/0x370 [ 4.186878] ___slab_alloc.part.108+0x4d4/0x748 [ 4.191419] __slab_alloc.isra.109+0x30/0x78 [ 4.195702] kmem_cache_alloc+0x40c/0x420 [ 4.199725] dma_pool_alloc+0xac/0x1f8 [ 4.203486] cdns3_allocate_trb_pool+0xb4/0xd0 pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags) { ... page = kmalloc(sizeof(*page), mem_flags); page->vaddr = dma_alloc_coherent(pool->dev, pool->allocation, &page->dma, mem_flags); ... } kmalloc was called with mem_flags, which is passed down in cdns3_allocate_trb_pool() and have GFP_DMA32 flags. kmall_fix_flags() report warning. GFP_DMA32 is not useful at all. dma_alloc_coherent() will handle DMA memory region correctly by pool->dev. GFP_DMA32 can be removed safely. Signed-off-by: Frank Li Link: https://lore.kernel.org/r/20220609154456.2871672-1-Frank.Li@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdns3-gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index 29662c8ac024..555caafe4f04 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -220,7 +220,7 @@ int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) if (!priv_ep->trb_pool) { priv_ep->trb_pool = dma_pool_alloc(priv_dev->eps_dma_pool, - GFP_DMA32 | GFP_ATOMIC, + GFP_ATOMIC, &priv_ep->trb_pool_dma); if (!priv_ep->trb_pool) From 3497b9a5c8c3d4efaa15ab542cc6a774b0e0a7c6 Mon Sep 17 00:00:00 2001 From: Li Jun Date: Tue, 7 Jun 2022 10:20:04 +0800 Subject: [PATCH 0233/1436] usb: dwc3: add power down scale setting Some SoC(e.g NXP imx8MQ) may have a wrong default power down scale setting so need init it to be the correct value, the power down scale setting description in DWC3 databook: Power Down Scale (PwrDnScale) The USB3 suspend_clk input replaces pipe3_rx_pclk as a clock source to a small part of the USB3 core that operates when the SS PHY is in its lowest power (P3) state, and therefore does not provide a clock. The Power Down Scale field specifies how many suspend_clk periods fit into a 16 kHz clock period. When performing the division, round up the remainder. For example, when using an 8-bit/16-bit/32-bit PHY and 25-MHz Suspend clock, Power Down Scale = 25000 kHz/16 kHz = 13'd1563 (rounder up) So use the suspend clock rate to calculate it. Reviewed-by: Thinh Nguyen Signed-off-by: Li Jun Link: https://lore.kernel.org/r/1654568404-3461-1-git-send-email-jun.li@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 34 ++++++++++++++++++++++++++++++++++ drivers/usb/dwc3/core.h | 1 + 2 files changed, 35 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index e027c0420dc3..b4c47002828c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1029,6 +1029,37 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg); } +static void dwc3_set_power_down_clk_scale(struct dwc3 *dwc) +{ + u32 scale; + u32 reg; + + if (!dwc->susp_clk) + return; + + /* + * The power down scale field specifies how many suspend_clk + * periods fit into a 16KHz clock period. When performing + * the division, round up the remainder. + * + * The power down scale value is calculated using the fastest + * frequency of the suspend_clk. If it isn't fixed (but within + * the accuracy requirement), the driver may not know the max + * rate of the suspend_clk, so only update the power down scale + * if the default is less than the calculated value from + * clk_get_rate() or if the default is questionably high + * (3x or more) to be within the requirement. + */ + scale = DIV_ROUND_UP(clk_get_rate(dwc->susp_clk), 16000); + reg = dwc3_readl(dwc->regs, DWC3_GCTL); + if ((reg & DWC3_GCTL_PWRDNSCALE_MASK) < DWC3_GCTL_PWRDNSCALE(scale) || + (reg & DWC3_GCTL_PWRDNSCALE_MASK) > DWC3_GCTL_PWRDNSCALE(scale*3)) { + reg &= ~(DWC3_GCTL_PWRDNSCALE_MASK); + reg |= DWC3_GCTL_PWRDNSCALE(scale); + dwc3_writel(dwc->regs, DWC3_GCTL, reg); + } +} + /** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure @@ -1105,6 +1136,9 @@ static int dwc3_core_init(struct dwc3 *dwc) if (ret) goto err1; + /* Set power down scale of suspend_clk */ + dwc3_set_power_down_clk_scale(dwc); + /* Adjust Frame Length */ dwc3_frame_length_adjustment(dwc); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 81c486b3941c..722808d8c0af 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -231,6 +231,7 @@ /* Global Configuration Register */ #define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19) +#define DWC3_GCTL_PWRDNSCALE_MASK GENMASK(31, 19) #define DWC3_GCTL_U2RSTECN BIT(16) #define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6) #define DWC3_GCTL_CLK_BUS (0) From b5c5b13cb45e2c88181308186b0001992cb41954 Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 2 Jun 2022 15:08:49 +0400 Subject: [PATCH 0234/1436] usb: host: Fix refcount leak in ehci_hcd_ppc_of_probe of_find_compatible_node() returns a node pointer with refcount incremented, we should use of_node_put() on it when done. Add missing of_node_put() to avoid refcount leak. Fixes: 796bcae7361c ("USB: powerpc: Workaround for the PPC440EPX USBH_23 errata [take 3]") Acked-by: Alan Stern Signed-off-by: Miaoqian Lin Link: https://lore.kernel.org/r/20220602110849.58549-1-linmq006@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-ppc-of.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 6bbaee74f7e7..28a19693c19f 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -148,6 +148,7 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op) } else { ehci->has_amcc_usb23 = 1; } + of_node_put(np); } if (of_get_property(dn, "big-endian", NULL)) { From 302970b4cad3ebfda2c05ce06c322ccdc447d17e Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Fri, 3 Jun 2022 18:12:30 +0400 Subject: [PATCH 0235/1436] usb: ohci-nxp: Fix refcount leak in ohci_hcd_nxp_probe of_parse_phandle() returns a node pointer with refcount incremented, we should use of_node_put() on it when not need anymore. Add missing of_node_put() to avoid refcount leak. Fixes: 73108aa90cbf ("USB: ohci-nxp: Use isp1301 driver") Acked-by: Alan Stern Signed-off-by: Miaoqian Lin Link: https://lore.kernel.org/r/20220603141231.979-1-linmq006@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-nxp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 85878e8ad331..106a6bcefb08 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -164,6 +164,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) } isp1301_i2c_client = isp1301_get_client(isp1301_node); + of_node_put(isp1301_node); if (!isp1301_i2c_client) return -EPROBE_DEFER; From 1e073e3ed9ff9ec14e7e360ed89a81256d895588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Tue, 7 Jun 2022 15:34:54 +0200 Subject: [PATCH 0236/1436] usb: host: ohci-at91: add support to enter suspend using SMC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Linux is running under OP-TEE, the SFR is set as secured and thus the AT91_OHCIICR_USB_SUSPEND register isn't accessible. Add a SMC to do the appropriate call to suspend the controller. The SMC id is fetched from the device-tree property "microchip,suspend-smc-id". if present, then the syscon regmap is not used to enter suspend and a SMC is issued. Reviewed-by: Claudiu Beznea Acked-by: Alan Stern Signed-off-by: Clément Léger Link: https://lore.kernel.org/r/20220607133454.727063-1-clement.leger@bootlin.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-at91.c | 69 ++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index a24aea3d2759..98326465e2dc 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -13,6 +13,7 @@ * This file is licenced under the GPL. */ +#include #include #include #include @@ -55,6 +56,7 @@ struct ohci_at91_priv { bool clocked; bool wakeup; /* Saved wake-up state for resume */ struct regmap *sfr_regmap; + u32 suspend_smc_id; }; /* interface and function clocks; sometimes also an AHB clock */ @@ -135,6 +137,19 @@ static void at91_stop_hc(struct platform_device *pdev) static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *); +static u32 at91_dt_suspend_smc(struct device *dev) +{ + u32 suspend_smc_id; + + if (!dev->of_node) + return 0; + + if (of_property_read_u32(dev->of_node, "microchip,suspend-smc-id", &suspend_smc_id)) + return 0; + + return suspend_smc_id; +} + static struct regmap *at91_dt_syscon_sfr(void) { struct regmap *regmap; @@ -215,9 +230,13 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver, goto err; } - ohci_at91->sfr_regmap = at91_dt_syscon_sfr(); - if (!ohci_at91->sfr_regmap) - dev_dbg(dev, "failed to find sfr node\n"); + ohci_at91->suspend_smc_id = at91_dt_suspend_smc(dev); + if (!ohci_at91->suspend_smc_id) { + dev_dbg(dev, "failed to find sfr suspend smc id, using regmap\n"); + ohci_at91->sfr_regmap = at91_dt_syscon_sfr(); + if (!ohci_at91->sfr_regmap) + dev_dbg(dev, "failed to find sfr node\n"); + } board = hcd->self.controller->platform_data; ohci = hcd_to_ohci(hcd); @@ -303,24 +322,30 @@ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf) return length; } -static int ohci_at91_port_suspend(struct regmap *regmap, u8 set) +static int ohci_at91_port_suspend(struct ohci_at91_priv *ohci_at91, u8 set) { + struct regmap *regmap = ohci_at91->sfr_regmap; u32 regval; int ret; - if (!regmap) - return 0; + if (ohci_at91->suspend_smc_id) { + struct arm_smccc_res res; - ret = regmap_read(regmap, AT91_SFR_OHCIICR, ®val); - if (ret) - return ret; + arm_smccc_smc(ohci_at91->suspend_smc_id, set, 0, 0, 0, 0, 0, 0, &res); + if (res.a0) + return -EINVAL; + } else if (regmap) { + ret = regmap_read(regmap, AT91_SFR_OHCIICR, ®val); + if (ret) + return ret; - if (set) - regval |= AT91_OHCIICR_USB_SUSPEND; - else - regval &= ~AT91_OHCIICR_USB_SUSPEND; + if (set) + regval |= AT91_OHCIICR_USB_SUSPEND; + else + regval &= ~AT91_OHCIICR_USB_SUSPEND; - regmap_write(regmap, AT91_SFR_OHCIICR, regval); + regmap_write(regmap, AT91_SFR_OHCIICR, regval); + } return 0; } @@ -357,9 +382,8 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_SUSPEND: dev_dbg(hcd->self.controller, "SetPortFeat: SUSPEND\n"); - if (valid_port(wIndex) && ohci_at91->sfr_regmap) { - ohci_at91_port_suspend(ohci_at91->sfr_regmap, - 1); + if (valid_port(wIndex)) { + ohci_at91_port_suspend(ohci_at91, 1); return 0; } break; @@ -400,9 +424,8 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case USB_PORT_FEAT_SUSPEND: dev_dbg(hcd->self.controller, "ClearPortFeature: SUSPEND\n"); - if (valid_port(wIndex) && ohci_at91->sfr_regmap) { - ohci_at91_port_suspend(ohci_at91->sfr_regmap, - 0); + if (valid_port(wIndex)) { + ohci_at91_port_suspend(ohci_at91, 0); return 0; } break; @@ -630,10 +653,10 @@ ohci_hcd_at91_drv_suspend(struct device *dev) /* flush the writes */ (void) ohci_readl (ohci, &ohci->regs->control); msleep(1); - ohci_at91_port_suspend(ohci_at91->sfr_regmap, 1); + ohci_at91_port_suspend(ohci_at91, 1); at91_stop_clock(ohci_at91); } else { - ohci_at91_port_suspend(ohci_at91->sfr_regmap, 1); + ohci_at91_port_suspend(ohci_at91, 1); } return ret; @@ -645,7 +668,7 @@ ohci_hcd_at91_drv_resume(struct device *dev) struct usb_hcd *hcd = dev_get_drvdata(dev); struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd); - ohci_at91_port_suspend(ohci_at91->sfr_regmap, 0); + ohci_at91_port_suspend(ohci_at91, 0); if (ohci_at91->wakeup) disable_irq_wake(hcd->irq); From df22ecc41b54def624735b83784857e708bd1502 Mon Sep 17 00:00:00 2001 From: Kushagra Verma Date: Fri, 3 Jun 2022 13:52:15 +0530 Subject: [PATCH 0237/1436] usb: dwc3: Remove the checks of -ENOSYS Commit 57303488cd37d ("usb: dwc3: adapt dwc3 core to use Generic PHY Framework") added if statements that check 'ret == -ENOSYS || ret == -ENODEV', but the function phy_get() which is called by devm_phy_get() returns the phy driver or -ENODEV if the phy driver was not found. So, remove the check of -ENOSYS in the if statements. Signed-off-by: Kushagra Verma Link: https://lore.kernel.org/r/HK0PR01MB2801E19D4FE569545BB7592DF8A19@HK0PR01MB2801.apcprd01.prod.exchangelabs.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index b4c47002828c..a8b42530b603 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1318,7 +1318,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); if (IS_ERR(dwc->usb2_generic_phy)) { ret = PTR_ERR(dwc->usb2_generic_phy); - if (ret == -ENOSYS || ret == -ENODEV) + if (ret == -ENODEV) dwc->usb2_generic_phy = NULL; else return dev_err_probe(dev, ret, "no usb2 phy configured\n"); @@ -1327,7 +1327,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); if (IS_ERR(dwc->usb3_generic_phy)) { ret = PTR_ERR(dwc->usb3_generic_phy); - if (ret == -ENOSYS || ret == -ENODEV) + if (ret == -ENODEV) dwc->usb3_generic_phy = NULL; else return dev_err_probe(dev, ret, "no usb3 phy configured\n"); From e3fa404a261bb8b7795b62be1b9af7b7dc1030f6 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 28 May 2022 16:59:17 +0200 Subject: [PATCH 0238/1436] USB: Follow-up to SPDX identifiers addition - remove now useless comments All these files have been updated in the commit given in the Fixes: tag below. When the SPDX-License-Identifier: has been added, the corresponding text at the beginning of the files has not been deleted. All these texts are about GPL-2.0, with different variation in the wording. Remove these now useless lines to save some LoC. Fixes: 5fd54ace4721 ("USB: add SPDX identifiers to all remaining files in drivers/usb/") Signed-off-by: Christophe JAILLET Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/audio-v2.h | 3 --- include/linux/usb/audio.h | 3 --- include/linux/usb/cdc-wdm.h | 4 ---- include/linux/usb/cdc.h | 4 ---- include/linux/usb/gadget.h | 2 -- include/linux/usb/input.h | 4 ---- include/linux/usb/isp1301.h | 10 ---------- include/linux/usb/m66592.h | 14 -------------- include/linux/usb/of.h | 2 -- include/linux/usb/r8a66597.h | 14 -------------- include/linux/usb/serial.h | 5 ----- include/linux/usb/storage.h | 2 -- include/linux/usb/tegra_usb_phy.h | 10 ---------- include/linux/usb/ulpi.h | 4 ---- include/linux/usb/xhci-dbgp.h | 4 ---- 15 files changed, 85 deletions(-) diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index 8fc2abd7aecb..ca796dc1a984 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h @@ -2,9 +2,6 @@ /* * Copyright (c) 2010 Daniel Mack * - * This software is distributed under the terms of the GNU General Public - * License ("GPL") version 2, as published by the Free Software Foundation. - * * This file holds USB constants and structures defined * by the USB Device Class Definition for Audio Devices in version 2.0. * Comments below reference relevant sections of the documents contained diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index 170acd500ea1..0747b24a1a7c 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h @@ -6,9 +6,6 @@ * Developed for Thumtronics by Grey Innovation * Ben Williamson * - * This software is distributed under the terms of the GNU General Public - * License ("GPL") version 2, as published by the Free Software Foundation. - * * This file holds USB constants and structures defined * by the USB Device Class Definition for Audio Devices. * Comments below reference relevant sections of that document: diff --git a/include/linux/usb/cdc-wdm.h b/include/linux/usb/cdc-wdm.h index 9f5a51f79ba5..85417f00a89a 100644 --- a/include/linux/usb/cdc-wdm.h +++ b/include/linux/usb/cdc-wdm.h @@ -3,10 +3,6 @@ * USB CDC Device Management subdriver * * Copyright (c) 2012 Bjørn Mork - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #ifndef __LINUX_USB_CDC_WDM_H diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h index 35d784cf32a4..0af0db51bc89 100644 --- a/include/linux/usb/cdc.h +++ b/include/linux/usb/cdc.h @@ -3,10 +3,6 @@ * USB CDC common helpers * * Copyright (c) 2015 Oliver Neukum - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. */ #ifndef __LINUX_USB_CDC_H #define __LINUX_USB_CDC_H diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3ad58b7a0824..dc3092cea99e 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -10,8 +10,6 @@ * * (C) Copyright 2002-2004 by David Brownell * All Rights Reserved. - * - * This software is licensed under the GNU GPL version 2. */ #ifndef __LINUX_USB_GADGET_H diff --git a/include/linux/usb/input.h b/include/linux/usb/input.h index 974befa72ac0..5e759b2cf551 100644 --- a/include/linux/usb/input.h +++ b/include/linux/usb/input.h @@ -1,10 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2005 Dmitry Torokhov - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ #ifndef __LINUX_USB_INPUT_H diff --git a/include/linux/usb/isp1301.h b/include/linux/usb/isp1301.h index dedb3b2473e8..fa986b926a12 100644 --- a/include/linux/usb/isp1301.h +++ b/include/linux/usb/isp1301.h @@ -3,16 +3,6 @@ * NXP ISP1301 USB transceiver driver * * Copyright (C) 2012 Roland Stigge - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __LINUX_USB_ISP1301_H diff --git a/include/linux/usb/m66592.h b/include/linux/usb/m66592.h index 2dfe68183495..5f04de2b47fd 100644 --- a/include/linux/usb/m66592.h +++ b/include/linux/usb/m66592.h @@ -3,20 +3,6 @@ * M66592 driver platform data * * Copyright (C) 2009 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef __LINUX_USB_M66592_H diff --git a/include/linux/usb/of.h b/include/linux/usb/of.h index dba55ccb9b53..98487fd7ab11 100644 --- a/include/linux/usb/of.h +++ b/include/linux/usb/of.h @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* * OF helpers for usb devices. - * - * This file is released under the GPLv2 */ #ifndef __LINUX_USB_OF_H diff --git a/include/linux/usb/r8a66597.h b/include/linux/usb/r8a66597.h index c0753d026bbf..f0fa7ddadbaa 100644 --- a/include/linux/usb/r8a66597.h +++ b/include/linux/usb/r8a66597.h @@ -5,20 +5,6 @@ * Copyright (C) 2009 Renesas Solutions Corp. * * Author : Yoshihiro Shimoda - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #ifndef __LINUX_USB_R8A66597_H diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 16ea5a4cc586..8ea319f89e1f 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -4,11 +4,6 @@ * * Copyright (C) 1999 - 2012 * Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * */ #ifndef __LINUX_USB_SERIAL_H diff --git a/include/linux/usb/storage.h b/include/linux/usb/storage.h index e0240f864548..2827ce72e502 100644 --- a/include/linux/usb/storage.h +++ b/include/linux/usb/storage.h @@ -9,8 +9,6 @@ * * This file contains definitions taken from the * USB Mass Storage Class Specification Overview - * - * Distributed under the terms of the GNU GPL, version two. */ /* Storage subclass codes */ diff --git a/include/linux/usb/tegra_usb_phy.h b/include/linux/usb/tegra_usb_phy.h index d3e65eb9e16f..46e73584b6e6 100644 --- a/include/linux/usb/tegra_usb_phy.h +++ b/include/linux/usb/tegra_usb_phy.h @@ -1,16 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2010 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __TEGRA_USB_PHY_H diff --git a/include/linux/usb/ulpi.h b/include/linux/usb/ulpi.h index 36c2982780ad..5050f502c1ed 100644 --- a/include/linux/usb/ulpi.h +++ b/include/linux/usb/ulpi.h @@ -3,10 +3,6 @@ * ulpi.h -- ULPI defines and function prorotypes * * Copyright (C) 2010 Nokia Corporation - * - * This software is distributed under the terms of the GNU General - * Public License ("GPL") as published by the Free Software Foundation, - * version 2 of that License. */ #ifndef __LINUX_USB_ULPI_H diff --git a/include/linux/usb/xhci-dbgp.h b/include/linux/usb/xhci-dbgp.h index 01fe768873f9..171fd74b1cfc 100644 --- a/include/linux/usb/xhci-dbgp.h +++ b/include/linux/usb/xhci-dbgp.h @@ -5,10 +5,6 @@ * Copyright (C) 2016 Intel Corporation * * Author: Lu Baolu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __LINUX_XHCI_DBGP_H From 3e00a22fdc9a9457f1c64d885532710e174babd8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 28 May 2022 17:13:56 +0200 Subject: [PATCH 0239/1436] USB: Follow-up to SPDX GPL-2.0+ identifiers addition - remove now useless comments All these files have been updated in the commit given in the Fixes: tag below. When the SPDX-License-Identifier: has been added, the corresponding text at the beginning of the files has not been deleted. All these texts are about GPL-2.0+, with different variation in the wording. Remove these now useless lines to save some LoC. Fixes: 5fd54ace4721 ("USB: add SPDX identifiers to all remaining files in drivers/usb/") Signed-off-by: Christophe JAILLET Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/c67x00.h | 15 --------------- include/linux/usb/composite.h | 14 -------------- include/linux/usb/ehci_def.h | 14 -------------- include/linux/usb/ehci_pdriver.h | 14 -------------- include/linux/usb/g_hid.h | 14 -------------- include/linux/usb/hcd.h | 14 -------------- include/linux/usb/musb-ux500.h | 10 ---------- include/linux/usb/net2280.h | 14 -------------- include/linux/usb/ohci_pdriver.h | 14 -------------- include/linux/usb/otg-fsm.h | 17 ++--------------- include/linux/usb/phy_companion.h | 10 ---------- include/linux/usb/rndis_host.h | 14 -------------- include/linux/usb/usb338x.h | 11 ----------- include/linux/usb/usbnet.h | 14 -------------- 14 files changed, 2 insertions(+), 187 deletions(-) diff --git a/include/linux/usb/c67x00.h b/include/linux/usb/c67x00.h index 2fc39e3b7281..45e0757e58f3 100644 --- a/include/linux/usb/c67x00.h +++ b/include/linux/usb/c67x00.h @@ -3,21 +3,6 @@ * usb_c67x00.h: platform definitions for the Cypress C67X00 USB chip * * Copyright (C) 2006-2008 Barco N.V. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA. */ #ifndef _LINUX_USB_C67X00_H diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 9d2762279286..43ac3fa760db 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -3,20 +3,6 @@ * composite.h -- framework for usb gadgets which are composite devices * * Copyright (C) 2006-2008 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __LINUX_USB_COMPOSITE_H diff --git a/include/linux/usb/ehci_def.h b/include/linux/usb/ehci_def.h index c892c5bc6638..fbabadd3b372 100644 --- a/include/linux/usb/ehci_def.h +++ b/include/linux/usb/ehci_def.h @@ -1,20 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2001-2002 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __LINUX_USB_EHCI_DEF_H diff --git a/include/linux/usb/ehci_pdriver.h b/include/linux/usb/ehci_pdriver.h index 89fc901e778f..0f1b166f5aa0 100644 --- a/include/linux/usb/ehci_pdriver.h +++ b/include/linux/usb/ehci_pdriver.h @@ -1,20 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2012 Hauke Mehrtens - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __USB_CORE_EHCI_PDRIVER_H diff --git a/include/linux/usb/g_hid.h b/include/linux/usb/g_hid.h index 7581e488c237..d56bfedeb079 100644 --- a/include/linux/usb/g_hid.h +++ b/include/linux/usb/g_hid.h @@ -3,20 +3,6 @@ * g_hid.h -- Header file for USB HID gadget driver * * Copyright (C) 2010 Fabien Chouteau - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __LINUX_USB_G_HID_H diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 2c1fc9212cf2..37ccb31b1d40 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -1,20 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (c) 2001-2002 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __USB_CORE_HCD_H diff --git a/include/linux/usb/musb-ux500.h b/include/linux/usb/musb-ux500.h index c4b7ad9850ca..d60dcfc56b5a 100644 --- a/include/linux/usb/musb-ux500.h +++ b/include/linux/usb/musb-ux500.h @@ -1,16 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2013 ST-Ericsson AB - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __MUSB_UX500_H__ diff --git a/include/linux/usb/net2280.h b/include/linux/usb/net2280.h index 08b85caecfaf..f29fe6a1f415 100644 --- a/include/linux/usb/net2280.h +++ b/include/linux/usb/net2280.h @@ -5,20 +5,6 @@ * * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) * Copyright (C) 2003 David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __LINUX_USB_NET2280_H diff --git a/include/linux/usb/ohci_pdriver.h b/include/linux/usb/ohci_pdriver.h index 7eb16cf587ee..2447c78b1766 100644 --- a/include/linux/usb/ohci_pdriver.h +++ b/include/linux/usb/ohci_pdriver.h @@ -1,20 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2012 Hauke Mehrtens - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __USB_CORE_OHCI_PDRIVER_H diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h index 784659d4dc99..6135d076c53d 100644 --- a/include/linux/usb/otg-fsm.h +++ b/include/linux/usb/otg-fsm.h @@ -1,19 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ -/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. +/* + * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. */ #ifndef __LINUX_USB_OTG_FSM_H diff --git a/include/linux/usb/phy_companion.h b/include/linux/usb/phy_companion.h index 263196f05015..862aaeca2319 100644 --- a/include/linux/usb/phy_companion.h +++ b/include/linux/usb/phy_companion.h @@ -3,18 +3,8 @@ * phy-companion.h -- phy companion to indicate the comparator part of PHY * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. * * Author: Kishon Vijay Abraham I - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __DRIVERS_PHY_COMPANION_H diff --git a/include/linux/usb/rndis_host.h b/include/linux/usb/rndis_host.h index cc42db51bbba..489cfb1d00f6 100644 --- a/include/linux/usb/rndis_host.h +++ b/include/linux/usb/rndis_host.h @@ -2,20 +2,6 @@ /* * Host Side support for RNDIS Networking Links * Copyright (C) 2005 by David Brownell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __LINUX_USB_RNDIS_HOST_H diff --git a/include/linux/usb/usb338x.h b/include/linux/usb/usb338x.h index 20020c1336d5..70a7e3cdb3c9 100644 --- a/include/linux/usb/usb338x.h +++ b/include/linux/usb/usb338x.h @@ -6,17 +6,6 @@ * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com) * Copyright (C) 2003 David Brownell * Copyright (C) 2014 Ricardo Ribalda - Qtechnology/AS - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #ifndef __LINUX_USB_USB338X_H diff --git a/include/linux/usb/usbnet.h b/include/linux/usb/usbnet.h index 1b4d72d5e891..4f5608cbd9ab 100644 --- a/include/linux/usb/usbnet.h +++ b/include/linux/usb/usbnet.h @@ -4,20 +4,6 @@ * * Copyright (C) 2000-2005 by David Brownell * Copyright (C) 2003-2005 David Hollis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __LINUX_USB_USBNET_H From ecf6dedd03b03f05459c3662d9b141bedbc1c39d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 May 2022 15:27:20 +0300 Subject: [PATCH 0240/1436] USB: usbip: clean up mixed use of _irq() and _irqsave() It generally doesn't make sense to use _irq() and _irqsave() in the same function because either some of the callers have disabled IRQs or they haven't. In this case, the v_recv_cmd_submit() appears to always be called with IRQs enabled so the code works fine. That means I could convert it to either _irq() or _irqsave() but I chose to use _irqsave() because it's more conservative and easier to review. Reviewed-by: Shuah Khan Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/Yo4gqLPtHO6XKMLn@kili Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vudc_rx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/usbip/vudc_rx.c b/drivers/usb/usbip/vudc_rx.c index 1e8a23d92cb4..d4a2f30a7580 100644 --- a/drivers/usb/usbip/vudc_rx.c +++ b/drivers/usb/usbip/vudc_rx.c @@ -104,18 +104,18 @@ static int v_recv_cmd_submit(struct vudc *udc, if (pdu->base.direction == USBIP_DIR_IN) address |= USB_DIR_IN; - spin_lock_irq(&udc->lock); + spin_lock_irqsave(&udc->lock, flags); urb_p->ep = vudc_find_endpoint(udc, address); if (!urb_p->ep) { /* we don't know the type, there may be isoc data! */ dev_err(&udc->pdev->dev, "request to nonexistent endpoint"); - spin_unlock_irq(&udc->lock); + spin_unlock_irqrestore(&udc->lock, flags); usbip_event_add(&udc->ud, VUDC_EVENT_ERROR_TCP); ret = -EPIPE; goto free_urbp; } urb_p->type = urb_p->ep->type; - spin_unlock_irq(&udc->lock); + spin_unlock_irqrestore(&udc->lock, flags); urb_p->new = 1; urb_p->seqnum = pdu->base.seqnum; From 62e4efe3375eb30292dabaec4481dc04550d3644 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 May 2022 15:30:13 +0300 Subject: [PATCH 0241/1436] usbip: vudc: Don't enable IRQs prematurely This code does: spin_unlock_irq(&udc->ud.lock); spin_unlock_irqrestore(&udc->lock, flags); which does not make sense. In theory, the first unlock could enable IRQs and then the second _irqrestore could disable them again. There would be a brief momemt where IRQs were enabled improperly. In real life, however, this function is always called with IRQs enabled and the bug does not affect runtime. Reviewed-by: Shuah Khan Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/Yo4hVWcZNYzKEkIQ@kili Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vudc_sysfs.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/usb/usbip/vudc_sysfs.c b/drivers/usb/usbip/vudc_sysfs.c index d1cf6b51bf85..c95e6b2bfd32 100644 --- a/drivers/usb/usbip/vudc_sysfs.c +++ b/drivers/usb/usbip/vudc_sysfs.c @@ -128,7 +128,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, goto unlock; } - spin_lock_irq(&udc->ud.lock); + spin_lock(&udc->ud.lock); if (udc->ud.status != SDEV_ST_AVAILABLE) { ret = -EINVAL; @@ -150,7 +150,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, } /* unlock and create threads and get tasks */ - spin_unlock_irq(&udc->ud.lock); + spin_unlock(&udc->ud.lock); spin_unlock_irqrestore(&udc->lock, flags); tcp_rx = kthread_create(&v_rx_loop, &udc->ud, "vudc_rx"); @@ -173,14 +173,14 @@ static ssize_t usbip_sockfd_store(struct device *dev, /* lock and update udc->ud state */ spin_lock_irqsave(&udc->lock, flags); - spin_lock_irq(&udc->ud.lock); + spin_lock(&udc->ud.lock); udc->ud.tcp_socket = socket; udc->ud.tcp_rx = tcp_rx; udc->ud.tcp_tx = tcp_tx; udc->ud.status = SDEV_ST_USED; - spin_unlock_irq(&udc->ud.lock); + spin_unlock(&udc->ud.lock); ktime_get_ts64(&udc->start_time); v_start_timer(udc); @@ -201,12 +201,12 @@ static ssize_t usbip_sockfd_store(struct device *dev, goto unlock; } - spin_lock_irq(&udc->ud.lock); + spin_lock(&udc->ud.lock); if (udc->ud.status != SDEV_ST_USED) { ret = -EINVAL; goto unlock_ud; } - spin_unlock_irq(&udc->ud.lock); + spin_unlock(&udc->ud.lock); usbip_event_add(&udc->ud, VUDC_EVENT_DOWN); } @@ -219,7 +219,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, sock_err: sockfd_put(socket); unlock_ud: - spin_unlock_irq(&udc->ud.lock); + spin_unlock(&udc->ud.lock); unlock: spin_unlock_irqrestore(&udc->lock, flags); mutex_unlock(&udc->ud.sysfs_lock); From 7afe69ad9221a77dc782b81f49cd7f99987740ed Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Fri, 27 May 2022 12:19:06 +0530 Subject: [PATCH 0242/1436] usb: common: usb-conn-gpio: Allow wakeup from system suspend Currently the VBUS/ID detection interrupts are disabled during system suspend. So the USB cable connect/disconnect event can't wakeup the system from low power mode. To allow this, we keep these interrupts enabled and configure them as wakeup capable. This behavior can be controlled through device wakeup source policy by the user space. Signed-off-by: Prashanth K Link: https://lore.kernel.org/r/1653634146-12215-1-git-send-email-quic_prashk@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/common/usb-conn-gpio.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/usb/common/usb-conn-gpio.c b/drivers/usb/common/usb-conn-gpio.c index 395f9bbe3056..b39c9f1c375d 100644 --- a/drivers/usb/common/usb-conn-gpio.c +++ b/drivers/usb/common/usb-conn-gpio.c @@ -257,6 +257,7 @@ static int usb_conn_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, info); + device_set_wakeup_capable(&pdev->dev, true); /* Perform initial detection */ usb_conn_queue_dwork(info, 0); @@ -286,6 +287,14 @@ static int __maybe_unused usb_conn_suspend(struct device *dev) { struct usb_conn_info *info = dev_get_drvdata(dev); + if (device_may_wakeup(dev)) { + if (info->id_gpiod) + enable_irq_wake(info->id_irq); + if (info->vbus_gpiod) + enable_irq_wake(info->vbus_irq); + return 0; + } + if (info->id_gpiod) disable_irq(info->id_irq); if (info->vbus_gpiod) @@ -300,6 +309,14 @@ static int __maybe_unused usb_conn_resume(struct device *dev) { struct usb_conn_info *info = dev_get_drvdata(dev); + if (device_may_wakeup(dev)) { + if (info->id_gpiod) + disable_irq_wake(info->id_irq); + if (info->vbus_gpiod) + disable_irq_wake(info->vbus_irq); + return 0; + } + pinctrl_pm_select_default_state(dev); if (info->id_gpiod) From f08aa7c80dac27ee00fa6827f447597d2fba5465 Mon Sep 17 00:00:00 2001 From: Tang Bin Date: Wed, 25 May 2022 21:53:32 +0800 Subject: [PATCH 0243/1436] usb: gadget: tegra-xudc: Fix error check in tegra_xudc_powerdomain_init() dev_pm_domain_attach_by_name() may return NULL in some cases, so IS_ERR() doesn't meet the requirements. Thus fix it. Fixes: 49db427232fe ("usb: gadget: Add UDC driver for tegra XUSB device mode controller") Signed-off-by: Tang Bin Link: https://lore.kernel.org/r/20220525135332.23144-1-tangbin@cmss.chinamobile.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/tegra-xudc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/udc/tegra-xudc.c b/drivers/usb/gadget/udc/tegra-xudc.c index 6d31ccf6aee5..3c37effdfa64 100644 --- a/drivers/usb/gadget/udc/tegra-xudc.c +++ b/drivers/usb/gadget/udc/tegra-xudc.c @@ -3691,15 +3691,15 @@ static int tegra_xudc_powerdomain_init(struct tegra_xudc *xudc) int err; xudc->genpd_dev_device = dev_pm_domain_attach_by_name(dev, "dev"); - if (IS_ERR(xudc->genpd_dev_device)) { - err = PTR_ERR(xudc->genpd_dev_device); + if (IS_ERR_OR_NULL(xudc->genpd_dev_device)) { + err = PTR_ERR(xudc->genpd_dev_device) ? : -ENODATA; dev_err(dev, "failed to get device power domain: %d\n", err); return err; } xudc->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "ss"); - if (IS_ERR(xudc->genpd_dev_ss)) { - err = PTR_ERR(xudc->genpd_dev_ss); + if (IS_ERR_OR_NULL(xudc->genpd_dev_ss)) { + err = PTR_ERR(xudc->genpd_dev_ss) ? : -ENODATA; dev_err(dev, "failed to get SuperSpeed power domain: %d\n", err); return err; } From 18fc7c435be3f17ea26a21b2e2312fcb9088e01f Mon Sep 17 00:00:00 2001 From: Tang Bin Date: Tue, 24 May 2022 20:14:04 +0800 Subject: [PATCH 0244/1436] usb: xhci: tegra: Fix error check In the function tegra_xusb_powerdomain_init(), dev_pm_domain_attach_by_name() may return NULL in some cases, so IS_ERR() doesn't meet the requirements. Thus fix it. Fixes: 6494a9ad86de ("usb: xhci: tegra: Add genpd support") Signed-off-by: Tang Bin Link: https://lore.kernel.org/r/20220524121404.18376-1-tangbin@cmss.chinamobile.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-tegra.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 996958a6565c..bdb776553826 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1010,15 +1010,15 @@ static int tegra_xusb_powerdomain_init(struct device *dev, int err; tegra->genpd_dev_host = dev_pm_domain_attach_by_name(dev, "xusb_host"); - if (IS_ERR(tegra->genpd_dev_host)) { - err = PTR_ERR(tegra->genpd_dev_host); + if (IS_ERR_OR_NULL(tegra->genpd_dev_host)) { + err = PTR_ERR(tegra->genpd_dev_host) ? : -ENODATA; dev_err(dev, "failed to get host pm-domain: %d\n", err); return err; } tegra->genpd_dev_ss = dev_pm_domain_attach_by_name(dev, "xusb_ss"); - if (IS_ERR(tegra->genpd_dev_ss)) { - err = PTR_ERR(tegra->genpd_dev_ss); + if (IS_ERR_OR_NULL(tegra->genpd_dev_ss)) { + err = PTR_ERR(tegra->genpd_dev_ss) ? : -ENODATA; dev_err(dev, "failed to get superspeed pm-domain: %d\n", err); return err; } From 4e27465a1506ea638f5adf80d50f50e911570701 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 May 2022 13:11:02 +0200 Subject: [PATCH 0245/1436] usb: typec: tcpm: fix typo in comment Spelling mistake (triple letters) in comment. Detected with the help of Coccinelle. Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20220521111145.81697-52-Julia.Lawall@inria.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 3bc2f4ebd1fe..7039383eac6d 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -471,7 +471,7 @@ struct tcpm_port { /* * When set, port requests PD_P_SNK_STDBY_MW upon entering SNK_DISCOVERY and - * the actual currrent limit after RX of PD_CTRL_PSRDY for PD link, + * the actual current limit after RX of PD_CTRL_PSRDY for PD link, * SNK_READY for non-pd link. */ bool slow_charger_loop; From 7563bc7327f0671570f259790a937c1373e378c0 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 May 2022 13:11:42 +0200 Subject: [PATCH 0246/1436] usb: gadget: bdc: fix typo in comment Spelling mistake (triple letters) in comment. Detected with the help of Coccinelle. Acked-by: Florian Fainelli Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20220521111145.81697-92-Julia.Lawall@inria.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/bdc/bdc_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/bdc/bdc_cmd.c b/drivers/usb/gadget/udc/bdc/bdc_cmd.c index 67887316a1a6..1848ced073f8 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_cmd.c +++ b/drivers/usb/gadget/udc/bdc/bdc_cmd.c @@ -307,7 +307,7 @@ int bdc_ep_clear_stall(struct bdc *bdc, int epnum) * his will reset the seq number for non EP0. */ if (epnum != 1) { - /* if the endpoint it not stallled */ + /* if the endpoint it not stalled */ if (!(ep->flags & BDC_EP_STALL)) { ret = bdc_ep_set_stall(bdc, epnum); if (ret) From 7013b2624c7b7b749b10fdce760eeb7f6af3fe99 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 21 May 2022 13:11:35 +0200 Subject: [PATCH 0247/1436] USB: chipidea: fix typo in comment Spelling mistake (triple letters) in comment. Detected with the help of Coccinelle. Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/20220521111145.81697-85-Julia.Lawall@inria.fr Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_imx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index 999c65390b7f..7daccb9c5006 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -21,7 +21,7 @@ struct imx_usbmisc_data { unsigned int pwr_pol:1; /* power polarity */ unsigned int evdo:1; /* set external vbus divider option */ unsigned int ulpi:1; /* connected to an ULPI phy */ - unsigned int hsic:1; /* HSIC controlller */ + unsigned int hsic:1; /* HSIC controller */ unsigned int ext_id:1; /* ID from exteranl event */ unsigned int ext_vbus:1; /* Vbus from exteranl event */ struct usb_phy *usb_phy; From 7c54e850ab70f156636d8ee6713839d20ac25782 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 23 May 2022 17:04:46 +0800 Subject: [PATCH 0248/1436] dt-bindings: usb: mtk-xhci: add support 'resets' property Add 'resets' property to support IP reset usually by top pericfg. Reviewed-by: AngeloGioacchino Del Regno Acked-by: Rob Herring Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220523090449.14430-1-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index 084d7135b2d9..892718459d25 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -113,6 +113,9 @@ properties: vbus-supply: description: Regulator of USB VBUS5v + resets: + maxItems: 1 + usb3-lpm-capable: true usb2-lpm-disable: true From 0efcd08571e5e769b794a54350e47b3817f3f8c9 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 23 May 2022 17:04:47 +0800 Subject: [PATCH 0249/1436] dt-bindings: usb: mtu3: add support 'resets' property Add 'resets' property to support IP reset usually by top pericfg. Reviewed-by: AngeloGioacchino Del Regno Acked-by: Rob Herring Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220523090449.14430-2-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml index 37b02a841dc4..e63b66545317 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.yaml @@ -107,6 +107,9 @@ properties: maximum-speed: enum: [super-speed-plus, super-speed, high-speed, full-speed] + resets: + maxItems: 1 + "#address-cells": enum: [1, 2] From 32b615ed4b7da586eb447212e3d2665b8aa6fdb2 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 23 May 2022 17:04:48 +0800 Subject: [PATCH 0250/1436] usb: xhci-mtk: add support optional controller reset Add support controller reset via a reset-controller usually in infracfg, it's different with the software reset by IPPC which only used to reset MAC, and it will also reset IPPC meanwhile. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220523090449.14430-3-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mtk.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index b1045f534a4b..01705e559c42 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "xhci.h" #include "xhci-mtk.h" @@ -550,6 +551,12 @@ static int xhci_mtk_probe(struct platform_device *pdev) if (ret) goto disable_ldos; + ret = device_reset_optional(dev); + if (ret) { + dev_err_probe(dev, ret, "failed to reset controller\n"); + goto disable_clk; + } + hcd = usb_create_hcd(driver, dev, dev_name(dev)); if (!hcd) { ret = -ENOMEM; From e84e3e99256e2aedab5f45f8e02bc98c891b9188 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Mon, 23 May 2022 17:04:49 +0800 Subject: [PATCH 0251/1436] usb: mtu3: add support controller reset Add support controller reset via a reset-controller usually in infracfg, it's different with the software reset by IPPC which only used to reset MAC, and it will also reset IPPC meanwhile. Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220523090449.14430-4-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_plat.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 4309ed939178..d14494b30064 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "mtu3.h" #include "mtu3_dr.h" @@ -345,6 +346,12 @@ static int mtu3_probe(struct platform_device *pdev) dev_info(dev, "wakeup irq %d\n", ssusb->wakeup_irq); } + ret = device_reset_optional(dev); + if (ret) { + dev_err_probe(dev, ret, "failed to reset controller\n"); + goto comm_exit; + } + ssusb_ip_sw_reset(ssusb); if (IS_ENABLED(CONFIG_USB_MTU3_HOST)) From 87d76b5f1d8eeb49efa16e2018e188864cbb9401 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Mon, 30 May 2022 00:38:46 +0200 Subject: [PATCH 0252/1436] usb: gadget: uvc: calculate the number of request depending on framesize The current limitation of possible number of requests being handled is dependent on the gadget speed. It makes more sense to depend on the typical frame size when calculating the number of requests. This patch is changing this and is using the previous limits as boundaries for reasonable minimum and maximum number of requests. For a 1080p jpeg encoded video stream with a maximum imagesize of e.g. 800kB with a maxburst of 8 and an multiplier of 1 the resulting number of requests is calculated to 49. 800768 1 nreqs = ------ * -------------- ~= 49 2 (1024 * 8 * 1) Tested-by: Dan Vacura Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20220529223848.105914-2-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc_queue.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c index 951934aa4454..ec500ee499ee 100644 --- a/drivers/usb/gadget/function/uvc_queue.c +++ b/drivers/usb/gadget/function/uvc_queue.c @@ -44,7 +44,8 @@ static int uvc_queue_setup(struct vb2_queue *vq, { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); struct uvc_video *video = container_of(queue, struct uvc_video, queue); - struct usb_composite_dev *cdev = video->uvc->func.config->cdev; + unsigned int req_size; + unsigned int nreq; if (*nbuffers > UVC_MAX_VIDEO_BUFFERS) *nbuffers = UVC_MAX_VIDEO_BUFFERS; @@ -53,10 +54,16 @@ static int uvc_queue_setup(struct vb2_queue *vq, sizes[0] = video->imagesize; - if (cdev->gadget->speed < USB_SPEED_SUPER) - video->uvc_num_requests = 4; - else - video->uvc_num_requests = 64; + req_size = video->ep->maxpacket + * max_t(unsigned int, video->ep->maxburst, 1) + * (video->ep->mult); + + /* We divide by two, to increase the chance to run + * into fewer requests for smaller framesizes. + */ + nreq = DIV_ROUND_UP(DIV_ROUND_UP(sizes[0], 2), req_size); + nreq = clamp(nreq, 4U, 64U); + video->uvc_num_requests = nreq; return 0; } From a725d0f6dfc5d3739d6499f30ec865305ba3544d Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Mon, 30 May 2022 00:38:48 +0200 Subject: [PATCH 0253/1436] usb: gadget: uvc: call uvc uvcg_warn on completed status instead of uvcg_info Likewise to the uvcvideo hostside driver, this patch is changing the usb_request message of an non zero completion handler call from dev_info to dev_warn. Reviewed-by: Laurent Pinchart Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20220529223848.105914-4-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/uvc_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/uvc_video.c b/drivers/usb/gadget/function/uvc_video.c index 5876bc73f929..93f42c7f800d 100644 --- a/drivers/usb/gadget/function/uvc_video.c +++ b/drivers/usb/gadget/function/uvc_video.c @@ -261,7 +261,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req) break; default: - uvcg_info(&video->uvc->func, + uvcg_warn(&video->uvc->func, "VS request completed with status %d.\n", req->status); uvcg_queue_cancel(queue, 0); From 757bdf1f2fb5f1281cb13da5f24860ae81c6140e Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Wed, 8 Jun 2022 23:47:42 +0530 Subject: [PATCH 0254/1436] usb: musb: remove schedule work called after flush MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In musb_remove() cancel_delayed_work_sync(&musb->irq_work) is called which flush the irq_work work queue. After cancel delayed work, musb_remove() call musb_gadget_cleanup->usb_del_gadget_udc->usb_del_gadget ->usb_gadget_remove_driver->usb_gadget_udc_stop->udc ->gadget->ops->udc_stop(udc->gadget); Where musb_gadget_stop() call "schedule_delayed_work(&musb->irq_work, 0)” which is already cancel/flush. So remove the schedule_delayed_work(&musb->irq_work, 0); from musb_gadget_stop function. Signed-off-by: Saurav Girepunje Link: https://lore.kernel.org/r/YqDnxkWZV2KfZh5q@Sauravs-MacBook-Air.local Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_gadget.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 51274b87f46c..daada4b66a92 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1910,8 +1910,6 @@ static int musb_gadget_stop(struct usb_gadget *g) */ /* Force check of devctl register for PM runtime */ - schedule_delayed_work(&musb->irq_work, 0); - pm_runtime_mark_last_busy(musb->controller); pm_runtime_put_autosuspend(musb->controller); From 5e1fa6dd4caa7ce26029427647bc2f424784a559 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Thu, 9 Jun 2022 15:42:31 +0800 Subject: [PATCH 0255/1436] usb: mtu3: sync interrupt before unbind the udc Register gadget irq to avoid the interrupt handler is occurred or scheduled during the unbind flow, may happen when do android function switch stress test. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220609074233.15532-1-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index 9977600616d7..d57cea62fe6b 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -680,6 +680,7 @@ int mtu3_gadget_setup(struct mtu3 *mtu) mtu->g.speed = USB_SPEED_UNKNOWN; mtu->g.sg_supported = 0; mtu->g.name = MTU3_DRIVER_NAME; + mtu->g.irq = mtu->irq; mtu->is_active = 0; mtu->delayed_status = false; From 54c4862f29725a0a20b09a10f2fa788a973713ee Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Thu, 9 Jun 2022 15:42:32 +0800 Subject: [PATCH 0256/1436] usb: mtu3: implement udc_async_callbacks of gadget operation Implement udc_async_callbacks hook function to avoid a race when unnbinding gadget drivers, refer to: 7dc0c55e9f30 ('USB: UDC core: Add udc_async_callbacks gadget op') Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220609074233.15532-2-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3.h | 1 + drivers/usb/mtu3/mtu3_gadget.c | 19 ++++++++++++++++--- drivers/usb/mtu3/mtu3_gadget_ep0.c | 2 +- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 022bbdc54e68..8408e1b1a24a 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -357,6 +357,7 @@ struct mtu3 { unsigned delayed_status:1; unsigned gen2cp:1; unsigned connected:1; + unsigned async_callbacks:1; u8 address; u8 test_mode_nr; diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index d57cea62fe6b..30999b4debb8 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -592,6 +592,18 @@ mtu3_gadget_set_speed(struct usb_gadget *g, enum usb_device_speed speed) spin_unlock_irqrestore(&mtu->lock, flags); } +static void mtu3_gadget_async_callbacks(struct usb_gadget *g, bool enable) +{ + struct mtu3 *mtu = gadget_to_mtu3(g); + unsigned long flags; + + dev_dbg(mtu->dev, "%s %s\n", __func__, enable ? "en" : "dis"); + + spin_lock_irqsave(&mtu->lock, flags); + mtu->async_callbacks = enable; + spin_unlock_irqrestore(&mtu->lock, flags); +} + static const struct usb_gadget_ops mtu3_gadget_ops = { .get_frame = mtu3_gadget_get_frame, .wakeup = mtu3_gadget_wakeup, @@ -600,6 +612,7 @@ static const struct usb_gadget_ops mtu3_gadget_ops = { .udc_start = mtu3_gadget_start, .udc_stop = mtu3_gadget_stop, .udc_set_speed = mtu3_gadget_set_speed, + .udc_async_callbacks = mtu3_gadget_async_callbacks, }; static void mtu3_state_reset(struct mtu3 *mtu) @@ -697,7 +710,7 @@ void mtu3_gadget_cleanup(struct mtu3 *mtu) void mtu3_gadget_resume(struct mtu3 *mtu) { dev_dbg(mtu->dev, "gadget RESUME\n"); - if (mtu->gadget_driver && mtu->gadget_driver->resume) { + if (mtu->async_callbacks && mtu->gadget_driver && mtu->gadget_driver->resume) { spin_unlock(&mtu->lock); mtu->gadget_driver->resume(&mtu->g); spin_lock(&mtu->lock); @@ -708,7 +721,7 @@ void mtu3_gadget_resume(struct mtu3 *mtu) void mtu3_gadget_suspend(struct mtu3 *mtu) { dev_dbg(mtu->dev, "gadget SUSPEND\n"); - if (mtu->gadget_driver && mtu->gadget_driver->suspend) { + if (mtu->async_callbacks && mtu->gadget_driver && mtu->gadget_driver->suspend) { spin_unlock(&mtu->lock); mtu->gadget_driver->suspend(&mtu->g); spin_lock(&mtu->lock); @@ -719,7 +732,7 @@ void mtu3_gadget_suspend(struct mtu3 *mtu) void mtu3_gadget_disconnect(struct mtu3 *mtu) { dev_dbg(mtu->dev, "gadget DISCONNECT\n"); - if (mtu->gadget_driver && mtu->gadget_driver->disconnect) { + if (mtu->async_callbacks && mtu->gadget_driver && mtu->gadget_driver->disconnect) { spin_unlock(&mtu->lock); mtu->gadget_driver->disconnect(&mtu->g); spin_lock(&mtu->lock); diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c index 0ca47212f1ec..7e7013508af6 100644 --- a/drivers/usb/mtu3/mtu3_gadget_ep0.c +++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c @@ -66,7 +66,7 @@ __acquires(mtu->lock) { int ret; - if (!mtu->gadget_driver) + if (!mtu->gadget_driver || !mtu->async_callbacks) return -EOPNOTSUPP; spin_unlock(&mtu->lock); From 13118959cb1a67eb80bf06152e35e0df733615e2 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Thu, 9 Jun 2022 15:42:33 +0800 Subject: [PATCH 0257/1436] usb: mtu3: register mtu3_irq by threaded irq Use threaded irq to improve time consuming top-half Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220609074233.15532-3-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index c4a2c37abf62..3c6a670efafa 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -965,7 +965,8 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) goto dma_mask_err; } - ret = devm_request_irq(dev, mtu->irq, mtu3_irq, 0, dev_name(dev), mtu); + ret = devm_request_threaded_irq(dev, mtu->irq, NULL, mtu3_irq, + IRQF_ONESHOT, dev_name(dev), mtu); if (ret) { dev_err(dev, "request irq %d failed!\n", mtu->irq); goto irq_err; From 5767f40053ebf599e47d688e65b259d0b6f3227a Mon Sep 17 00:00:00 2001 From: Sanket Goswami Date: Thu, 26 May 2022 12:03:04 +0530 Subject: [PATCH 0258/1436] ucsi_ccg: Do not hardcode interrupt polarity and type The current implementation supports only Level trigger with ACTIVE HIGH, which is overriding level and polarity set by the ACPI table, hence implement the common utility function to manage irq requests. Suggested-by: Heikki Krogerus Signed-off-by: Sanket Goswami Link: https://lore.kernel.org/r/20220526063305.3144352-2-Sanket.Goswami@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_ccg.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 6db7c8ddd51c..0707a7156299 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -627,6 +627,16 @@ err_clear_irq: return IRQ_HANDLED; } +static int ccg_request_irq(struct ucsi_ccg *uc) +{ + unsigned long flags = IRQF_ONESHOT; + + if (!has_acpi_companion(uc->dev)) + flags |= IRQF_TRIGGER_HIGH; + + return request_threaded_irq(uc->irq, NULL, ccg_irq_handler, flags, dev_name(uc->dev), uc); +} + static void ccg_pm_workaround_work(struct work_struct *pm_work) { ccg_irq_handler(0, container_of(pm_work, struct ucsi_ccg, pm_work)); @@ -1250,9 +1260,7 @@ static int ccg_restart(struct ucsi_ccg *uc) return status; } - status = request_threaded_irq(uc->irq, NULL, ccg_irq_handler, - IRQF_ONESHOT | IRQF_TRIGGER_HIGH, - dev_name(dev), uc); + status = ccg_request_irq(uc); if (status < 0) { dev_err(dev, "request_threaded_irq failed - %d\n", status); return status; @@ -1331,6 +1339,7 @@ static int ucsi_ccg_probe(struct i2c_client *client, uc->dev = dev; uc->client = client; + uc->irq = client->irq; mutex_init(&uc->lock); init_completion(&uc->complete); INIT_WORK(&uc->work, ccg_update_firmware); @@ -1366,16 +1375,12 @@ static int ucsi_ccg_probe(struct i2c_client *client, ucsi_set_drvdata(uc->ucsi, uc); - status = request_threaded_irq(client->irq, NULL, ccg_irq_handler, - IRQF_ONESHOT | IRQF_TRIGGER_HIGH, - dev_name(dev), uc); + status = ccg_request_irq(uc); if (status < 0) { dev_err(uc->dev, "request_threaded_irq failed - %d\n", status); goto out_ucsi_destroy; } - uc->irq = client->irq; - status = ucsi_register(uc->ucsi); if (status) goto out_free_irq; From 5fd6c4f0a649c956b2c50c18e0da765b7f5e3eff Mon Sep 17 00:00:00 2001 From: Sanket Goswami Date: Thu, 26 May 2022 12:03:05 +0530 Subject: [PATCH 0259/1436] ucsi_ccg: ACPI based I2c client enumeration for AMD ASICs Some of the AMD platforms have Cypress CCGX PD controller connected to system I2C i.e designware I2C controller. Added support to enumerate the CCGX client by adding ACPI ID to the firmware. Suggested-by: Heikki Krogerus Signed-off-by: Sanket Goswami Link: https://lore.kernel.org/r/20220526063305.3144352-3-Sanket.Goswami@amd.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_ccg.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index 0707a7156299..5c0bf48be766 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -1423,6 +1423,12 @@ static const struct i2c_device_id ucsi_ccg_device_id[] = { }; MODULE_DEVICE_TABLE(i2c, ucsi_ccg_device_id); +static const struct acpi_device_id amd_i2c_ucsi_match[] = { + {"AMDI0042"}, + {} +}; +MODULE_DEVICE_TABLE(acpi, amd_i2c_ucsi_match); + static int ucsi_ccg_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -1464,6 +1470,7 @@ static struct i2c_driver ucsi_ccg_driver = { .name = "ucsi_ccg", .pm = &ucsi_ccg_pm, .dev_groups = ucsi_ccg_groups, + .acpi_match_table = amd_i2c_ucsi_match, }, .probe = ucsi_ccg_probe, .remove = ucsi_ccg_remove, From d2b47721a10037c17b378decc611341bfff60c44 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 10 Jun 2022 09:53:47 +0200 Subject: [PATCH 0260/1436] staging: greybus: audio: replace safe list iteration No entry is being removed from the list when iterating the widget list in gbaudio_dapm_free_controls() so there's no need to use list_for_each_entry_safe(). Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220610075347.18917-1-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/audio_helper.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/staging/greybus/audio_helper.c b/drivers/staging/greybus/audio_helper.c index 07461a5d97c7..05e91e6bc2a0 100644 --- a/drivers/staging/greybus/audio_helper.c +++ b/drivers/staging/greybus/audio_helper.c @@ -115,7 +115,7 @@ int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm, int num) { int i; - struct snd_soc_dapm_widget *w, *next_w, *tmp_w; + struct snd_soc_dapm_widget *w, *tmp_w; #ifdef CONFIG_DEBUG_FS struct dentry *parent = dapm->debugfs_dapm; struct dentry *debugfs_w = NULL; @@ -125,8 +125,7 @@ int gbaudio_dapm_free_controls(struct snd_soc_dapm_context *dapm, for (i = 0; i < num; i++) { /* below logic can be optimized to identify widget pointer */ w = NULL; - list_for_each_entry_safe(tmp_w, next_w, &dapm->card->widgets, - list) { + list_for_each_entry(tmp_w, &dapm->card->widgets, list) { if (tmp_w->dapm == dapm && !strcmp(tmp_w->name, widget->name)) { w = tmp_w; From 4bbdc208a5ff3ba970fecd4fdb36a9ce6ca06895 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 10 Jun 2022 19:08:43 +0900 Subject: [PATCH 0261/1436] staging: olpc_dcon: Replace flush_scheduled_work() with flush_work(). Since "struct dcon_priv" is per a device struct, I assume that dcon_set_source_sync() needs to wait for only one work associated with that device. Therefore, wait for only that work using flush_work(). Signed-off-by: Tetsuo Handa Link: https://lore.kernel.org/r/a973969d-cfd0-adc8-2651-d299199dbd7b@I-love.SAKURA.ne.jp Signed-off-by: Greg Kroah-Hartman --- drivers/staging/olpc_dcon/olpc_dcon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index b9d570e9ad3b..9363c5cfe50f 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -383,7 +383,7 @@ static void dcon_set_source(struct dcon_priv *dcon, int arg) static void dcon_set_source_sync(struct dcon_priv *dcon, int arg) { dcon_set_source(dcon, arg); - flush_scheduled_work(); + flush_work(&dcon->switch_source); } static ssize_t dcon_mode_show(struct device *dev, From 20646f5b1e798bcc20044ae90ac3702f177bf254 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 6 Jun 2022 17:23:45 +0200 Subject: [PATCH 0262/1436] netfilter: xtables: Bring SPDX identifier back Commit e2be04c7f995 ("License cleanup: add SPDX license identifier to uapi header files with a license") added the correct SPDX identifier to include/uapi/linux/netfilter/xt_IDLETIMER.h. A subsequent commit removed it for no reason and reintroduced the UAPI license incorrectness as the file is now missing the UAPI exception again. Add it back and remove the GPLv2 boilerplate while at it. Fixes: 68983a354a65 ("netfilter: xtables: Add snapshot of hardidletimer target") Cc: Manoj Basapathi Cc: Subash Abhinov Kasiviswanathan Cc: Pablo Neira Ayuso Cc: netfilter-devel@vger.kernel.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/netfilter/xt_IDLETIMER.h | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/include/uapi/linux/netfilter/xt_IDLETIMER.h b/include/uapi/linux/netfilter/xt_IDLETIMER.h index 49ddcdc61c09..7bfb31a66fc9 100644 --- a/include/uapi/linux/netfilter/xt_IDLETIMER.h +++ b/include/uapi/linux/netfilter/xt_IDLETIMER.h @@ -1,6 +1,5 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* - * linux/include/linux/netfilter/xt_IDLETIMER.h - * * Header file for Xtables timer target module. * * Copyright (C) 2004, 2010 Nokia Corporation @@ -10,20 +9,6 @@ * by Luciano Coelho * * Contact: Luciano Coelho - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef _XT_IDLETIMER_H From a6546f89eac9bfad4b50a7f8ccfbefe0ae01e7df Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:10 +0200 Subject: [PATCH 0263/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_8.RULE Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license version 2 as published by the free software foundation extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/vfio-mediated-device.rst | 4 +--- arch/arm/boot/bootp/bootp.lds | 5 +---- include/linux/input/elan-i2c-ids.h | 5 +---- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/Documentation/driver-api/vfio-mediated-device.rst b/Documentation/driver-api/vfio-mediated-device.rst index eded8719180f..66bd00d7aecf 100644 --- a/Documentation/driver-api/vfio-mediated-device.rst +++ b/Documentation/driver-api/vfio-mediated-device.rst @@ -1,3 +1,4 @@ +.. SPDX-License-Identifier: GPL-2.0-only .. include:: ===================== @@ -8,9 +9,6 @@ VFIO Mediated devices :Author: Neo Jia :Author: Kirti Wankhede -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License version 2 as -published by the Free Software Foundation. Virtual Function I/O (VFIO) Mediated devices[1] diff --git a/arch/arm/boot/bootp/bootp.lds b/arch/arm/boot/bootp/bootp.lds index fc54394f4340..160128186bf8 100644 --- a/arch/arm/boot/bootp/bootp.lds +++ b/arch/arm/boot/bootp/bootp.lds @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/arch/arm/boot/bootp/bootp.lds * * Copyright (C) 2000-2002 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ OUTPUT_ARCH(arm) ENTRY(_start) diff --git a/include/linux/input/elan-i2c-ids.h b/include/linux/input/elan-i2c-ids.h index 520858d12680..51cca17ee94c 100644 --- a/include/linux/input/elan-i2c-ids.h +++ b/include/linux/input/elan-i2c-ids.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Elan I2C/SMBus Touchpad device whitelist * @@ -11,10 +12,6 @@ * copyright (c) 2011-2012 Cypress Semiconductor, Inc. * copyright (c) 2011-2012 Google, Inc. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * * Trademarks are the property of their respective owners. */ From 52e6676ef56f4803b1ef14ed427c5824050163a3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:11 +0200 Subject: [PATCH 0264/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_30.RULE (part 1) Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license as published by the free software foundation version 2 this program is distributed as is without any warranty of any kind whether express or implied without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/bcm11351.dtsi | 14 ++------------ arch/arm/boot/dts/bcm21664-garnet.dts | 14 ++------------ arch/arm/boot/dts/bcm21664.dtsi | 14 ++------------ arch/arm/boot/dts/bcm28155-ap.dts | 14 ++------------ arch/arm/boot/dts/dra72x-mmc-iodelay.dtsi | 10 +--------- arch/arm/boot/dts/dra74x-mmc-iodelay.dtsi | 10 +--------- arch/arm/include/debug/brcmstb.S | 14 ++------------ arch/arm/mach-bcm/Makefile | 9 +-------- arch/arm/mach-bcm/bcm63xx.c | 14 ++------------ arch/arm/mach-bcm/bcm_cygnus.c | 14 ++------------ arch/arm/mach-bcm/bcm_hr2.c | 14 ++------------ arch/arm/mach-bcm/bcm_kona_smc.c | 14 ++------------ arch/arm/mach-bcm/bcm_kona_smc.h | 14 ++------------ arch/arm/mach-bcm/bcm_nsp.c | 14 ++------------ arch/arm/mach-bcm/board_bcm21664.c | 14 ++------------ arch/arm/mach-bcm/board_bcm23550.c | 14 ++------------ arch/arm/mach-bcm/board_bcm281xx.c | 14 ++------------ arch/arm/mach-bcm/brcmstb.c | 14 ++------------ arch/arm/mach-bcm/kona_l2_cache.c | 14 ++------------ arch/arm/mach-bcm/kona_l2_cache.h | 14 ++------------ arch/arm/mach-bcm/platsmp-brcmstb.c | 10 +--------- arch/arm/mach-davinci/board-dm365-evm.c | 11 +---------- arch/arm/mach-davinci/davinci.h | 10 +--------- arch/arm/mach-davinci/dm365.c | 10 +--------- arch/arm/mach-davinci/pm.h | 10 +--------- arch/arm/mach-omap1/gpio15xx.c | 10 +--------- arch/arm/mach-omap1/gpio16xx.c | 10 +--------- arch/arm/mach-omap1/gpio7xx.c | 10 +--------- arch/arm/mach-omap2/am33xx.h | 10 +--------- arch/arm/mach-omap2/clockdomains33xx_data.c | 10 +--------- arch/arm/mach-omap2/clockdomains81xx_data.c | 10 +--------- arch/arm/mach-omap2/cm-regbits-33xx.h | 10 +--------- arch/arm/mach-omap2/cm33xx.c | 10 +--------- arch/arm/mach-omap2/cm33xx.h | 10 +--------- arch/arm/mach-omap2/cm81xx.h | 10 +--------- arch/arm/mach-omap2/omap_hwmod_81xx_data.c | 11 +---------- arch/arm/mach-omap2/powerdomains33xx_data.c | 10 +--------- arch/arm/mach-omap2/prm-regbits-33xx.h | 10 +--------- arch/arm/mach-omap2/prm33xx.c | 10 +--------- arch/arm/mach-omap2/prm33xx.h | 10 +--------- arch/arm/mach-omap2/ti81xx.h | 10 +--------- drivers/char/hw_random/iproc-rng200.c | 9 +-------- drivers/clk/bcm/clk-bcm21664.c | 10 +--------- drivers/clk/bcm/clk-bcm281xx.c | 10 +--------- drivers/clk/bcm/clk-bcm63xx.c | 14 ++------------ drivers/clk/bcm/clk-cygnus.c | 14 ++------------ drivers/clk/bcm/clk-hr2.c | 14 ++------------ drivers/clk/bcm/clk-iproc-armpll.c | 14 ++------------ drivers/clk/bcm/clk-iproc-asiu.c | 14 ++------------ drivers/clk/bcm/clk-iproc-pll.c | 14 ++------------ drivers/clk/bcm/clk-iproc.h | 14 ++------------ drivers/clk/bcm/clk-kona-setup.c | 10 +--------- drivers/clk/bcm/clk-kona.c | 10 +--------- drivers/clk/bcm/clk-kona.h | 10 +--------- drivers/clk/bcm/clk-ns2.c | 14 ++------------ drivers/clk/bcm/clk-nsp.c | 14 ++------------ drivers/clk/ti/adpll.c | 11 +---------- drivers/clk/ti/clk-2xxx.c | 10 +--------- drivers/clk/ti/clk-33xx.c | 10 +--------- drivers/clk/ti/clk-3xxx.c | 10 +--------- drivers/clk/ti/clk-43xx.c | 10 +--------- drivers/clk/ti/clk-816x.c | 11 +---------- drivers/clk/ti/clock.h | 10 +--------- drivers/clk/ti/fapll.c | 11 +---------- 64 files changed, 90 insertions(+), 657 deletions(-) diff --git a/arch/arm/boot/dts/bcm11351.dtsi b/arch/arm/boot/dts/bcm11351.dtsi index 6197e7d80e3b..53696078bbf0 100644 --- a/arch/arm/boot/dts/bcm11351.dtsi +++ b/arch/arm/boot/dts/bcm11351.dtsi @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2012-2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2012-2013 Broadcom Corporation #include #include diff --git a/arch/arm/boot/dts/bcm21664-garnet.dts b/arch/arm/boot/dts/bcm21664-garnet.dts index be468f4adc37..1854cd907a1b 100644 --- a/arch/arm/boot/dts/bcm21664-garnet.dts +++ b/arch/arm/boot/dts/bcm21664-garnet.dts @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation /dts-v1/; diff --git a/arch/arm/boot/dts/bcm21664.dtsi b/arch/arm/boot/dts/bcm21664.dtsi index cc58f2b926b9..2684c37cb3a0 100644 --- a/arch/arm/boot/dts/bcm21664.dtsi +++ b/arch/arm/boot/dts/bcm21664.dtsi @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/arch/arm/boot/dts/bcm28155-ap.dts b/arch/arm/boot/dts/bcm28155-ap.dts index ead6e9804dbf..41fe31024188 100644 --- a/arch/arm/boot/dts/bcm28155-ap.dts +++ b/arch/arm/boot/dts/bcm28155-ap.dts @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013 Broadcom Corporation /dts-v1/; diff --git a/arch/arm/boot/dts/dra72x-mmc-iodelay.dtsi b/arch/arm/boot/dts/dra72x-mmc-iodelay.dtsi index a9dce919d443..34eea3c048bd 100644 --- a/arch/arm/boot/dts/dra72x-mmc-iodelay.dtsi +++ b/arch/arm/boot/dts/dra72x-mmc-iodelay.dtsi @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MMC IOdelay values for TI's DRA72x, DRA71x and AM571x SoCs. * * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ /* diff --git a/arch/arm/boot/dts/dra74x-mmc-iodelay.dtsi b/arch/arm/boot/dts/dra74x-mmc-iodelay.dtsi index e86da7a970b6..b9d040135c5f 100644 --- a/arch/arm/boot/dts/dra74x-mmc-iodelay.dtsi +++ b/arch/arm/boot/dts/dra74x-mmc-iodelay.dtsi @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MMC IOdelay values for TI's DRA74x, DRA75x and AM572x SoCs. * * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ /* diff --git a/arch/arm/include/debug/brcmstb.S b/arch/arm/include/debug/brcmstb.S index f684e3a815f6..f6175e6e28cd 100644 --- a/arch/arm/include/debug/brcmstb.S +++ b/arch/arm/include/debug/brcmstb.S @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2016 Broadcom */ #include #include diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile index b2394ddb0558..61806baf2f48 100644 --- a/arch/arm/mach-bcm/Makefile +++ b/arch/arm/mach-bcm/Makefile @@ -1,14 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Copyright (C) 2012-2015 Broadcom Corporation # -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation version 2. -# -# This program is distributed "as is" WITHOUT ANY WARRANTY of any -# kind, whether express or implied; without even the implied warranty -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. # Cygnus obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o diff --git a/arch/arm/mach-bcm/bcm63xx.c b/arch/arm/mach-bcm/bcm63xx.c index c4c66ae51308..f855e361dfba 100644 --- a/arch/arm/mach-bcm/bcm63xx.c +++ b/arch/arm/mach-bcm/bcm63xx.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include diff --git a/arch/arm/mach-bcm/bcm_cygnus.c b/arch/arm/mach-bcm/bcm_cygnus.c index 7ae894c7849b..2469b66cc59e 100644 --- a/arch/arm/mach-bcm/bcm_cygnus.c +++ b/arch/arm/mach-bcm/bcm_cygnus.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include diff --git a/arch/arm/mach-bcm/bcm_hr2.c b/arch/arm/mach-bcm/bcm_hr2.c index c104f28995d7..a19cc206ec76 100644 --- a/arch/arm/mach-bcm/bcm_hr2.c +++ b/arch/arm/mach-bcm/bcm_hr2.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2017 Broadcom #include diff --git a/arch/arm/mach-bcm/bcm_kona_smc.c b/arch/arm/mach-bcm/bcm_kona_smc.c index 43829e49ad93..eae26eeff819 100644 --- a/arch/arm/mach-bcm/bcm_kona_smc.c +++ b/arch/arm/mach-bcm/bcm_kona_smc.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013 Broadcom Corporation #include #include #include diff --git a/arch/arm/mach-bcm/bcm_kona_smc.h b/arch/arm/mach-bcm/bcm_kona_smc.h index 2e29ec67e414..17f3811fa543 100644 --- a/arch/arm/mach-bcm/bcm_kona_smc.h +++ b/arch/arm/mach-bcm/bcm_kona_smc.h @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2013 Broadcom Corporation */ #ifndef BCM_KONA_SMC_H #define BCM_KONA_SMC_H diff --git a/arch/arm/mach-bcm/bcm_nsp.c b/arch/arm/mach-bcm/bcm_nsp.c index a1101a3d318e..65ed9f8a518a 100644 --- a/arch/arm/mach-bcm/bcm_nsp.c +++ b/arch/arm/mach-bcm/bcm_nsp.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2015 Broadcom Corporation #include diff --git a/arch/arm/mach-bcm/board_bcm21664.c b/arch/arm/mach-bcm/board_bcm21664.c index c5bf01641172..9ce9ed092b09 100644 --- a/arch/arm/mach-bcm/board_bcm21664.c +++ b/arch/arm/mach-bcm/board_bcm21664.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include diff --git a/arch/arm/mach-bcm/board_bcm23550.c b/arch/arm/mach-bcm/board_bcm23550.c index 0ac01debd077..dd6e9cb785e0 100644 --- a/arch/arm/mach-bcm/board_bcm23550.c +++ b/arch/arm/mach-bcm/board_bcm23550.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Broadcom #include diff --git a/arch/arm/mach-bcm/board_bcm281xx.c b/arch/arm/mach-bcm/board_bcm281xx.c index 1238ac801530..91f6d633ee8e 100644 --- a/arch/arm/mach-bcm/board_bcm281xx.c +++ b/arch/arm/mach-bcm/board_bcm281xx.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2012-2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2012-2014 Broadcom Corporation #include #include diff --git a/arch/arm/mach-bcm/brcmstb.c b/arch/arm/mach-bcm/brcmstb.c index 5f127d5f1045..2e3385ced82a 100644 --- a/arch/arm/mach-bcm/brcmstb.c +++ b/arch/arm/mach-bcm/brcmstb.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013-2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013-2014 Broadcom Corporation #include #include diff --git a/arch/arm/mach-bcm/kona_l2_cache.c b/arch/arm/mach-bcm/kona_l2_cache.c index 59ad86304092..457c66e1d7ae 100644 --- a/arch/arm/mach-bcm/kona_l2_cache.c +++ b/arch/arm/mach-bcm/kona_l2_cache.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2012-2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2012-2014 Broadcom Corporation #include diff --git a/arch/arm/mach-bcm/kona_l2_cache.h b/arch/arm/mach-bcm/kona_l2_cache.h index 46f84a95ab1c..77c5dc033910 100644 --- a/arch/arm/mach-bcm/kona_l2_cache.h +++ b/arch/arm/mach-bcm/kona_l2_cache.h @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2012-2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2012-2014 Broadcom Corporation */ #ifdef CONFIG_ARCH_BCM_MOBILE_L2_CACHE void kona_l2_cache_init(void); diff --git a/arch/arm/mach-bcm/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c index 9b457714a41c..8989299ebdd6 100644 --- a/arch/arm/mach-bcm/platsmp-brcmstb.c +++ b/arch/arm/mach-bcm/platsmp-brcmstb.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom STB CPU SMP and hotplug support for ARM * * Copyright (C) 2013-2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c index 9adcb5879d14..d8c6c360818b 100644 --- a/arch/arm/mach-davinci/board-dm365-evm.c +++ b/arch/arm/mach-davinci/board-dm365-evm.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DaVinci DM365 EVM board support * * Copyright (C) 2009 Texas Instruments Incorporated - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include @@ -861,4 +853,3 @@ MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM365 EVM") .init_late = davinci_init_late, .dma_zone_size = SZ_128M, MACHINE_END - diff --git a/arch/arm/mach-davinci/davinci.h b/arch/arm/mach-davinci/davinci.h index e895eaf9c7cc..b7172797692b 100644 --- a/arch/arm/mach-davinci/davinci.h +++ b/arch/arm/mach-davinci/davinci.h @@ -1,18 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This file contains the processor specific definitions * of the TI DM644x, DM355, DM365, and DM646x. * * Copyright (C) 2011 Texas Instruments Incorporated * Copyright (c) 2007 Deep Root Systems, LLC - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __DAVINCI_H #define __DAVINCI_H diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c index 73ccc916f60a..7538bb87f373 100644 --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DaVinci DM365 chip specific setup * * Copyright (C) 2009 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-davinci/pm.h b/arch/arm/mach-davinci/pm.h index 5a5f0ecc0704..6f50d6eb8da8 100644 --- a/arch/arm/mach-davinci/pm.h +++ b/arch/arm/mach-davinci/pm.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI DaVinci platform support for power management. * * Copyright (C) 2009 Texas Instruments, Inc. https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _MACH_DAVINCI_PM_H #define _MACH_DAVINCI_PM_H diff --git a/arch/arm/mach-omap1/gpio15xx.c b/arch/arm/mach-omap1/gpio15xx.c index 3faf2b7c2d09..c675f11de99d 100644 --- a/arch/arm/mach-omap1/gpio15xx.c +++ b/arch/arm/mach-omap1/gpio15xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP15xx specific gpio init * @@ -5,15 +6,6 @@ * * Author: * Charulatha V - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c index 2a25751007d4..cf052714b3f8 100644 --- a/arch/arm/mach-omap1/gpio16xx.c +++ b/arch/arm/mach-omap1/gpio16xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP16xx specific gpio init * @@ -5,15 +6,6 @@ * * Author: * Charulatha V - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap1/gpio7xx.c b/arch/arm/mach-omap1/gpio7xx.c index 46b7d5d4d255..c372b357eab4 100644 --- a/arch/arm/mach-omap1/gpio7xx.c +++ b/arch/arm/mach-omap1/gpio7xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP7xx specific gpio init * @@ -5,15 +6,6 @@ * * Author: * Charulatha V - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/am33xx.h b/arch/arm/mach-omap2/am33xx.h index bf2b5f87e404..32bcfcf34817 100644 --- a/arch/arm/mach-omap2/am33xx.h +++ b/arch/arm/mach-omap2/am33xx.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This file contains the address info for various AM33XX modules. * * Copyright (C) 2011 Texas Instruments, Inc. - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __ASM_ARCH_AM33XX_H diff --git a/arch/arm/mach-omap2/clockdomains33xx_data.c b/arch/arm/mach-omap2/clockdomains33xx_data.c index b4d5144df445..87f4e927eb18 100644 --- a/arch/arm/mach-omap2/clockdomains33xx_data.c +++ b/arch/arm/mach-omap2/clockdomains33xx_data.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AM33XX Clock Domain data. * * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/ * Vaibhav Hiremath - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/clockdomains81xx_data.c b/arch/arm/mach-omap2/clockdomains81xx_data.c index 127dc7ace71f..549cf61487a5 100644 --- a/arch/arm/mach-omap2/clockdomains81xx_data.c +++ b/arch/arm/mach-omap2/clockdomains81xx_data.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI81XX Clock Domain data. * * Copyright (C) 2010 Texas Instruments, Inc. - https://www.ti.com/ * Copyright (C) 2013 SKTB SKiT, http://www.skitlab.ru/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __ARCH_ARM_MACH_OMAP2_CLOCKDOMAINS_81XX_H diff --git a/arch/arm/mach-omap2/cm-regbits-33xx.h b/arch/arm/mach-omap2/cm-regbits-33xx.h index e7ae2bb515e3..1b97219aaba4 100644 --- a/arch/arm/mach-omap2/cm-regbits-33xx.h +++ b/arch/arm/mach-omap2/cm-regbits-33xx.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AM33XX Power Management register bits * @@ -5,15 +6,6 @@ * Vaibhav Hiremath * * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c index ac4882ebdca3..d61fa06117b4 100644 --- a/arch/arm/mach-omap2/cm33xx.c +++ b/arch/arm/mach-omap2/cm33xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AM33XX CM functions * @@ -5,15 +6,6 @@ * Vaibhav Hiremath * * Reference taken from from OMAP4 cminst44xx.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/cm33xx.h b/arch/arm/mach-omap2/cm33xx.h index af63d1892c33..456267a7af71 100644 --- a/arch/arm/mach-omap2/cm33xx.h +++ b/arch/arm/mach-omap2/cm33xx.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AM33XX CM offset macros * * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/ * Vaibhav Hiremath - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __ARCH_ARM_MACH_OMAP2_CM_33XX_H diff --git a/arch/arm/mach-omap2/cm81xx.h b/arch/arm/mach-omap2/cm81xx.h index bd91223e838e..ffcde1812c6c 100644 --- a/arch/arm/mach-omap2/cm81xx.h +++ b/arch/arm/mach-omap2/cm81xx.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Clock domain register offsets for TI81XX. * * Copyright (C) 2010 Texas Instruments, Inc. - https://www.ti.com/ * Copyright (C) 2013 SKTB SKiT, http://www.skitlab.ru/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __ARCH_ARM_MACH_OMAP2_CM_TI81XX_H diff --git a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c index 450ab990c66a..9b5c728fb7da 100644 --- a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c @@ -1,18 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DM81xx hwmod data. * * Copyright (C) 2010 Texas Instruments, Inc. - https://www.ti.com/ * Copyright (C) 2013 SKTB SKiT, http://www.skitlab.ru/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/arch/arm/mach-omap2/powerdomains33xx_data.c b/arch/arm/mach-omap2/powerdomains33xx_data.c index 626055e59aed..1d58fd1a2dce 100644 --- a/arch/arm/mach-omap2/powerdomains33xx_data.c +++ b/arch/arm/mach-omap2/powerdomains33xx_data.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AM33XX Power domain data * * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/prm-regbits-33xx.h b/arch/arm/mach-omap2/prm-regbits-33xx.h index 7dfdff09ddeb..3748c5266ae1 100644 --- a/arch/arm/mach-omap2/prm-regbits-33xx.h +++ b/arch/arm/mach-omap2/prm-regbits-33xx.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AM33XX PRM_XXX register bits * * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __ARCH_ARM_MACH_OMAP2_PRM_REGBITS_33XX_H diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c index 9144cc0479af..4b65a0f9cf7d 100644 --- a/arch/arm/mach-omap2/prm33xx.c +++ b/arch/arm/mach-omap2/prm33xx.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AM33XX PRM functions * * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/prm33xx.h b/arch/arm/mach-omap2/prm33xx.h index a469a36c00d8..3081f3deb650 100644 --- a/arch/arm/mach-omap2/prm33xx.h +++ b/arch/arm/mach-omap2/prm33xx.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AM33XX PRM instance offset macros * * Copyright (C) 2011-2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __ARCH_ARM_MACH_OMAP2_PRM33XX_H diff --git a/arch/arm/mach-omap2/ti81xx.h b/arch/arm/mach-omap2/ti81xx.h index 192b0e7d3eb4..fe9f7f388cbd 100644 --- a/arch/arm/mach-omap2/ti81xx.h +++ b/arch/arm/mach-omap2/ti81xx.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This file contains the address data for various TI81XX modules. * * Copyright (C) 2010 Texas Instruments, Inc. - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __ASM_ARCH_TI81XX_H diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c index a43743887db1..06bc060534d8 100644 --- a/drivers/char/hw_random/iproc-rng200.c +++ b/drivers/char/hw_random/iproc-rng200.c @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Broadcom Corporation * -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation version 2. -* -* This program is distributed "as is" WITHOUT ANY WARRANTY of any -* kind, whether express or implied; without even the implied warranty -* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. */ /* * DESCRIPTION: The Broadcom iProc RNG200 Driver diff --git a/drivers/clk/bcm/clk-bcm21664.c b/drivers/clk/bcm/clk-bcm21664.c index eeae4cad2281..520c3aeb4ea9 100644 --- a/drivers/clk/bcm/clk-bcm21664.c +++ b/drivers/clk/bcm/clk-bcm21664.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Broadcom Corporation * Copyright 2014 Linaro Limited - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include "clk-kona.h" diff --git a/drivers/clk/bcm/clk-bcm281xx.c b/drivers/clk/bcm/clk-bcm281xx.c index 502a487d62c5..823d5dfa31b8 100644 --- a/drivers/clk/bcm/clk-bcm281xx.c +++ b/drivers/clk/bcm/clk-bcm281xx.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Broadcom Corporation * Copyright 2013 Linaro Limited - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include "clk-kona.h" diff --git a/drivers/clk/bcm/clk-bcm63xx.c b/drivers/clk/bcm/clk-bcm63xx.c index fbc17ae5ff2b..c8383834fb39 100644 --- a/drivers/clk/bcm/clk-bcm63xx.c +++ b/drivers/clk/bcm/clk-bcm63xx.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2015 Broadcom Corporation #include #include #include diff --git a/drivers/clk/bcm/clk-cygnus.c b/drivers/clk/bcm/clk-cygnus.c index b8d073e4855f..43b04fc4c493 100644 --- a/drivers/clk/bcm/clk-cygnus.c +++ b/drivers/clk/bcm/clk-cygnus.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/clk/bcm/clk-hr2.c b/drivers/clk/bcm/clk-hr2.c index f7c5b7379475..9f6318f3752b 100644 --- a/drivers/clk/bcm/clk-hr2.c +++ b/drivers/clk/bcm/clk-hr2.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2017 Broadcom #include #include diff --git a/drivers/clk/bcm/clk-iproc-armpll.c b/drivers/clk/bcm/clk-iproc-armpll.c index d7d628214b85..9e86c0c10b57 100644 --- a/drivers/clk/bcm/clk-iproc-armpll.c +++ b/drivers/clk/bcm/clk-iproc-armpll.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/clk/bcm/clk-iproc-asiu.c b/drivers/clk/bcm/clk-iproc-asiu.c index e062dd4992ea..dcacf55c55ae 100644 --- a/drivers/clk/bcm/clk-iproc-asiu.c +++ b/drivers/clk/bcm/clk-iproc-asiu.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/clk/bcm/clk-iproc-pll.c b/drivers/clk/bcm/clk-iproc-pll.c index 33da30f99c79..1a098db12062 100644 --- a/drivers/clk/bcm/clk-iproc-pll.c +++ b/drivers/clk/bcm/clk-iproc-pll.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/clk/bcm/clk-iproc.h b/drivers/clk/bcm/clk-iproc.h index d7e5b94bed45..0151d6ae1661 100644 --- a/drivers/clk/bcm/clk-iproc.h +++ b/drivers/clk/bcm/clk-iproc.h @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2014 Broadcom Corporation */ #ifndef _CLK_IPROC_H #define _CLK_IPROC_H diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c index 5dd65164c8b1..338558f6fbae 100644 --- a/drivers/clk/bcm/clk-kona-setup.c +++ b/drivers/clk/bcm/clk-kona-setup.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Broadcom Corporation * Copyright 2013 Linaro Limited - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c index cc3b1e1bc087..ec5749e301ba 100644 --- a/drivers/clk/bcm/clk-kona.c +++ b/drivers/clk/bcm/clk-kona.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2013 Broadcom Corporation * Copyright 2013 Linaro Limited - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include "clk-kona.h" diff --git a/drivers/clk/bcm/clk-kona.h b/drivers/clk/bcm/clk-kona.h index f4b39bb5558a..e09655024ac2 100644 --- a/drivers/clk/bcm/clk-kona.h +++ b/drivers/clk/bcm/clk-kona.h @@ -1,15 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Broadcom Corporation * Copyright 2013 Linaro Limited - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _CLK_KONA_H diff --git a/drivers/clk/bcm/clk-ns2.c b/drivers/clk/bcm/clk-ns2.c index adc14145861a..065f4290aaad 100644 --- a/drivers/clk/bcm/clk-ns2.c +++ b/drivers/clk/bcm/clk-ns2.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2015 Broadcom Corporation #include #include diff --git a/drivers/clk/bcm/clk-nsp.c b/drivers/clk/bcm/clk-nsp.c index cf66f640a47d..c24c9adbc6f3 100644 --- a/drivers/clk/bcm/clk-nsp.c +++ b/drivers/clk/bcm/clk-nsp.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2015 Broadcom Corporation #include #include diff --git a/drivers/clk/ti/adpll.c b/drivers/clk/ti/adpll.c index 962502ca7ff0..f5e7e2049241 100644 --- a/drivers/clk/ti/adpll.c +++ b/drivers/clk/ti/adpll.c @@ -1,13 +1,4 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only #include #include diff --git a/drivers/clk/ti/clk-2xxx.c b/drivers/clk/ti/clk-2xxx.c index 657c4fe07a95..363c4fdbe01f 100644 --- a/drivers/clk/ti/clk-2xxx.c +++ b/drivers/clk/ti/clk-2xxx.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP2 Clock init * * Copyright (C) 2013 Texas Instruments, Inc * Tero Kristo (t-kristo@ti.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c index b4d142adede4..85c50ea39e6d 100644 --- a/drivers/clk/ti/clk-33xx.c +++ b/drivers/clk/ti/clk-33xx.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AM33XX Clock init * * Copyright (C) 2013 Texas Instruments, Inc * Tero Kristo (t-kristo@ti.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c index 8aa5f5793835..ae943ea63c6c 100644 --- a/drivers/clk/ti/clk-3xxx.c +++ b/drivers/clk/ti/clk-3xxx.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP3 Clock init * * Copyright (C) 2013 Texas Instruments, Inc * Tero Kristo (t-kristo@ti.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c index 2ff4ff3d95d5..f24f6eb2157a 100644 --- a/drivers/clk/ti/clk-43xx.c +++ b/drivers/clk/ti/clk-43xx.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * AM43XX Clock init * * Copyright (C) 2013 Texas Instruments, Inc * Tero Kristo (t-kristo@ti.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c index 9daf3825f289..3b8e483aec92 100644 --- a/drivers/clk/ti/clk-816x.c +++ b/drivers/clk/ti/clk-816x.c @@ -1,13 +1,4 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only #include #include diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index c841d2d28111..37ab53339a9b 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI Clock driver internal definitions * * Copyright (C) 2014 Texas Instruments, Inc * Tero Kristo (t-kristo@ti.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __DRIVERS_CLK_TI_CLOCK__ #define __DRIVERS_CLK_TI_CLOCK__ diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c index 749c6b73abff..2db3fc4a443e 100644 --- a/drivers/clk/ti/fapll.c +++ b/drivers/clk/ti/fapll.c @@ -1,13 +1,4 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only #include #include From 2aec85b26f39fa9e036c5872950c0ef9b479a1ec Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:13 +0200 Subject: [PATCH 0265/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_30.RULE (part 2) Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license as published by the free software foundation version 2 this program is distributed as is without any warranty of any kind whether express or implied without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/dma/bcm-sba-raid.c | 14 ++------------ drivers/dma/ti/edma.c | 10 +--------- drivers/gpio/gpio-bcm-kona.c | 10 +--------- drivers/gpio/gpio-brcmstb.c | 14 ++------------ drivers/i2c/busses/i2c-bcm-iproc.c | 14 ++------------ drivers/i2c/busses/i2c-bcm-kona.c | 14 ++------------ drivers/i2c/busses/i2c-brcmstb.c | 14 ++------------ drivers/input/keyboard/bcm-keypad.c | 14 ++------------ drivers/input/misc/gpio_decoder.c | 10 +--------- drivers/input/touchscreen/bcm_iproc_tsc.c | 9 +-------- drivers/irqchip/irq-keystone.c | 10 +--------- drivers/mailbox/bcm-flexrm-mailbox.c | 14 ++------------ drivers/media/i2c/adv7343_regs.h | 10 +--------- drivers/media/i2c/adv7393_regs.h | 10 +--------- drivers/media/platform/ti/davinci/vpif.h | 11 +---------- drivers/media/platform/ti/davinci/vpif_display.h | 10 +--------- drivers/memory/ti-emif-sram-pm.S | 10 +--------- drivers/mfd/lp873x.c | 10 +--------- drivers/mfd/tps65217.c | 10 +--------- drivers/mmc/host/sdhci-bcm-kona.c | 14 ++------------ drivers/mmc/host/sdhci-iproc.c | 14 ++------------ drivers/net/can/ti_hecc.c | 11 +---------- drivers/nvmem/bcm-ocotp.c | 14 ++------------ drivers/phy/broadcom/phy-bcm-cygnus-pcie.c | 14 ++------------ drivers/phy/broadcom/phy-bcm-ns2-pcie.c | 14 ++------------ drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c | 14 ++------------ drivers/phy/motorola/phy-cpcap-usb.c | 10 +--------- drivers/phy/ti/phy-dm816x-usb.c | 11 +---------- drivers/pinctrl/bcm/pinctrl-bcm281xx.c | 14 ++------------ drivers/pinctrl/bcm/pinctrl-cygnus-mux.c | 14 ++------------ drivers/pinctrl/bcm/pinctrl-ns2-mux.c | 10 +--------- drivers/pinctrl/bcm/pinctrl-nsp-gpio.c | 14 ++------------ drivers/pinctrl/bcm/pinctrl-nsp-mux.c | 10 +--------- drivers/power/reset/brcm-kona-reset.c | 14 ++------------ drivers/power/reset/brcmstb-reboot.c | 14 ++------------ drivers/ptp/ptp_dte.c | 14 ++------------ drivers/pwm/pwm-bcm-iproc.c | 14 ++------------ drivers/pwm/pwm-bcm-kona.c | 14 ++------------ drivers/regulator/cpcap-regulator.c | 10 +--------- drivers/regulator/isl6271a-regulator.c | 10 +--------- drivers/regulator/tps65023-regulator.c | 10 +--------- drivers/regulator/tps6507x-regulator.c | 10 +--------- drivers/regulator/tps65217-regulator.c | 10 +--------- drivers/soc/ti/knav_dma.c | 10 +--------- drivers/uio/uio_pruss.c | 10 +--------- drivers/video/backlight/tps65217_bl.c | 10 +--------- include/dt-bindings/clock/bcm21664.h | 10 +--------- include/dt-bindings/clock/bcm281xx.h | 10 +--------- include/linux/mfd/lp873x.h | 10 +--------- include/linux/mfd/tps65217.h | 10 +--------- include/linux/platform_data/davinci_asp.h | 10 +--------- include/linux/platform_data/gpio-davinci.h | 10 +--------- include/linux/platform_data/uio_dmem_genirq.h | 10 +--------- include/linux/platform_data/uio_pruss.h | 10 +--------- include/linux/reset/bcm63xx_pmb.h | 10 +--------- include/linux/soc/ti/knav_dma.h | 10 +--------- include/linux/soc/ti/knav_qmss.h | 10 +--------- include/linux/sram.h | 14 ++------------ include/linux/ti-emif-sram.h | 10 +--------- include/linux/wkup_m3_ipc.h | 10 +--------- include/media/i2c/adv7343.h | 10 +--------- include/media/i2c/adv7393.h | 10 +--------- net/hsr/hsr_debugfs.c | 10 +--------- sound/soc/bcm/cygnus-pcm.c | 14 ++------------ sound/soc/bcm/cygnus-ssp.c | 14 ++------------ sound/soc/bcm/cygnus-ssp.h | 14 ++------------ 66 files changed, 91 insertions(+), 671 deletions(-) diff --git a/drivers/dma/bcm-sba-raid.c b/drivers/dma/bcm-sba-raid.c index 64239da02e74..064761289a73 100644 --- a/drivers/dma/bcm-sba-raid.c +++ b/drivers/dma/bcm-sba-raid.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2017 Broadcom /* * Broadcom SBA RAID Driver diff --git a/drivers/dma/ti/edma.c b/drivers/dma/ti/edma.c index 3ea8ef7f57df..4cbca80ee16e 100644 --- a/drivers/dma/ti/edma.c +++ b/drivers/dma/ti/edma.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI EDMA DMA engine driver * * Copyright 2012 Texas Instruments - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index e84474494429..70770429ba48 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Broadcom Kona GPIO Driver * * Author: Broadcom Corporation * Copyright (C) 2012-2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 6b7439b44690..85429dd6b3b6 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2015-2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2015-2017 Broadcom #include #include diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 6304d1dd2dd6..85d8a6b04885 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index 8e350f20cde0..16bf41f1f086 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013 Broadcom Corporation #include #include diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index b00f35c0b066..ff63ed5ec961 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/input/keyboard/bcm-keypad.c b/drivers/input/keyboard/bcm-keypad.c index 166d6023a538..56a919ec23b5 100644 --- a/drivers/input/keyboard/bcm-keypad.c +++ b/drivers/input/keyboard/bcm-keypad.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/input/misc/gpio_decoder.c b/drivers/input/misc/gpio_decoder.c index 145826a1a9a1..ee668eba302f 100644 --- a/drivers/input/misc/gpio_decoder.c +++ b/drivers/input/misc/gpio_decoder.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * * A generic driver to read multiple gpio lines and translate the * encoded numeric value into an input event. */ diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c index 7de1fd24ce36..35e2fe9911a4 100644 --- a/drivers/input/touchscreen/bcm_iproc_tsc.c +++ b/drivers/input/touchscreen/bcm_iproc_tsc.c @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Broadcom Corporation * -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation version 2. -* -* This program is distributed "as is" WITHOUT ANY WARRANTY of any -* kind, whether express or implied; without even the implied warranty -* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. */ #include #include diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index d47c8041e5bc..ba9792e60329 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Texas Instruments Keystone IRQ controller IP driver * * Copyright (C) 2014 Texas Instruments, Inc. * Author: Sajesh Kumar Saran * Grygorii Strashko - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/mailbox/bcm-flexrm-mailbox.c b/drivers/mailbox/bcm-flexrm-mailbox.c index 22acb51531cb..fda16f76401e 100644 --- a/drivers/mailbox/bcm-flexrm-mailbox.c +++ b/drivers/mailbox/bcm-flexrm-mailbox.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2017 Broadcom /* * Broadcom FlexRM Mailbox Driver diff --git a/drivers/media/i2c/adv7343_regs.h b/drivers/media/i2c/adv7343_regs.h index 2f04ce4b9118..e0357e6272e3 100644 --- a/drivers/media/i2c/adv7343_regs.h +++ b/drivers/media/i2c/adv7343_regs.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ADV7343 encoder related structure and register definitions * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef ADV7343_REGS_H diff --git a/drivers/media/i2c/adv7393_regs.h b/drivers/media/i2c/adv7393_regs.h index 78968330f0be..6eb8732b5324 100644 --- a/drivers/media/i2c/adv7393_regs.h +++ b/drivers/media/i2c/adv7393_regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ADV7393 encoder related structure and register definitions * @@ -7,15 +8,6 @@ * Based on ADV7343 driver, * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef ADV7393_REGS_H diff --git a/drivers/media/platform/ti/davinci/vpif.h b/drivers/media/platform/ti/davinci/vpif.h index c6d1d890478a..651943e3e375 100644 --- a/drivers/media/platform/ti/davinci/vpif.h +++ b/drivers/media/platform/ti/davinci/vpif.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * VPIF header file * * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef VPIF_H @@ -685,4 +677,3 @@ struct vpif_params { }; #endif /* End of #ifndef VPIF_H */ - diff --git a/drivers/media/platform/ti/davinci/vpif_display.h b/drivers/media/platform/ti/davinci/vpif_display.h index f98062e79167..f27474e0fc36 100644 --- a/drivers/media/platform/ti/davinci/vpif_display.h +++ b/drivers/media/platform/ti/davinci/vpif_display.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * VPIF display header file * * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef VPIF_DISPLAY_H diff --git a/drivers/memory/ti-emif-sram-pm.S b/drivers/memory/ti-emif-sram-pm.S index d1c83bd5b98e..9bcac35c3304 100644 --- a/drivers/memory/ti-emif-sram-pm.S +++ b/drivers/memory/ti-emif-sram-pm.S @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Low level PM code for TI EMIF * * Copyright (C) 2016-2017 Texas Instruments Incorporated - http://www.ti.com/ * Dave Gerlach - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/mfd/lp873x.c b/drivers/mfd/lp873x.c index 858c9e0a49a4..b6166dec492d 100644 --- a/drivers/mfd/lp873x.c +++ b/drivers/mfd/lp873x.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ * * Author: Keerthy - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 8027b0a9e14f..8e8da204a02e 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65217.c * * TPS65217 chip family multi-function driver * * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index 4d4aac85cc7a..61a12f2f7f03 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013 Broadcom Corporation #include #include diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 032bf852397f..6db35b1b8557 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation /* * iProc SDHCI platform driver diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index debe17bfd0f0..7ce26cdbeb77 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI HECC (CAN) device driver * @@ -6,16 +7,6 @@ * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2019 Jeroen Hofstee - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed as is WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/drivers/nvmem/bcm-ocotp.c b/drivers/nvmem/bcm-ocotp.c index dfea96c52463..a128c7f5e351 100644 --- a/drivers/nvmem/bcm-ocotp.c +++ b/drivers/nvmem/bcm-ocotp.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Broadcom #include #include diff --git a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c index 548e46776100..cc29b08e49eb 100644 --- a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c +++ b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2015 Broadcom Corporation #include #include diff --git a/drivers/phy/broadcom/phy-bcm-ns2-pcie.c b/drivers/phy/broadcom/phy-bcm-ns2-pcie.c index 9e7434a0d3e0..2eaa41f8fc70 100644 --- a/drivers/phy/broadcom/phy-bcm-ns2-pcie.c +++ b/drivers/phy/broadcom/phy-bcm-ns2-pcie.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Broadcom #include #include diff --git a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c index 65a399acc845..36ad02c33ac5 100644 --- a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c +++ b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2017 Broadcom #include #include diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 6ee478bc5211..2f8210167b77 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Motorola CPCAP PMIC USB PHY driver * Copyright (C) 2017 Tony Lindgren @@ -5,15 +6,6 @@ * Some parts based on earlier Motorola Linux kernel tree code in * board-mapphone-usb.c and cpcap-usb-det.c: * Copyright (C) 2007 - 2011 Motorola, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/phy/ti/phy-dm816x-usb.c b/drivers/phy/ti/phy-dm816x-usb.c index 9fe6ea6fdae5..fb619908f912 100644 --- a/drivers/phy/ti/phy-dm816x-usb.c +++ b/drivers/phy/ti/phy-dm816x-usb.c @@ -1,13 +1,4 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only #include #include diff --git a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c index 9ab1f427286a..fd52a83387ef 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm281xx.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm281xx.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013-2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013-2017 Broadcom #include #include diff --git a/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c b/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c index 4344c5732400..5251460f6327 100644 --- a/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c +++ b/drivers/pinctrl/bcm/pinctrl-cygnus-mux.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014-2017 Broadcom /* * Broadcom Cygnus IOMUX driver diff --git a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c index 0fe4a1fcdf00..960e253f0be4 100644 --- a/drivers/pinctrl/bcm/pinctrl-ns2-mux.c +++ b/drivers/pinctrl/bcm/pinctrl-ns2-mux.c @@ -1,13 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2016 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. * * This file contains the Northstar2 IOMUX driver that supports group * based PINMUX configuration. The PWM is functional only when the diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c index 643dbd315033..3c792bf03bda 100644 --- a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c +++ b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014-2017 Broadcom /* * This file contains the Broadcom Northstar Plus (NSP) GPIO driver that diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c index f1d60a708815..db8f79920ff0 100644 --- a/drivers/pinctrl/bcm/pinctrl-nsp-mux.c +++ b/drivers/pinctrl/bcm/pinctrl-nsp-mux.c @@ -1,13 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright (C) 2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. * * This file contains the Northstar plus (NSP) IOMUX driver that supports * group based PINMUX configuration. The Northstar plus IOMUX controller diff --git a/drivers/power/reset/brcm-kona-reset.c b/drivers/power/reset/brcm-kona-reset.c index 8eaa959d8be6..3de024e3ceb7 100644 --- a/drivers/power/reset/brcm-kona-reset.c +++ b/drivers/power/reset/brcm-kona-reset.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Broadcom #include #include diff --git a/drivers/power/reset/brcmstb-reboot.c b/drivers/power/reset/brcmstb-reboot.c index 884b53c483c0..0f2944dc9355 100644 --- a/drivers/power/reset/brcmstb-reboot.c +++ b/drivers/power/reset/brcmstb-reboot.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013 Broadcom Corporation #include #include diff --git a/drivers/ptp/ptp_dte.c b/drivers/ptp/ptp_dte.c index 82d31ba32690..8641fd060491 100644 --- a/drivers/ptp/ptp_dte.c +++ b/drivers/ptp/ptp_dte.c @@ -1,15 +1,5 @@ -/* - * Copyright 2017 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2017 Broadcom #include #include diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c index 0226bf697f09..7251037d4dd5 100644 --- a/drivers/pwm/pwm-bcm-iproc.c +++ b/drivers/pwm/pwm-bcm-iproc.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2016 Broadcom - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Broadcom #include #include diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index f171169c1c1f..4fa6e249e4cf 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include #include diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c index 79b3eb3222c6..b0c225d98631 100644 --- a/drivers/regulator/cpcap-regulator.c +++ b/drivers/regulator/cpcap-regulator.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Motorola CPCAP PMIC regulator driver * @@ -6,15 +7,6 @@ * * Rewritten for mainline kernel to use device tree and regmap * Copyright (C) 2017 Tony Lindgren - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 6f28bba81d13..591a64e1ca61 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * isl6271a-regulator.c * * Support for Intersil ISL6271A voltage regulator * * Copyright (C) 2010 Marek Vasut - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #include diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index f25806531c7e..d24333344f93 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65023-regulator.c * * Supports TPS65023 Regulator * * Copyright (C) 2009 Texas Instrument Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #include diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index eafbc2bb4b57..b83816ee6867 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps6507x-regulator.c * * Regulator driver for TPS65073 PMIC * * Copyright (C) 2009 Texas Instrument Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. */ #include diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index e88ed96f4744..6bb5b02e19e2 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65217-regulator.c * * Regulator driver for TPS65217 PMIC * * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c index d756591de973..84afebd355be 100644 --- a/drivers/soc/ti/knav_dma.c +++ b/drivers/soc/ti/knav_dma.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Texas Instruments Incorporated * Authors: Santosh Shilimkar * Sandeep Nair * Cyril Chemparathy - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c index e9096f53b4cc..83966dbd3bbf 100644 --- a/drivers/uio/uio_pruss.c +++ b/drivers/uio/uio_pruss.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Programmable Real-Time Unit Sub System (PRUSS) UIO driver (uio_pruss) * @@ -5,15 +6,6 @@ * and DDR RAM to user space for applications interacting with PRUSS firmware * * Copyright (C) 2010-11 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index 8457166f357f..d96d713fe7db 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65217_bl.c * @@ -5,15 +6,6 @@ * * Copyright (C) 2012 Matthias Kaehlcke * Author: Matthias Kaehlcke - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/include/dt-bindings/clock/bcm21664.h b/include/dt-bindings/clock/bcm21664.h index 5a7f0e4750a8..7c7492742f3d 100644 --- a/include/dt-bindings/clock/bcm21664.h +++ b/include/dt-bindings/clock/bcm21664.h @@ -1,15 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Broadcom Corporation * Copyright 2013 Linaro Limited - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _CLOCK_BCM21664_H diff --git a/include/dt-bindings/clock/bcm281xx.h b/include/dt-bindings/clock/bcm281xx.h index a763460cf1af..d74ca42112e7 100644 --- a/include/dt-bindings/clock/bcm281xx.h +++ b/include/dt-bindings/clock/bcm281xx.h @@ -1,15 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2013 Broadcom Corporation * Copyright 2013 Linaro Limited - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _CLOCK_BCM281XX_H diff --git a/include/linux/mfd/lp873x.h b/include/linux/mfd/lp873x.h index 5546688c7da7..fe8174cc8637 100644 --- a/include/linux/mfd/lp873x.h +++ b/include/linux/mfd/lp873x.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Functions to access LP873X power management chip. * * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __LINUX_MFD_LP873X_H diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index db7091824ed0..877d9c41c53d 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -1,18 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/mfd/tps65217.h * * Functions to access TPS65217 power management chip. * * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __LINUX_MFD_TPS65217_H diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index 76b13ef67562..c8645b2ed3c0 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI DaVinci Audio Serial Port support * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __DAVINCI_ASP_H diff --git a/include/linux/platform_data/gpio-davinci.h b/include/linux/platform_data/gpio-davinci.h index e182a46e609f..b82e44662efe 100644 --- a/include/linux/platform_data/gpio-davinci.h +++ b/include/linux/platform_data/gpio-davinci.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * DaVinci GPIO Platform Related Defines * * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __DAVINCI_GPIO_PLATFORM_H diff --git a/include/linux/platform_data/uio_dmem_genirq.h b/include/linux/platform_data/uio_dmem_genirq.h index 973c1bb32168..c8f6de685306 100644 --- a/include/linux/platform_data/uio_dmem_genirq.h +++ b/include/linux/platform_data/uio_dmem_genirq.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * include/linux/platform_data/uio_dmem_genirq.h * * Copyright (C) 2012 Damian Hobson-Garcia - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _UIO_DMEM_GENIRQ_H diff --git a/include/linux/platform_data/uio_pruss.h b/include/linux/platform_data/uio_pruss.h index 31f2e22661bc..f76fa393b802 100644 --- a/include/linux/platform_data/uio_pruss.h +++ b/include/linux/platform_data/uio_pruss.h @@ -1,18 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * include/linux/platform_data/uio_pruss.h * * Platform data for uio_pruss driver * * Copyright (C) 2010-11 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _UIO_PRUSS_H_ diff --git a/include/linux/reset/bcm63xx_pmb.h b/include/linux/reset/bcm63xx_pmb.h index bb4af7b5eb36..c77b6999518a 100644 --- a/include/linux/reset/bcm63xx_pmb.h +++ b/include/linux/reset/bcm63xx_pmb.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Broadcom BCM63xx Processor Monitor Bus shared routines (SMP and reset) * * Copyright (C) 2015, Broadcom Corporation * Author: Florian Fainelli - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __BCM63XX_PMB_H #define __BCM63XX_PMB_H diff --git a/include/linux/soc/ti/knav_dma.h b/include/linux/soc/ti/knav_dma.h index 7127ec301537..18d806a8e52c 100644 --- a/include/linux/soc/ti/knav_dma.h +++ b/include/linux/soc/ti/knav_dma.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2014 Texas Instruments Incorporated * Authors: Sandeep Nair - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __SOC_TI_KEYSTONE_NAVIGATOR_DMA_H__ diff --git a/include/linux/soc/ti/knav_qmss.h b/include/linux/soc/ti/knav_qmss.h index c75ef99c99ca..175f466ebcc3 100644 --- a/include/linux/soc/ti/knav_qmss.h +++ b/include/linux/soc/ti/knav_qmss.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Keystone Navigator Queue Management Sub-System header * @@ -5,15 +6,6 @@ * Author: Sandeep Nair * Cyril Chemparathy * Santosh Shilimkar - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __SOC_TI_KNAV_QMSS_H__ diff --git a/include/linux/sram.h b/include/linux/sram.h index 4fb405fb0480..d7dee19505c6 100644 --- a/include/linux/sram.h +++ b/include/linux/sram.h @@ -1,15 +1,5 @@ -/* - * Generic SRAM Driver Interface - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Generic SRAM Driver Interface */ #ifndef __LINUX_SRAM_H__ #define __LINUX_SRAM_H__ diff --git a/include/linux/ti-emif-sram.h b/include/linux/ti-emif-sram.h index 2fc854155c27..441b2988e66a 100644 --- a/include/linux/ti-emif-sram.h +++ b/include/linux/ti-emif-sram.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI AM33XX EMIF Routines * * Copyright (C) 2016-2017 Texas Instruments Inc. * Dave Gerlach - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __LINUX_TI_EMIF_H #define __LINUX_TI_EMIF_H diff --git a/include/linux/wkup_m3_ipc.h b/include/linux/wkup_m3_ipc.h index 26d1eb058fa3..5e1b26f988e2 100644 --- a/include/linux/wkup_m3_ipc.h +++ b/include/linux/wkup_m3_ipc.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI Wakeup M3 for AMx3 SoCs Power Management Routines * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Dave Gerlach - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _LINUX_WKUP_M3_IPC_H diff --git a/include/media/i2c/adv7343.h b/include/media/i2c/adv7343.h index b8937035c5d3..d35d3e925795 100644 --- a/include/media/i2c/adv7343.h +++ b/include/media/i2c/adv7343.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ADV7343 header file * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef ADV7343_H diff --git a/include/media/i2c/adv7393.h b/include/media/i2c/adv7393.h index b28edf351842..c73b36321d06 100644 --- a/include/media/i2c/adv7393.h +++ b/include/media/i2c/adv7393.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * ADV7393 header file * @@ -7,15 +8,6 @@ * Based on ADV7343 driver, * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed .as is. WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef ADV7393_H diff --git a/net/hsr/hsr_debugfs.c b/net/hsr/hsr_debugfs.c index fe6094e9a2db..de476a417631 100644 --- a/net/hsr/hsr_debugfs.c +++ b/net/hsr/hsr_debugfs.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * debugfs code for HSR & PRP * Copyright (C) 2019 Texas Instruments Incorporated * * Author(s): * Murali Karicheri - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c index 3abeaf0f1b1c..8f488f92936b 100644 --- a/sound/soc/bcm/cygnus-pcm.c +++ b/sound/soc/bcm/cygnus-pcm.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014-2015 Broadcom Corporation #include #include #include diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c index 9698f4531c90..b0254e724ec9 100644 --- a/sound/soc/bcm/cygnus-ssp.c +++ b/sound/soc/bcm/cygnus-ssp.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014-2015 Broadcom Corporation #include #include #include diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h index 33dd34305928..74152b2d770d 100644 --- a/sound/soc/bcm/cygnus-ssp.h +++ b/sound/soc/bcm/cygnus-ssp.h @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014-2015 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (C) 2014-2015 Broadcom Corporation */ #ifndef __CYGNUS_SSP_H__ #define __CYGNUS_SSP_H__ From 0fdebc5ec2ca492d69df2d93a6a7abade4941aae Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:14 +0200 Subject: [PATCH 0266/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_56.RULE (part 1) Based on the normalized pattern: this file is licensed under the terms of the gnu general public license version 2 this program is licensed as is without any warranty of any kind whether express or implied extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/am33xx.dtsi | 5 +---- arch/arm/boot/dts/am3517.dtsi | 5 +---- arch/arm/boot/dts/am4372.dtsi | 5 +---- arch/arm/boot/dts/artpec6-devboard.dts | 9 ++------- arch/arm/boot/dts/dm814x.dtsi | 6 +----- arch/arm/boot/dts/dm816x.dtsi | 6 +----- arch/arm/boot/dts/dra62x.dtsi | 6 +----- arch/arm/boot/dts/dra7-dspeve-thermal.dtsi | 5 +---- arch/arm/boot/dts/dra7-iva-thermal.dtsi | 5 +---- arch/arm/boot/dts/imx6q-gk802.dts | 9 ++------- arch/arm/boot/dts/omap2.dtsi | 5 +---- arch/arm/boot/dts/omap2420.dtsi | 5 +---- arch/arm/boot/dts/omap2430.dtsi | 5 +---- arch/arm/boot/dts/omap3-cpu-thermal.dtsi | 5 +---- arch/arm/boot/dts/omap3.dtsi | 5 +---- arch/arm/boot/dts/omap34xx.dtsi | 5 +---- arch/arm/boot/dts/omap36xx.dtsi | 5 +---- arch/arm/boot/dts/omap4-cpu-thermal.dtsi | 5 +---- arch/arm/boot/dts/omap443x.dtsi | 5 +---- arch/arm/boot/dts/omap4460.dtsi | 5 +---- arch/arm/boot/dts/omap5-core-thermal.dtsi | 5 +---- arch/arm/boot/dts/omap5-gpu-thermal.dtsi | 5 +---- arch/arm/boot/dts/orion5x-lacie-d2-network.dts | 5 +---- .../arm/boot/dts/orion5x-lacie-ethernet-disk-mini-v2.dts | 9 ++------- arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts | 5 +---- arch/arm/boot/dts/orion5x-mv88f5181.dtsi | 9 ++------- arch/arm/boot/dts/orion5x-mv88f5182.dtsi | 9 ++------- arch/arm/boot/dts/orion5x-netgear-wnr854t.dts | 9 ++------- arch/arm/boot/dts/orion5x-rd88f5182-nas.dts | 9 ++------- arch/arm/boot/dts/orion5x.dtsi | 9 ++------- arch/arm/include/asm/hardware/cache-aurora-l2.h | 5 +---- arch/arm/include/asm/hardware/cache-feroceon-l2.h | 6 +----- arch/arm/include/asm/hardware/cache-tauros2.h | 5 +---- arch/arm/mach-davinci/board-da830-evm.c | 6 ++---- arch/arm/mach-davinci/board-da850-evm.c | 6 ++---- arch/arm/mach-davinci/board-dm355-evm.c | 6 ++---- arch/arm/mach-davinci/board-dm355-leopard.c | 5 +---- arch/arm/mach-davinci/board-dm644x-evm.c | 6 ++---- arch/arm/mach-davinci/board-dm646x-evm.c | 7 +------ arch/arm/mach-davinci/board-mityomapl138.c | 5 +---- arch/arm/mach-davinci/board-neuros-osd2.c | 5 +---- arch/arm/mach-davinci/board-omapl138-hawk.c | 5 +---- arch/arm/mach-davinci/common.c | 6 ++---- arch/arm/mach-davinci/common.h | 6 ++---- arch/arm/mach-davinci/cpuidle.h | 5 +---- arch/arm/mach-davinci/cputype.h | 6 ++---- arch/arm/mach-davinci/da830.c | 6 ++---- arch/arm/mach-davinci/da850.c | 6 ++---- arch/arm/mach-davinci/da8xx.h | 6 ++---- arch/arm/mach-davinci/dm355.c | 6 ++---- arch/arm/mach-davinci/dm644x.c | 6 ++---- arch/arm/mach-davinci/dm646x.c | 6 ++---- arch/arm/mach-davinci/hardware.h | 6 ++---- arch/arm/mach-davinci/mux.c | 6 ++---- arch/arm/mach-davinci/mux.h | 6 ++---- arch/arm/mach-davinci/pm_domain.c | 5 +---- arch/arm/mach-davinci/serial.h | 6 ++---- arch/arm/mach-dove/bridge-regs.h | 9 ++------- arch/arm/mach-dove/cm-a510.c | 5 +---- arch/arm/mach-dove/common.c | 5 +---- arch/arm/mach-dove/common.h | 5 +---- arch/arm/mach-dove/dove-db-setup.c | 5 +---- arch/arm/mach-dove/dove.h | 9 ++------- arch/arm/mach-dove/irq.c | 5 +---- arch/arm/mach-dove/irqs.h | 9 ++------- arch/arm/mach-dove/mpp.c | 5 +---- arch/arm/mach-dove/pcie.c | 5 +---- arch/arm/mach-dove/pm.h | 6 +----- arch/arm/mach-lpc18xx/board-dt.c | 5 +---- arch/arm/mach-lpc32xx/pm.c | 6 ++---- arch/arm/mach-lpc32xx/suspend.S | 6 ++---- arch/arm/mach-mv78xx0/bridge-regs.h | 6 +----- arch/arm/mach-mv78xx0/buffalo-wxl-setup.c | 5 +---- arch/arm/mach-mv78xx0/common.c | 5 +---- arch/arm/mach-mv78xx0/common.h | 5 +---- arch/arm/mach-mv78xx0/db78x00-bp-setup.c | 5 +---- arch/arm/mach-mv78xx0/irq.c | 5 +---- arch/arm/mach-mv78xx0/irqs.h | 9 ++------- arch/arm/mach-mv78xx0/mpp.c | 5 +---- arch/arm/mach-mv78xx0/mpp.h | 6 +----- arch/arm/mach-mv78xx0/mv78xx0.h | 5 +---- arch/arm/mach-mv78xx0/pcie.c | 5 +---- arch/arm/mach-mv78xx0/rd78x00-masa-setup.c | 5 +---- arch/arm/mach-mvebu/armada-370-xp.h | 5 +---- arch/arm/mach-mvebu/board-v7.c | 5 +---- arch/arm/mach-mvebu/coherency.c | 5 +---- arch/arm/mach-mvebu/coherency.h | 6 +----- arch/arm/mach-mvebu/coherency_ll.S | 5 +---- arch/arm/mach-mvebu/common.h | 5 +---- arch/arm/mach-mvebu/cpu-reset.c | 5 +---- arch/arm/mach-mvebu/dove.c | 5 +---- arch/arm/mach-mvebu/headsmp-a9.S | 5 +---- arch/arm/mach-mvebu/headsmp.S | 5 +---- arch/arm/mach-mvebu/kirkwood.c | 5 +---- arch/arm/mach-mvebu/kirkwood.h | 5 +---- arch/arm/mach-mvebu/mvebu-soc-id.c | 5 +---- arch/arm/mach-mvebu/mvebu-soc-id.h | 5 +---- arch/arm/mach-mvebu/platsmp-a9.c | 5 +---- arch/arm/mach-mvebu/platsmp.c | 5 +---- arch/arm/mach-mvebu/pm-board.c | 5 +---- arch/arm/mach-mvebu/pm.c | 5 +---- arch/arm/mach-mvebu/pmsu.c | 5 +---- arch/arm/mach-mvebu/pmsu.h | 5 +---- arch/arm/mach-mvebu/pmsu_ll.S | 5 +---- arch/arm/mach-mvebu/system-controller.c | 5 +---- arch/arm/mach-omap1/mtd-xip.h | 6 ++---- arch/arm/mach-omap1/pm_bus.c | 6 +----- arch/arm/mach-omap2/prcm43xx.h | 5 +---- arch/arm/mach-omap2/vc.c | 6 +----- arch/arm/mach-orion5x/board-d2net.c | 5 +---- arch/arm/mach-orion5x/board-dt.c | 5 +---- arch/arm/mach-orion5x/board-rd88f5182.c | 5 +---- arch/arm/mach-orion5x/bridge-regs.h | 9 ++------- arch/arm/mach-orion5x/common.c | 5 +---- arch/arm/mach-orion5x/db88f5281-setup.c | 5 +---- arch/arm/mach-orion5x/irq.c | 5 +---- arch/arm/mach-orion5x/irqs.h | 5 +---- arch/arm/mach-orion5x/kurobox_pro-setup.c | 5 +---- arch/arm/mach-orion5x/ls_hgl-setup.c | 5 +---- arch/arm/mach-orion5x/mpp.c | 5 +---- arch/arm/mach-orion5x/net2big-setup.c | 6 +----- arch/arm/mach-orion5x/orion5x.h | 5 +---- arch/arm/mach-orion5x/pci.c | 5 +---- arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c | 5 +---- arch/arm/mach-orion5x/rd88f5181l-ge-setup.c | 5 +---- arch/arm/mach-orion5x/rd88f5182-setup.c | 5 +---- arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c | 5 +---- arch/arm/mach-orion5x/ts78xx-setup.c | 5 +---- arch/arm/mach-orion5x/wnr854t-setup.c | 9 ++------- arch/arm/mach-orion5x/wrt350n-v2-setup.c | 9 ++------- arch/arm/mach-pxa/eseries.c | 7 +------ arch/arm/mach-pxa/standby.S | 6 ++---- arch/arm/mach-spear/generic.h | 5 +---- arch/arm/mach-spear/misc_regs.h | 5 +---- arch/arm/mach-spear/pl080.c | 5 +---- arch/arm/mach-spear/pl080.h | 5 +---- arch/arm/mach-spear/restart.c | 5 +---- arch/arm/mach-spear/spear.h | 5 +---- arch/arm/mach-spear/spear1310.c | 5 +---- arch/arm/mach-spear/spear1340.c | 5 +---- arch/arm/mach-spear/spear13xx.c | 5 +---- arch/arm/mach-spear/spear300.c | 5 +---- arch/arm/mach-spear/spear310.c | 5 +---- arch/arm/mach-spear/spear320.c | 5 +---- arch/arm/mach-spear/spear3xx.c | 5 +---- arch/arm/mach-spear/spear6xx.c | 5 +---- arch/arm/mach-spear/time.c | 5 +---- arch/arm/mm/cache-feroceon-l2.c | 5 +---- arch/arm/mm/cache-tauros2.c | 5 +---- 149 files changed, 185 insertions(+), 656 deletions(-) diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi index 9a8698bd2852..32d397b3950b 100644 --- a/arch/arm/boot/dts/am33xx.dtsi +++ b/arch/arm/boot/dts/am33xx.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for AM33XX SoC * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/am3517.dtsi b/arch/arm/boot/dts/am3517.dtsi index de33c4f89f33..cb316135bc7c 100644 --- a/arch/arm/boot/dts/am3517.dtsi +++ b/arch/arm/boot/dts/am3517.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for am3517 SoC * * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include "omap3.dtsi" diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 61a1d88f9df6..8613355bbd5e 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for AM4372 SoC * * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/artpec6-devboard.dts b/arch/arm/boot/dts/artpec6-devboard.dts index d20d95359b28..042a9cc920c6 100644 --- a/arch/arm/boot/dts/artpec6-devboard.dts +++ b/arch/arm/boot/dts/artpec6-devboard.dts @@ -1,10 +1,5 @@ -/* - * Axis ARTPEC-6 development board. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Axis ARTPEC-6 development board. /dts-v1/; #include "artpec6.dtsi" diff --git a/arch/arm/boot/dts/dm814x.dtsi b/arch/arm/boot/dts/dm814x.dtsi index a92630113f57..8104969c67c1 100644 --- a/arch/arm/boot/dts/dm814x.dtsi +++ b/arch/arm/boot/dts/dm814x.dtsi @@ -1,8 +1,4 @@ -/* - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only #include #include diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi index eb0a95da94b2..649b33194455 100644 --- a/arch/arm/boot/dts/dm816x.dtsi +++ b/arch/arm/boot/dts/dm816x.dtsi @@ -1,8 +1,4 @@ -/* - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only #include #include diff --git a/arch/arm/boot/dts/dra62x.dtsi b/arch/arm/boot/dts/dra62x.dtsi index cc4878aaa8ea..cfefa670515c 100644 --- a/arch/arm/boot/dts/dra62x.dtsi +++ b/arch/arm/boot/dts/dra62x.dtsi @@ -1,8 +1,4 @@ -/* - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only #include "dm814x.dtsi" diff --git a/arch/arm/boot/dts/dra7-dspeve-thermal.dtsi b/arch/arm/boot/dts/dra7-dspeve-thermal.dtsi index e75569383dd8..747ff0db90c7 100644 --- a/arch/arm/boot/dts/dra7-dspeve-thermal.dtsi +++ b/arch/arm/boot/dts/dra7-dspeve-thermal.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for DRA7x SoC DSPEVE thermal * * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/dra7-iva-thermal.dtsi b/arch/arm/boot/dts/dra7-iva-thermal.dtsi index a7077321613f..0a31313065df 100644 --- a/arch/arm/boot/dts/dra7-iva-thermal.dtsi +++ b/arch/arm/boot/dts/dra7-iva-thermal.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for DRA7x SoC IVA thermal * * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/imx6q-gk802.dts b/arch/arm/boot/dts/imx6q-gk802.dts index ccc2487d47ca..2fda68f9d3f6 100644 --- a/arch/arm/boot/dts/imx6q-gk802.dts +++ b/arch/arm/boot/dts/imx6q-gk802.dts @@ -1,10 +1,5 @@ -/* - * Copyright (C) 2013 Philipp Zabel - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013 Philipp Zabel /dts-v1/; #include diff --git a/arch/arm/boot/dts/omap2.dtsi b/arch/arm/boot/dts/omap2.dtsi index 5750ca1233cc..afabb36a8ac1 100644 --- a/arch/arm/boot/dts/omap2.dtsi +++ b/arch/arm/boot/dts/omap2.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP2 SoC * * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/omap2420.dtsi b/arch/arm/boot/dts/omap2420.dtsi index bb529a2a295d..821da51cb870 100644 --- a/arch/arm/boot/dts/omap2420.dtsi +++ b/arch/arm/boot/dts/omap2420.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP2420 SoC * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include "omap2.dtsi" diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi index 23115ba61bc0..b9a9e6e45266 100644 --- a/arch/arm/boot/dts/omap2430.dtsi +++ b/arch/arm/boot/dts/omap2430.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP243x SoC * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include "omap2.dtsi" diff --git a/arch/arm/boot/dts/omap3-cpu-thermal.dtsi b/arch/arm/boot/dts/omap3-cpu-thermal.dtsi index a9069cca5888..0da759f8e2c2 100644 --- a/arch/arm/boot/dts/omap3-cpu-thermal.dtsi +++ b/arch/arm/boot/dts/omap3-cpu-thermal.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP3 SoC CPU thermal * * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index 64b7e6fddd1b..825075ff0e34 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP3 SoC * * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/omap34xx.dtsi b/arch/arm/boot/dts/omap34xx.dtsi index 8b8451399784..2eb73ae7ef3e 100644 --- a/arch/arm/boot/dts/omap34xx.dtsi +++ b/arch/arm/boot/dts/omap34xx.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP34xx/OMAP35xx SoC * * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi index 22b33098b1a2..32ac7924a130 100644 --- a/arch/arm/boot/dts/omap36xx.dtsi +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP3 SoC * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/omap4-cpu-thermal.dtsi b/arch/arm/boot/dts/omap4-cpu-thermal.dtsi index 03d054b2bf9a..4d7eeb133dad 100644 --- a/arch/arm/boot/dts/omap4-cpu-thermal.dtsi +++ b/arch/arm/boot/dts/omap4-cpu-thermal.dtsi @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP4/5 SoC CPU thermal * * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ * Contact: Eduardo Valentin - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/omap443x.dtsi b/arch/arm/boot/dts/omap443x.dtsi index 8466161197ae..238aceb799f8 100644 --- a/arch/arm/boot/dts/omap443x.dtsi +++ b/arch/arm/boot/dts/omap443x.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP443x SoC * * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include "omap4.dtsi" diff --git a/arch/arm/boot/dts/omap4460.dtsi b/arch/arm/boot/dts/omap4460.dtsi index 3d6db1db94e0..1b27a862ae81 100644 --- a/arch/arm/boot/dts/omap4460.dtsi +++ b/arch/arm/boot/dts/omap4460.dtsi @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP4460 SoC * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include "omap4.dtsi" diff --git a/arch/arm/boot/dts/omap5-core-thermal.dtsi b/arch/arm/boot/dts/omap5-core-thermal.dtsi index 02e76338bfbc..e0d8e39a0014 100644 --- a/arch/arm/boot/dts/omap5-core-thermal.dtsi +++ b/arch/arm/boot/dts/omap5-core-thermal.dtsi @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP543x SoC CORE thermal * * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ * Contact: Eduardo Valentin - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/omap5-gpu-thermal.dtsi b/arch/arm/boot/dts/omap5-gpu-thermal.dtsi index bf8fa9372e57..1b4b7d9136c8 100644 --- a/arch/arm/boot/dts/omap5-gpu-thermal.dtsi +++ b/arch/arm/boot/dts/omap5-gpu-thermal.dtsi @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree Source for OMAP543x SoC GPU thermal * * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ * Contact: Eduardo Valentin - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/arch/arm/boot/dts/orion5x-lacie-d2-network.dts b/arch/arm/boot/dts/orion5x-lacie-d2-network.dts index 422958d13d42..03471d30bfd9 100644 --- a/arch/arm/boot/dts/orion5x-lacie-d2-network.dts +++ b/arch/arm/boot/dts/orion5x-lacie-d2-network.dts @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Thomas Petazzoni * Copyright (C) 2009 Simon Guinot - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ /dts-v1/; diff --git a/arch/arm/boot/dts/orion5x-lacie-ethernet-disk-mini-v2.dts b/arch/arm/boot/dts/orion5x-lacie-ethernet-disk-mini-v2.dts index 0043e0040153..f17e25ac98dd 100644 --- a/arch/arm/boot/dts/orion5x-lacie-ethernet-disk-mini-v2.dts +++ b/arch/arm/boot/dts/orion5x-lacie-ethernet-disk-mini-v2.dts @@ -1,10 +1,5 @@ -/* - * Copyright (C) 2012 Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2012 Thomas Petazzoni /* * TODO: add Orion USB device port init when kernel.org support is added. diff --git a/arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts b/arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts index 0ca6208a267d..d57859998350 100644 --- a/arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts +++ b/arch/arm/boot/dts/orion5x-maxtor-shared-storage-2.dts @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Thomas Petazzoni * Copyright (C) Sylver Bruneau - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ /dts-v1/; diff --git a/arch/arm/boot/dts/orion5x-mv88f5181.dtsi b/arch/arm/boot/dts/orion5x-mv88f5181.dtsi index f667012b26ca..819f9efb7058 100644 --- a/arch/arm/boot/dts/orion5x-mv88f5181.dtsi +++ b/arch/arm/boot/dts/orion5x-mv88f5181.dtsi @@ -1,10 +1,5 @@ -/* - * Copyright (C) 2016 Jamie Lentin - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Jamie Lentin #include "orion5x.dtsi" diff --git a/arch/arm/boot/dts/orion5x-mv88f5182.dtsi b/arch/arm/boot/dts/orion5x-mv88f5182.dtsi index d1ed71c60209..86b87fb26dc9 100644 --- a/arch/arm/boot/dts/orion5x-mv88f5182.dtsi +++ b/arch/arm/boot/dts/orion5x-mv88f5182.dtsi @@ -1,10 +1,5 @@ -/* - * Copyright (C) 2014 Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Thomas Petazzoni #include "orion5x.dtsi" diff --git a/arch/arm/boot/dts/orion5x-netgear-wnr854t.dts b/arch/arm/boot/dts/orion5x-netgear-wnr854t.dts index ea081afa469d..4f4888ec9138 100644 --- a/arch/arm/boot/dts/orion5x-netgear-wnr854t.dts +++ b/arch/arm/boot/dts/orion5x-netgear-wnr854t.dts @@ -1,10 +1,5 @@ -/* - * Copyright (C) 2016 Jamie Lentin - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2016 Jamie Lentin /dts-v1/; diff --git a/arch/arm/boot/dts/orion5x-rd88f5182-nas.dts b/arch/arm/boot/dts/orion5x-rd88f5182-nas.dts index 487324f7c54e..fd78aa02a3c5 100644 --- a/arch/arm/boot/dts/orion5x-rd88f5182-nas.dts +++ b/arch/arm/boot/dts/orion5x-rd88f5182-nas.dts @@ -1,10 +1,5 @@ -/* - * Copyright (C) 2014 Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Thomas Petazzoni /dts-v1/; diff --git a/arch/arm/boot/dts/orion5x.dtsi b/arch/arm/boot/dts/orion5x.dtsi index 61e631b3fd8b..2d41f5c166ee 100644 --- a/arch/arm/boot/dts/orion5x.dtsi +++ b/arch/arm/boot/dts/orion5x.dtsi @@ -1,10 +1,5 @@ -/* - * Copyright (C) 2012 Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2012 Thomas Petazzoni #define MBUS_ID(target,attributes) (((target) << 24) | ((attributes) << 16)) diff --git a/arch/arm/include/asm/hardware/cache-aurora-l2.h b/arch/arm/include/asm/hardware/cache-aurora-l2.h index 39769ffa0051..9694808ee97c 100644 --- a/arch/arm/include/asm/hardware/cache-aurora-l2.h +++ b/arch/arm/include/asm/hardware/cache-aurora-l2.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AURORA shared L2 cache controller support * @@ -5,10 +6,6 @@ * * Yehuda Yitschak * Gregory CLEMENT - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __ASM_ARM_HARDWARE_AURORA_L2_H diff --git a/arch/arm/include/asm/hardware/cache-feroceon-l2.h b/arch/arm/include/asm/hardware/cache-feroceon-l2.h index 12e1588dc4f1..eb2e7b7f70a8 100644 --- a/arch/arm/include/asm/hardware/cache-feroceon-l2.h +++ b/arch/arm/include/asm/hardware/cache-feroceon-l2.h @@ -1,13 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * arch/arm/include/asm/hardware/cache-feroceon-l2.h * * Copyright (C) 2008 Marvell Semiconductor - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ extern void __init feroceon_l2_init(int l2_wt_override); extern int __init feroceon_of_init(void); - diff --git a/arch/arm/include/asm/hardware/cache-tauros2.h b/arch/arm/include/asm/hardware/cache-tauros2.h index 295e2e40151b..4e493facaa31 100644 --- a/arch/arm/include/asm/hardware/cache-tauros2.h +++ b/arch/arm/include/asm/hardware/cache-tauros2.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * arch/arm/include/asm/hardware/cache-tauros2.h * * Copyright (C) 2008 Marvell Semiconductor - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define CACHE_TAUROS2_PREFETCH_ON (1 << 0) diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c index a0aaab5c7aa6..6299e5c8f4ea 100644 --- a/arch/arm/mach-davinci/board-da830-evm.c +++ b/arch/arm/mach-davinci/board-da830-evm.c @@ -1,13 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DA830/OMAP L137 EVM board * * Author: Mark A. Greer * Derived from: arch/arm/mach-davinci/board-dm644x-evm.c * - * 2007, 2009 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007, 2009 (c) MontaVista Software, Inc. */ #include #include diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index efc26b472ef8..92d74bc71967 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DA850/OMAP-L138 EVM board * @@ -6,10 +7,7 @@ * Derived from: arch/arm/mach-davinci/board-da830-evm.c * Original Copyrights follow: * - * 2007, 2009 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007, 2009 (c) MontaVista Software, Inc. */ #include #include diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c index f7c56f662d4c..b48ab1c3e48b 100644 --- a/arch/arm/mach-davinci/board-dm355-evm.c +++ b/arch/arm/mach-davinci/board-dm355-evm.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DaVinci EVM board support * * Author: Kevin Hilman, Deep Root Systems, LLC * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) MontaVista Software, Inc. */ #include #include diff --git a/arch/arm/mach-davinci/board-dm355-leopard.c b/arch/arm/mach-davinci/board-dm355-leopard.c index 0f2b61266197..32b9d607d025 100644 --- a/arch/arm/mach-davinci/board-dm355-leopard.c +++ b/arch/arm/mach-davinci/board-dm355-leopard.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DM355 leopard board support * * Based on board-dm355-evm.c - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c index 9f405af36a6f..ebdd5c334ac1 100644 --- a/arch/arm/mach-davinci/board-dm644x-evm.c +++ b/arch/arm/mach-davinci/board-dm644x-evm.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DaVinci EVM board support * * Author: Kevin Hilman, MontaVista Software, Inc. * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) MontaVista Software, Inc. */ #include #include diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index 84ad065e98c2..28861fee493b 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DaVinci DM646X EVM board * @@ -5,11 +6,6 @@ * Copyright (C) 2006 Texas Instruments. * * (C) 2007-2008, MontaVista Software, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * */ /************************************************************************** @@ -870,4 +866,3 @@ MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T EVM") .init_late = davinci_init_late, .dma_zone_size = SZ_128M, MACHINE_END - diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c index 3f084bdb9bc5..a46e7b9ff8e0 100644 --- a/arch/arm/mach-davinci/board-mityomapl138.c +++ b/arch/arm/mach-davinci/board-mityomapl138.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Critical Link MityOMAP-L138 SoM * * Copyright (C) 2010 Critical Link LLC - https://www.criticallink.com - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of - * any kind, whether express or implied. */ #define pr_fmt(fmt) "MityOMAPL138: " fmt diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c index 94be492b8a9e..9748a2c12cc4 100644 --- a/arch/arm/mach-davinci/board-neuros-osd2.c +++ b/arch/arm/mach-davinci/board-neuros-osd2.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Neuros Technologies OSD2 board support * @@ -18,10 +19,6 @@ * * For more information please refer to * http://wiki.neurostechnology.com/index.php/OSD_2.0_HD - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-davinci/board-omapl138-hawk.c b/arch/arm/mach-davinci/board-omapl138-hawk.c index 20f71856bf7e..8a80115999ad 100644 --- a/arch/arm/mach-davinci/board-omapl138-hawk.c +++ b/arch/arm/mach-davinci/board-omapl138-hawk.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hawkboard.org based on TI's OMAP-L138 Platform * * Initial code: Syed Mohammed Khasim * * Copyright (C) 2009 Texas Instruments Incorporated - https://www.ti.com - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of - * any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-davinci/common.c b/arch/arm/mach-davinci/common.c index 0a6f826ff136..c1ce6b2a8d48 100644 --- a/arch/arm/mach-davinci/common.c +++ b/arch/arm/mach-davinci/common.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Code commons to all DaVinci SoCs. * * Author: Mark A. Greer * - * 2009 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2009 (c) MontaVista Software, Inc. */ #include #include diff --git a/arch/arm/mach-davinci/common.h b/arch/arm/mach-davinci/common.h index 139b83de011d..772b51e0ac5e 100644 --- a/arch/arm/mach-davinci/common.h +++ b/arch/arm/mach-davinci/common.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Header for code common to all DaVinci machines. * * Author: Kevin Hilman, MontaVista Software, Inc. * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) MontaVista Software, Inc. */ #ifndef __ARCH_ARM_MACH_DAVINCI_COMMON_H diff --git a/arch/arm/mach-davinci/cpuidle.h b/arch/arm/mach-davinci/cpuidle.h index 0d9193aefab5..976d43073597 100644 --- a/arch/arm/mach-davinci/cpuidle.h +++ b/arch/arm/mach-davinci/cpuidle.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI DaVinci cpuidle platform support * * 2009 (C) Texas Instruments, Inc. https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #ifndef _MACH_DAVINCI_CPUIDLE_H #define _MACH_DAVINCI_CPUIDLE_H diff --git a/arch/arm/mach-davinci/cputype.h b/arch/arm/mach-davinci/cputype.h index 1fe9f84d5ee6..4590afdbe449 100644 --- a/arch/arm/mach-davinci/cputype.h +++ b/arch/arm/mach-davinci/cputype.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * DaVinci CPU type detection * @@ -8,10 +9,7 @@ * compiled in to the kernel, the macros return 0 so that * resulting code can be optimized out. * - * 2009 (c) Deep Root Systems, LLC. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2009 (c) Deep Root Systems, LLC. */ #ifndef _ASM_ARCH_CPU_H #define _ASM_ARCH_CPU_H diff --git a/arch/arm/mach-davinci/da830.c b/arch/arm/mach-davinci/da830.c index 1b86657c6e9d..eab5fac18806 100644 --- a/arch/arm/mach-davinci/da830.c +++ b/arch/arm/mach-davinci/da830.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DA830/OMAP L137 chip specific setup * * Author: Mark A. Greer * - * 2009 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2009 (c) MontaVista Software, Inc. */ #include #include diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c index cd514c136de0..635e88daf5dd 100644 --- a/arch/arm/mach-davinci/da850.c +++ b/arch/arm/mach-davinci/da850.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DA850/OMAP-L138 chip specific setup * @@ -6,10 +7,7 @@ * Derived from: arch/arm/mach-davinci/da830.c * Original Copyrights follow: * - * 2009 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2009 (c) MontaVista Software, Inc. */ #include diff --git a/arch/arm/mach-davinci/da8xx.h b/arch/arm/mach-davinci/da8xx.h index 699df08714ba..382811dbbc3b 100644 --- a/arch/arm/mach-davinci/da8xx.h +++ b/arch/arm/mach-davinci/da8xx.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Chip specific defines for DA8XX/OMAP L1XX SoC * * Author: Mark A. Greer * - * 2007, 2009-2010 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007, 2009-2010 (c) MontaVista Software, Inc. */ #ifndef __ASM_ARCH_DAVINCI_DA8XX_H #define __ASM_ARCH_DAVINCI_DA8XX_H diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c index 1d7443c59b14..a12ba859beca 100644 --- a/arch/arm/mach-davinci/dm355.c +++ b/arch/arm/mach-davinci/dm355.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DaVinci DM355 chip specific setup * * Author: Kevin Hilman, Deep Root Systems, LLC * - * 2007 (c) Deep Root Systems, LLC. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) Deep Root Systems, LLC. */ #include diff --git a/arch/arm/mach-davinci/dm644x.c b/arch/arm/mach-davinci/dm644x.c index 1ce48d0fb16d..c8a276c42957 100644 --- a/arch/arm/mach-davinci/dm644x.c +++ b/arch/arm/mach-davinci/dm644x.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DaVinci DM644x chip specific setup * * Author: Kevin Hilman, Deep Root Systems, LLC * - * 2007 (c) Deep Root Systems, LLC. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) Deep Root Systems, LLC. */ #include diff --git a/arch/arm/mach-davinci/dm646x.c b/arch/arm/mach-davinci/dm646x.c index 971b2d4e2595..fbee617d00ca 100644 --- a/arch/arm/mach-davinci/dm646x.c +++ b/arch/arm/mach-davinci/dm646x.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI DaVinci DM646x chip specific setup * * Author: Kevin Hilman, Deep Root Systems, LLC * - * 2007 (c) Deep Root Systems, LLC. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) Deep Root Systems, LLC. */ #include diff --git a/arch/arm/mach-davinci/hardware.h b/arch/arm/mach-davinci/hardware.h index 16bb42291d39..7848b6a240b4 100644 --- a/arch/arm/mach-davinci/hardware.h +++ b/arch/arm/mach-davinci/hardware.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Hardware definitions common to all DaVinci family processors * * Author: Kevin Hilman, Deep Root Systems, LLC * - * 2007 (c) Deep Root Systems, LLC. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) Deep Root Systems, LLC. */ #ifndef __ASM_ARCH_HARDWARE_H #define __ASM_ARCH_HARDWARE_H diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c index bab1eea7fca6..814a6b714010 100644 --- a/arch/arm/mach-davinci/mux.c +++ b/arch/arm/mach-davinci/mux.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Utility to set the DAVINCI MUX register from a table in mux.h * @@ -8,10 +9,7 @@ * * Written by Tony Lindgren * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) MontaVista Software, Inc. * * Copyright (C) 2008 Texas Instruments. */ diff --git a/arch/arm/mach-davinci/mux.h b/arch/arm/mach-davinci/mux.h index b0d1c4fb78dc..b5effe16402c 100644 --- a/arch/arm/mach-davinci/mux.h +++ b/arch/arm/mach-davinci/mux.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Pin-multiplex helper macros for TI DaVinci family devices * * Author: Vladimir Barinov, MontaVista Software, Inc. * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) MontaVista Software, Inc. * * Copyright (C) 2008 Texas Instruments. */ diff --git a/arch/arm/mach-davinci/pm_domain.c b/arch/arm/mach-davinci/pm_domain.c index e251fd593bfd..6b21d5bd999c 100644 --- a/arch/arm/mach-davinci/pm_domain.c +++ b/arch/arm/mach-davinci/pm_domain.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Runtime PM support code for DaVinci * * Author: Kevin Hilman * * Copyright (C) 2012 Texas Instruments, Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-davinci/serial.h b/arch/arm/mach-davinci/serial.h index 14473cb19852..c4a4ba553d45 100644 --- a/arch/arm/mach-davinci/serial.h +++ b/arch/arm/mach-davinci/serial.h @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * DaVinci serial device definitions * * Author: Kevin Hilman, MontaVista Software, Inc. * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2007 (c) MontaVista Software, Inc. */ #ifndef __ASM_ARCH_SERIAL_H #define __ASM_ARCH_SERIAL_H diff --git a/arch/arm/mach-dove/bridge-regs.h b/arch/arm/mach-dove/bridge-regs.h index ace0b0bfbf11..6fbc152d0950 100644 --- a/arch/arm/mach-dove/bridge-regs.h +++ b/arch/arm/mach-dove/bridge-regs.h @@ -1,10 +1,5 @@ -/* - * Mbus-L to Mbus Bridge Registers - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Mbus-L to Mbus Bridge Registers */ #ifndef __ASM_ARCH_BRIDGE_REGS_H #define __ASM_ARCH_BRIDGE_REGS_H diff --git a/arch/arm/mach-dove/cm-a510.c b/arch/arm/mach-dove/cm-a510.c index 9f25c993d863..beb532537c22 100644 --- a/arch/arm/mach-dove/cm-a510.c +++ b/arch/arm/mach-dove/cm-a510.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-dove/cm-a510.c * @@ -5,10 +6,6 @@ * Konstantin Sinyuk * * Based on Marvell DB-MV88AP510-BP Development Board Setup - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index dbe970e37895..cd4ae7e4768d 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-dove/common.c * * Core functions for Marvell Dove 88AP510 System On Chip - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-dove/common.h b/arch/arm/mach-dove/common.h index 1d725224d146..57ebc413d68c 100644 --- a/arch/arm/mach-dove/common.h +++ b/arch/arm/mach-dove/common.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * arch/arm/mach-dove/common.h * * Core functions for Marvell Dove 88AP510 System On Chip - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __ARCH_DOVE_COMMON_H diff --git a/arch/arm/mach-dove/dove-db-setup.c b/arch/arm/mach-dove/dove-db-setup.c index 418ab21b9d9b..d5bf54040577 100644 --- a/arch/arm/mach-dove/dove-db-setup.c +++ b/arch/arm/mach-dove/dove-db-setup.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-dove/dove-db-setup.c * * Marvell DB-MV88AP510-BP Development Board Setup - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-dove/dove.h b/arch/arm/mach-dove/dove.h index 320ed1696abd..e5054e3b0b78 100644 --- a/arch/arm/mach-dove/dove.h +++ b/arch/arm/mach-dove/dove.h @@ -1,10 +1,5 @@ -/* - * Generic definitions for Marvell Dove 88AP510 SoC - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Generic definitions for Marvell Dove 88AP510 SoC */ #ifndef __ASM_ARCH_DOVE_H #define __ASM_ARCH_DOVE_H diff --git a/arch/arm/mach-dove/irq.c b/arch/arm/mach-dove/irq.c index d36f6b8269c2..027a8f87bc2e 100644 --- a/arch/arm/mach-dove/irq.c +++ b/arch/arm/mach-dove/irq.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-dove/irq.c * * Dove IRQ handling. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-dove/irqs.h b/arch/arm/mach-dove/irqs.h index a0742179faff..5467098c7042 100644 --- a/arch/arm/mach-dove/irqs.h +++ b/arch/arm/mach-dove/irqs.h @@ -1,10 +1,5 @@ -/* - * IRQ definitions for Marvell Dove 88AP510 SoC - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* IRQ definitions for Marvell Dove 88AP510 SoC */ #ifndef __ASM_ARCH_IRQS_H #define __ASM_ARCH_IRQS_H diff --git a/arch/arm/mach-dove/mpp.c b/arch/arm/mach-dove/mpp.c index 6acd8488bb05..93cb137da5f8 100644 --- a/arch/arm/mach-dove/mpp.c +++ b/arch/arm/mach-dove/mpp.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-dove/mpp.c * * MPP functions for Marvell Dove SoCs - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-dove/pcie.c b/arch/arm/mach-dove/pcie.c index 2a493bdfffc6..91420da4cfd2 100644 --- a/arch/arm/mach-dove/pcie.c +++ b/arch/arm/mach-dove/pcie.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-dove/pcie.c * * PCIe functions for Marvell Dove 88AP510 SoC - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-dove/pm.h b/arch/arm/mach-dove/pm.h index 01267746d707..a4c3aba1e2d0 100644 --- a/arch/arm/mach-dove/pm.h +++ b/arch/arm/mach-dove/pm.h @@ -1,8 +1,4 @@ -/* - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef __ASM_ARCH_PM_H #define __ASM_ARCH_PM_H diff --git a/arch/arm/mach-lpc18xx/board-dt.c b/arch/arm/mach-lpc18xx/board-dt.c index fdcee78d1bc4..4729eb83401a 100644 --- a/arch/arm/mach-lpc18xx/board-dt.c +++ b/arch/arm/mach-lpc18xx/board-dt.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree board file for NXP LPC18xx/43xx * * Copyright (C) 2015 Joachim Eastwood - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-lpc32xx/pm.c b/arch/arm/mach-lpc32xx/pm.c index b27fa1b9f56c..2572bd89a5e8 100644 --- a/arch/arm/mach-lpc32xx/pm.c +++ b/arch/arm/mach-lpc32xx/pm.c @@ -1,13 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-lpc32xx/pm.c * * Original authors: Vitaly Wool, Dmitry Chigirev * Modified by Kevin Wells * - * 2005 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2005 (c) MontaVista Software, Inc. */ /* diff --git a/arch/arm/mach-lpc32xx/suspend.S b/arch/arm/mach-lpc32xx/suspend.S index 3f0a8282ef6f..a95c5e0e4038 100644 --- a/arch/arm/mach-lpc32xx/suspend.S +++ b/arch/arm/mach-lpc32xx/suspend.S @@ -1,13 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * arch/arm/mach-lpc32xx/suspend.S * * Original authors: Dmitry Chigirev, Vitaly Wool * Modified by Kevin Wells * - * 2005 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2005 (c) MontaVista Software, Inc. */ #include #include diff --git a/arch/arm/mach-mv78xx0/bridge-regs.h b/arch/arm/mach-mv78xx0/bridge-regs.h index 2f54e1753d45..d57ac967c4b3 100644 --- a/arch/arm/mach-mv78xx0/bridge-regs.h +++ b/arch/arm/mach-mv78xx0/bridge-regs.h @@ -1,8 +1,4 @@ -/* - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ #ifndef __ASM_ARCH_BRIDGE_REGS_H #define __ASM_ARCH_BRIDGE_REGS_H diff --git a/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c b/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c index e112f2e7cc9a..9aa765d4cdc8 100644 --- a/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c +++ b/arch/arm/mach-mv78xx0/buffalo-wxl-setup.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-mv78xx0/buffalo-wxl-setup.c * * Buffalo WXL (Terastation Duo) Setup routines * * sebastien requiem - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c index dd762d1b083f..461a68945c26 100644 --- a/arch/arm/mach-mv78xx0/common.c +++ b/arch/arm/mach-mv78xx0/common.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-mv78xx0/common.c * * Core functions for Marvell MV78xx0 SoCs - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mv78xx0/common.h b/arch/arm/mach-mv78xx0/common.h index 6889af26077d..d8c6c2400e27 100644 --- a/arch/arm/mach-mv78xx0/common.h +++ b/arch/arm/mach-mv78xx0/common.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * arch/arm/mach-mv78xx0/common.h * * Core functions for Marvell MV78xx0 SoCs - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __ARCH_MV78XX0_COMMON_H diff --git a/arch/arm/mach-mv78xx0/db78x00-bp-setup.c b/arch/arm/mach-mv78xx0/db78x00-bp-setup.c index cf16e08d4cf5..da633a33a0c1 100644 --- a/arch/arm/mach-mv78xx0/db78x00-bp-setup.c +++ b/arch/arm/mach-mv78xx0/db78x00-bp-setup.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-mv78xx0/db78x00-bp-setup.c * * Marvell DB-78x00-BP Development Board Setup - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mv78xx0/irq.c b/arch/arm/mach-mv78xx0/irq.c index 0b5f055ca1c3..a34b6855fb19 100644 --- a/arch/arm/mach-mv78xx0/irq.c +++ b/arch/arm/mach-mv78xx0/irq.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-mv78xx0/irq.c * * MV78xx0 IRQ handling. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-mv78xx0/irqs.h b/arch/arm/mach-mv78xx0/irqs.h index 67e0fe730a13..12b357d383d8 100644 --- a/arch/arm/mach-mv78xx0/irqs.h +++ b/arch/arm/mach-mv78xx0/irqs.h @@ -1,10 +1,5 @@ -/* - * IRQ definitions for Marvell MV78xx0 SoCs - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* IRQ definitions for Marvell MV78xx0 SoCs */ #ifndef __ASM_ARCH_IRQS_H #define __ASM_ARCH_IRQS_H diff --git a/arch/arm/mach-mv78xx0/mpp.c b/arch/arm/mach-mv78xx0/mpp.c index 72843c02e95a..aff0e612cbba 100644 --- a/arch/arm/mach-mv78xx0/mpp.c +++ b/arch/arm/mach-mv78xx0/mpp.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-mv78x00/mpp.c * * MPP functions for Marvell MV78x00 SoCs - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-mv78xx0/mpp.h b/arch/arm/mach-mv78xx0/mpp.h index 3752302ae2ee..47db52f45546 100644 --- a/arch/arm/mach-mv78xx0/mpp.h +++ b/arch/arm/mach-mv78xx0/mpp.h @@ -1,12 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/arch/arm/mach-mv78xx0/mpp.h -- Multi Purpose Pins * - * * sebastien requiem - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __MV78X00_MPP_H diff --git a/arch/arm/mach-mv78xx0/mv78xx0.h b/arch/arm/mach-mv78xx0/mv78xx0.h index c1a9a1d1b295..3f19bef7d7ac 100644 --- a/arch/arm/mach-mv78xx0/mv78xx0.h +++ b/arch/arm/mach-mv78xx0/mv78xx0.h @@ -1,10 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Generic definitions for Marvell MV78xx0 SoC flavors: * MV781x0 and MV782x0. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __ASM_ARCH_MV78XX0_H diff --git a/arch/arm/mach-mv78xx0/pcie.c b/arch/arm/mach-mv78xx0/pcie.c index e15646af7f26..9de2e47721b8 100644 --- a/arch/arm/mach-mv78xx0/pcie.c +++ b/arch/arm/mach-mv78xx0/pcie.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-mv78xx0/pcie.c * * PCIe functions for Marvell MV78xx0 SoCs - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c b/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c index 308ab71ec822..80ca8b1a81de 100644 --- a/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c +++ b/arch/arm/mach-mv78xx0/rd78x00-masa-setup.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-mv78x00/rd78x00-masa-setup.c * * Marvell RD-78x00-mASA Development Board Setup - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h index 09413b678409..c96ecdafe31f 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.h +++ b/arch/arm/mach-mvebu/armada-370-xp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Generic definitions for Marvell Armada_370_XP SoCs * @@ -6,10 +7,6 @@ * Lior Amsalem * Gregory CLEMENT * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __MACH_ARMADA_370_XP_H diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c index d2df5ef9382b..fd5d0c8ff695 100644 --- a/arch/arm/mach-mvebu/board-v7.c +++ b/arch/arm/mach-mvebu/board-v7.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Device Tree support for Armada 370 and XP platforms. * @@ -6,10 +7,6 @@ * Lior Amsalem * Gregory CLEMENT * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 49e3c8d20c2f..883dab1b54f3 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Coherency fabric (Aurora) support for Armada 370, 375, 38x and XP * platforms. @@ -8,10 +9,6 @@ * Gregory Clement * Thomas Petazzoni * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * The Armada 370, 375, 38x and XP SOCs have a coherency fabric which is * responsible for ensuring hardware coherency between all CPUs and between * CPUs and I/O masters. This file initializes the coherency fabric and diff --git a/arch/arm/mach-mvebu/coherency.h b/arch/arm/mach-mvebu/coherency.h index 6067f14263f7..cae866ab4867 100644 --- a/arch/arm/mach-mvebu/coherency.h +++ b/arch/arm/mach-mvebu/coherency.h @@ -1,14 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * arch/arm/mach-mvebu/include/mach/coherency.h * - * * Coherency fabric (Aurora) support for Armada 370 and XP platforms. * * Copyright (C) 2012 Marvell - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __MACH_370_XP_COHERENCY_H diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S index a3a64bf97250..eb81656e32d4 100644 --- a/arch/arm/mach-mvebu/coherency_ll.S +++ b/arch/arm/mach-mvebu/coherency_ll.S @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Coherency fabric: low level functions * @@ -5,10 +6,6 @@ * * Gregory CLEMENT * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * This file implements the assembly function to add a CPU to the * coherency fabric. This function is called by each of the secondary * CPUs during their early boot in an SMP kernel, this why this diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h index 6b775492cfad..fbfa3c4f30df 100644 --- a/arch/arm/mach-mvebu/common.h +++ b/arch/arm/mach-mvebu/common.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Core functions for Marvell System On Chip * @@ -6,10 +7,6 @@ * Lior Amsalem * Gregory CLEMENT * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __ARCH_MVEBU_COMMON_H diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c index f33a31c6aff8..66b6c0c6ce1d 100644 --- a/arch/arm/mach-mvebu/cpu-reset.c +++ b/arch/arm/mach-mvebu/cpu-reset.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2014 Marvell * * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) "mvebu-cpureset: " fmt diff --git a/arch/arm/mach-mvebu/dove.c b/arch/arm/mach-mvebu/dove.c index d076c5771adc..c938ba725d3e 100644 --- a/arch/arm/mach-mvebu/dove.c +++ b/arch/arm/mach-mvebu/dove.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-mvebu/dove.c * * Marvell Dove 88AP510 System On Chip FDT Board - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S index b093a196e801..df723cf85cae 100644 --- a/arch/arm/mach-mvebu/headsmp-a9.S +++ b/arch/arm/mach-mvebu/headsmp-a9.S @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * SMP support: Entry point for secondary CPUs of Marvell EBU * Cortex-A9 based SOCs (Armada 375 and Armada 38x). @@ -6,10 +7,6 @@ * * Gregory CLEMENT * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mvebu/headsmp.S b/arch/arm/mach-mvebu/headsmp.S index 2c4032e368ba..f05c59dad32a 100644 --- a/arch/arm/mach-mvebu/headsmp.S +++ b/arch/arm/mach-mvebu/headsmp.S @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * SMP support: Entry point for secondary CPUs * @@ -7,10 +8,6 @@ * Gregory CLEMENT * Thomas Petazzoni * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * This file implements the assembly entry point for secondary CPUs in * an SMP kernel. The only thing we need to do is to add the CPU to * the coherency fabric by writing to 2 registers. Currently the base diff --git a/arch/arm/mach-mvebu/kirkwood.c b/arch/arm/mach-mvebu/kirkwood.c index 06b1706595f4..8ff34753e760 100644 --- a/arch/arm/mach-mvebu/kirkwood.c +++ b/arch/arm/mach-mvebu/kirkwood.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2012 (C), Jason Cooper * * arch/arm/mach-mvebu/kirkwood.c * * Flattened Device Tree board initialization - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mvebu/kirkwood.h b/arch/arm/mach-mvebu/kirkwood.h index 89f3d1f51643..15135994ce2f 100644 --- a/arch/arm/mach-mvebu/kirkwood.h +++ b/arch/arm/mach-mvebu/kirkwood.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * arch/arm/mach-mvebu/kirkwood.h * * Generic definitions for Marvell Kirkwood SoC flavors: * 88F6180, 88F6192 and 88F6281. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define KIRKWOOD_REGS_PHYS_BASE 0xf1000000 diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.c b/arch/arm/mach-mvebu/mvebu-soc-id.c index a99434bcee84..f436c7b8c7ae 100644 --- a/arch/arm/mach-mvebu/mvebu-soc-id.c +++ b/arch/arm/mach-mvebu/mvebu-soc-id.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ID and revision information for mvebu SoCs * @@ -5,10 +6,6 @@ * * Gregory CLEMENT * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * All the mvebu SoCs have information related to their variant and * revision that can be read from the PCI control register. This is * done before the PCI initialization to avoid any conflict. Once the diff --git a/arch/arm/mach-mvebu/mvebu-soc-id.h b/arch/arm/mach-mvebu/mvebu-soc-id.h index e124a0b82a3e..225649b2288a 100644 --- a/arch/arm/mach-mvebu/mvebu-soc-id.h +++ b/arch/arm/mach-mvebu/mvebu-soc-id.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Marvell EBU SoC ID and revision definitions. * * Copyright (C) 2014 Marvell Semiconductor - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __LINUX_MVEBU_SOC_ID_H diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c index d715dec1c197..785ee2af5baa 100644 --- a/arch/arm/mach-mvebu/platsmp-a9.c +++ b/arch/arm/mach-mvebu/platsmp-a9.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9 * based SOCs (Armada 375/38x). @@ -6,10 +7,6 @@ * * Gregory CLEMENT * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index c130497dc6cc..18384ea6862c 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Symmetric Multi Processing (SMP) support for Armada XP * @@ -8,10 +9,6 @@ * Gregory CLEMENT * Thomas Petazzoni * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * The Armada XP SoC has 4 ARMv7 PJ4B CPUs running in full HW coherency * This file implements the routines for preparing the SMP infrastructure * and waking up the secondary CPUs diff --git a/arch/arm/mach-mvebu/pm-board.c b/arch/arm/mach-mvebu/pm-board.c index 070552511699..7fa1806acd65 100644 --- a/arch/arm/mach-mvebu/pm-board.c +++ b/arch/arm/mach-mvebu/pm-board.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Board-level suspend/resume support. * * Copyright (C) 2014-2015 Marvell * * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c index c487be61d6d8..b149d9b77505 100644 --- a/arch/arm/mach-mvebu/pm.c +++ b/arch/arm/mach-mvebu/pm.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Suspend/resume support. Currently supporting Armada XP only. * * Copyright (C) 2014 Marvell * * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index 73d5d72dfc3e..af27a7156675 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Power Management Service Unit(PMSU) support for Armada 370/XP platforms. * @@ -7,10 +8,6 @@ * Gregory Clement * Thomas Petazzoni * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * The Armada 370 and Armada XP SOCs have a power management service * unit which is responsible for powering down and waking up CPUs and * other SOC units diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h index ea79269c2702..1e847388e8dd 100644 --- a/arch/arm/mach-mvebu/pmsu.h +++ b/arch/arm/mach-mvebu/pmsu.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Power Management Service Unit (PMSU) support for Armada 370/XP platforms. * * Copyright (C) 2012 Marvell - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __MACH_MVEBU_PMSU_H diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S index 7aae9a25cfeb..f7d21385fd88 100644 --- a/arch/arm/mach-mvebu/pmsu_ll.S +++ b/arch/arm/mach-mvebu/pmsu_ll.S @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2014 Marvell * * Thomas Petazzoni * Gregory Clement - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-mvebu/system-controller.c b/arch/arm/mach-mvebu/system-controller.c index 04d9ebe6a90a..48224b6ed6dc 100644 --- a/arch/arm/mach-mvebu/system-controller.c +++ b/arch/arm/mach-mvebu/system-controller.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * System controller support for Armada 370, 375 and XP platforms. * @@ -7,10 +8,6 @@ * Gregory CLEMENT * Thomas Petazzoni * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * The Armada 370, 375 and Armada XP SoCs have a range of * miscellaneous registers, that do not belong to a particular device, * but rather provide system-level features. This basic diff --git a/arch/arm/mach-omap1/mtd-xip.h b/arch/arm/mach-omap1/mtd-xip.h index b675d501b13d..5ae312ff08a1 100644 --- a/arch/arm/mach-omap1/mtd-xip.h +++ b/arch/arm/mach-omap1/mtd-xip.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * MTD primitives for XIP support. Architecture specific functions. * @@ -5,10 +6,7 @@ * * Author: Vladimir Barinov * - * (c) 2005 MontaVista Software, Inc. This file is licensed under the - * terms of the GNU General Public License version 2. This program is - * licensed "as is" without any warranty of any kind, whether express or - * implied. + * (c) 2005 MontaVista Software, Inc. */ #ifndef __ARCH_OMAP_MTD_XIP_H__ diff --git a/arch/arm/mach-omap1/pm_bus.c b/arch/arm/mach-omap1/pm_bus.c index 667c1637ff91..c04619ac0631 100644 --- a/arch/arm/mach-omap1/pm_bus.c +++ b/arch/arm/mach-omap1/pm_bus.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Runtime PM support code for OMAP1 * * Author: Kevin Hilman, Deep Root Systems, LLC * * Copyright (C) 2010 Texas Instruments, Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include @@ -43,4 +40,3 @@ static int __init omap1_pm_runtime_init(void) return 0; } core_initcall(omap1_pm_runtime_init); - diff --git a/arch/arm/mach-omap2/prcm43xx.h b/arch/arm/mach-omap2/prcm43xx.h index b65cccab6ad9..38ed69b150cb 100644 --- a/arch/arm/mach-omap2/prcm43xx.h +++ b/arch/arm/mach-omap2/prcm43xx.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * AM43x PRCM defines * * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com/ - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #ifndef __ARCH_ARM_MACH_OMAP2_PRCM_43XX_H diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c index 86f1ac4c2412..ea02d40405c4 100644 --- a/arch/arm/mach-omap2/vc.c +++ b/arch/arm/mach-omap2/vc.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP Voltage Controller (VC) interface * * Copyright (C) 2011 Texas Instruments, Inc. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include @@ -895,4 +892,3 @@ void __init omap_vc_init_channel(struct voltagedomain *voltdm) else if (cpu_is_omap44xx()) omap4_vc_init_channel(voltdm); } - diff --git a/arch/arm/mach-orion5x/board-d2net.c b/arch/arm/mach-orion5x/board-d2net.c index a89376a5cd92..0297e302d7bc 100644 --- a/arch/arm/mach-orion5x/board-d2net.c +++ b/arch/arm/mach-orion5x/board-d2net.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/board-d2net.c * * LaCie d2Network and Big Disk Network NAS setup * * Copyright (C) 2009 Simon Guinot - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-orion5x/board-dt.c b/arch/arm/mach-orion5x/board-dt.c index 3d36f1d95196..e3736ffc8347 100644 --- a/arch/arm/mach-orion5x/board-dt.c +++ b/arch/arm/mach-orion5x/board-dt.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2012 (C), Thomas Petazzoni * * arch/arm/mach-orion5x/board-dt.c * * Flattened Device Tree board initialization - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-orion5x/board-rd88f5182.c b/arch/arm/mach-orion5x/board-rd88f5182.c index b7b0f52f4c0a..596601367989 100644 --- a/arch/arm/mach-orion5x/board-rd88f5182.c +++ b/arch/arm/mach-orion5x/board-rd88f5182.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/rd88f5182-setup.c * * Marvell Orion-NAS Reference Design Setup * * Maintainer: Ronen Shitrit - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-orion5x/bridge-regs.h b/arch/arm/mach-orion5x/bridge-regs.h index 305598eaaee1..fe85bc5b131f 100644 --- a/arch/arm/mach-orion5x/bridge-regs.h +++ b/arch/arm/mach-orion5x/bridge-regs.h @@ -1,10 +1,5 @@ -/* - * Orion CPU Bridge Registers - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Orion CPU Bridge Registers */ #ifndef __ASM_ARCH_BRIDGE_REGS_H #define __ASM_ARCH_BRIDGE_REGS_H diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index 7bcb41137bbf..2e711b7252c6 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/common.c * * Core functions for Marvell Orion 5x SoCs * * Maintainer: Tzachi Perelstein - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c index 39eae10ac8de..fe1a4cef1ba2 100644 --- a/arch/arm/mach-orion5x/db88f5281-setup.c +++ b/arch/arm/mach-orion5x/db88f5281-setup.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/db88f5281-setup.c * * Marvell Orion-2 Development Board Setup * * Maintainer: Tzachi Perelstein - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-orion5x/irq.c b/arch/arm/mach-orion5x/irq.c index 1ae775d02d90..e17727e53cb4 100644 --- a/arch/arm/mach-orion5x/irq.c +++ b/arch/arm/mach-orion5x/irq.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/irq.c * * Core IRQ functions for Marvell Orion System On Chip * * Maintainer: Tzachi Perelstein - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-orion5x/irqs.h b/arch/arm/mach-orion5x/irqs.h index 506c8e0b30c4..a70c47cfa6bc 100644 --- a/arch/arm/mach-orion5x/irqs.h +++ b/arch/arm/mach-orion5x/irqs.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * IRQ definitions for Orion SoC * * Maintainer: Tzachi Perelstein - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __ASM_ARCH_IRQS_H diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c index 83d43cff4bd7..acba06618080 100644 --- a/arch/arm/mach-orion5x/kurobox_pro-setup.c +++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/kurobox_pro-setup.c * * Maintainer: Ronen Shitrit - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-orion5x/ls_hgl-setup.c b/arch/arm/mach-orion5x/ls_hgl-setup.c index 47ba6e0502f5..af07f617465f 100644 --- a/arch/arm/mach-orion5x/ls_hgl-setup.c +++ b/arch/arm/mach-orion5x/ls_hgl-setup.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/ls_hgl-setup.c * * Maintainer: Zhu Qingsen - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-orion5x/mpp.c b/arch/arm/mach-orion5x/mpp.c index 19ef18594415..b9855dce6ba0 100644 --- a/arch/arm/mach-orion5x/mpp.c +++ b/arch/arm/mach-orion5x/mpp.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/mpp.c * * MPP functions for Marvell Orion 5x SoCs - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-orion5x/net2big-setup.c b/arch/arm/mach-orion5x/net2big-setup.c index bf6be4cfd238..695cc683cd83 100644 --- a/arch/arm/mach-orion5x/net2big-setup.c +++ b/arch/arm/mach-orion5x/net2big-setup.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/net2big-setup.c * * LaCie 2Big Network NAS setup * * Copyright (C) 2009 Simon Guinot - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include @@ -432,4 +429,3 @@ MACHINE_START(NET2BIG, "LaCie 2Big Network") .fixup = tag_fixup_mem32, .restart = orion5x_restart, MACHINE_END - diff --git a/arch/arm/mach-orion5x/orion5x.h b/arch/arm/mach-orion5x/orion5x.h index 2b66120fba86..26f1ccb8cb28 100644 --- a/arch/arm/mach-orion5x/orion5x.h +++ b/arch/arm/mach-orion5x/orion5x.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Generic definitions of Orion SoC flavors: * Orion-1, Orion-VoIP, Orion-NAS, Orion-2, and Orion-1-90. * * Maintainer: Tzachi Perelstein - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __ASM_ARCH_ORION5X_H diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c index 92e938bba20d..997fe39a86da 100644 --- a/arch/arm/mach-orion5x/pci.c +++ b/arch/arm/mach-orion5x/pci.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/pci.c * * PCI and PCIe functions for Marvell Orion System On Chip * * Maintainer: Tzachi Perelstein - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c index c65ab7db36ad..432fc8357d9e 100644 --- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c +++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c * * Marvell Orion-VoIP FXO Reference Design Setup - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c index 76b8138d9d79..d4b1a9c3cd36 100644 --- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c +++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/rd88f5181l-ge-setup.c * * Marvell Orion-VoIP GE Reference Design Setup - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c index fe3e67c81fb8..6ffcfc6445e2 100644 --- a/arch/arm/mach-orion5x/rd88f5182-setup.c +++ b/arch/arm/mach-orion5x/rd88f5182-setup.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/rd88f5182-setup.c * * Marvell Orion-NAS Reference Design Setup * * Maintainer: Ronen Shitrit - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c index 5f388a1ed1e4..93f74fd6b4da 100644 --- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c +++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/rd88f6183-ap-ge-setup.c * * Marvell Orion-1-90 AP GE Reference Design Setup - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c index a39764faf2a0..af810e7ccd79 100644 --- a/arch/arm/mach-orion5x/ts78xx-setup.c +++ b/arch/arm/mach-orion5x/ts78xx-setup.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-orion5x/ts78xx-setup.c * * Maintainer: Alexander Clouter - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c index 83589a28a491..e5f327054dd3 100644 --- a/arch/arm/mach-orion5x/wnr854t-setup.c +++ b/arch/arm/mach-orion5x/wnr854t-setup.c @@ -1,10 +1,5 @@ -/* - * arch/arm/mach-orion5x/wnr854t-setup.c - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only +// arch/arm/mach-orion5x/wnr854t-setup.c #include #include #include diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c index cea08d4a2597..e6a2da6662df 100644 --- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c +++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c @@ -1,10 +1,5 @@ -/* - * arch/arm/mach-orion5x/wrt350n-v2-setup.c - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ +// SPDX-License-Identifier: GPL-2.0-only +// arch/arm/mach-orion5x/wrt350n-v2-setup.c #include #include #include diff --git a/arch/arm/mach-pxa/eseries.c b/arch/arm/mach-pxa/eseries.c index 08f8737aa8fd..2c1e7bc5bac5 100644 --- a/arch/arm/mach-pxa/eseries.c +++ b/arch/arm/mach-pxa/eseries.c @@ -1,13 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Hardware definitions for the Toshiba eseries PDAs * * Copyright (c) 2003 Ian Molton - * - * This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - * */ #include diff --git a/arch/arm/mach-pxa/standby.S b/arch/arm/mach-pxa/standby.S index 938310b708a0..ad32b9c0ebce 100644 --- a/arch/arm/mach-pxa/standby.S +++ b/arch/arm/mach-pxa/standby.S @@ -1,12 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * PXA27x standby mode * * Author: David Burrage * - * 2005 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2005 (c) MontaVista Software, Inc. */ #include diff --git a/arch/arm/mach-spear/generic.h b/arch/arm/mach-spear/generic.h index 8ec2b92dca19..43b7996ab754 100644 --- a/arch/arm/mach-spear/generic.h +++ b/arch/arm/mach-spear/generic.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * spear machine family generic header file * * Copyright (C) 2009-2012 ST Microelectronics * Rajeev Kumar * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __MACH_GENERIC_H diff --git a/arch/arm/mach-spear/misc_regs.h b/arch/arm/mach-spear/misc_regs.h index 53cd74301f58..72aa801a3a89 100644 --- a/arch/arm/mach-spear/misc_regs.h +++ b/arch/arm/mach-spear/misc_regs.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Miscellaneous registers definitions for SPEAr3xx machine family * * Copyright (C) 2009 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __MACH_MISC_REGS_H diff --git a/arch/arm/mach-spear/pl080.c b/arch/arm/mach-spear/pl080.c index 38b479f413dc..d6b8627d2544 100644 --- a/arch/arm/mach-spear/pl080.c +++ b/arch/arm/mach-spear/pl080.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/plat-spear/pl080.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-spear/pl080.h b/arch/arm/mach-spear/pl080.h index 608dec6725ae..3732d940dbfb 100644 --- a/arch/arm/mach-spear/pl080.h +++ b/arch/arm/mach-spear/pl080.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * arch/arm/plat-spear/include/plat/pl080.h * @@ -5,10 +6,6 @@ * * Copyright (C) 2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __PLAT_PL080_H diff --git a/arch/arm/mach-spear/restart.c b/arch/arm/mach-spear/restart.c index 43417d0db6d9..76fb16cc8132 100644 --- a/arch/arm/mach-spear/restart.c +++ b/arch/arm/mach-spear/restart.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/plat-spear/restart.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2009 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/arch/arm/mach-spear/spear.h b/arch/arm/mach-spear/spear.h index 5ed841ccf8a3..432efd407c76 100644 --- a/arch/arm/mach-spear/spear.h +++ b/arch/arm/mach-spear/spear.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * SPEAr3xx/6xx Machine family specific definition * * Copyright (C) 2009,2012 ST Microelectronics * Rajeev Kumar * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __MACH_SPEAR_H diff --git a/arch/arm/mach-spear/spear1310.c b/arch/arm/mach-spear/spear1310.c index 549ab2be1b74..89d388388e02 100644 --- a/arch/arm/mach-spear/spear1310.c +++ b/arch/arm/mach-spear/spear1310.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-spear13xx/spear1310.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) "SPEAr1310: " fmt diff --git a/arch/arm/mach-spear/spear1340.c b/arch/arm/mach-spear/spear1340.c index a212af90c0bc..a391f154eff9 100644 --- a/arch/arm/mach-spear/spear1340.c +++ b/arch/arm/mach-spear/spear1340.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-spear13xx/spear1340.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) "SPEAr1340: " fmt diff --git a/arch/arm/mach-spear/spear13xx.c b/arch/arm/mach-spear/spear13xx.c index 9d4bdce2e865..ac5b76bbeab5 100644 --- a/arch/arm/mach-spear/spear13xx.c +++ b/arch/arm/mach-spear/spear13xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-spear13xx/spear13xx.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) "SPEAr13xx: " fmt diff --git a/arch/arm/mach-spear/spear300.c b/arch/arm/mach-spear/spear300.c index 1f2a6bbcf096..1d6b6e10fcf6 100644 --- a/arch/arm/mach-spear/spear300.c +++ b/arch/arm/mach-spear/spear300.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-spear3xx/spear300.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2009-2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) "SPEAr300: " fmt diff --git a/arch/arm/mach-spear/spear310.c b/arch/arm/mach-spear/spear310.c index f0fc140a59cf..da4643b9f3bb 100644 --- a/arch/arm/mach-spear/spear310.c +++ b/arch/arm/mach-spear/spear310.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-spear3xx/spear310.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2009-2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) "SPEAr310: " fmt diff --git a/arch/arm/mach-spear/spear320.c b/arch/arm/mach-spear/spear320.c index cb464ae7c08a..12aa82b987ac 100644 --- a/arch/arm/mach-spear/spear320.c +++ b/arch/arm/mach-spear/spear320.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-spear3xx/spear320.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2009-2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) "SPEAr320: " fmt diff --git a/arch/arm/mach-spear/spear3xx.c b/arch/arm/mach-spear/spear3xx.c index fab3d6df69ff..2ba406e92c41 100644 --- a/arch/arm/mach-spear/spear3xx.c +++ b/arch/arm/mach-spear/spear3xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-spear3xx/spear3xx.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2009-2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) "SPEAr3xx: " fmt diff --git a/arch/arm/mach-spear/spear6xx.c b/arch/arm/mach-spear/spear6xx.c index d061080b191f..58183493e06d 100644 --- a/arch/arm/mach-spear/spear6xx.c +++ b/arch/arm/mach-spear/spear6xx.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-spear6xx/spear6xx.c * @@ -7,10 +8,6 @@ * Rajeev Kumar * * Copyright 2012 Stefan Roese - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mach-spear/time.c b/arch/arm/mach-spear/time.c index d1fdb6066f7b..6baf952fa902 100644 --- a/arch/arm/mach-spear/time.c +++ b/arch/arm/mach-spear/time.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/plat-spear/time.c * * Copyright (C) 2010 ST Microelectronics * Shiraz Hashim - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/arch/arm/mm/cache-feroceon-l2.c b/arch/arm/mm/cache-feroceon-l2.c index 5c1b7a7b9af6..25dbd84a1aaf 100644 --- a/arch/arm/mm/cache-feroceon-l2.c +++ b/arch/arm/mm/cache-feroceon-l2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mm/cache-feroceon-l2.c - Feroceon L2 cache controller support * * Copyright (C) 2008 Marvell Semiconductor * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * References: * - Unified Layer 2 Cache for Feroceon CPU Cores, * Document ID MV-S104858-00, Rev. A, October 23 2007. diff --git a/arch/arm/mm/cache-tauros2.c b/arch/arm/mm/cache-tauros2.c index 88255bea65e4..b1e1aba602f7 100644 --- a/arch/arm/mm/cache-tauros2.c +++ b/arch/arm/mm/cache-tauros2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mm/cache-tauros2.c - Tauros2 L2 cache controller support * * Copyright (C) 2008 Marvell Semiconductor * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * References: * - PJ1 CPU Core Datasheet, * Document ID MV-S104837-01, Rev 0.7, January 24 2008. From 3bb165608ec6a6f775dcd0a6ef5f0b4493e74d73 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 19:29:33 +0200 Subject: [PATCH 0267/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_56.RULE (part 2) Based on the normalized pattern: this file is licensed under the terms of the gnu general public license version 2 this program is licensed as is without any warranty of any kind whether express or implied extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/bus/mvebu-mbus.c | 5 +---- drivers/bus/sunxi-rsb.c | 6 +----- drivers/bus/tegra-gmi.c | 5 +---- drivers/bus/ts-nbus.c | 5 +---- drivers/clk/axs10x/i2s_pll_clock.c | 5 +---- drivers/clk/axs10x/pll_clock.c | 5 +---- drivers/clk/clk-hsdk-pll.c | 5 +---- drivers/clk/clk-moxart.c | 5 +---- drivers/clk/mmp/clk-apbc.c | 5 +---- drivers/clk/mmp/clk-apmu.c | 5 +---- drivers/clk/mmp/clk-frac.c | 5 +---- drivers/clk/mmp/clk-gate.c | 5 +---- drivers/clk/mmp/clk-mix.c | 5 +---- drivers/clk/mmp/clk-mmp2.c | 5 +---- drivers/clk/mmp/clk-of-mmp2.c | 5 +---- drivers/clk/mmp/clk-of-pxa168.c | 5 +---- drivers/clk/mmp/clk-of-pxa1928.c | 5 +---- drivers/clk/mmp/clk-of-pxa910.c | 5 +---- drivers/clk/mmp/clk-pxa168.c | 5 +---- drivers/clk/mmp/clk-pxa910.c | 5 +---- drivers/clk/nxp/clk-lpc18xx-ccu.c | 5 +---- drivers/clk/nxp/clk-lpc18xx-cgu.c | 5 +---- drivers/clk/nxp/clk-lpc18xx-creg.c | 5 +---- drivers/clk/spear/clk-aux-synth.c | 5 +---- drivers/clk/spear/clk-frac-synth.c | 5 +---- drivers/clk/spear/clk-gpt-synth.c | 5 +---- drivers/clk/spear/clk-vco-pll.c | 5 +---- drivers/clk/spear/clk.c | 5 +---- drivers/clk/spear/clk.h | 5 +---- drivers/clk/spear/spear1310_clock.c | 5 +---- drivers/clk/spear/spear1340_clock.c | 5 +---- drivers/clk/spear/spear3xx_clock.c | 5 +---- drivers/clk/spear/spear6xx_clock.c | 5 +---- drivers/cpufreq/mvebu-cpufreq.c | 5 +---- drivers/cpuidle/cpuidle-at91.c | 5 +---- drivers/cpuidle/cpuidle-kirkwood.c | 5 +---- drivers/dma/bestcomm/ata.c | 7 +------ drivers/dma/bestcomm/bestcomm.c | 7 +------ drivers/dma/bestcomm/fec.c | 7 +------ drivers/dma/bestcomm/sram.c | 7 +------ drivers/dma/moxart-dma.c | 5 +---- drivers/dma/ppc4xx/adma.h | 5 +---- drivers/edac/edac_pci.c | 7 ++----- drivers/edac/fsl_ddr_edac.c | 6 ++---- drivers/edac/fsl_ddr_edac.h | 7 ++----- drivers/edac/mpc85xx_edac.h | 7 ++----- drivers/gpio/gpio-mpc8xxx.c | 5 +---- drivers/gpio/gpio-mvebu.c | 5 +---- drivers/gpio/gpio-spear-spics.c | 5 +---- drivers/gpio/gpio-ts4800.c | 5 +---- 50 files changed, 54 insertions(+), 212 deletions(-) diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c index db612045616f..a6ec0566db12 100644 --- a/drivers/bus/mvebu-mbus.c +++ b/drivers/bus/mvebu-mbus.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Address map functions for Marvell EBU SoCs (Kirkwood, Armada * 370/XP, Dove, Orion5x and MV78xx0) * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * The Marvell EBU SoCs have a configurable physical address space: * the physical address at which certain devices (PCIe, NOR, NAND, * etc.) sit can be configured. The configuration takes place through diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c index 60b082fe2ed0..4cd2e127946e 100644 --- a/drivers/bus/sunxi-rsb.c +++ b/drivers/bus/sunxi-rsb.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * RSB (Reduced Serial Bus) driver. * * Author: Chen-Yu Tsai * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - * * The RSB controller looks like an SMBus controller which only supports * byte and word data transfers. But, it differs from standard SMBus * protocol on several aspects: @@ -31,7 +28,6 @@ * This document is officially released by Allwinner. * * This driver is based on i2c-sun6i-p2wi.c, the P2WI bus driver. - * */ #include diff --git a/drivers/bus/tegra-gmi.c b/drivers/bus/tegra-gmi.c index 35b59f92fa66..662266719682 100644 --- a/drivers/bus/tegra-gmi.c +++ b/drivers/bus/tegra-gmi.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for NVIDIA Generic Memory Interface * * Copyright (C) 2016 Host Mobility AB. All rights reserved. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/bus/ts-nbus.c b/drivers/bus/ts-nbus.c index 9989ce904a37..38c886dc2ed6 100644 --- a/drivers/bus/ts-nbus.c +++ b/drivers/bus/ts-nbus.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NBUS driver for TS-4600 based boards * * Copyright (c) 2016 - Savoir-faire Linux * Author: Sebastien Bourdelin * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * This driver implements a GPIOs bit-banged bus, called the NBUS by Technologic * Systems. It is used to communicate with the peripherals in the FPGA on the * TS-4600 SoM. diff --git a/drivers/clk/axs10x/i2s_pll_clock.c b/drivers/clk/axs10x/i2s_pll_clock.c index e9da0e69bf6c..e1fda6ad5cd5 100644 --- a/drivers/clk/axs10x/i2s_pll_clock.c +++ b/drivers/clk/axs10x/i2s_pll_clock.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synopsys AXS10X SDP I2S PLL clock driver * * Copyright (C) 2016 Synopsys - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/axs10x/pll_clock.c b/drivers/clk/axs10x/pll_clock.c index 500345d99adb..90fb0e6ff573 100644 --- a/drivers/clk/axs10x/pll_clock.c +++ b/drivers/clk/axs10x/pll_clock.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synopsys AXS10X SDP Generic PLL clock driver * * Copyright (C) 2017 Synopsys - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/clk-hsdk-pll.c b/drivers/clk/clk-hsdk-pll.c index b4f8852201cb..60007b508590 100644 --- a/drivers/clk/clk-hsdk-pll.c +++ b/drivers/clk/clk-hsdk-pll.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Synopsys HSDK SDP Generic PLL clock driver * * Copyright (C) 2017 Synopsys - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/clk-moxart.c b/drivers/clk/clk-moxart.c index 58428d0043fd..3786a0153ad1 100644 --- a/drivers/clk/clk-moxart.c +++ b/drivers/clk/clk-moxart.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MOXA ART SoCs clock driver. * * Copyright (C) 2013 Jonas Jensen * * Jonas Jensen - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-apbc.c b/drivers/clk/mmp/clk-apbc.c index fb294ada0b03..23c43a46604e 100644 --- a/drivers/clk/mmp/clk-apbc.c +++ b/drivers/clk/mmp/clk-apbc.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mmp APB clock operation source file * * Copyright (C) 2012 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-apmu.c b/drivers/clk/mmp/clk-apmu.c index b7ce8f52026e..9313428b083a 100644 --- a/drivers/clk/mmp/clk-apmu.c +++ b/drivers/clk/mmp/clk-apmu.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mmp AXI peripharal clock operation source file * * Copyright (C) 2012 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c index 48f592bd633d..1b90867b60c4 100644 --- a/drivers/clk/mmp/clk-frac.c +++ b/drivers/clk/mmp/clk-frac.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mmp factor clock operation source file * * Copyright (C) 2012 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-gate.c b/drivers/clk/mmp/clk-gate.c index 1755916ddef2..350eeb3e9e25 100644 --- a/drivers/clk/mmp/clk-gate.c +++ b/drivers/clk/mmp/clk-gate.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mmp gate clock operation source file * * Copyright (C) 2014 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index 7a351ec65564..454d131f475e 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mmp mix(div and mux) clock operation source file * * Copyright (C) 2014 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c index 7460031714da..aabacfa10158 100644 --- a/drivers/clk/mmp/clk-mmp2.c +++ b/drivers/clk/mmp/clk-mmp2.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mmp2 clock framework source file * * Copyright (C) 2012 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-of-mmp2.c b/drivers/clk/mmp/clk-of-mmp2.c index 50a780274ba0..bcf60f43aa13 100644 --- a/drivers/clk/mmp/clk-of-mmp2.c +++ b/drivers/clk/mmp/clk-of-mmp2.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * mmp2 clock framework source file * * Copyright (C) 2012 Marvell * Chao Xie * Copyright (C) 2020 Lubomir Rintel - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-of-pxa168.c b/drivers/clk/mmp/clk-of-pxa168.c index f110c02e83cb..48dfb18b490e 100644 --- a/drivers/clk/mmp/clk-of-pxa168.c +++ b/drivers/clk/mmp/clk-of-pxa168.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * pxa168 clock framework source file * * Copyright (C) 2012 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-of-pxa1928.c b/drivers/clk/mmp/clk-of-pxa1928.c index 998fc4207b0e..2508a0d795f8 100644 --- a/drivers/clk/mmp/clk-of-pxa1928.c +++ b/drivers/clk/mmp/clk-of-pxa1928.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * pxa1928 clock framework source file * @@ -7,10 +8,6 @@ * Based on drivers/clk/mmp/clk-of-mmp2.c: * Copyright (C) 2012 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include #include diff --git a/drivers/clk/mmp/clk-of-pxa910.c b/drivers/clk/mmp/clk-of-pxa910.c index 1dcabe95cb67..4d15bac987eb 100644 --- a/drivers/clk/mmp/clk-of-pxa910.c +++ b/drivers/clk/mmp/clk-of-pxa910.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * pxa910 clock framework source file * * Copyright (C) 2012 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c index b351039cac09..8a9b8fb3a465 100644 --- a/drivers/clk/mmp/clk-pxa168.c +++ b/drivers/clk/mmp/clk-pxa168.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * pxa168 clock framework source file * * Copyright (C) 2012 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c index f254ceff3ea7..9fcd76316d7e 100644 --- a/drivers/clk/mmp/clk-pxa910.c +++ b/drivers/clk/mmp/clk-pxa910.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * pxa910 clock framework source file * * Copyright (C) 2012 Marvell * Chao Xie - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/nxp/clk-lpc18xx-ccu.c b/drivers/clk/nxp/clk-lpc18xx-ccu.c index f2e171a01fb4..ddb28b38f549 100644 --- a/drivers/clk/nxp/clk-lpc18xx-ccu.c +++ b/drivers/clk/nxp/clk-lpc18xx-ccu.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Clk driver for NXP LPC18xx/LPC43xx Clock Control Unit (CCU) * * Copyright (C) 2015 Joachim Eastwood - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/nxp/clk-lpc18xx-cgu.c b/drivers/clk/nxp/clk-lpc18xx-cgu.c index c23ac463ab0f..f253ef1996b1 100644 --- a/drivers/clk/nxp/clk-lpc18xx-cgu.c +++ b/drivers/clk/nxp/clk-lpc18xx-cgu.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Clk driver for NXP LPC18xx/LPC43xx Clock Generation Unit (CGU) * * Copyright (C) 2015 Joachim Eastwood - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/nxp/clk-lpc18xx-creg.c b/drivers/clk/nxp/clk-lpc18xx-creg.c index c6e802e7e6ec..3d3982e9c661 100644 --- a/drivers/clk/nxp/clk-lpc18xx-creg.c +++ b/drivers/clk/nxp/clk-lpc18xx-creg.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Clk driver for NXP LPC18xx/43xx Configuration Registers (CREG) * * Copyright (C) 2015 Joachim Eastwood - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c index 906410413bc1..637938e804f8 100644 --- a/drivers/clk/spear/clk-aux-synth.c +++ b/drivers/clk/spear/clk-aux-synth.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 ST Microelectronics * Viresh Kumar * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * Auxiliary Synthesizer clock implementation */ diff --git a/drivers/clk/spear/clk-frac-synth.c b/drivers/clk/spear/clk-frac-synth.c index f5be02205ac6..2380df293a2c 100644 --- a/drivers/clk/spear/clk-frac-synth.c +++ b/drivers/clk/spear/clk-frac-synth.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 ST Microelectronics * Viresh Kumar * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * Fractional Synthesizer clock implementation */ diff --git a/drivers/clk/spear/clk-gpt-synth.c b/drivers/clk/spear/clk-gpt-synth.c index 6ed406d943ba..4ef747c2abbb 100644 --- a/drivers/clk/spear/clk-gpt-synth.c +++ b/drivers/clk/spear/clk-gpt-synth.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 ST Microelectronics * Viresh Kumar * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * General Purpose Timer Synthesizer clock implementation */ diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c index fed194169666..348eeab0a906 100644 --- a/drivers/clk/spear/clk-vco-pll.c +++ b/drivers/clk/spear/clk-vco-pll.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 ST Microelectronics * Viresh Kumar * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * VCO-PLL clock implementation */ diff --git a/drivers/clk/spear/clk.c b/drivers/clk/spear/clk.c index 157fe099ea6a..50847cccdf58 100644 --- a/drivers/clk/spear/clk.c +++ b/drivers/clk/spear/clk.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2012 ST Microelectronics * Viresh Kumar * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * SPEAr clk - Common routines */ diff --git a/drivers/clk/spear/clk.h b/drivers/clk/spear/clk.h index af0e25f496c1..3d580d1bdadd 100644 --- a/drivers/clk/spear/clk.h +++ b/drivers/clk/spear/clk.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Clock framework definitions for SPEAr platform * * Copyright (C) 2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #ifndef __SPEAR_CLK_H diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c index 8c8974866789..9d5959a4251a 100644 --- a/drivers/clk/spear/spear1310_clock.c +++ b/drivers/clk/spear/spear1310_clock.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-spear13xx/spear1310_clock.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c index c0dc94355c87..8b51229d0471 100644 --- a/drivers/clk/spear/spear1340_clock.c +++ b/drivers/clk/spear/spear1340_clock.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * arch/arm/mach-spear13xx/spear1340_clock.c * @@ -5,10 +6,6 @@ * * Copyright (C) 2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/spear/spear3xx_clock.c b/drivers/clk/spear/spear3xx_clock.c index c403c66b6583..41717ff707f6 100644 --- a/drivers/clk/spear/spear3xx_clock.c +++ b/drivers/clk/spear/spear3xx_clock.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPEAr3xx machines clock framework source file * * Copyright (C) 2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/clk/spear/spear6xx_clock.c b/drivers/clk/spear/spear6xx_clock.c index 47810be7f15c..490701ac9e93 100644 --- a/drivers/clk/spear/spear6xx_clock.c +++ b/drivers/clk/spear/spear6xx_clock.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPEAr6xx machines clock framework source file * * Copyright (C) 2012 ST Microelectronics * Viresh Kumar - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/cpufreq/mvebu-cpufreq.c b/drivers/cpufreq/mvebu-cpufreq.c index 6d33a639f902..7f3cfe668f30 100644 --- a/drivers/cpufreq/mvebu-cpufreq.c +++ b/drivers/cpufreq/mvebu-cpufreq.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * CPUFreq support for Armada 370/XP platforms. * @@ -6,10 +7,6 @@ * Yehuda Yitschak * Gregory Clement * Thomas Petazzoni - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #define pr_fmt(fmt) "mvebu-pmsu: " fmt diff --git a/drivers/cpuidle/cpuidle-at91.c b/drivers/cpuidle/cpuidle-at91.c index 9c5853b6ca4a..45ee8e1e71ae 100644 --- a/drivers/cpuidle/cpuidle-at91.c +++ b/drivers/cpuidle/cpuidle-at91.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * based on arch/arm/mach-kirkwood/cpuidle.c * * CPU idle support for AT91 SoC * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * The cpu idle uses wait-for-interrupt and RAM self refresh in order * to implement two idle states - * #1 wait-for-interrupt diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c index 511c4f46027a..13bf743f885b 100644 --- a/drivers/cpuidle/cpuidle-kirkwood.c +++ b/drivers/cpuidle/cpuidle-kirkwood.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * CPU idle Marvell Kirkwood SoCs * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * The cpu idle uses wait-for-interrupt and DDR self refresh in order * to implement two idle states - * #1 wait-for-interrupt diff --git a/drivers/dma/bestcomm/ata.c b/drivers/dma/bestcomm/ata.c index e169f18da551..502a45d76adc 100644 --- a/drivers/dma/bestcomm/ata.c +++ b/drivers/dma/bestcomm/ata.c @@ -1,16 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Bestcomm ATA task driver * - * * Patterned after bestcomm/fec.c by Dale Farnsworth * 2003-2004 (c) MontaVista, Software, Inc. * * Copyright (C) 2006-2007 Sylvain Munaut * Copyright (C) 2006 Freescale - John Rigby - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include @@ -154,4 +150,3 @@ EXPORT_SYMBOL_GPL(bcom_ata_release); MODULE_DESCRIPTION("BestComm ATA task driver"); MODULE_AUTHOR("John Rigby"); MODULE_LICENSE("GPL v2"); - diff --git a/drivers/dma/bestcomm/bestcomm.c b/drivers/dma/bestcomm/bestcomm.c index 1822a7034630..eabbcfcaa7cb 100644 --- a/drivers/dma/bestcomm/bestcomm.c +++ b/drivers/dma/bestcomm/bestcomm.c @@ -1,16 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for MPC52xx processor BestComm peripheral controller * - * * Copyright (C) 2006-2007 Sylvain Munaut * Copyright (C) 2005 Varma Electronics Oy, * ( by Andrey Volkov ) * Copyright (C) 2003-2004 MontaVista, Software, Inc. * ( by Dale Farnsworth ) - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include @@ -528,4 +524,3 @@ MODULE_AUTHOR("Sylvain Munaut "); MODULE_AUTHOR("Andrey Volkov "); MODULE_AUTHOR("Dale Farnsworth "); MODULE_LICENSE("GPL v2"); - diff --git a/drivers/dma/bestcomm/fec.c b/drivers/dma/bestcomm/fec.c index d203618ac11f..3a4a2f7910c6 100644 --- a/drivers/dma/bestcomm/fec.c +++ b/drivers/dma/bestcomm/fec.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Bestcomm FEC tasks driver * - * * Copyright (C) 2006-2007 Sylvain Munaut * Copyright (C) 2003-2004 MontaVista, Software, Inc. * ( by Dale Farnsworth ) - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include @@ -267,4 +263,3 @@ EXPORT_SYMBOL_GPL(bcom_fec_tx_release); MODULE_DESCRIPTION("BestComm FEC tasks driver"); MODULE_AUTHOR("Dale Farnsworth "); MODULE_LICENSE("GPL v2"); - diff --git a/drivers/dma/bestcomm/sram.c b/drivers/dma/bestcomm/sram.c index 2074e0e3fa21..c465758e7193 100644 --- a/drivers/dma/bestcomm/sram.c +++ b/drivers/dma/bestcomm/sram.c @@ -1,14 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Simple memory allocator for on-board SRAM * - * * Maintainer : Sylvain Munaut * * Copyright (C) 2005 Sylvain Munaut - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include @@ -176,4 +172,3 @@ void bcom_sram_free(void *ptr) spin_unlock(&bcom_sram->lock); } EXPORT_SYMBOL_GPL(bcom_sram_free); - diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c index 74755093e14b..7459382a8353 100644 --- a/drivers/dma/moxart-dma.c +++ b/drivers/dma/moxart-dma.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * MOXA ART SoCs DMA Engine support. * * Copyright (C) 2013 Jonas Jensen * * Jonas Jensen - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/dma/ppc4xx/adma.h b/drivers/dma/ppc4xx/adma.h index 26b7a5ed9ac7..f8a5d7c1fb40 100644 --- a/drivers/dma/ppc4xx/adma.h +++ b/drivers/dma/ppc4xx/adma.h @@ -1,11 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * 2006-2009 (C) DENX Software Engineering. * * Author: Yuri Tikhonov - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of - * any kind, whether express or implied. */ #ifndef _PPC440SPE_ADMA_H diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 2205d7e731db..64c142aecca7 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * EDAC PCI component * * Author: Dave Jiang * - * 2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - * + * 2007 (c) MontaVista Software, Inc. */ #include #include diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index 6d8ea226010d..ac2102b25706 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Freescale Memory Controller kernel module * @@ -9,10 +10,7 @@ * * Author: Dave Jiang * - * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. + * 2006-2007 (c) MontaVista Software, Inc. */ #include #include diff --git a/drivers/edac/fsl_ddr_edac.h b/drivers/edac/fsl_ddr_edac.h index 589b9b4a5e8a..332439d7b2d9 100644 --- a/drivers/edac/fsl_ddr_edac.h +++ b/drivers/edac/fsl_ddr_edac.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Freescale Memory Controller kernel module * @@ -7,11 +8,7 @@ * * Author: Dave Jiang * - * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - * + * 2006-2007 (c) MontaVista Software, Inc. */ #ifndef _FSL_DDR_EDAC_H_ #define _FSL_DDR_EDAC_H_ diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h index 3f6fb16ad34f..66a046ae33ee 100644 --- a/drivers/edac/mpc85xx_edac.h +++ b/drivers/edac/mpc85xx_edac.h @@ -1,12 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Freescale MPC85xx Memory Controller kernel module * Author: Dave Jiang * - * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under - * the terms of the GNU General Public License version 2. This program - * is licensed "as is" without any warranty of any kind, whether express - * or implied. - * + * 2006-2007 (c) MontaVista Software, Inc. */ #ifndef _MPC85XX_EDAC_H_ #define _MPC85XX_EDAC_H_ diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index a964e25ea620..15049822937a 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GPIOs on MPC512x/8349/8572/8610/QorIQ and compatible * * Copyright (C) 2008 Peter Korsgaard * Copyright (C) 2016 Freescale Semiconductor Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 2db19cd640a4..aa126ab80f0c 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GPIO driver for Marvell SoCs * @@ -7,10 +8,6 @@ * Andrew Lunn * Sebastian Hesselbarth * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - * * This driver is a fairly straightforward GPIO driver for the * complete family of Marvell EBU SoC platforms (Orion, Dove, * Kirkwood, Discovery, Armada 370/XP). The only complexity of this diff --git a/drivers/gpio/gpio-spear-spics.c b/drivers/gpio/gpio-spear-spics.c index 49aac2bb8d2c..51539185400d 100644 --- a/drivers/gpio/gpio-spear-spics.c +++ b/drivers/gpio/gpio-spear-spics.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPEAr platform SPI chipselect abstraction over gpiolib * * Copyright (C) 2012 ST Microelectronics * Shiraz Hashim - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include diff --git a/drivers/gpio/gpio-ts4800.c b/drivers/gpio/gpio-ts4800.c index 8c0d82d926dd..95d80ba14bee 100644 --- a/drivers/gpio/gpio-ts4800.c +++ b/drivers/gpio/gpio-ts4800.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * GPIO driver for the TS-4800 board * * Copyright (c) 2016 - Savoir-faire Linux - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include From 94c0ded75c85201bfb8fce95dab44cc53addfcb5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:18 +0200 Subject: [PATCH 0268/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_133.RULE Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license version 2 as published by the free software foundation this program is distributed in the hope that it will be useful merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/mediatek/mt6755.dtsi | 9 +-------- arch/arm64/boot/dts/mediatek/mt6795.dtsi | 9 +-------- arch/arm64/boot/dts/mediatek/mt8173.dtsi | 9 +-------- include/dt-bindings/power/mt6797-power.h | 9 +-------- 4 files changed, 4 insertions(+), 32 deletions(-) diff --git a/arch/arm64/boot/dts/mediatek/mt6755.dtsi b/arch/arm64/boot/dts/mediatek/mt6755.dtsi index 01ba77669717..b55d3fac9bd4 100644 --- a/arch/arm64/boot/dts/mediatek/mt6755.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt6755.dtsi @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016 MediaTek Inc. * Author: Mars.C - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm64/boot/dts/mediatek/mt6795.dtsi b/arch/arm64/boot/dts/mediatek/mt6795.dtsi index c85659d0ff5d..1413f32c70af 100644 --- a/arch/arm64/boot/dts/mediatek/mt6795.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt6795.dtsi @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2015 MediaTek Inc. * Author: Mars.C - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi index 40d7b47fc52e..e14b6e68c4df 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2014 MediaTek Inc. * Author: Eddie Huang - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/include/dt-bindings/power/mt6797-power.h b/include/dt-bindings/power/mt6797-power.h index a60c1d81cf75..bd451d860e6a 100644 --- a/include/dt-bindings/power/mt6797-power.h +++ b/include/dt-bindings/power/mt6797-power.h @@ -1,14 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017 MediaTek Inc. * Author: Mars.C - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DT_BINDINGS_POWER_MT6797_POWER_H From b7bc1c9e5b04da3d2e578fe91d666c9060e77c63 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:19 +0200 Subject: [PATCH 0269/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_147.RULE Based on the normalized pattern: licensed under gplv2 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- Documentation/arm/samsung-s3c24xx/cpufreq.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/arm/samsung-s3c24xx/cpufreq.rst b/Documentation/arm/samsung-s3c24xx/cpufreq.rst index 2ddc26c03b1f..ed19ce1a4629 100644 --- a/Documentation/arm/samsung-s3c24xx/cpufreq.rst +++ b/Documentation/arm/samsung-s3c24xx/cpufreq.rst @@ -1,3 +1,4 @@ +.. SPDX-License-Identifier: GPL-2.0-only ======================= S3C24XX CPUfreq support ======================= @@ -73,4 +74,3 @@ Document Author --------------- Ben Dooks, Copyright 2009 Simtec Electronics -Licensed under GPLv2 From 1accad5e74635d7f9d994e692649fbe736afe150 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:20 +0200 Subject: [PATCH 0270/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_149.RULE Based on the normalized pattern: netapp provides this source code under the gpl v2 license the gpl v2 license is available at https://opensource org/licenses/gpl-license php this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall the copyright owner or contributors be liable for any direct indirect incidental special exemplary or consequential damages (including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption) however caused and on any theory of liability whether in contract strict liability or tort (including negligence or otherwise) arising in any way out of the use of this software even if advised of the possibility of such damage extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- include/linux/sunrpc/bc_xprt.h | 17 +---------------- net/sunrpc/backchannel_rqst.c | 16 +--------------- net/sunrpc/sunrpc.h | 16 +--------------- 3 files changed, 3 insertions(+), 46 deletions(-) diff --git a/include/linux/sunrpc/bc_xprt.h b/include/linux/sunrpc/bc_xprt.h index f07c334c599f..db30a159f9d5 100644 --- a/include/linux/sunrpc/bc_xprt.h +++ b/include/linux/sunrpc/bc_xprt.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /****************************************************************************** (c) 2008 NetApp. All Rights Reserved. -NetApp provides this source code under the GPL v2 License. -The GPL v2 license is available at -https://opensource.org/licenses/gpl-license.php. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ @@ -83,4 +69,3 @@ static inline void xprt_free_bc_request(struct rpc_rqst *req) } #endif /* CONFIG_SUNRPC_BACKCHANNEL */ #endif /* _LINUX_SUNRPC_BC_XPRT_H */ - diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 5a6b61dcdf2d..253a54c2fcfe 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -1,23 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /****************************************************************************** (c) 2007 Network Appliance, Inc. All Rights Reserved. (c) 2009 NetApp. All Rights Reserved. -NetApp provides this source code under the GPL v2 License. -The GPL v2 license is available at -https://opensource.org/licenses/gpl-license.php. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ diff --git a/net/sunrpc/sunrpc.h b/net/sunrpc/sunrpc.h index 2f59464e6524..d4a362c9e4b3 100644 --- a/net/sunrpc/sunrpc.h +++ b/net/sunrpc/sunrpc.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /****************************************************************************** (c) 2008 NetApp. All Rights Reserved. -NetApp provides this source code under the GPL v2 License. -The GPL v2 license is available at -https://opensource.org/licenses/gpl-license.php. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ******************************************************************************/ From 298b95f111be85f2d5a18dc0177eb9a64130f9b4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:21 +0200 Subject: [PATCH 0271/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_152.RULE Based on the normalized pattern: this software is distributed under the terms of the gnu general public license ( gpl ) version 2 as published by the free software foundation this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall the copyright owner or contributors be liable for any direct indirect incidental special exemplary or consequential damages (including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption) however caused and on any theory of liability whether in contract strict liability or tort (including negligence or otherwise) arising in any way out of the use of this software even if advised of the possibility of such damage extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- include/linux/platform_data/usb-omap.h | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/include/linux/platform_data/usb-omap.h b/include/linux/platform_data/usb-omap.h index 5e70d667031c..580978e468f8 100644 --- a/include/linux/platform_data/usb-omap.h +++ b/include/linux/platform_data/usb-omap.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * usb-omap.h - Platform data for the various OMAP USB IPs * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com - * - * This software is distributed under the terms of the GNU General Public - * License ("GPL") version 2, as published by the Free Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. */ #define OMAP3_HS_USB_PORTS 3 From 1f88a7433f1b8aa941880f395783148f8bc9bd3c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:23 +0200 Subject: [PATCH 0272/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_160.RULE Based on the normalized pattern: the code contained herein is licensed under the gnu general public license you may obtain a copy of the gnu general public license version 2 at the following locations: http://www opensource org/licenses/gpl-license html http://www gnu org/copyleft/gpl html extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/imx23-pinfunc.h | 8 +------- arch/arm/boot/dts/imx28-pinfunc.h | 8 +------- arch/arm/boot/dts/mxs-pinfunc.h | 8 +------- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/arch/arm/boot/dts/imx23-pinfunc.h b/arch/arm/boot/dts/imx23-pinfunc.h index 5c0f32ca3a93..468c079f3c2b 100644 --- a/arch/arm/boot/dts/imx23-pinfunc.h +++ b/arch/arm/boot/dts/imx23-pinfunc.h @@ -1,14 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Header providing constants for i.MX23 pinctrl bindings. * * Copyright (C) 2013 Lothar Waßmann - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html */ #ifndef __DT_BINDINGS_MX23_PINCTRL_H__ diff --git a/arch/arm/boot/dts/imx28-pinfunc.h b/arch/arm/boot/dts/imx28-pinfunc.h index e11f69ba0fe4..d427e6c2fa78 100644 --- a/arch/arm/boot/dts/imx28-pinfunc.h +++ b/arch/arm/boot/dts/imx28-pinfunc.h @@ -1,14 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Header providing constants for i.MX28 pinctrl bindings. * * Copyright (C) 2013 Lothar Waßmann - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html */ #ifndef __DT_BINDINGS_MX28_PINCTRL_H__ diff --git a/arch/arm/boot/dts/mxs-pinfunc.h b/arch/arm/boot/dts/mxs-pinfunc.h index c6da987b20cb..31297abcbc71 100644 --- a/arch/arm/boot/dts/mxs-pinfunc.h +++ b/arch/arm/boot/dts/mxs-pinfunc.h @@ -1,14 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Header providing constants for i.MX28 pinctrl bindings. * * Copyright (C) 2013 Lothar Waßmann - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html */ #ifndef __DT_BINDINGS_MXS_PINCTRL_H__ From e6550b3ee1f4bd41d3c8011218d8bee717dc8a5a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:24 +0200 Subject: [PATCH 0273/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_168.RULE (part 1) Based on the normalized pattern: this program is free software you may redistribute it and/or modify it under the terms of the gnu general public license as published by the free software foundation version 2 of the license 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 authors or copyright holders 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 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/cisco/enic/cq_desc.h | 15 +-------------- .../net/ethernet/cisco/enic/cq_enet_desc.h | 15 +-------------- drivers/net/ethernet/cisco/enic/enic.h | 15 +-------------- drivers/net/ethernet/cisco/enic/enic_api.c | 19 ++----------------- drivers/net/ethernet/cisco/enic/enic_api.h | 19 ++----------------- drivers/net/ethernet/cisco/enic/enic_dev.c | 19 ++----------------- drivers/net/ethernet/cisco/enic/enic_dev.h | 19 ++----------------- .../net/ethernet/cisco/enic/enic_ethtool.c | 19 ++----------------- drivers/net/ethernet/cisco/enic/enic_pp.c | 19 ++----------------- drivers/net/ethernet/cisco/enic/enic_pp.h | 19 ++----------------- drivers/net/ethernet/cisco/enic/enic_res.c | 15 +-------------- drivers/net/ethernet/cisco/enic/enic_res.h | 15 +-------------- .../net/ethernet/cisco/enic/rq_enet_desc.h | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_cq.c | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_cq.h | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_dev.c | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_dev.h | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_devcmd.h | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_enet.h | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_intr.c | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_intr.h | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_nic.h | 15 +-------------- .../net/ethernet/cisco/enic/vnic_resource.h | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_rq.c | 16 +--------------- drivers/net/ethernet/cisco/enic/vnic_rq.h | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_rss.h | 14 +------------- drivers/net/ethernet/cisco/enic/vnic_stats.h | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_vic.c | 19 ++----------------- drivers/net/ethernet/cisco/enic/vnic_vic.h | 19 ++----------------- drivers/net/ethernet/cisco/enic/vnic_wq.c | 15 +-------------- drivers/net/ethernet/cisco/enic/vnic_wq.h | 15 +-------------- .../net/ethernet/cisco/enic/wq_enet_desc.h | 15 +-------------- drivers/scsi/fnic/cq_desc.h | 14 +------------- drivers/scsi/fnic/cq_enet_desc.h | 14 +------------- drivers/scsi/fnic/cq_exch_desc.h | 14 +------------- drivers/scsi/fnic/fcpio.h | 14 +------------- drivers/scsi/fnic/fnic.h | 14 +------------- drivers/scsi/fnic/fnic_attrs.c | 14 +------------- drivers/scsi/fnic/fnic_debugfs.c | 18 ++---------------- drivers/scsi/fnic/fnic_fcs.c | 14 +------------- drivers/scsi/fnic/fnic_fip.h | 14 +------------- drivers/scsi/fnic/fnic_io.h | 14 +------------- drivers/scsi/fnic/fnic_isr.c | 15 +-------------- drivers/scsi/fnic/fnic_main.c | 15 +-------------- drivers/scsi/fnic/fnic_res.c | 14 +------------- drivers/scsi/fnic/fnic_res.h | 14 +------------- drivers/scsi/fnic/fnic_scsi.c | 14 +------------- drivers/scsi/fnic/fnic_stats.h | 18 ++---------------- drivers/scsi/fnic/fnic_trace.c | 18 ++---------------- drivers/scsi/fnic/fnic_trace.h | 18 ++---------------- drivers/scsi/fnic/rq_enet_desc.h | 14 +------------- drivers/scsi/fnic/vnic_cq.c | 14 +------------- drivers/scsi/fnic/vnic_cq.h | 14 +------------- drivers/scsi/fnic/vnic_cq_copy.h | 14 +------------- drivers/scsi/fnic/vnic_dev.c | 14 +------------- drivers/scsi/fnic/vnic_dev.h | 14 +------------- drivers/scsi/fnic/vnic_devcmd.h | 14 +------------- drivers/scsi/fnic/vnic_intr.c | 14 +------------- drivers/scsi/fnic/vnic_intr.h | 14 +------------- drivers/scsi/fnic/vnic_nic.h | 14 +------------- drivers/scsi/fnic/vnic_resource.h | 14 +------------- drivers/scsi/fnic/vnic_rq.c | 15 +-------------- drivers/scsi/fnic/vnic_rq.h | 14 +------------- drivers/scsi/fnic/vnic_scsi.h | 14 +------------- drivers/scsi/fnic/vnic_stats.h | 14 +------------- drivers/scsi/fnic/vnic_wq.c | 14 +------------- drivers/scsi/fnic/vnic_wq.h | 14 +------------- drivers/scsi/fnic/vnic_wq_copy.c | 15 +-------------- drivers/scsi/fnic/vnic_wq_copy.h | 14 +------------- drivers/scsi/fnic/wq_enet_desc.h | 14 +------------- drivers/scsi/snic/cq_desc.h | 18 ++---------------- drivers/scsi/snic/cq_enet_desc.h | 18 ++---------------- drivers/scsi/snic/snic.h | 18 ++---------------- 73 files changed, 89 insertions(+), 1033 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/cq_desc.h b/drivers/net/ethernet/cisco/enic/cq_desc.h index d6dd1b4edf6e..462c5435a206 100644 --- a/drivers/net/ethernet/cisco/enic/cq_desc.h +++ b/drivers/net/ethernet/cisco/enic/cq_desc.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _CQ_DESC_H_ diff --git a/drivers/net/ethernet/cisco/enic/cq_enet_desc.h b/drivers/net/ethernet/cisco/enic/cq_enet_desc.h index ac37cacc6136..d25426470a29 100644 --- a/drivers/net/ethernet/cisco/enic/cq_enet_desc.h +++ b/drivers/net/ethernet/cisco/enic/cq_enet_desc.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _CQ_ENET_DESC_H_ diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h index 52aaf1bb5205..a0964b629ffc 100644 --- a/drivers/net/ethernet/cisco/enic/enic.h +++ b/drivers/net/ethernet/cisco/enic/enic.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _ENIC_H_ diff --git a/drivers/net/ethernet/cisco/enic/enic_api.c b/drivers/net/ethernet/cisco/enic/enic_api.c index 3bdc74fba1e3..e3b700c28bc4 100644 --- a/drivers/net/ethernet/cisco/enic/enic_api.c +++ b/drivers/net/ethernet/cisco/enic/enic_api.c @@ -1,20 +1,5 @@ -/* - * Copyright 2013 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - * - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2013 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/net/ethernet/cisco/enic/enic_api.h b/drivers/net/ethernet/cisco/enic/enic_api.h index 6b9f9255af28..e01790fb0415 100644 --- a/drivers/net/ethernet/cisco/enic/enic_api.h +++ b/drivers/net/ethernet/cisco/enic/enic_api.h @@ -1,20 +1,5 @@ -/** - * Copyright 2013 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - * - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2013 Cisco Systems, Inc. All rights reserved. */ #ifndef __ENIC_API_H__ #define __ENIC_API_H__ diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.c b/drivers/net/ethernet/cisco/enic/enic_dev.c index f8d2a6a34282..2cbae7c6cc3d 100644 --- a/drivers/net/ethernet/cisco/enic/enic_dev.c +++ b/drivers/net/ethernet/cisco/enic/enic_dev.c @@ -1,20 +1,5 @@ -/* - * Copyright 2011 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - * - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2011 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.h b/drivers/net/ethernet/cisco/enic/enic_dev.h index f5bb058b3f96..698d0cb02064 100644 --- a/drivers/net/ethernet/cisco/enic/enic_dev.h +++ b/drivers/net/ethernet/cisco/enic/enic_dev.h @@ -1,20 +1,5 @@ -/* - * Copyright 2011 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - * - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2011 Cisco Systems, Inc. All rights reserved. */ #ifndef _ENIC_DEV_H_ #define _ENIC_DEV_H_ diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index 6c11f9d62526..60d8c0fbc037 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -1,20 +1,5 @@ -/* - * Copyright 2013 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - * - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2013 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/net/ethernet/cisco/enic/enic_pp.c b/drivers/net/ethernet/cisco/enic/enic_pp.c index 80f46dbd5117..4720a952725d 100644 --- a/drivers/net/ethernet/cisco/enic/enic_pp.c +++ b/drivers/net/ethernet/cisco/enic/enic_pp.c @@ -1,20 +1,5 @@ -/* - * Copyright 2011 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - * - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2011 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/net/ethernet/cisco/enic/enic_pp.h b/drivers/net/ethernet/cisco/enic/enic_pp.h index a09ff392c1c6..20a2687713ef 100644 --- a/drivers/net/ethernet/cisco/enic/enic_pp.h +++ b/drivers/net/ethernet/cisco/enic/enic_pp.h @@ -1,20 +1,5 @@ -/* - * Copyright 2011 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - * - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2011 Cisco Systems, Inc. All rights reserved. */ #ifndef _ENIC_PP_H_ #define _ENIC_PP_H_ diff --git a/drivers/net/ethernet/cisco/enic/enic_res.c b/drivers/net/ethernet/cisco/enic/enic_res.c index 40b20817ddd5..1c48aebdbab0 100644 --- a/drivers/net/ethernet/cisco/enic/enic_res.c +++ b/drivers/net/ethernet/cisco/enic/enic_res.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/net/ethernet/cisco/enic/enic_res.h b/drivers/net/ethernet/cisco/enic/enic_res.h index 81f98a8b60e9..b8ee42d297aa 100644 --- a/drivers/net/ethernet/cisco/enic/enic_res.h +++ b/drivers/net/ethernet/cisco/enic/enic_res.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _ENIC_RES_H_ diff --git a/drivers/net/ethernet/cisco/enic/rq_enet_desc.h b/drivers/net/ethernet/cisco/enic/rq_enet_desc.h index e6dd30988d6f..0ab5fd6b8d46 100644 --- a/drivers/net/ethernet/cisco/enic/rq_enet_desc.h +++ b/drivers/net/ethernet/cisco/enic/rq_enet_desc.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _RQ_ENET_DESC_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_cq.c b/drivers/net/ethernet/cisco/enic/vnic_cq.c index 519323460f26..27c885e91552 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_cq.c +++ b/drivers/net/ethernet/cisco/enic/vnic_cq.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/net/ethernet/cisco/enic/vnic_cq.h b/drivers/net/ethernet/cisco/enic/vnic_cq.h index 4e6aa65857f7..eed5bf59e5d2 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_cq.h +++ b/drivers/net/ethernet/cisco/enic/vnic_cq.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_CQ_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.c b/drivers/net/ethernet/cisco/enic/vnic_dev.c index 45015931b335..12a83fa1302d 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_dev.c +++ b/drivers/net/ethernet/cisco/enic/vnic_dev.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.h b/drivers/net/ethernet/cisco/enic/vnic_dev.h index 714fc1ed79e3..6273794b923b 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_dev.h +++ b/drivers/net/ethernet/cisco/enic/vnic_dev.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_DEV_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_devcmd.h b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h index fcc4a3ccdd94..db56d778877a 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_devcmd.h +++ b/drivers/net/ethernet/cisco/enic/vnic_devcmd.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_DEVCMD_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_enet.h b/drivers/net/ethernet/cisco/enic/vnic_enet.h index 7d6fbb5635a4..5acc236069de 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_enet.h +++ b/drivers/net/ethernet/cisco/enic/vnic_enet.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_ENIC_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_intr.c b/drivers/net/ethernet/cisco/enic/vnic_intr.c index 23604e3d4455..25319f072a04 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_intr.c +++ b/drivers/net/ethernet/cisco/enic/vnic_intr.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/net/ethernet/cisco/enic/vnic_intr.h b/drivers/net/ethernet/cisco/enic/vnic_intr.h index 2b1636392294..33a72aa10b26 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_intr.h +++ b/drivers/net/ethernet/cisco/enic/vnic_intr.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_INTR_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_nic.h b/drivers/net/ethernet/cisco/enic/vnic_nic.h index 84ff8ca17fcb..04fee45b5d39 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_nic.h +++ b/drivers/net/ethernet/cisco/enic/vnic_nic.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_NIC_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_resource.h b/drivers/net/ethernet/cisco/enic/vnic_resource.h index 4e45f88ac1d4..b4776e334d63 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_resource.h +++ b/drivers/net/ethernet/cisco/enic/vnic_resource.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_RESOURCE_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_rq.c b/drivers/net/ethernet/cisco/enic/vnic_rq.c index a3e7b003ada1..5ae80551f17c 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_rq.c +++ b/drivers/net/ethernet/cisco/enic/vnic_rq.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 @@ -216,4 +203,3 @@ void vnic_rq_clean(struct vnic_rq *rq, vnic_dev_clear_desc_ring(&rq->ring); } - diff --git a/drivers/net/ethernet/cisco/enic/vnic_rq.h b/drivers/net/ethernet/cisco/enic/vnic_rq.h index 0413103ebe94..0bc595abc03b 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_rq.h +++ b/drivers/net/ethernet/cisco/enic/vnic_rq.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_RQ_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_rss.h b/drivers/net/ethernet/cisco/enic/vnic_rss.h index 881fa18542b3..4dcf0e61cb13 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_rss.h +++ b/drivers/net/ethernet/cisco/enic/vnic_rss.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_RSS_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_stats.h b/drivers/net/ethernet/cisco/enic/vnic_stats.h index 74c81ed6fdab..2dd04322d760 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_stats.h +++ b/drivers/net/ethernet/cisco/enic/vnic_stats.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_STATS_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_vic.c b/drivers/net/ethernet/cisco/enic/vnic_vic.c index 24ef8cd40545..20fcb20b42ed 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_vic.c +++ b/drivers/net/ethernet/cisco/enic/vnic_vic.c @@ -1,20 +1,5 @@ -/* - * Copyright 2010 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - * - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2010 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/net/ethernet/cisco/enic/vnic_vic.h b/drivers/net/ethernet/cisco/enic/vnic_vic.h index 057776908828..b51c1c52f8bf 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_vic.h +++ b/drivers/net/ethernet/cisco/enic/vnic_vic.h @@ -1,20 +1,5 @@ -/* - * Copyright 2010 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - * - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2010 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_VIC_H_ #define _VNIC_VIC_H_ diff --git a/drivers/net/ethernet/cisco/enic/vnic_wq.c b/drivers/net/ethernet/cisco/enic/vnic_wq.c index eb75891974df..29c7900349b2 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_wq.c +++ b/drivers/net/ethernet/cisco/enic/vnic_wq.c @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/net/ethernet/cisco/enic/vnic_wq.h b/drivers/net/ethernet/cisco/enic/vnic_wq.h index 01209613d57d..75c526911074 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_wq.h +++ b/drivers/net/ethernet/cisco/enic/vnic_wq.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_WQ_H_ diff --git a/drivers/net/ethernet/cisco/enic/wq_enet_desc.h b/drivers/net/ethernet/cisco/enic/wq_enet_desc.h index c7021e3a631f..425e46a804ee 100644 --- a/drivers/net/ethernet/cisco/enic/wq_enet_desc.h +++ b/drivers/net/ethernet/cisco/enic/wq_enet_desc.h @@ -1,20 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008-2010 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _WQ_ENET_DESC_H_ diff --git a/drivers/scsi/fnic/cq_desc.h b/drivers/scsi/fnic/cq_desc.h index d1225cf6320e..0eb4ba277264 100644 --- a/drivers/scsi/fnic/cq_desc.h +++ b/drivers/scsi/fnic/cq_desc.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _CQ_DESC_H_ #define _CQ_DESC_H_ diff --git a/drivers/scsi/fnic/cq_enet_desc.h b/drivers/scsi/fnic/cq_enet_desc.h index a9fa26f82ddd..b6113291cf68 100644 --- a/drivers/scsi/fnic/cq_enet_desc.h +++ b/drivers/scsi/fnic/cq_enet_desc.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _CQ_ENET_DESC_H_ #define _CQ_ENET_DESC_H_ diff --git a/drivers/scsi/fnic/cq_exch_desc.h b/drivers/scsi/fnic/cq_exch_desc.h index 501660cfe228..4d94329c8ef5 100644 --- a/drivers/scsi/fnic/cq_exch_desc.h +++ b/drivers/scsi/fnic/cq_exch_desc.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _CQ_EXCH_DESC_H_ #define _CQ_EXCH_DESC_H_ diff --git a/drivers/scsi/fnic/fcpio.h b/drivers/scsi/fnic/fcpio.h index 12d770d885c5..54a0b2ba8f6f 100644 --- a/drivers/scsi/fnic/fcpio.h +++ b/drivers/scsi/fnic/fcpio.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _FCPIO_H_ #define _FCPIO_H_ diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 85ec6163ddab..d82de34f6fd7 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _FNIC_H_ #define _FNIC_H_ diff --git a/drivers/scsi/fnic/fnic_attrs.c b/drivers/scsi/fnic/fnic_attrs.c index bbe2ca4971b2..a61e0c5e6506 100644 --- a/drivers/scsi/fnic/fnic_attrs.c +++ b/drivers/scsi/fnic/fnic_attrs.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c index 866b4c983ace..6fedc3b7d1ab 100644 --- a/drivers/scsi/fnic/fnic_debugfs.c +++ b/drivers/scsi/fnic/fnic_debugfs.c @@ -1,19 +1,5 @@ -/* - * Copyright 2012 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2012 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 1885218f9d15..79ddfaaf71a4 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/scsi/fnic/fnic_fip.h b/drivers/scsi/fnic/fnic_fip.h index 7761f33ab5d4..79f53029737b 100644 --- a/drivers/scsi/fnic/fnic_fip.h +++ b/drivers/scsi/fnic/fnic_fip.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _FNIC_FIP_H_ diff --git a/drivers/scsi/fnic/fnic_io.h b/drivers/scsi/fnic/fnic_io.h index 1cb6a68c8e4e..f4c8769df312 100644 --- a/drivers/scsi/fnic/fnic_io.h +++ b/drivers/scsi/fnic/fnic_io.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _FNIC_IO_H_ #define _FNIC_IO_H_ diff --git a/drivers/scsi/fnic/fnic_isr.c b/drivers/scsi/fnic/fnic_isr.c index 2fb2731f50fb..8896758fed8c 100644 --- a/drivers/scsi/fnic/fnic_isr.c +++ b/drivers/scsi/fnic/fnic_isr.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 @@ -332,4 +320,3 @@ void fnic_clear_intr_mode(struct fnic *fnic) pci_free_irq_vectors(fnic->pdev); vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX); } - diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index 51e7c344ddc3..9eba910aaa86 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 @@ -1159,4 +1147,3 @@ static void __exit fnic_cleanup_module(void) module_init(fnic_init_module); module_exit(fnic_cleanup_module); - diff --git a/drivers/scsi/fnic/fnic_res.c b/drivers/scsi/fnic/fnic_res.c index 50488f8e169d..a1c9cfcace7f 100644 --- a/drivers/scsi/fnic/fnic_res.c +++ b/drivers/scsi/fnic/fnic_res.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/scsi/fnic/fnic_res.h b/drivers/scsi/fnic/fnic_res.h index ef8aaf2156dd..92a2fcfd3ea9 100644 --- a/drivers/scsi/fnic/fnic_res.h +++ b/drivers/scsi/fnic/fnic_res.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _FNIC_RES_H_ #define _FNIC_RES_H_ diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 3d64877bda8d..09eb33201f3c 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/scsi/fnic/fnic_stats.h b/drivers/scsi/fnic/fnic_stats.h index 086f729f3c46..bdf639eef8cf 100644 --- a/drivers/scsi/fnic/fnic_stats.h +++ b/drivers/scsi/fnic/fnic_stats.h @@ -1,19 +1,5 @@ -/* - * Copyright 2013 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2013 Cisco Systems, Inc. All rights reserved. */ #ifndef _FNIC_STATS_H_ #define _FNIC_STATS_H_ diff --git a/drivers/scsi/fnic/fnic_trace.c b/drivers/scsi/fnic/fnic_trace.c index 4a7536bb0ab3..e03967463561 100644 --- a/drivers/scsi/fnic/fnic_trace.c +++ b/drivers/scsi/fnic/fnic_trace.c @@ -1,19 +1,5 @@ -/* - * Copyright 2012 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2012 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/fnic/fnic_trace.h b/drivers/scsi/fnic/fnic_trace.h index 8aa55c1e2025..d1c301bf3fde 100644 --- a/drivers/scsi/fnic/fnic_trace.h +++ b/drivers/scsi/fnic/fnic_trace.h @@ -1,19 +1,5 @@ -/* - * Copyright 2012 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2012 Cisco Systems, Inc. All rights reserved. */ #ifndef __FNIC_TRACE_H__ #define __FNIC_TRACE_H__ diff --git a/drivers/scsi/fnic/rq_enet_desc.h b/drivers/scsi/fnic/rq_enet_desc.h index 92e80ae6b725..9bc509d355c4 100644 --- a/drivers/scsi/fnic/rq_enet_desc.h +++ b/drivers/scsi/fnic/rq_enet_desc.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _RQ_ENET_DESC_H_ #define _RQ_ENET_DESC_H_ diff --git a/drivers/scsi/fnic/vnic_cq.c b/drivers/scsi/fnic/vnic_cq.c index c5db32eda5ef..ed3dd443fe3e 100644 --- a/drivers/scsi/fnic/vnic_cq.c +++ b/drivers/scsi/fnic/vnic_cq.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/scsi/fnic/vnic_cq.h b/drivers/scsi/fnic/vnic_cq.h index 4ede6809fb1e..e7cc1f165390 100644 --- a/drivers/scsi/fnic/vnic_cq.h +++ b/drivers/scsi/fnic/vnic_cq.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_CQ_H_ #define _VNIC_CQ_H_ diff --git a/drivers/scsi/fnic/vnic_cq_copy.h b/drivers/scsi/fnic/vnic_cq_copy.h index 7901ce255a81..1b198ee59dd6 100644 --- a/drivers/scsi/fnic/vnic_cq_copy.h +++ b/drivers/scsi/fnic/vnic_cq_copy.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_CQ_COPY_H_ #define _VNIC_CQ_COPY_H_ diff --git a/drivers/scsi/fnic/vnic_dev.c b/drivers/scsi/fnic/vnic_dev.c index 5988c300cc82..3e5b437c0492 100644 --- a/drivers/scsi/fnic/vnic_dev.c +++ b/drivers/scsi/fnic/vnic_dev.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/scsi/fnic/vnic_dev.h b/drivers/scsi/fnic/vnic_dev.h index ef5309a5df5d..7a568d141cde 100644 --- a/drivers/scsi/fnic/vnic_dev.h +++ b/drivers/scsi/fnic/vnic_dev.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_DEV_H_ #define _VNIC_DEV_H_ diff --git a/drivers/scsi/fnic/vnic_devcmd.h b/drivers/scsi/fnic/vnic_devcmd.h index c20d30e36dfc..f876d223b2b4 100644 --- a/drivers/scsi/fnic/vnic_devcmd.h +++ b/drivers/scsi/fnic/vnic_devcmd.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_DEVCMD_H_ #define _VNIC_DEVCMD_H_ diff --git a/drivers/scsi/fnic/vnic_intr.c b/drivers/scsi/fnic/vnic_intr.c index 4f4dc8793d23..df7f63acd879 100644 --- a/drivers/scsi/fnic/vnic_intr.c +++ b/drivers/scsi/fnic/vnic_intr.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/scsi/fnic/vnic_intr.h b/drivers/scsi/fnic/vnic_intr.h index d5fb40e7c98e..acc194c0f522 100644 --- a/drivers/scsi/fnic/vnic_intr.h +++ b/drivers/scsi/fnic/vnic_intr.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_INTR_H_ #define _VNIC_INTR_H_ diff --git a/drivers/scsi/fnic/vnic_nic.h b/drivers/scsi/fnic/vnic_nic.h index f15b83eeaced..6896f16d564b 100644 --- a/drivers/scsi/fnic/vnic_nic.h +++ b/drivers/scsi/fnic/vnic_nic.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_NIC_H_ #define _VNIC_NIC_H_ diff --git a/drivers/scsi/fnic/vnic_resource.h b/drivers/scsi/fnic/vnic_resource.h index 7c6163f73bd3..3d260b831fc5 100644 --- a/drivers/scsi/fnic/vnic_resource.h +++ b/drivers/scsi/fnic/vnic_resource.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_RESOURCE_H_ #define _VNIC_RESOURCE_H_ diff --git a/drivers/scsi/fnic/vnic_rq.c b/drivers/scsi/fnic/vnic_rq.c index 6a35b1be0032..350607d13c9a 100644 --- a/drivers/scsi/fnic/vnic_rq.c +++ b/drivers/scsi/fnic/vnic_rq.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 @@ -191,4 +179,3 @@ void vnic_rq_clean(struct vnic_rq *rq, vnic_dev_clear_desc_ring(&rq->ring); } - diff --git a/drivers/scsi/fnic/vnic_rq.h b/drivers/scsi/fnic/vnic_rq.h index aebdfbd6ad3c..1066255de808 100644 --- a/drivers/scsi/fnic/vnic_rq.h +++ b/drivers/scsi/fnic/vnic_rq.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_RQ_H_ #define _VNIC_RQ_H_ diff --git a/drivers/scsi/fnic/vnic_scsi.h b/drivers/scsi/fnic/vnic_scsi.h index e343e1d0f801..4e12f7b32d9d 100644 --- a/drivers/scsi/fnic/vnic_scsi.h +++ b/drivers/scsi/fnic/vnic_scsi.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_SCSI_H_ #define _VNIC_SCSI_H_ diff --git a/drivers/scsi/fnic/vnic_stats.h b/drivers/scsi/fnic/vnic_stats.h index 5372e23c1cb3..4396397b089d 100644 --- a/drivers/scsi/fnic/vnic_stats.h +++ b/drivers/scsi/fnic/vnic_stats.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_STATS_H_ #define _VNIC_STATS_H_ diff --git a/drivers/scsi/fnic/vnic_wq.c b/drivers/scsi/fnic/vnic_wq.c index 442972c04e65..426b901c80f3 100644 --- a/drivers/scsi/fnic/vnic_wq.c +++ b/drivers/scsi/fnic/vnic_wq.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 diff --git a/drivers/scsi/fnic/vnic_wq.h b/drivers/scsi/fnic/vnic_wq.h index 5d1e0a44d94a..041618e13ce2 100644 --- a/drivers/scsi/fnic/vnic_wq.h +++ b/drivers/scsi/fnic/vnic_wq.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_WQ_H_ #define _VNIC_WQ_H_ diff --git a/drivers/scsi/fnic/vnic_wq_copy.c b/drivers/scsi/fnic/vnic_wq_copy.c index 7b18635df7e6..96569d4ccc58 100644 --- a/drivers/scsi/fnic/vnic_wq_copy.c +++ b/drivers/scsi/fnic/vnic_wq_copy.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 @@ -108,4 +96,3 @@ void vnic_wq_copy_init(struct vnic_wq_copy *wq, unsigned int cq_index, iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable); iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset); } - diff --git a/drivers/scsi/fnic/vnic_wq_copy.h b/drivers/scsi/fnic/vnic_wq_copy.h index 6aff9740c3df..2f8340144e79 100644 --- a/drivers/scsi/fnic/vnic_wq_copy.h +++ b/drivers/scsi/fnic/vnic_wq_copy.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _VNIC_WQ_COPY_H_ #define _VNIC_WQ_COPY_H_ diff --git a/drivers/scsi/fnic/wq_enet_desc.h b/drivers/scsi/fnic/wq_enet_desc.h index b121cbad18b8..9a933a5dee79 100644 --- a/drivers/scsi/fnic/wq_enet_desc.h +++ b/drivers/scsi/fnic/wq_enet_desc.h @@ -1,19 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 _WQ_ENET_DESC_H_ #define _WQ_ENET_DESC_H_ diff --git a/drivers/scsi/snic/cq_desc.h b/drivers/scsi/snic/cq_desc.h index a5290562c1fa..52a916fd0824 100644 --- a/drivers/scsi/snic/cq_desc.h +++ b/drivers/scsi/snic/cq_desc.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _CQ_DESC_H_ #define _CQ_DESC_H_ diff --git a/drivers/scsi/snic/cq_enet_desc.h b/drivers/scsi/snic/cq_enet_desc.h index 0a1be2ed0288..bd7381e52521 100644 --- a/drivers/scsi/snic/cq_enet_desc.h +++ b/drivers/scsi/snic/cq_enet_desc.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _CQ_ENET_DESC_H_ #define _CQ_ENET_DESC_H_ diff --git a/drivers/scsi/snic/snic.h b/drivers/scsi/snic/snic.h index 4ec7e30678e1..32f5a34b6987 100644 --- a/drivers/scsi/snic/snic.h +++ b/drivers/scsi/snic/snic.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _SNIC_H_ #define _SNIC_H_ From dfb99b050e4bc5bfb74973761752395d82644e48 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:25 +0200 Subject: [PATCH 0274/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_168.RULE (part 2) Based on the normalized pattern: this program is free software you may redistribute it and/or modify it under the terms of the gnu general public license as published by the free software foundation version 2 of the license 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 authors or copyright holders 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 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/snic/snic_attrs.c | 18 ++---------------- drivers/scsi/snic/snic_ctl.c | 18 ++---------------- drivers/scsi/snic/snic_debugfs.c | 18 ++---------------- drivers/scsi/snic/snic_disc.c | 18 ++---------------- drivers/scsi/snic/snic_disc.h | 18 ++---------------- drivers/scsi/snic/snic_fwint.h | 18 ++---------------- drivers/scsi/snic/snic_io.c | 18 ++---------------- drivers/scsi/snic/snic_io.h | 18 ++---------------- drivers/scsi/snic/snic_isr.c | 18 ++---------------- drivers/scsi/snic/snic_main.c | 18 ++---------------- drivers/scsi/snic/snic_res.c | 18 ++---------------- drivers/scsi/snic/snic_res.h | 18 ++---------------- drivers/scsi/snic/snic_scsi.c | 18 ++---------------- drivers/scsi/snic/snic_stats.h | 18 ++---------------- drivers/scsi/snic/snic_trc.c | 18 ++---------------- drivers/scsi/snic/snic_trc.h | 18 ++---------------- drivers/scsi/snic/vnic_cq.c | 18 ++---------------- drivers/scsi/snic/vnic_cq.h | 18 ++---------------- drivers/scsi/snic/vnic_cq_fw.h | 18 ++---------------- drivers/scsi/snic/vnic_dev.c | 18 ++---------------- drivers/scsi/snic/vnic_dev.h | 18 ++---------------- drivers/scsi/snic/vnic_devcmd.h | 18 ++---------------- drivers/scsi/snic/vnic_intr.c | 18 ++---------------- drivers/scsi/snic/vnic_intr.h | 18 ++---------------- drivers/scsi/snic/vnic_resource.h | 18 ++---------------- drivers/scsi/snic/vnic_snic.h | 18 ++---------------- drivers/scsi/snic/vnic_stats.h | 18 ++---------------- drivers/scsi/snic/vnic_wq.c | 18 ++---------------- drivers/scsi/snic/vnic_wq.h | 18 ++---------------- drivers/scsi/snic/wq_enet_desc.h | 18 ++---------------- include/media/i2c/ov2659.h | 14 +------------- samples/v4l/v4l2-pci-skeleton.c | 14 +------------- 32 files changed, 62 insertions(+), 506 deletions(-) diff --git a/drivers/scsi/snic/snic_attrs.c b/drivers/scsi/snic/snic_attrs.c index dc03ce1ec909..3ddbdbc3ded1 100644 --- a/drivers/scsi/snic/snic_attrs.c +++ b/drivers/scsi/snic/snic_attrs.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_ctl.c b/drivers/scsi/snic/snic_ctl.c index 703f229862fc..5f4fca96b192 100644 --- a/drivers/scsi/snic/snic_ctl.c +++ b/drivers/scsi/snic/snic_ctl.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_debugfs.c b/drivers/scsi/snic/snic_debugfs.c index 5e0faeba516e..57bdc3ba49d9 100644 --- a/drivers/scsi/snic/snic_debugfs.c +++ b/drivers/scsi/snic/snic_debugfs.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_disc.c b/drivers/scsi/snic/snic_disc.c index 27e98df83b31..9b2b5f8c23b9 100644 --- a/drivers/scsi/snic/snic_disc.c +++ b/drivers/scsi/snic/snic_disc.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_disc.h b/drivers/scsi/snic/snic_disc.h index 97fa3f5c5bb4..9ad7f84a3484 100644 --- a/drivers/scsi/snic/snic_disc.h +++ b/drivers/scsi/snic/snic_disc.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef __SNIC_DISC_H #define __SNIC_DISC_H diff --git a/drivers/scsi/snic/snic_fwint.h b/drivers/scsi/snic/snic_fwint.h index 2a045a57e365..e6b3e8b431c0 100644 --- a/drivers/scsi/snic/snic_fwint.h +++ b/drivers/scsi/snic/snic_fwint.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef __SNIC_FWINT_H #define __SNIC_FWINT_H diff --git a/drivers/scsi/snic/snic_io.c b/drivers/scsi/snic/snic_io.c index 159ee94d2a55..32a77bee41d5 100644 --- a/drivers/scsi/snic/snic_io.c +++ b/drivers/scsi/snic/snic_io.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_io.h b/drivers/scsi/snic/snic_io.h index 093d6524cd42..de6694a24c5f 100644 --- a/drivers/scsi/snic/snic_io.h +++ b/drivers/scsi/snic/snic_io.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _SNIC_IO_H #define _SNIC_IO_H diff --git a/drivers/scsi/snic/snic_isr.c b/drivers/scsi/snic/snic_isr.c index c4da3673f2ae..471a37422da9 100644 --- a/drivers/scsi/snic/snic_isr.c +++ b/drivers/scsi/snic/snic_isr.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c index 29d56396058c..174f7811fe50 100644 --- a/drivers/scsi/snic/snic_main.c +++ b/drivers/scsi/snic/snic_main.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_res.c b/drivers/scsi/snic/snic_res.c index b54912c8ca0c..43f1a2823514 100644 --- a/drivers/scsi/snic/snic_res.c +++ b/drivers/scsi/snic/snic_res.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_res.h b/drivers/scsi/snic/snic_res.h index 273f72f2a023..53cf6b19ab28 100644 --- a/drivers/scsi/snic/snic_res.h +++ b/drivers/scsi/snic/snic_res.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef __SNIC_RES_H #define __SNIC_RES_H diff --git a/drivers/scsi/snic/snic_scsi.c b/drivers/scsi/snic/snic_scsi.c index 5f17666f3e1d..961af6fc21bc 100644 --- a/drivers/scsi/snic/snic_scsi.c +++ b/drivers/scsi/snic/snic_scsi.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_stats.h b/drivers/scsi/snic/snic_stats.h index faf0cb601954..f0285c5a35f8 100644 --- a/drivers/scsi/snic/snic_stats.h +++ b/drivers/scsi/snic/snic_stats.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef __SNIC_STATS_H #define __SNIC_STATS_H diff --git a/drivers/scsi/snic/snic_trc.c b/drivers/scsi/snic/snic_trc.c index f23fe2f88438..c2e5ab7e976c 100644 --- a/drivers/scsi/snic/snic_trc.c +++ b/drivers/scsi/snic/snic_trc.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/snic_trc.h b/drivers/scsi/snic/snic_trc.h index ce305b4b8fa2..c38e0dadc958 100644 --- a/drivers/scsi/snic/snic_trc.h +++ b/drivers/scsi/snic/snic_trc.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef __SNIC_TRC_H #define __SNIC_TRC_H diff --git a/drivers/scsi/snic/vnic_cq.c b/drivers/scsi/snic/vnic_cq.c index 3455dd7e73f4..0d5d3bd4be1c 100644 --- a/drivers/scsi/snic/vnic_cq.c +++ b/drivers/scsi/snic/vnic_cq.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/vnic_cq.h b/drivers/scsi/snic/vnic_cq.h index 6e651c3e16f7..6cee911eec5f 100644 --- a/drivers/scsi/snic/vnic_cq.h +++ b/drivers/scsi/snic/vnic_cq.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_CQ_H_ #define _VNIC_CQ_H_ diff --git a/drivers/scsi/snic/vnic_cq_fw.h b/drivers/scsi/snic/vnic_cq_fw.h index c2d1bbd44bd1..d74954bc70e3 100644 --- a/drivers/scsi/snic/vnic_cq_fw.h +++ b/drivers/scsi/snic/vnic_cq_fw.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_CQ_FW_H_ #define _VNIC_CQ_FW_H_ diff --git a/drivers/scsi/snic/vnic_dev.c b/drivers/scsi/snic/vnic_dev.c index 05e374f80946..760f3f22095c 100644 --- a/drivers/scsi/snic/vnic_dev.c +++ b/drivers/scsi/snic/vnic_dev.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/vnic_dev.h b/drivers/scsi/snic/vnic_dev.h index e65726da6504..d2f9b6f7b313 100644 --- a/drivers/scsi/snic/vnic_dev.h +++ b/drivers/scsi/snic/vnic_dev.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_DEV_H_ #define _VNIC_DEV_H_ diff --git a/drivers/scsi/snic/vnic_devcmd.h b/drivers/scsi/snic/vnic_devcmd.h index 0e0fa38f8d90..9d82fcb7414b 100644 --- a/drivers/scsi/snic/vnic_devcmd.h +++ b/drivers/scsi/snic/vnic_devcmd.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_DEVCMD_H_ #define _VNIC_DEVCMD_H_ diff --git a/drivers/scsi/snic/vnic_intr.c b/drivers/scsi/snic/vnic_intr.c index a7d54806787d..23627f9591f2 100644 --- a/drivers/scsi/snic/vnic_intr.c +++ b/drivers/scsi/snic/vnic_intr.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/vnic_intr.h b/drivers/scsi/snic/vnic_intr.h index 4547f603fe5e..7bff60fafb07 100644 --- a/drivers/scsi/snic/vnic_intr.h +++ b/drivers/scsi/snic/vnic_intr.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_INTR_H_ #define _VNIC_INTR_H_ diff --git a/drivers/scsi/snic/vnic_resource.h b/drivers/scsi/snic/vnic_resource.h index 9713d6835db3..372596b0915f 100644 --- a/drivers/scsi/snic/vnic_resource.h +++ b/drivers/scsi/snic/vnic_resource.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_RESOURCE_H_ #define _VNIC_RESOURCE_H_ diff --git a/drivers/scsi/snic/vnic_snic.h b/drivers/scsi/snic/vnic_snic.h index 514d39f5cf00..ffc8a0fee577 100644 --- a/drivers/scsi/snic/vnic_snic.h +++ b/drivers/scsi/snic/vnic_snic.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_SNIC_H_ #define _VNIC_SNIC_H_ diff --git a/drivers/scsi/snic/vnic_stats.h b/drivers/scsi/snic/vnic_stats.h index 370a37c97748..38155aae7a52 100644 --- a/drivers/scsi/snic/vnic_stats.h +++ b/drivers/scsi/snic/vnic_stats.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_STATS_H_ #define _VNIC_STATS_H_ diff --git a/drivers/scsi/snic/vnic_wq.c b/drivers/scsi/snic/vnic_wq.c index 1e91d432089e..48be9a3f4c3d 100644 --- a/drivers/scsi/snic/vnic_wq.c +++ b/drivers/scsi/snic/vnic_wq.c @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright 2014 Cisco Systems, Inc. All rights reserved. #include #include diff --git a/drivers/scsi/snic/vnic_wq.h b/drivers/scsi/snic/vnic_wq.h index 7cc031c7ceba..1415da4b68dc 100644 --- a/drivers/scsi/snic/vnic_wq.h +++ b/drivers/scsi/snic/vnic_wq.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _VNIC_WQ_H_ #define _VNIC_WQ_H_ diff --git a/drivers/scsi/snic/wq_enet_desc.h b/drivers/scsi/snic/wq_enet_desc.h index 68f62b6d105b..e8025331b503 100644 --- a/drivers/scsi/snic/wq_enet_desc.h +++ b/drivers/scsi/snic/wq_enet_desc.h @@ -1,19 +1,5 @@ -/* - * Copyright 2014 Cisco Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright 2014 Cisco Systems, Inc. All rights reserved. */ #ifndef _WQ_ENET_DESC_H_ #define _WQ_ENET_DESC_H_ diff --git a/include/media/i2c/ov2659.h b/include/media/i2c/ov2659.h index 4216adc1ede2..c9ea318a8fc3 100644 --- a/include/media/i2c/ov2659.h +++ b/include/media/i2c/ov2659.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Omnivision OV2659 CMOS Image Sensor driver * @@ -5,19 +6,6 @@ * * Benoit Parrot * Lad, Prabhakar - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 OV2659_H diff --git a/samples/v4l/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c index 6311b7465220..a61f94db18d9 100644 --- a/samples/v4l/v4l2-pci-skeleton.c +++ b/samples/v4l/v4l2-pci-skeleton.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * This is a V4L2 PCI Skeleton Driver. It gives an initial skeleton source * for use with other PCI drivers. @@ -6,19 +7,6 @@ * input 0 and an HDMI connector as input 1. * * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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 AUTHORS OR COPYRIGHT HOLDERS - * 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 From 2eb72d6696c685369fca7cd63cb4b76d1be099e0 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:26 +0200 Subject: [PATCH 0275/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_179.RULE Based on the normalized pattern: gpl header start do not alter or remove copyright notices or this file header this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license version 2 only as published by the free software foundation this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license version 2 for more details (a copy is included in the license file that accompanied this code) you should have received a copy of the gnu general public license version 2 along with this program if not see http://www gnu org/licenses please visit http://www xyratex com/contact if you need additional information or have any questions gpl header end extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/x86/crypto/crc32-pclmul_asm.S | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/arch/x86/crypto/crc32-pclmul_asm.S b/arch/x86/crypto/crc32-pclmul_asm.S index c392a6edbfff..c4bd1b47a600 100644 --- a/arch/x86/crypto/crc32-pclmul_asm.S +++ b/arch/x86/crypto/crc32-pclmul_asm.S @@ -1,24 +1,4 @@ -/* GPL HEADER START - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License version 2 for more details (a copy is included - * in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU General Public License - * version 2 along with this program; If not, see http://www.gnu.org/licenses - * - * Please visit http://www.xyratex.com/contact if you need additional - * information or have any questions. - * - * GPL HEADER END +/* SPDX-License-Identifier: GPL-2.0-only */ */ /* From a601378552a08e4812e4363a93cb736c9001556e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:27 +0200 Subject: [PATCH 0276/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_292.RULE Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license version 2 as published by the free software foundation you should have received a copy of the gnu general public license along with this program if not see this software is provided as is and without any express or implied warranties including without limitation the implied warranties of merchantability and fitness for a particular purpose extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/chelsio/cxgb/common.h | 11 +---------- drivers/net/ethernet/chelsio/cxgb/cphy.h | 11 +---------- drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h | 12 +----------- drivers/net/ethernet/chelsio/cxgb/elmer0.h | 12 +----------- drivers/net/ethernet/chelsio/cxgb/espi.c | 11 +---------- drivers/net/ethernet/chelsio/cxgb/espi.h | 11 +---------- drivers/net/ethernet/chelsio/cxgb/gmac.h | 11 +---------- drivers/net/ethernet/chelsio/cxgb/mv88x201x.c | 11 +---------- drivers/net/ethernet/chelsio/cxgb/pm3393.c | 11 +---------- drivers/net/ethernet/chelsio/cxgb/regs.h | 11 +---------- drivers/net/ethernet/chelsio/cxgb/sge.c | 11 +---------- drivers/net/ethernet/chelsio/cxgb/sge.h | 11 +---------- drivers/net/ethernet/chelsio/cxgb/subr.c | 11 +---------- .../net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h | 12 +----------- 14 files changed, 14 insertions(+), 143 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb/common.h b/drivers/net/ethernet/chelsio/cxgb/common.h index 0321be77366c..e56eff701395 100644 --- a/drivers/net/ethernet/chelsio/cxgb/common.h +++ b/drivers/net/ethernet/chelsio/cxgb/common.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /***************************************************************************** * * * File: common.h * @@ -6,16 +7,6 @@ * Description: * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/cphy.h b/drivers/net/ethernet/chelsio/cxgb/cphy.h index bf43da6c6a63..12639b688ddc 100644 --- a/drivers/net/ethernet/chelsio/cxgb/cphy.h +++ b/drivers/net/ethernet/chelsio/cxgb/cphy.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /***************************************************************************** * * * File: cphy.h * @@ -6,16 +7,6 @@ * Description: * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h b/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h index 5249686afe71..a30fb407115d 100644 --- a/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h +++ b/drivers/net/ethernet/chelsio/cxgb/cpl5_cmd.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /***************************************************************************** * * * File: cpl5_cmd.h * @@ -6,16 +7,6 @@ * Description: * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * @@ -635,4 +626,3 @@ struct cpl_mss_change { }; #endif /* _CXGB_CPL5_CMD_H_ */ - diff --git a/drivers/net/ethernet/chelsio/cxgb/elmer0.h b/drivers/net/ethernet/chelsio/cxgb/elmer0.h index 81526ad36339..0427e894c277 100644 --- a/drivers/net/ethernet/chelsio/cxgb/elmer0.h +++ b/drivers/net/ethernet/chelsio/cxgb/elmer0.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /***************************************************************************** * * * File: elmer0.h * @@ -6,16 +7,6 @@ * Description: * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * @@ -154,4 +145,3 @@ enum { #define MI1_OP_INDIRECT_READ 3 #endif /* _CXGB_ELMER0_H_ */ - diff --git a/drivers/net/ethernet/chelsio/cxgb/espi.c b/drivers/net/ethernet/chelsio/cxgb/espi.c index 3e182eee799e..ef70569435be 100644 --- a/drivers/net/ethernet/chelsio/cxgb/espi.c +++ b/drivers/net/ethernet/chelsio/cxgb/espi.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /***************************************************************************** * * * File: espi.c * @@ -7,16 +8,6 @@ * Ethernet SPI functionality. * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/espi.h b/drivers/net/ethernet/chelsio/cxgb/espi.h index 162de5259df9..f588e9f3b37a 100644 --- a/drivers/net/ethernet/chelsio/cxgb/espi.h +++ b/drivers/net/ethernet/chelsio/cxgb/espi.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /***************************************************************************** * * * File: espi.h * @@ -6,16 +7,6 @@ * Description: * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/gmac.h b/drivers/net/ethernet/chelsio/cxgb/gmac.h index 5913eaf442b5..96077da1ed5e 100644 --- a/drivers/net/ethernet/chelsio/cxgb/gmac.h +++ b/drivers/net/ethernet/chelsio/cxgb/gmac.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /***************************************************************************** * * * File: gmac.h * @@ -7,16 +8,6 @@ * Generic MAC functionality. * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c b/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c index 7ddb301bcba0..556c8ad68fa8 100644 --- a/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c +++ b/drivers/net/ethernet/chelsio/cxgb/mv88x201x.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /***************************************************************************** * * * File: mv88x201x.c * @@ -7,16 +8,6 @@ * Marvell PHY (mv88x201x) functionality. * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/pm3393.c b/drivers/net/ethernet/chelsio/cxgb/pm3393.c index 0bb37e4680c7..cbfa03d5663a 100644 --- a/drivers/net/ethernet/chelsio/cxgb/pm3393.c +++ b/drivers/net/ethernet/chelsio/cxgb/pm3393.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /***************************************************************************** * * * File: pm3393.c * @@ -7,16 +8,6 @@ * PMC/SIERRA (pm3393) MAC-PHY functionality. * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/regs.h b/drivers/net/ethernet/chelsio/cxgb/regs.h index 964ce59ee169..f751e680cf7d 100644 --- a/drivers/net/ethernet/chelsio/cxgb/regs.h +++ b/drivers/net/ethernet/chelsio/cxgb/regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /***************************************************************************** * * * File: regs.h * @@ -6,16 +7,6 @@ * Description: * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c index 12e76fd0ae91..861edff5ed89 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb/sge.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /***************************************************************************** * * * File: sge.c * @@ -7,16 +8,6 @@ * DMA engine. * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.h b/drivers/net/ethernet/chelsio/cxgb/sge.h index 716705b96f26..f7e6f64040ea 100644 --- a/drivers/net/ethernet/chelsio/cxgb/sge.h +++ b/drivers/net/ethernet/chelsio/cxgb/sge.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /***************************************************************************** * * * File: sge.h * @@ -6,16 +7,6 @@ * Description: * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/subr.c b/drivers/net/ethernet/chelsio/cxgb/subr.c index 007c591b8bf5..367a9e4581d5 100644 --- a/drivers/net/ethernet/chelsio/cxgb/subr.c +++ b/drivers/net/ethernet/chelsio/cxgb/subr.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /***************************************************************************** * * * File: subr.c * @@ -7,16 +8,6 @@ * Various subroutines (intr,pio,etc.) used by Chelsio 10G Ethernet driver. * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * diff --git a/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h b/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h index 7f79cc7ceb75..4c883170683b 100644 --- a/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb/suni1x10gexp_regs.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /***************************************************************************** * * * File: suni1x10gexp_regs.h * @@ -7,16 +8,6 @@ * PMC/SIERRA (pm3393) MAC-PHY functionality. * * part of the Chelsio 10Gb Ethernet Driver. * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License, version 2, as * - * published by the Free Software Foundation. * - * * - * You should have received a copy of the GNU General Public License along * - * with this program; if not, see . * - * * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * * * http://www.chelsio.com * * * @@ -1639,4 +1630,3 @@ #define SUNI1x10GEXP_BITMSK_PL4IDU_DIP4I 0x0002 #endif /* _CXGB_SUNI1x10GEXP_REGS_H_ */ - From 336371516a42a9edf2d4fd968212b699e831cc55 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:29 +0200 Subject: [PATCH 0277/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_298.RULE Based on the normalized pattern: this package is free software you can redistribute it and/or modify it under the terms of the gnu general public license version 2 as published by the free software foundation this package is provided as is and without any express or implied warranties including without limitation the implied warranties of merchantibility and fitness for a particular purpose extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap1/board-sx1.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/arch/arm/mach-omap1/board-sx1.h b/arch/arm/mach-omap1/board-sx1.h index 355adbdaae33..fafe54a2e444 100644 --- a/arch/arm/mach-omap1/board-sx1.h +++ b/arch/arm/mach-omap1/board-sx1.h @@ -1,15 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Siemens SX1 board definitions * * Copyright: Vovan888 at gmail com - * - * This package is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #ifndef __ASM_ARCH_SX1_I2C_CHIPS_H From e634cf4e44d9770bfcb059e45ad6b9ba6a1e0bdc Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:30 +0200 Subject: [PATCH 0278/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_318.RULE Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license as published by the free software foundation version 2 this program is distributed as is without any warranty of any kind whether express or implied without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details you should have received a copy of the gnu general public license along with this program if not write to the free software foundation inc 59 temple place suite 330 boston ma 02111-1307 usa extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/pinctrl-as3722.c | 15 +-------------- drivers/pinctrl/pinctrl-palmas.c | 15 +-------------- drivers/pinctrl/pinctrl-utils.c | 15 +-------------- drivers/pinctrl/pinctrl-utils.h | 15 +-------------- drivers/regulator/max8973-regulator.c | 15 +-------------- drivers/regulator/tps51632-regulator.c | 15 +-------------- drivers/regulator/tps62360-regulator.c | 15 +-------------- 7 files changed, 7 insertions(+), 98 deletions(-) diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c index 4313756b52e6..f0e5d87ac50b 100644 --- a/drivers/pinctrl/pinctrl-as3722.c +++ b/drivers/pinctrl/pinctrl-as3722.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * ams AS3722 pin control and GPIO driver. * * Copyright (c) 2013, NVIDIA Corporation. * * Author: Laxman Dewangan - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #include diff --git a/drivers/pinctrl/pinctrl-palmas.c b/drivers/pinctrl/pinctrl-palmas.c index d42f18cb1bc7..fecc25d35d02 100644 --- a/drivers/pinctrl/pinctrl-palmas.c +++ b/drivers/pinctrl/pinctrl-palmas.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * pinctrl-palmas.c -- TI PALMAS series pin control driver. * * Copyright (c) 2013, NVIDIA Corporation. * * Author: Laxman Dewangan - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #include diff --git a/drivers/pinctrl/pinctrl-utils.c b/drivers/pinctrl/pinctrl-utils.c index 93df0d4c0a24..3580e0fd94ed 100644 --- a/drivers/pinctrl/pinctrl-utils.c +++ b/drivers/pinctrl/pinctrl-utils.c @@ -1,23 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Utils functions to implement the pincontrol driver. * * Copyright (c) 2013, NVIDIA Corporation. * * Author: Laxman Dewangan - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #include #include diff --git a/drivers/pinctrl/pinctrl-utils.h b/drivers/pinctrl/pinctrl-utils.h index 8f9f2d28c5b8..cec407a8cc4e 100644 --- a/drivers/pinctrl/pinctrl-utils.h +++ b/drivers/pinctrl/pinctrl-utils.h @@ -1,23 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Utils functions to implement the pincontrol driver. * * Copyright (c) 2013, NVIDIA Corporation. * * Author: Laxman Dewangan - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #ifndef __PINCTRL_UTILS_H__ #define __PINCTRL_UTILS_H__ diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index cb7e50003f70..fdcb0f508984 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * max8973-regulator.c -- Maxim max8973A * @@ -6,20 +7,6 @@ * Copyright (c) 2012, NVIDIA Corporation. * * Author: Laxman Dewangan - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #include diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index a15e415e61d5..85e3326b99eb 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps51632-regulator.c -- TI TPS51632 * @@ -7,20 +8,6 @@ * Copyright (c) 2012, NVIDIA Corporation. * * Author: Laxman Dewangan - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #include diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index 574958690ace..7c697bdf344e 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps62360.c -- TI tps62360 * @@ -6,20 +7,6 @@ * Copyright (c) 2012, NVIDIA Corporation. * * Author: Laxman Dewangan - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, - * whether express or implied; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA */ #include From abd462747539bbc630e50e8be59e3aebca63441d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:31 +0200 Subject: [PATCH 0279/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_319.RULE Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license version 2 as published by the free software foundation this program is distributed as is without any warranty of any kind whether expressed or implied without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license version 2 for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-lp873x.c | 10 +--------- drivers/gpio/gpio-lp87565.c | 10 +--------- drivers/gpio/gpio-pisosr.c | 10 +--------- drivers/gpio/gpio-tpic2810.c | 10 +--------- drivers/mfd/tps65086.c | 10 +--------- drivers/mfd/tps65218.c | 10 +--------- drivers/mfd/tps65912-core.c | 10 +--------- drivers/mfd/tps65912-i2c.c | 10 +--------- drivers/mfd/tps65912-spi.c | 10 +--------- drivers/regulator/lp873x-regulator.c | 10 +--------- drivers/regulator/tps65086-regulator.c | 10 +--------- drivers/regulator/tps65218-regulator.c | 10 +--------- drivers/regulator/tps65912-regulator.c | 10 +--------- include/linux/mfd/tps65086.h | 10 +--------- include/linux/mfd/tps65218.h | 10 +--------- include/linux/mfd/tps65912.h | 10 +--------- 16 files changed, 16 insertions(+), 144 deletions(-) diff --git a/drivers/gpio/gpio-lp873x.c b/drivers/gpio/gpio-lp873x.c index 70fad87ff2db..5c79ba1f229c 100644 --- a/drivers/gpio/gpio-lp873x.c +++ b/drivers/gpio/gpio-lp873x.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ * Keerthy * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver */ diff --git a/drivers/gpio/gpio-lp87565.c b/drivers/gpio/gpio-lp87565.c index fcde6708b5df..d3ce027de081 100644 --- a/drivers/gpio/gpio-lp87565.c +++ b/drivers/gpio/gpio-lp87565.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ * Keerthy * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the LP873X driver */ diff --git a/drivers/gpio/gpio-pisosr.c b/drivers/gpio/gpio-pisosr.c index 81a47ae09ff8..67071bea08c2 100644 --- a/drivers/gpio/gpio-pisosr.c +++ b/drivers/gpio/gpio-pisosr.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Andrew F. Davis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include diff --git a/drivers/gpio/gpio-tpic2810.c b/drivers/gpio/gpio-tpic2810.c index 99d5a84a9129..a09b1e69b072 100644 --- a/drivers/gpio/gpio-tpic2810.c +++ b/drivers/gpio/gpio-tpic2810.c @@ -1,15 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Andrew F. Davis - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c index 3bd5728844a0..cbae9777a24e 100644 --- a/drivers/mfd/tps65086.c +++ b/drivers/mfd/tps65086.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65912 driver */ diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index 167e9fc308ef..49bb8fd168f8 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for TPS65218 Integrated power management chipsets * * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index c282a05e7146..7d994b8a5965 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Core functions for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera */ diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c index 06eb2784d322..afb7f7d97dc0 100644 --- a/drivers/mfd/tps65912-i2c.c +++ b/drivers/mfd/tps65912-i2c.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C access driver for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera */ diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index bba38fbc781d..9e976f9c6bbe 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI access driver for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera */ diff --git a/drivers/regulator/lp873x-regulator.c b/drivers/regulator/lp873x-regulator.c index c38387e0fbb2..d6e597922cb5 100644 --- a/drivers/regulator/lp873x-regulator.c +++ b/drivers/regulator/lp873x-regulator.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulator driver for LP873X PMIC * * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include diff --git a/drivers/regulator/tps65086-regulator.c b/drivers/regulator/tps65086-regulator.c index 070c956216b0..f1bc54c825dd 100644 --- a/drivers/regulator/tps65086-regulator.c +++ b/drivers/regulator/tps65086-regulator.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * * Author: Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65912 driver */ diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index fa263545a70e..48809c3b3abc 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65218-regulator.c * * Regulator driver for TPS65218 PMIC * * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index b52d4f2874b7..76f90202ae09 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Regulator driver for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera */ diff --git a/include/linux/mfd/tps65086.h b/include/linux/mfd/tps65086.h index e0a417e53766..16f87cccc003 100644 --- a/include/linux/mfd/tps65086.h +++ b/include/linux/mfd/tps65086.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65912 driver */ diff --git a/include/linux/mfd/tps65218.h b/include/linux/mfd/tps65218.h index 122e24ddbd4b..2946be2f15f3 100644 --- a/include/linux/mfd/tps65218.h +++ b/include/linux/mfd/tps65218.h @@ -1,18 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * linux/mfd/tps65218.h * * Functions to access TPS65218 power management chip. * * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #ifndef __LINUX_MFD_TPS65218_H diff --git a/include/linux/mfd/tps65912.h b/include/linux/mfd/tps65912.h index 8a61386cb8c1..860ec0a16c96 100644 --- a/include/linux/mfd/tps65912.h +++ b/include/linux/mfd/tps65912.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera */ From 5a729246e57eac410e4a13f5aba66ae2dc552632 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:32 +0200 Subject: [PATCH 0280/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_320.RULE Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license version 2 as published by the free software foundation this program is distributed as is without any warranty of any kind whether express or implied without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap1/timer.c | 10 +--------- arch/arm/mach-omap2/display.c | 10 +--------- arch/arm/mach-omap2/omap_opp_data.h | 10 +--------- arch/arm/mach-omap2/opp3xxx_data.c | 10 +--------- arch/arm/mach-omap2/opp4xxx_data.c | 10 +--------- arch/arm/mach-versatile/spc.c | 10 +--------- drivers/bus/omap_l3_noc.c | 10 +--------- drivers/bus/omap_l3_noc.h | 10 +--------- drivers/clk/keystone/sci-clk.c | 10 +--------- drivers/clk/ti/apll.c | 10 +--------- drivers/clk/ti/autoidle.c | 10 +--------- drivers/clk/ti/clk-dra7-atl.c | 10 +--------- drivers/clk/ti/clk.c | 10 +--------- drivers/clk/ti/clkctrl.c | 10 +--------- drivers/clk/ti/clkt_dflt.c | 10 +--------- drivers/clk/ti/clockdomain.c | 10 +--------- drivers/clk/ti/composite.c | 10 +--------- drivers/clk/ti/divider.c | 10 +--------- drivers/clk/ti/dpll.c | 10 +--------- drivers/clk/ti/fixed-factor.c | 10 +--------- drivers/clk/ti/gate.c | 10 +--------- drivers/clk/ti/interface.c | 10 +--------- drivers/clk/ti/mux.c | 10 +--------- drivers/cpufreq/scpi-cpufreq.c | 10 +--------- drivers/input/misc/palmas-pwrbutton.c | 10 +--------- drivers/input/misc/tps65218-pwrbutton.c | 10 +--------- drivers/misc/sram-exec.c | 10 +--------- drivers/power/supply/cpcap-battery.c | 10 +--------- drivers/regulator/ti-abb-regulator.c | 10 +--------- drivers/reset/reset-ti-sci.c | 10 +--------- drivers/reset/reset-ti-syscon.c | 10 +--------- drivers/thermal/hisi_thermal.c | 10 +--------- include/dt-bindings/clock/ti-dra7-atl.h | 10 +--------- include/dt-bindings/pinctrl/hisi.h | 10 +--------- include/dt-bindings/pinctrl/keystone.h | 10 +--------- include/linux/clk/ti.h | 10 +--------- include/linux/pm_wakeirq.h | 14 ++------------ include/linux/soc/ti/ti-msgmgr.h | 10 +--------- 38 files changed, 39 insertions(+), 345 deletions(-) diff --git a/arch/arm/mach-omap1/timer.c b/arch/arm/mach-omap1/timer.c index 9ed64345f06e..f5cd4bbf7566 100644 --- a/arch/arm/mach-omap1/timer.c +++ b/arch/arm/mach-omap1/timer.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP1 Dual-Mode Timers - platform device registration * @@ -9,15 +10,6 @@ * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ * Tarun Kanti DebBarma * Thara Gopinath - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 21413a9b7b6c..47149b278ad5 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP2plus display device setup / initialization. * * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ * Senthilvadivu Guruswamy * Sumit Semwal - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/omap_opp_data.h b/arch/arm/mach-omap2/omap_opp_data.h index 533dd643069a..88375ab38e31 100644 --- a/arch/arm/mach-omap2/omap_opp_data.h +++ b/arch/arm/mach-omap2/omap_opp_data.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * OMAP SoC specific OPP Data helpers * @@ -6,15 +7,6 @@ * Kevin Hilman * Copyright (C) 2010 Nokia Corporation. * Eduardo Valentin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H #define __ARCH_ARM_MACH_OMAP2_OMAP_OPP_DATA_H diff --git a/arch/arm/mach-omap2/opp3xxx_data.c b/arch/arm/mach-omap2/opp3xxx_data.c index b610c5fb423b..90257e2fb3d6 100644 --- a/arch/arm/mach-omap2/opp3xxx_data.c +++ b/arch/arm/mach-omap2/opp3xxx_data.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP3 OPP table definitions. * @@ -7,15 +8,6 @@ * Copyright (C) 2010-2011 Nokia Corporation. * Eduardo Valentin * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c index d937c5ef41c6..a9851886017d 100644 --- a/arch/arm/mach-omap2/opp4xxx_data.c +++ b/arch/arm/mach-omap2/opp4xxx_data.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP4 OPP table definitions. * @@ -8,15 +9,6 @@ * Copyright (C) 2010-2011 Nokia Corporation. * Eduardo Valentin * Paul Walmsley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/arch/arm/mach-versatile/spc.c b/arch/arm/mach-versatile/spc.c index 6e6985e756af..5e44170e1a9a 100644 --- a/arch/arm/mach-versatile/spc.c +++ b/arch/arm/mach-versatile/spc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Versatile Express Serial Power Controller (SPC) support * @@ -6,15 +7,6 @@ * Authors: Sudeep KarkadaNagesha * Achin Gupta * Lorenzo Pieralisi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c index dcfb32ee5cb6..eb1ba6319fda 100644 --- a/drivers/bus/omap_l3_noc.c +++ b/drivers/bus/omap_l3_noc.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP L3 Interconnect error handling driver * * Copyright (C) 2011-2015 Texas Instruments Incorporated - http://www.ti.com/ * Santosh Shilimkar * Sricharan - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/bus/omap_l3_noc.h b/drivers/bus/omap_l3_noc.h index 73431f81da28..bb3eebd3465d 100644 --- a/drivers/bus/omap_l3_noc.h +++ b/drivers/bus/omap_l3_noc.h @@ -1,18 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * OMAP L3 Interconnect error handling driver header * * Copyright (C) 2011-2015 Texas Instruments Incorporated - http://www.ti.com/ * Santosh Shilimkar * sricharan - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __OMAP_L3_NOC_H #define __OMAP_L3_NOC_H diff --git a/drivers/clk/keystone/sci-clk.c b/drivers/clk/keystone/sci-clk.c index 7e1b136e71ae..d4b4e74e22da 100644 --- a/drivers/clk/keystone/sci-clk.c +++ b/drivers/clk/keystone/sci-clk.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SCI Clock driver for keystone based devices * * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/ * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c index e4db6b9a55c6..dd0709c9c249 100644 --- a/drivers/clk/ti/apll.c +++ b/drivers/clk/ti/apll.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP APLL clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * J Keerthy - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c index d6e5f1511ace..27e6b9cb1881 100644 --- a/drivers/clk/ti/autoidle.c +++ b/drivers/clk/ti/autoidle.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI clock autoidle support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index aa0950c4f498..f0f5bf68b6d2 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * DRA7 ATL (Audio Tracking Logic) clock driver * * Copyright (C) 2013 Texas Instruments, Inc. * * Peter Ujfalusi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index 3463579220b5..ef2a445c63a3 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clkctrl.c b/drivers/clk/ti/clkctrl.c index 617360e20d86..3b5ebae3740f 100644 --- a/drivers/clk/ti/clkctrl.c +++ b/drivers/clk/ti/clkctrl.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP clkctrl clock support * * Copyright (C) 2017 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clkt_dflt.c b/drivers/clk/ti/clkt_dflt.c index 91751dd26b16..a756ab1a5856 100644 --- a/drivers/clk/ti/clkt_dflt.c +++ b/drivers/clk/ti/clkt_dflt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Default clock type * @@ -8,15 +9,6 @@ * Richard Woodruff * Paul Walmsley * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c index 24179c907774..c897ad7e681e 100644 --- a/drivers/clk/ti/clockdomain.c +++ b/drivers/clk/ti/clockdomain.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP clockdomain support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c index 779b9900f636..77b771dd050a 100644 --- a/drivers/clk/ti/composite.c +++ b/drivers/clk/ti/composite.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI composite clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index 9fbea0997b43..488d3da60c31 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI Divider Clock * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 7c6dc8449b22..8ed43bc6b7cc 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP DPLL clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/fixed-factor.c b/drivers/clk/ti/fixed-factor.c index 8cb00d0af966..c80cee0f5d3d 100644 --- a/drivers/clk/ti/fixed-factor.c +++ b/drivers/clk/ti/fixed-factor.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI Fixed Factor Clock * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c index 0033de9beb4c..307702921431 100644 --- a/drivers/clk/ti/gate.c +++ b/drivers/clk/ti/gate.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP gate clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c index dd2b455183a9..f47beeea211e 100644 --- a/drivers/clk/ti/interface.c +++ b/drivers/clk/ti/interface.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * OMAP interface clock support * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index 15de513d2d81..46b45b3e8319 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI Multiplexer Clock * * Copyright (C) 2013 Texas Instruments, Inc. * * Tero Kristo - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c index bda3e7d42964..fd2c16821d54 100644 --- a/drivers/cpufreq/scpi-cpufreq.c +++ b/drivers/cpufreq/scpi-cpufreq.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * System Control and Power Interface (SCPI) based CPUFreq Interface driver * * Copyright (C) 2015 ARM Ltd. * Sudeep Holla - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c index 2213e06b611d..465e6693077a 100644 --- a/drivers/input/misc/palmas-pwrbutton.c +++ b/drivers/input/misc/palmas-pwrbutton.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Texas Instruments' Palmas Power Button Input Driver * * Copyright (C) 2012-2014 Texas Instruments Incorporated - http://www.ti.com/ * Girish S Ghongdemath * Nishanth Menon - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c index f011447c44fb..fc450fce0932 100644 --- a/drivers/input/misc/tps65218-pwrbutton.c +++ b/drivers/input/misc/tps65218-pwrbutton.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Texas Instruments' TPS65217 and TPS65218 Power Button Input Driver * * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ * Author: Felipe Balbi * Author: Marcin Niestroj - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/misc/sram-exec.c b/drivers/misc/sram-exec.c index 6cc31789b38d..a948e95d4375 100644 --- a/drivers/misc/sram-exec.c +++ b/drivers/misc/sram-exec.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SRAM protect-exec region helper functions * * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ * Dave Gerlach - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/power/supply/cpcap-battery.c b/drivers/power/supply/cpcap-battery.c index ae284bdd6cc3..d98d9244e394 100644 --- a/drivers/power/supply/cpcap-battery.c +++ b/drivers/power/supply/cpcap-battery.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Battery driver for CPCAP PMIC * @@ -7,15 +8,6 @@ * drivers: * * Copyright (C) 2009-2010 Motorola, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index bd7b2f287250..cf18452386ca 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Texas Instruments SoC Adaptive Body Bias(ABB) Regulator * @@ -7,15 +8,6 @@ * Copyright (C) 2012-2013 Texas Instruments, Inc. * Andrii Tseglytskyi * Nishanth Menon - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include #include diff --git a/drivers/reset/reset-ti-sci.c b/drivers/reset/reset-ti-sci.c index b799aefad547..cc01fa5b0bea 100644 --- a/drivers/reset/reset-ti-sci.c +++ b/drivers/reset/reset-ti-sci.c @@ -1,17 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Texas Instrument's System Control Interface (TI-SCI) reset driver * * Copyright (C) 2015-2017 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/reset/reset-ti-syscon.c b/drivers/reset/reset-ti-syscon.c index 2b92775d58f0..f0dd7ffc3b72 100644 --- a/drivers/reset/reset-ti-syscon.c +++ b/drivers/reset/reset-ti-syscon.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI SYSCON regmap reset driver * * Copyright (C) 2015-2016 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis * Suman Anna - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index b29ab09040d5..19a242c69ce6 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * HiSilicon thermal sensor driver * @@ -6,15 +7,6 @@ * * Xinwei Kong * Leo Yan - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include diff --git a/include/dt-bindings/clock/ti-dra7-atl.h b/include/dt-bindings/clock/ti-dra7-atl.h index 42dd4164f6f4..b0e71e3cce95 100644 --- a/include/dt-bindings/clock/ti-dra7-atl.h +++ b/include/dt-bindings/clock/ti-dra7-atl.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This header provides constants for DRA7 ATL (Audio Tracking Logic) * @@ -6,15 +7,6 @@ * Copyright (C) 2013 Texas Instruments, Inc. * * Peter Ujfalusi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DT_BINDINGS_CLK_DRA7_ATL_H diff --git a/include/dt-bindings/pinctrl/hisi.h b/include/dt-bindings/pinctrl/hisi.h index 93064c750c8c..2175ec89c82f 100644 --- a/include/dt-bindings/pinctrl/hisi.h +++ b/include/dt-bindings/pinctrl/hisi.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This header provides constants for hisilicon pinctrl bindings. * * Copyright (c) 2015 HiSilicon Limited. * Copyright (c) 2015 Linaro Limited. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DT_BINDINGS_PINCTRL_HISI_H diff --git a/include/dt-bindings/pinctrl/keystone.h b/include/dt-bindings/pinctrl/keystone.h index 7f97d776a8ff..66f8aecada53 100644 --- a/include/dt-bindings/pinctrl/keystone.h +++ b/include/dt-bindings/pinctrl/keystone.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This header provides constants for Keystone pinctrl bindings. * * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef _DT_BINDINGS_PINCTRL_KEYSTONE_H diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index 3486f20a3753..cbfcbf186ce3 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h @@ -1,16 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI clock drivers support * * Copyright (C) 2013 Texas Instruments, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef __LINUX_CLK_TI_H__ #define __LINUX_CLK_TI_H__ diff --git a/include/linux/pm_wakeirq.h b/include/linux/pm_wakeirq.h index e63a63aa47a3..dd42d16945d0 100644 --- a/include/linux/pm_wakeirq.h +++ b/include/linux/pm_wakeirq.h @@ -1,15 +1,5 @@ -/* - * pm_wakeirq.h - Device wakeirq helper functions - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* pm_wakeirq.h - Device wakeirq helper functions */ #ifndef _LINUX_PM_WAKEIRQ_H #define _LINUX_PM_WAKEIRQ_H diff --git a/include/linux/soc/ti/ti-msgmgr.h b/include/linux/soc/ti/ti-msgmgr.h index 69a8d7682c4b..543da257a5f2 100644 --- a/include/linux/soc/ti/ti-msgmgr.h +++ b/include/linux/soc/ti/ti-msgmgr.h @@ -1,17 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Texas Instruments' Message Manager * * Copyright (C) 2015-2022 Texas Instruments Incorporated - https://www.ti.com/ * Nishanth Menon - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #ifndef TI_MSGMGR_H From fa82cce7a6bbb35ecf7fe66231c7076052cf66d5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:34 +0200 Subject: [PATCH 0281/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_385.RULE Based on the normalized pattern: licensed under the gpl v2 extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/sparc/vdso/vdso2c.c | 2 +- arch/x86/entry/vdso/vdso2c.c | 2 +- scripts/gcc-plugins/latent_entropy_plugin.c | 2 +- scripts/gcc-plugins/stackleak_plugin.c | 2 +- scripts/gcc-plugins/structleak_plugin.c | 2 +- tools/power/cpupower/debug/i386/dump_psb.c | 6 ++---- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/arch/sparc/vdso/vdso2c.c b/arch/sparc/vdso/vdso2c.c index ab7504176a7f..dc81240aab6f 100644 --- a/arch/sparc/vdso/vdso2c.c +++ b/arch/sparc/vdso/vdso2c.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vdso2c - A vdso image preparation tool * Copyright (c) 2014 Andy Lutomirski and others - * Licensed under the GPL v2 * * vdso2c requires stripped and unstripped input. It would be trivial * to fully strip the input in here, but, for reasons described below, diff --git a/arch/x86/entry/vdso/vdso2c.c b/arch/x86/entry/vdso/vdso2c.c index edfe9780f6d1..90d15f2a7205 100644 --- a/arch/x86/entry/vdso/vdso2c.c +++ b/arch/x86/entry/vdso/vdso2c.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * vdso2c - A vdso image preparation tool * Copyright (c) 2014 Andy Lutomirski and others - * Licensed under the GPL v2 * * vdso2c requires stripped and unstripped input. It would be trivial * to fully strip the input in here, but, for reasons described below, diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c index 848918764174..39e86be60dd2 100644 --- a/scripts/gcc-plugins/latent_entropy_plugin.c +++ b/scripts/gcc-plugins/latent_entropy_plugin.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2012-2016 by the PaX Team * Copyright 2016 by Emese Revfy - * Licensed under the GPL v2 * * Note: the choice of the license means that the compilation process is * NOT 'eligible' as defined by gcc's library exception to the GPL v3, diff --git a/scripts/gcc-plugins/stackleak_plugin.c b/scripts/gcc-plugins/stackleak_plugin.c index ff91885f9470..c5c2ce113c92 100644 --- a/scripts/gcc-plugins/stackleak_plugin.c +++ b/scripts/gcc-plugins/stackleak_plugin.c @@ -1,7 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2011-2017 by the PaX Team * Modified by Alexander Popov - * Licensed under the GPL v2 * * Note: the choice of the license means that the compilation process is * NOT 'eligible' as defined by gcc's library exception to the GPL v3, diff --git a/scripts/gcc-plugins/structleak_plugin.c b/scripts/gcc-plugins/structleak_plugin.c index 8bc04068ed39..d8c744233832 100644 --- a/scripts/gcc-plugins/structleak_plugin.c +++ b/scripts/gcc-plugins/structleak_plugin.c @@ -1,6 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright 2013-2017 by PaX Team - * Licensed under the GPL v2 * * Note: the choice of the license means that the compilation process is * NOT 'eligible' as defined by gcc's library exception to the GPL v3, diff --git a/tools/power/cpupower/debug/i386/dump_psb.c b/tools/power/cpupower/debug/i386/dump_psb.c index 2c768cf70128..6fb81b42ea61 100644 --- a/tools/power/cpupower/debug/i386/dump_psb.c +++ b/tools/power/cpupower/debug/i386/dump_psb.c @@ -1,7 +1,5 @@ -/* - * dump_psb. (c) 2004, Dave Jones, Red Hat Inc. - * Licensed under the GPL v2. - */ +// SPDX-License-Identifier: GPL-2.0-only +// dump_psb. (c) 2004, Dave Jones, Red Hat Inc. #include #include From 99c926cecdfd1200e1af4c5d7ade4fe4f4219116 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:35 +0200 Subject: [PATCH 0282/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_390.RULE Based on the normalized pattern: this software file (the file ) is distributed by marvell international ltd under the terms of the gnu general public license version 2 june 1991 (the license ) you may use redistribute and/or modify this file in accordance with the terms and conditions of the license a copy of which is available by writing to the free software foundation inc 51 franklin street fifth floor boston ma 02110-1301 usa or on the worldwide web at http://www gnu org/licenses/old-licenses/gpl-2 0 txt the file is distributed as-is without warranty of any kind and the implied warranties of merchantability or fitness for a particular purpose are expressly disclaimed the license provides additional details about this warranty disclaimer extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btmrvl_debugfs.c | 15 +-------------- drivers/bluetooth/btmrvl_drv.h | 16 +--------------- drivers/bluetooth/btmrvl_main.c | 15 +-------------- drivers/bluetooth/btmrvl_sdio.c | 15 +-------------- drivers/bluetooth/btmrvl_sdio.h | 16 +--------------- 5 files changed, 5 insertions(+), 72 deletions(-) diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index db35b917aecf..32329a2e526f 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell Bluetooth driver: debugfs related functions * * Copyright (C) 2009, Marvell International Ltd. - * - * This software file (the "File") is distributed by Marvell International - * Ltd. under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. **/ #include diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index fb7729779166..d7df05c56b28 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * Marvell Bluetooth driver: global definitions & declarations * * Copyright (C) 2009, Marvell International Ltd. - * - * This software file (the "File") is distributed by Marvell International - * Ltd. under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. - * */ #include diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 181338f60530..9658b33c824a 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell Bluetooth driver * * Copyright (C) 2009, Marvell International Ltd. - * - * This software file (the "File") is distributed by Marvell International - * Ltd. under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. **/ #include diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index b8ef66f89fc1..ba057ebfda5c 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1,21 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Marvell BT-over-SDIO driver: SDIO interface related functions. * * Copyright (C) 2009, Marvell International Ltd. - * - * This software file (the "File") is distributed by Marvell International - * Ltd. under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. **/ #include diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h index 3a522d23ee6e..72dd3b7d82aa 100644 --- a/drivers/bluetooth/btmrvl_sdio.h +++ b/drivers/bluetooth/btmrvl_sdio.h @@ -1,22 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /** * Marvell BT-over-SDIO driver: SDIO interface related definitions * * Copyright (C) 2009, Marvell International Ltd. - * - * This software file (the "File") is distributed by Marvell International - * Ltd. under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. - * **/ #define SDIO_HEADER_LEN 4 From 828c91f7937f62b0c60c86af63772c4161962e6a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:36 +0200 Subject: [PATCH 0283/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_391.RULE Based on the normalized pattern: this software file (the file ) is distributed by nxp under the terms of the gnu general public license version 2 june 1991 (the license ) you may use redistribute and/or modify this file in accordance with the terms and conditions of the license a copy of which is available by writing to the free software foundation inc 51 franklin street fifth floor boston ma 02110-1301 usa or on the worldwide web at http://www gnu org/licenses/old-licenses/gpl-2 0 txt the file is distributed as-is without warranty of any kind and the implied warranties of merchantability or fitness for a particular purpose are expressly disclaimed the license provides additional details about this warranty disclaimer extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/mwifiex/11ac.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/11ac.h | 14 +------------- drivers/net/wireless/marvell/mwifiex/11h.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/11n.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/11n.h | 14 +------------- .../net/wireless/marvell/mwifiex/11n_aggr.c | 14 +------------- .../net/wireless/marvell/mwifiex/11n_aggr.h | 14 +------------- .../wireless/marvell/mwifiex/11n_rxreorder.c | 14 +------------- .../wireless/marvell/mwifiex/11n_rxreorder.h | 14 +------------- drivers/net/wireless/marvell/mwifiex/Makefile | 13 +------------ .../net/wireless/marvell/mwifiex/cfg80211.c | 14 +------------- .../net/wireless/marvell/mwifiex/cfg80211.h | 14 +------------- drivers/net/wireless/marvell/mwifiex/cfp.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/cmdevt.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/debugfs.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/decl.h | 14 +------------- drivers/net/wireless/marvell/mwifiex/ethtool.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/fw.h | 14 +------------- drivers/net/wireless/marvell/mwifiex/ie.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/init.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/ioctl.h | 14 +------------- drivers/net/wireless/marvell/mwifiex/join.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/main.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/main.h | 14 +------------- drivers/net/wireless/marvell/mwifiex/pcie.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/pcie.h | 14 +------------- .../net/wireless/marvell/mwifiex/pcie_quirks.c | 18 ++---------------- .../net/wireless/marvell/mwifiex/pcie_quirks.h | 18 ++---------------- drivers/net/wireless/marvell/mwifiex/scan.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/sdio.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/sdio.h | 14 +------------- drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 14 +------------- .../net/wireless/marvell/mwifiex/sta_cmdresp.c | 14 +------------- .../net/wireless/marvell/mwifiex/sta_event.c | 14 +------------- .../net/wireless/marvell/mwifiex/sta_ioctl.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/sta_rx.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/sta_tx.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/txrx.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/uap_cmd.c | 14 +------------- .../net/wireless/marvell/mwifiex/uap_event.c | 14 +------------- .../net/wireless/marvell/mwifiex/uap_txrx.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/usb.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/usb.h | 14 +------------- drivers/net/wireless/marvell/mwifiex/util.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/util.h | 14 +------------- drivers/net/wireless/marvell/mwifiex/wmm.c | 14 +------------- drivers/net/wireless/marvell/mwifiex/wmm.h | 14 +------------- 47 files changed, 49 insertions(+), 616 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/11ac.c b/drivers/net/wireless/marvell/mwifiex/11ac.c index 756f019ef28a..b9278d996c56 100644 --- a/drivers/net/wireless/marvell/mwifiex/11ac.c +++ b/drivers/net/wireless/marvell/mwifiex/11ac.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: 802.11ac * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/11ac.h b/drivers/net/wireless/marvell/mwifiex/11ac.h index 29e83468cf3f..65a88d6d8b88 100644 --- a/drivers/net/wireless/marvell/mwifiex/11ac.h +++ b/drivers/net/wireless/marvell/mwifiex/11ac.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: 802.11ac * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_11AC_H_ diff --git a/drivers/net/wireless/marvell/mwifiex/11h.c b/drivers/net/wireless/marvell/mwifiex/11h.c index 3fa25cd64cda..74850a15f289 100644 --- a/drivers/net/wireless/marvell/mwifiex/11h.c +++ b/drivers/net/wireless/marvell/mwifiex/11h.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: 802.11h * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "main.h" diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c index 9ff2058bcd7e..4af57e6d4393 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.c +++ b/drivers/net/wireless/marvell/mwifiex/11n.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: 802.11n * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/11n.h b/drivers/net/wireless/marvell/mwifiex/11n.h index 83a88eecbda6..94b5e3e4ba08 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.h +++ b/drivers/net/wireless/marvell/mwifiex/11n.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: 802.11n * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_11N_H_ diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c index 46f41dbcf30d..34b4b34276d6 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: 802.11n Aggregation * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/11n_aggr.h b/drivers/net/wireless/marvell/mwifiex/11n_aggr.h index 382c1265c441..69b6888812f1 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_aggr.h +++ b/drivers/net/wireless/marvell/mwifiex/11n_aggr.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: 802.11n Aggregation * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_11N_AGGR_H_ diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index 1046b59647f5..bd835288ce57 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: 802.11n RX Re-ordering * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.h b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.h index 465f244b3636..c205a3bbc8b3 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.h +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: 802.11n RX Re-ordering * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_11N_RXREORDER_H_ diff --git a/drivers/net/wireless/marvell/mwifiex/Makefile b/drivers/net/wireless/marvell/mwifiex/Makefile index 2bd00f40958e..12d8affced18 100644 --- a/drivers/net/wireless/marvell/mwifiex/Makefile +++ b/drivers/net/wireless/marvell/mwifiex/Makefile @@ -1,18 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only # # Copyright 2011-2020 NXP # -# This software file (the "File") is distributed by NXP -# under the terms of the GNU General Public License Version 2, June 1991 -# (the "License"). You may use, redistribute and/or modify this File in -# accordance with the terms and conditions of the License, a copy of which -# is available by writing to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the -# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. -# -# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE -# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE -# ARE EXPRESSLY DISCLAIMED. The License provides additional details about -# this warranty disclaimer. mwifiex-y += main.o diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 6f23ec34e2e2..b78add863d4f 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: CFG80211 * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "cfg80211.h" diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.h b/drivers/net/wireless/marvell/mwifiex/cfg80211.h index 530a63f13f14..50f7001f5ef0 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.h +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: CFG80211 * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef __MWIFIEX_CFG80211__ diff --git a/drivers/net/wireless/marvell/mwifiex/cfp.c b/drivers/net/wireless/marvell/mwifiex/cfp.c index fb91ecfc5546..d39092b99212 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfp.c +++ b/drivers/net/wireless/marvell/mwifiex/cfp.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: Channel, Frequence and Power * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/cmdevt.c b/drivers/net/wireless/marvell/mwifiex/cmdevt.c index d6a61f850c6f..d3339d67e7a0 100644 --- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c +++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: commands and events * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include diff --git a/drivers/net/wireless/marvell/mwifiex/debugfs.c b/drivers/net/wireless/marvell/mwifiex/debugfs.c index dded92db1f37..bda53cb91f37 100644 --- a/drivers/net/wireless/marvell/mwifiex/debugfs.c +++ b/drivers/net/wireless/marvell/mwifiex/debugfs.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: debugfs * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include diff --git a/drivers/net/wireless/marvell/mwifiex/decl.h b/drivers/net/wireless/marvell/mwifiex/decl.h index 6bd23c9b1eed..88648c062713 100644 --- a/drivers/net/wireless/marvell/mwifiex/decl.h +++ b/drivers/net/wireless/marvell/mwifiex/decl.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: generic data structures and APIs * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_DECL_H_ diff --git a/drivers/net/wireless/marvell/mwifiex/ethtool.c b/drivers/net/wireless/marvell/mwifiex/ethtool.c index 9bdad3f59039..17c6e7fedfc4 100644 --- a/drivers/net/wireless/marvell/mwifiex/ethtool.c +++ b/drivers/net/wireless/marvell/mwifiex/ethtool.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: ethtool * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "main.h" diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 63c25c69ed2b..26a48d8f49be 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: Firmware specific macros & structures * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_FW_H_ diff --git a/drivers/net/wireless/marvell/mwifiex/ie.c b/drivers/net/wireless/marvell/mwifiex/ie.c index 40e99eaf5a30..26694cee15d3 100644 --- a/drivers/net/wireless/marvell/mwifiex/ie.c +++ b/drivers/net/wireless/marvell/mwifiex/ie.c @@ -1,21 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: management IE handling- setting and * deleting IE. * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "main.h" diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 88c72d1827a0..fc77489cc511 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: HW/FW Initialization * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/ioctl.h b/drivers/net/wireless/marvell/mwifiex/ioctl.h index 3db449efa167..091e7ca79376 100644 --- a/drivers/net/wireless/marvell/mwifiex/ioctl.h +++ b/drivers/net/wireless/marvell/mwifiex/ioctl.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: ioctl data structures & APIs * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_IOCTL_H_ diff --git a/drivers/net/wireless/marvell/mwifiex/join.c b/drivers/net/wireless/marvell/mwifiex/join.c index 173ccf79cbfc..a6e254a1185c 100644 --- a/drivers/net/wireless/marvell/mwifiex/join.c +++ b/drivers/net/wireless/marvell/mwifiex/join.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: association and ad-hoc start/join * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index ace7371c4773..da2e6557e684 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: major functions * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 332dd1c8db35..87729d251fed 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: major data structures and prototypes * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_MAIN_H_ diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index d5fb29400bad..20352039a5c3 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: PCIE specific handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h index 981e330c77d7..de901b3b59ad 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h @@ -1,22 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* @file mwifiex_pcie.h * * @brief This file contains definitions for PCI-E interface. * driver. * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_PCIE_H diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c index 0234cf3c2974..dd6d21f1dbfd 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c @@ -1,19 +1,5 @@ -/* - * NXP Wireless LAN device driver: PCIE and platform specific quirks - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. - */ +// SPDX-License-Identifier: GPL-2.0-only +// NXP Wireless LAN device driver: PCIE and platform specific quirks #include diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h index 8ec4176d698f..d6ff964aec5b 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h @@ -1,19 +1,5 @@ -/* - * NXP Wireless LAN device driver: PCIE and platform specific quirks - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* NXP Wireless LAN device driver: PCIE and platform specific quirks */ #include "pcie.h" diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 0b877f3f6b97..ac8001c84293 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: scan ioctl and command handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 76004bda0c02..1a886978ed5d 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: SDIO specific handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.h b/drivers/net/wireless/marvell/mwifiex/sdio.h index 28e8f76bdd58..3a24bb48b299 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.h +++ b/drivers/net/wireless/marvell/mwifiex/sdio.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: SDIO specific definitions * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_SDIO_H diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index 1e2798dce18f..9380d809bb44 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: station command handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c index 1a4ae8a42a31..7b69d27e0c0e 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: station command response handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index 7d42c5d2dbf6..b95e90a7d124 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: station event handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index 4062e515697a..a2ad2b53f016 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: functions for station ioctl * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/sta_rx.c b/drivers/net/wireless/marvell/mwifiex/sta_rx.c index 0d2adf887900..13659b02ba88 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_rx.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_rx.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: station RX data handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include diff --git a/drivers/net/wireless/marvell/mwifiex/sta_tx.c b/drivers/net/wireless/marvell/mwifiex/sta_tx.c index a9b5eb992220..13c0e67ededf 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_tx.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_tx.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: station TX data handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/txrx.c b/drivers/net/wireless/marvell/mwifiex/txrx.c index a8479b879382..54c204608dab 100644 --- a/drivers/net/wireless/marvell/mwifiex/txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/txrx.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: generic TX/RX data handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c index 630e1679c3f9..e78a201cd150 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: AP specific command handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "main.h" diff --git a/drivers/net/wireless/marvell/mwifiex/uap_event.c b/drivers/net/wireless/marvell/mwifiex/uap_event.c index 2e25d72dcac5..58ef5020a46a 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_event.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_event.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: AP event handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c index 4e49ed21c5ce..e495f7eaea03 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: AP TX and RX data handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/usb.c b/drivers/net/wireless/marvell/mwifiex/usb.c index 8f01fcbe9396..c2f2ce2a3f95 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.c +++ b/drivers/net/wireless/marvell/mwifiex/usb.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: USB specific handling * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "main.h" diff --git a/drivers/net/wireless/marvell/mwifiex/usb.h b/drivers/net/wireless/marvell/mwifiex/usb.h index 61a96b7fbf21..7e920b51994c 100644 --- a/drivers/net/wireless/marvell/mwifiex/usb.h +++ b/drivers/net/wireless/marvell/mwifiex/usb.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * This file contains definitions for mwifiex USB interface driver. * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_USB_H diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index d5edb1e89f5b..94c2d219835d 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: utility functions * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/util.h b/drivers/net/wireless/marvell/mwifiex/util.h index 44aa80eb7827..4699c505c0a0 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.h +++ b/drivers/net/wireless/marvell/mwifiex/util.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: utility functions * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_UTIL_H_ diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.c b/drivers/net/wireless/marvell/mwifiex/wmm.c index 0b375608df7d..00a5679b5c51 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.c +++ b/drivers/net/wireless/marvell/mwifiex/wmm.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * NXP Wireless LAN device driver: WMM * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #include "decl.h" diff --git a/drivers/net/wireless/marvell/mwifiex/wmm.h b/drivers/net/wireless/marvell/mwifiex/wmm.h index 1cb3d1804758..4f53a271dae0 100644 --- a/drivers/net/wireless/marvell/mwifiex/wmm.h +++ b/drivers/net/wireless/marvell/mwifiex/wmm.h @@ -1,20 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * NXP Wireless LAN device driver: WMM * * Copyright 2011-2020 NXP - * - * This software file (the "File") is distributed by NXP - * under the terms of the GNU General Public License Version 2, June 1991 - * (the "License"). You may use, redistribute and/or modify this File in - * accordance with the terms and conditions of the License, a copy of which - * is available by writing to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the - * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. - * - * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE - * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE - * ARE EXPRESSLY DISCLAIMED. The License provides additional details about - * this warranty disclaimer. */ #ifndef _MWIFIEX_WMM_H_ From 577b61cee5b2d91a50b633768d4a5a75fa5e36b6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:37 +0200 Subject: [PATCH 0284/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_398.RULE Based on the normalized pattern: this file is licensed under the terms of the gnu general public license version 2 this program as licensed as is without any warranty of any kind whether express or implied extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/kgdb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c index 9f8d0fa7b718..a20deebf233f 100644 --- a/arch/powerpc/kernel/kgdb.c +++ b/arch/powerpc/kernel/kgdb.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * PowerPC backend to the KGDB stub. * @@ -8,10 +9,6 @@ * PPC32 support restored by Vitaly Wool and * Sergei Shtylyov * Copyright (C) 2007-2008 Wind River Systems, Inc. - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program as licensed "as is" without any warranty of any - * kind, whether express or implied. */ #include From ce3f3ccc90b8207946a4eea45c4bd539e35cbe2c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Jun 2022 16:11:39 +0200 Subject: [PATCH 0285/1436] treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_406.RULE Based on the normalized pattern: this file is licensed under the term of the gnu general public license version 2 the program licensed as is without any warranty of any kind whether express or implied extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/dma/ppc4xx/dma.h | 5 +---- drivers/dma/ppc4xx/xor.h | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/dma/ppc4xx/dma.h b/drivers/dma/ppc4xx/dma.h index bcde2df2f373..1ff4be23db0f 100644 --- a/drivers/dma/ppc4xx/dma.h +++ b/drivers/dma/ppc4xx/dma.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * 440SPe's DMA engines support header file * * 2006-2009 (C) DENX Software Engineering. * * Author: Yuri Tikhonov - * - * This file is licensed under the term of the GNU General Public License - * version 2. The program licensed "as is" without any warranty of any - * kind, whether express or implied. */ #ifndef _PPC440SPE_DMA_H diff --git a/drivers/dma/ppc4xx/xor.h b/drivers/dma/ppc4xx/xor.h index daed7384daac..da1230df2817 100644 --- a/drivers/dma/ppc4xx/xor.h +++ b/drivers/dma/ppc4xx/xor.h @@ -1,13 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ /* * 440SPe's XOR engines support header file * * 2006-2009 (C) DENX Software Engineering. * * Author: Yuri Tikhonov - * - * This file is licensed under the term of the GNU General Public License - * version 2. The program licensed "as is" without any warranty of any - * kind, whether express or implied. */ #ifndef _PPC440SPE_XOR_H From 3493536142000805c1492a0d9d5b6c03a725711d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 6 Jun 2022 10:41:04 +0200 Subject: [PATCH 0286/1436] vme: remove ca91cx42 Universe-II support This is one of four remaining drivers using the ancient virt_to_bus() interface instead of the dma-mapping interface, making it incompatible with most modern machines. As nobody has cleaned this up, there is a high chance that this driver has no actual users. The chip was introduced in 1997 and only supports 32-bit legacy PCI. It was replaced by TSI148 in 2004, but that chip has since been discontinued, while a version of the older Universe II remains in production after 25 years. The vme_vmivme7805 board uses Universe-II, so this also gets removed in the process, but PCI add-on cards based on TSI148 can still work in theory. If there are users of the Universe-II driver after all, it is of course possible to revert this patch and fix it to use the dma-mapping interface like the tsi148 driver does. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20220606084109.4108188-2-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/vme/Kconfig | 2 - drivers/vme/Makefile | 1 - drivers/vme/boards/Kconfig | 10 - drivers/vme/boards/Makefile | 6 - drivers/vme/boards/vme_vmivme7805.c | 106 -- drivers/vme/boards/vme_vmivme7805.h | 33 - drivers/vme/bridges/Kconfig | 7 - drivers/vme/bridges/Makefile | 1 - drivers/vme/bridges/vme_ca91cx42.c | 1928 --------------------------- drivers/vme/bridges/vme_ca91cx42.h | 579 -------- 10 files changed, 2673 deletions(-) delete mode 100644 drivers/vme/boards/Kconfig delete mode 100644 drivers/vme/boards/Makefile delete mode 100644 drivers/vme/boards/vme_vmivme7805.c delete mode 100644 drivers/vme/boards/vme_vmivme7805.h delete mode 100644 drivers/vme/bridges/vme_ca91cx42.c delete mode 100644 drivers/vme/bridges/vme_ca91cx42.h diff --git a/drivers/vme/Kconfig b/drivers/vme/Kconfig index c13dd9d2a604..26feabba19d2 100644 --- a/drivers/vme/Kconfig +++ b/drivers/vme/Kconfig @@ -13,6 +13,4 @@ if VME_BUS source "drivers/vme/bridges/Kconfig" -source "drivers/vme/boards/Kconfig" - endif # VME diff --git a/drivers/vme/Makefile b/drivers/vme/Makefile index 8bfe4b370c41..2dfb929a23de 100644 --- a/drivers/vme/Makefile +++ b/drivers/vme/Makefile @@ -5,4 +5,3 @@ obj-$(CONFIG_VME_BUS) += vme.o obj-y += bridges/ -obj-y += boards/ diff --git a/drivers/vme/boards/Kconfig b/drivers/vme/boards/Kconfig deleted file mode 100644 index 7a255f72980b..000000000000 --- a/drivers/vme/boards/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -comment "VME Board Drivers" - -config VMIVME_7805 - tristate "VMIVME-7805" - help - If you say Y here you get support for the VMIVME-7805 board. - This board has an additional control interface to the Universe II - chip. This driver has to be included if you want to access VME bus - with VMIVME-7805 board. diff --git a/drivers/vme/boards/Makefile b/drivers/vme/boards/Makefile deleted file mode 100644 index 87122381452c..000000000000 --- a/drivers/vme/boards/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the VME board drivers. -# - -obj-$(CONFIG_VMIVME_7805) += vme_vmivme7805.o diff --git a/drivers/vme/boards/vme_vmivme7805.c b/drivers/vme/boards/vme_vmivme7805.c deleted file mode 100644 index 51e056bae943..000000000000 --- a/drivers/vme/boards/vme_vmivme7805.c +++ /dev/null @@ -1,106 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Support for the VMIVME-7805 board access to the Universe II bridge. - * - * Author: Arthur Benilov - * Copyright 2010 Ion Beam Application, Inc. - */ - -#include -#include -#include -#include -#include -#include - -#include "vme_vmivme7805.h" - -static int vmic_probe(struct pci_dev *, const struct pci_device_id *); -static void vmic_remove(struct pci_dev *); - -/** Base address to access FPGA register */ -static void __iomem *vmic_base; - -static const char driver_name[] = "vmivme_7805"; - -static const struct pci_device_id vmic_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_VMIC, PCI_DEVICE_ID_VTIMR) }, - { }, -}; - -static struct pci_driver vmic_driver = { - .name = driver_name, - .id_table = vmic_ids, - .probe = vmic_probe, - .remove = vmic_remove, -}; - -static int vmic_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - int retval; - u32 data; - - /* Enable the device */ - retval = pci_enable_device(pdev); - if (retval) { - dev_err(&pdev->dev, "Unable to enable device\n"); - goto err; - } - - /* Map Registers */ - retval = pci_request_regions(pdev, driver_name); - if (retval) { - dev_err(&pdev->dev, "Unable to reserve resources\n"); - goto err_resource; - } - - /* Map registers in BAR 0 */ - vmic_base = ioremap(pci_resource_start(pdev, 0), 16); - if (!vmic_base) { - dev_err(&pdev->dev, "Unable to remap CRG region\n"); - retval = -EIO; - goto err_remap; - } - - /* Clear the FPGA VME IF contents */ - iowrite32(0, vmic_base + VME_CONTROL); - - /* Clear any initial BERR */ - data = ioread32(vmic_base + VME_CONTROL) & 0x00000FFF; - data |= BM_VME_CONTROL_BERRST; - iowrite32(data, vmic_base + VME_CONTROL); - - /* Enable the vme interface and byte swapping */ - data = ioread32(vmic_base + VME_CONTROL) & 0x00000FFF; - data = data | BM_VME_CONTROL_MASTER_ENDIAN | - BM_VME_CONTROL_SLAVE_ENDIAN | - BM_VME_CONTROL_ABLE | - BM_VME_CONTROL_BERRI | - BM_VME_CONTROL_BPENA | - BM_VME_CONTROL_VBENA; - iowrite32(data, vmic_base + VME_CONTROL); - - return 0; - -err_remap: - pci_release_regions(pdev); -err_resource: - pci_disable_device(pdev); -err: - return retval; -} - -static void vmic_remove(struct pci_dev *pdev) -{ - iounmap(vmic_base); - pci_release_regions(pdev); - pci_disable_device(pdev); - -} - -module_pci_driver(vmic_driver); - -MODULE_DESCRIPTION("VMIVME-7805 board support driver"); -MODULE_AUTHOR("Arthur Benilov "); -MODULE_LICENSE("GPL"); - diff --git a/drivers/vme/boards/vme_vmivme7805.h b/drivers/vme/boards/vme_vmivme7805.h deleted file mode 100644 index c2c5e3053d3f..000000000000 --- a/drivers/vme/boards/vme_vmivme7805.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * vmivme_7805.h - * - * Support for the VMIVME-7805 board access to the Universe II bridge. - * - * Author: Arthur Benilov - * Copyright 2010 Ion Beam Application, Inc. - */ - - -#ifndef _VMIVME_7805_H -#define _VMIVME_7805_H - -#ifndef PCI_VENDOR_ID_VMIC -#define PCI_VENDOR_ID_VMIC 0x114A -#endif - -#ifndef PCI_DEVICE_ID_VTIMR -#define PCI_DEVICE_ID_VTIMR 0x0004 -#endif - -#define VME_CONTROL 0x0000 -#define BM_VME_CONTROL_MASTER_ENDIAN 0x0001 -#define BM_VME_CONTROL_SLAVE_ENDIAN 0x0002 -#define BM_VME_CONTROL_ABLE 0x0004 -#define BM_VME_CONTROL_BERRI 0x0040 -#define BM_VME_CONTROL_BERRST 0x0080 -#define BM_VME_CONTROL_BPENA 0x0400 -#define BM_VME_CONTROL_VBENA 0x0800 - -#endif /* _VMIVME_7805_H */ - diff --git a/drivers/vme/bridges/Kconfig b/drivers/vme/bridges/Kconfig index cb3baed64914..9493b22b5276 100644 --- a/drivers/vme/bridges/Kconfig +++ b/drivers/vme/bridges/Kconfig @@ -1,13 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only comment "VME Bridge Drivers" -config VME_CA91CX42 - tristate "Universe II" - depends on VIRT_TO_BUS - help - If you say Y here you get support for the Tundra CA91C142 - (Universe II) VME bridge chip. - config VME_TSI148 tristate "Tempe" depends on HAS_DMA diff --git a/drivers/vme/bridges/Makefile b/drivers/vme/bridges/Makefile index 0a6cf843438a..043f9cd7a510 100644 --- a/drivers/vme/bridges/Makefile +++ b/drivers/vme/bridges/Makefile @@ -1,4 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VME_CA91CX42) += vme_ca91cx42.o obj-$(CONFIG_VME_TSI148) += vme_tsi148.o obj-$(CONFIG_VME_FAKE) += vme_fake.o diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c deleted file mode 100644 index 439b0edeca08..000000000000 --- a/drivers/vme/bridges/vme_ca91cx42.c +++ /dev/null @@ -1,1928 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Support for the Tundra Universe I/II VME-PCI Bridge Chips - * - * Author: Martyn Welch - * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc. - * - * Based on work by Tom Armistead and Ajit Prem - * Copyright 2004 Motorola Inc. - * - * Derived from ca91c042.c by Michael Wyrick - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../vme_bridge.h" -#include "vme_ca91cx42.h" - -static int ca91cx42_probe(struct pci_dev *, const struct pci_device_id *); -static void ca91cx42_remove(struct pci_dev *); - -/* Module parameters */ -static int geoid; - -static const char driver_name[] = "vme_ca91cx42"; - -static const struct pci_device_id ca91cx42_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C142) }, - { }, -}; - -MODULE_DEVICE_TABLE(pci, ca91cx42_ids); - -static struct pci_driver ca91cx42_driver = { - .name = driver_name, - .id_table = ca91cx42_ids, - .probe = ca91cx42_probe, - .remove = ca91cx42_remove, -}; - -static u32 ca91cx42_DMA_irqhandler(struct ca91cx42_driver *bridge) -{ - wake_up(&bridge->dma_queue); - - return CA91CX42_LINT_DMA; -} - -static u32 ca91cx42_LM_irqhandler(struct ca91cx42_driver *bridge, u32 stat) -{ - int i; - u32 serviced = 0; - - for (i = 0; i < 4; i++) { - if (stat & CA91CX42_LINT_LM[i]) { - /* We only enable interrupts if the callback is set */ - bridge->lm_callback[i](bridge->lm_data[i]); - serviced |= CA91CX42_LINT_LM[i]; - } - } - - return serviced; -} - -/* XXX This needs to be split into 4 queues */ -static u32 ca91cx42_MB_irqhandler(struct ca91cx42_driver *bridge, int mbox_mask) -{ - wake_up(&bridge->mbox_queue); - - return CA91CX42_LINT_MBOX; -} - -static u32 ca91cx42_IACK_irqhandler(struct ca91cx42_driver *bridge) -{ - wake_up(&bridge->iack_queue); - - return CA91CX42_LINT_SW_IACK; -} - -static u32 ca91cx42_VERR_irqhandler(struct vme_bridge *ca91cx42_bridge) -{ - int val; - struct ca91cx42_driver *bridge; - - bridge = ca91cx42_bridge->driver_priv; - - val = ioread32(bridge->base + DGCS); - - if (!(val & 0x00000800)) { - dev_err(ca91cx42_bridge->parent, "ca91cx42_VERR_irqhandler DMA " - "Read Error DGCS=%08X\n", val); - } - - return CA91CX42_LINT_VERR; -} - -static u32 ca91cx42_LERR_irqhandler(struct vme_bridge *ca91cx42_bridge) -{ - int val; - struct ca91cx42_driver *bridge; - - bridge = ca91cx42_bridge->driver_priv; - - val = ioread32(bridge->base + DGCS); - - if (!(val & 0x00000800)) - dev_err(ca91cx42_bridge->parent, "ca91cx42_LERR_irqhandler DMA " - "Read Error DGCS=%08X\n", val); - - return CA91CX42_LINT_LERR; -} - - -static u32 ca91cx42_VIRQ_irqhandler(struct vme_bridge *ca91cx42_bridge, - int stat) -{ - int vec, i, serviced = 0; - struct ca91cx42_driver *bridge; - - bridge = ca91cx42_bridge->driver_priv; - - - for (i = 7; i > 0; i--) { - if (stat & (1 << i)) { - vec = ioread32(bridge->base + - CA91CX42_V_STATID[i]) & 0xff; - - vme_irq_handler(ca91cx42_bridge, i, vec); - - serviced |= (1 << i); - } - } - - return serviced; -} - -static irqreturn_t ca91cx42_irqhandler(int irq, void *ptr) -{ - u32 stat, enable, serviced = 0; - struct vme_bridge *ca91cx42_bridge; - struct ca91cx42_driver *bridge; - - ca91cx42_bridge = ptr; - - bridge = ca91cx42_bridge->driver_priv; - - enable = ioread32(bridge->base + LINT_EN); - stat = ioread32(bridge->base + LINT_STAT); - - /* Only look at unmasked interrupts */ - stat &= enable; - - if (unlikely(!stat)) - return IRQ_NONE; - - if (stat & CA91CX42_LINT_DMA) - serviced |= ca91cx42_DMA_irqhandler(bridge); - if (stat & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 | - CA91CX42_LINT_LM3)) - serviced |= ca91cx42_LM_irqhandler(bridge, stat); - if (stat & CA91CX42_LINT_MBOX) - serviced |= ca91cx42_MB_irqhandler(bridge, stat); - if (stat & CA91CX42_LINT_SW_IACK) - serviced |= ca91cx42_IACK_irqhandler(bridge); - if (stat & CA91CX42_LINT_VERR) - serviced |= ca91cx42_VERR_irqhandler(ca91cx42_bridge); - if (stat & CA91CX42_LINT_LERR) - serviced |= ca91cx42_LERR_irqhandler(ca91cx42_bridge); - if (stat & (CA91CX42_LINT_VIRQ1 | CA91CX42_LINT_VIRQ2 | - CA91CX42_LINT_VIRQ3 | CA91CX42_LINT_VIRQ4 | - CA91CX42_LINT_VIRQ5 | CA91CX42_LINT_VIRQ6 | - CA91CX42_LINT_VIRQ7)) - serviced |= ca91cx42_VIRQ_irqhandler(ca91cx42_bridge, stat); - - /* Clear serviced interrupts */ - iowrite32(serviced, bridge->base + LINT_STAT); - - return IRQ_HANDLED; -} - -static int ca91cx42_irq_init(struct vme_bridge *ca91cx42_bridge) -{ - int result, tmp; - struct pci_dev *pdev; - struct ca91cx42_driver *bridge; - - bridge = ca91cx42_bridge->driver_priv; - - /* Need pdev */ - pdev = to_pci_dev(ca91cx42_bridge->parent); - - /* Disable interrupts from PCI to VME */ - iowrite32(0, bridge->base + VINT_EN); - - /* Disable PCI interrupts */ - iowrite32(0, bridge->base + LINT_EN); - /* Clear Any Pending PCI Interrupts */ - iowrite32(0x00FFFFFF, bridge->base + LINT_STAT); - - result = request_irq(pdev->irq, ca91cx42_irqhandler, IRQF_SHARED, - driver_name, ca91cx42_bridge); - if (result) { - dev_err(&pdev->dev, "Can't get assigned pci irq vector %02X\n", - pdev->irq); - return result; - } - - /* Ensure all interrupts are mapped to PCI Interrupt 0 */ - iowrite32(0, bridge->base + LINT_MAP0); - iowrite32(0, bridge->base + LINT_MAP1); - iowrite32(0, bridge->base + LINT_MAP2); - - /* Enable DMA, mailbox & LM Interrupts */ - tmp = CA91CX42_LINT_MBOX3 | CA91CX42_LINT_MBOX2 | CA91CX42_LINT_MBOX1 | - CA91CX42_LINT_MBOX0 | CA91CX42_LINT_SW_IACK | - CA91CX42_LINT_VERR | CA91CX42_LINT_LERR | CA91CX42_LINT_DMA; - - iowrite32(tmp, bridge->base + LINT_EN); - - return 0; -} - -static void ca91cx42_irq_exit(struct ca91cx42_driver *bridge, - struct pci_dev *pdev) -{ - struct vme_bridge *ca91cx42_bridge; - - /* Disable interrupts from PCI to VME */ - iowrite32(0, bridge->base + VINT_EN); - - /* Disable PCI interrupts */ - iowrite32(0, bridge->base + LINT_EN); - /* Clear Any Pending PCI Interrupts */ - iowrite32(0x00FFFFFF, bridge->base + LINT_STAT); - - ca91cx42_bridge = container_of((void *)bridge, struct vme_bridge, - driver_priv); - free_irq(pdev->irq, ca91cx42_bridge); -} - -static int ca91cx42_iack_received(struct ca91cx42_driver *bridge, int level) -{ - u32 tmp; - - tmp = ioread32(bridge->base + LINT_STAT); - - if (tmp & (1 << level)) - return 0; - else - return 1; -} - -/* - * Set up an VME interrupt - */ -static void ca91cx42_irq_set(struct vme_bridge *ca91cx42_bridge, int level, - int state, int sync) - -{ - struct pci_dev *pdev; - u32 tmp; - struct ca91cx42_driver *bridge; - - bridge = ca91cx42_bridge->driver_priv; - - /* Enable IRQ level */ - tmp = ioread32(bridge->base + LINT_EN); - - if (state == 0) - tmp &= ~CA91CX42_LINT_VIRQ[level]; - else - tmp |= CA91CX42_LINT_VIRQ[level]; - - iowrite32(tmp, bridge->base + LINT_EN); - - if ((state == 0) && (sync != 0)) { - pdev = to_pci_dev(ca91cx42_bridge->parent); - - synchronize_irq(pdev->irq); - } -} - -static int ca91cx42_irq_generate(struct vme_bridge *ca91cx42_bridge, int level, - int statid) -{ - u32 tmp; - struct ca91cx42_driver *bridge; - - bridge = ca91cx42_bridge->driver_priv; - - /* Universe can only generate even vectors */ - if (statid & 1) - return -EINVAL; - - mutex_lock(&bridge->vme_int); - - tmp = ioread32(bridge->base + VINT_EN); - - /* Set Status/ID */ - iowrite32(statid << 24, bridge->base + STATID); - - /* Assert VMEbus IRQ */ - tmp = tmp | (1 << (level + 24)); - iowrite32(tmp, bridge->base + VINT_EN); - - /* Wait for IACK */ - wait_event_interruptible(bridge->iack_queue, - ca91cx42_iack_received(bridge, level)); - - /* Return interrupt to low state */ - tmp = ioread32(bridge->base + VINT_EN); - tmp = tmp & ~(1 << (level + 24)); - iowrite32(tmp, bridge->base + VINT_EN); - - mutex_unlock(&bridge->vme_int); - - return 0; -} - -static int ca91cx42_slave_set(struct vme_slave_resource *image, int enabled, - unsigned long long vme_base, unsigned long long size, - dma_addr_t pci_base, u32 aspace, u32 cycle) -{ - unsigned int i, addr = 0, granularity; - unsigned int temp_ctl = 0; - unsigned int vme_bound, pci_offset; - struct vme_bridge *ca91cx42_bridge; - struct ca91cx42_driver *bridge; - - ca91cx42_bridge = image->parent; - - bridge = ca91cx42_bridge->driver_priv; - - i = image->number; - - switch (aspace) { - case VME_A16: - addr |= CA91CX42_VSI_CTL_VAS_A16; - break; - case VME_A24: - addr |= CA91CX42_VSI_CTL_VAS_A24; - break; - case VME_A32: - addr |= CA91CX42_VSI_CTL_VAS_A32; - break; - case VME_USER1: - addr |= CA91CX42_VSI_CTL_VAS_USER1; - break; - case VME_USER2: - addr |= CA91CX42_VSI_CTL_VAS_USER2; - break; - case VME_A64: - case VME_CRCSR: - case VME_USER3: - case VME_USER4: - default: - dev_err(ca91cx42_bridge->parent, "Invalid address space\n"); - return -EINVAL; - break; - } - - /* - * Bound address is a valid address for the window, adjust - * accordingly - */ - vme_bound = vme_base + size; - pci_offset = pci_base - vme_base; - - if ((i == 0) || (i == 4)) - granularity = 0x1000; - else - granularity = 0x10000; - - if (vme_base & (granularity - 1)) { - dev_err(ca91cx42_bridge->parent, "Invalid VME base " - "alignment\n"); - return -EINVAL; - } - if (vme_bound & (granularity - 1)) { - dev_err(ca91cx42_bridge->parent, "Invalid VME bound " - "alignment\n"); - return -EINVAL; - } - if (pci_offset & (granularity - 1)) { - dev_err(ca91cx42_bridge->parent, "Invalid PCI Offset " - "alignment\n"); - return -EINVAL; - } - - /* Disable while we are mucking around */ - temp_ctl = ioread32(bridge->base + CA91CX42_VSI_CTL[i]); - temp_ctl &= ~CA91CX42_VSI_CTL_EN; - iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]); - - /* Setup mapping */ - iowrite32(vme_base, bridge->base + CA91CX42_VSI_BS[i]); - iowrite32(vme_bound, bridge->base + CA91CX42_VSI_BD[i]); - iowrite32(pci_offset, bridge->base + CA91CX42_VSI_TO[i]); - - /* Setup address space */ - temp_ctl &= ~CA91CX42_VSI_CTL_VAS_M; - temp_ctl |= addr; - - /* Setup cycle types */ - temp_ctl &= ~(CA91CX42_VSI_CTL_PGM_M | CA91CX42_VSI_CTL_SUPER_M); - if (cycle & VME_SUPER) - temp_ctl |= CA91CX42_VSI_CTL_SUPER_SUPR; - if (cycle & VME_USER) - temp_ctl |= CA91CX42_VSI_CTL_SUPER_NPRIV; - if (cycle & VME_PROG) - temp_ctl |= CA91CX42_VSI_CTL_PGM_PGM; - if (cycle & VME_DATA) - temp_ctl |= CA91CX42_VSI_CTL_PGM_DATA; - - /* Write ctl reg without enable */ - iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]); - - if (enabled) - temp_ctl |= CA91CX42_VSI_CTL_EN; - - iowrite32(temp_ctl, bridge->base + CA91CX42_VSI_CTL[i]); - - return 0; -} - -static int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, - dma_addr_t *pci_base, u32 *aspace, u32 *cycle) -{ - unsigned int i, granularity = 0, ctl = 0; - unsigned long long vme_bound, pci_offset; - struct ca91cx42_driver *bridge; - - bridge = image->parent->driver_priv; - - i = image->number; - - if ((i == 0) || (i == 4)) - granularity = 0x1000; - else - granularity = 0x10000; - - /* Read Registers */ - ctl = ioread32(bridge->base + CA91CX42_VSI_CTL[i]); - - *vme_base = ioread32(bridge->base + CA91CX42_VSI_BS[i]); - vme_bound = ioread32(bridge->base + CA91CX42_VSI_BD[i]); - pci_offset = ioread32(bridge->base + CA91CX42_VSI_TO[i]); - - *pci_base = (dma_addr_t)*vme_base + pci_offset; - *size = (unsigned long long)((vme_bound - *vme_base) + granularity); - - *enabled = 0; - *aspace = 0; - *cycle = 0; - - if (ctl & CA91CX42_VSI_CTL_EN) - *enabled = 1; - - if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A16) - *aspace = VME_A16; - if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A24) - *aspace = VME_A24; - if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_A32) - *aspace = VME_A32; - if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_USER1) - *aspace = VME_USER1; - if ((ctl & CA91CX42_VSI_CTL_VAS_M) == CA91CX42_VSI_CTL_VAS_USER2) - *aspace = VME_USER2; - - if (ctl & CA91CX42_VSI_CTL_SUPER_SUPR) - *cycle |= VME_SUPER; - if (ctl & CA91CX42_VSI_CTL_SUPER_NPRIV) - *cycle |= VME_USER; - if (ctl & CA91CX42_VSI_CTL_PGM_PGM) - *cycle |= VME_PROG; - if (ctl & CA91CX42_VSI_CTL_PGM_DATA) - *cycle |= VME_DATA; - - return 0; -} - -/* - * Allocate and map PCI Resource - */ -static int ca91cx42_alloc_resource(struct vme_master_resource *image, - unsigned long long size) -{ - unsigned long long existing_size; - int retval = 0; - struct pci_dev *pdev; - struct vme_bridge *ca91cx42_bridge; - - ca91cx42_bridge = image->parent; - - /* Find pci_dev container of dev */ - if (!ca91cx42_bridge->parent) { - dev_err(ca91cx42_bridge->parent, "Dev entry NULL\n"); - return -EINVAL; - } - pdev = to_pci_dev(ca91cx42_bridge->parent); - - existing_size = (unsigned long long)(image->bus_resource.end - - image->bus_resource.start); - - /* If the existing size is OK, return */ - if (existing_size == (size - 1)) - return 0; - - if (existing_size != 0) { - iounmap(image->kern_base); - image->kern_base = NULL; - kfree(image->bus_resource.name); - release_resource(&image->bus_resource); - memset(&image->bus_resource, 0, sizeof(image->bus_resource)); - } - - if (!image->bus_resource.name) { - image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC); - if (!image->bus_resource.name) { - retval = -ENOMEM; - goto err_name; - } - } - - sprintf((char *)image->bus_resource.name, "%s.%d", - ca91cx42_bridge->name, image->number); - - image->bus_resource.start = 0; - image->bus_resource.end = (unsigned long)size; - image->bus_resource.flags = IORESOURCE_MEM; - - retval = pci_bus_alloc_resource(pdev->bus, - &image->bus_resource, size, 0x10000, PCIBIOS_MIN_MEM, - 0, NULL, NULL); - if (retval) { - dev_err(ca91cx42_bridge->parent, "Failed to allocate mem " - "resource for window %d size 0x%lx start 0x%lx\n", - image->number, (unsigned long)size, - (unsigned long)image->bus_resource.start); - goto err_resource; - } - - image->kern_base = ioremap( - image->bus_resource.start, size); - if (!image->kern_base) { - dev_err(ca91cx42_bridge->parent, "Failed to remap resource\n"); - retval = -ENOMEM; - goto err_remap; - } - - return 0; - -err_remap: - release_resource(&image->bus_resource); -err_resource: - kfree(image->bus_resource.name); - memset(&image->bus_resource, 0, sizeof(image->bus_resource)); -err_name: - return retval; -} - -/* - * Free and unmap PCI Resource - */ -static void ca91cx42_free_resource(struct vme_master_resource *image) -{ - iounmap(image->kern_base); - image->kern_base = NULL; - release_resource(&image->bus_resource); - kfree(image->bus_resource.name); - memset(&image->bus_resource, 0, sizeof(image->bus_resource)); -} - - -static int ca91cx42_master_set(struct vme_master_resource *image, int enabled, - unsigned long long vme_base, unsigned long long size, u32 aspace, - u32 cycle, u32 dwidth) -{ - int retval = 0; - unsigned int i, granularity = 0; - unsigned int temp_ctl = 0; - unsigned long long pci_bound, vme_offset, pci_base; - struct vme_bridge *ca91cx42_bridge; - struct ca91cx42_driver *bridge; - - ca91cx42_bridge = image->parent; - - bridge = ca91cx42_bridge->driver_priv; - - i = image->number; - - if ((i == 0) || (i == 4)) - granularity = 0x1000; - else - granularity = 0x10000; - - /* Verify input data */ - if (vme_base & (granularity - 1)) { - dev_err(ca91cx42_bridge->parent, "Invalid VME Window " - "alignment\n"); - retval = -EINVAL; - goto err_window; - } - if (size & (granularity - 1)) { - dev_err(ca91cx42_bridge->parent, "Invalid VME Window " - "alignment\n"); - retval = -EINVAL; - goto err_window; - } - - spin_lock(&image->lock); - - /* - * Let's allocate the resource here rather than further up the stack as - * it avoids pushing loads of bus dependent stuff up the stack - */ - retval = ca91cx42_alloc_resource(image, size); - if (retval) { - spin_unlock(&image->lock); - dev_err(ca91cx42_bridge->parent, "Unable to allocate memory " - "for resource name\n"); - retval = -ENOMEM; - goto err_res; - } - - pci_base = (unsigned long long)image->bus_resource.start; - - /* - * Bound address is a valid address for the window, adjust - * according to window granularity. - */ - pci_bound = pci_base + size; - vme_offset = vme_base - pci_base; - - /* Disable while we are mucking around */ - temp_ctl = ioread32(bridge->base + CA91CX42_LSI_CTL[i]); - temp_ctl &= ~CA91CX42_LSI_CTL_EN; - iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]); - - /* Setup cycle types */ - temp_ctl &= ~CA91CX42_LSI_CTL_VCT_M; - if (cycle & VME_BLT) - temp_ctl |= CA91CX42_LSI_CTL_VCT_BLT; - if (cycle & VME_MBLT) - temp_ctl |= CA91CX42_LSI_CTL_VCT_MBLT; - - /* Setup data width */ - temp_ctl &= ~CA91CX42_LSI_CTL_VDW_M; - switch (dwidth) { - case VME_D8: - temp_ctl |= CA91CX42_LSI_CTL_VDW_D8; - break; - case VME_D16: - temp_ctl |= CA91CX42_LSI_CTL_VDW_D16; - break; - case VME_D32: - temp_ctl |= CA91CX42_LSI_CTL_VDW_D32; - break; - case VME_D64: - temp_ctl |= CA91CX42_LSI_CTL_VDW_D64; - break; - default: - spin_unlock(&image->lock); - dev_err(ca91cx42_bridge->parent, "Invalid data width\n"); - retval = -EINVAL; - goto err_dwidth; - break; - } - - /* Setup address space */ - temp_ctl &= ~CA91CX42_LSI_CTL_VAS_M; - switch (aspace) { - case VME_A16: - temp_ctl |= CA91CX42_LSI_CTL_VAS_A16; - break; - case VME_A24: - temp_ctl |= CA91CX42_LSI_CTL_VAS_A24; - break; - case VME_A32: - temp_ctl |= CA91CX42_LSI_CTL_VAS_A32; - break; - case VME_CRCSR: - temp_ctl |= CA91CX42_LSI_CTL_VAS_CRCSR; - break; - case VME_USER1: - temp_ctl |= CA91CX42_LSI_CTL_VAS_USER1; - break; - case VME_USER2: - temp_ctl |= CA91CX42_LSI_CTL_VAS_USER2; - break; - case VME_A64: - case VME_USER3: - case VME_USER4: - default: - spin_unlock(&image->lock); - dev_err(ca91cx42_bridge->parent, "Invalid address space\n"); - retval = -EINVAL; - goto err_aspace; - break; - } - - temp_ctl &= ~(CA91CX42_LSI_CTL_PGM_M | CA91CX42_LSI_CTL_SUPER_M); - if (cycle & VME_SUPER) - temp_ctl |= CA91CX42_LSI_CTL_SUPER_SUPR; - if (cycle & VME_PROG) - temp_ctl |= CA91CX42_LSI_CTL_PGM_PGM; - - /* Setup mapping */ - iowrite32(pci_base, bridge->base + CA91CX42_LSI_BS[i]); - iowrite32(pci_bound, bridge->base + CA91CX42_LSI_BD[i]); - iowrite32(vme_offset, bridge->base + CA91CX42_LSI_TO[i]); - - /* Write ctl reg without enable */ - iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]); - - if (enabled) - temp_ctl |= CA91CX42_LSI_CTL_EN; - - iowrite32(temp_ctl, bridge->base + CA91CX42_LSI_CTL[i]); - - spin_unlock(&image->lock); - return 0; - -err_aspace: -err_dwidth: - ca91cx42_free_resource(image); -err_res: -err_window: - return retval; -} - -static int __ca91cx42_master_get(struct vme_master_resource *image, - int *enabled, unsigned long long *vme_base, unsigned long long *size, - u32 *aspace, u32 *cycle, u32 *dwidth) -{ - unsigned int i, ctl; - unsigned long long pci_base, pci_bound, vme_offset; - struct ca91cx42_driver *bridge; - - bridge = image->parent->driver_priv; - - i = image->number; - - ctl = ioread32(bridge->base + CA91CX42_LSI_CTL[i]); - - pci_base = ioread32(bridge->base + CA91CX42_LSI_BS[i]); - vme_offset = ioread32(bridge->base + CA91CX42_LSI_TO[i]); - pci_bound = ioread32(bridge->base + CA91CX42_LSI_BD[i]); - - *vme_base = pci_base + vme_offset; - *size = (unsigned long long)(pci_bound - pci_base); - - *enabled = 0; - *aspace = 0; - *cycle = 0; - *dwidth = 0; - - if (ctl & CA91CX42_LSI_CTL_EN) - *enabled = 1; - - /* Setup address space */ - switch (ctl & CA91CX42_LSI_CTL_VAS_M) { - case CA91CX42_LSI_CTL_VAS_A16: - *aspace = VME_A16; - break; - case CA91CX42_LSI_CTL_VAS_A24: - *aspace = VME_A24; - break; - case CA91CX42_LSI_CTL_VAS_A32: - *aspace = VME_A32; - break; - case CA91CX42_LSI_CTL_VAS_CRCSR: - *aspace = VME_CRCSR; - break; - case CA91CX42_LSI_CTL_VAS_USER1: - *aspace = VME_USER1; - break; - case CA91CX42_LSI_CTL_VAS_USER2: - *aspace = VME_USER2; - break; - } - - /* XXX Not sure howto check for MBLT */ - /* Setup cycle types */ - if (ctl & CA91CX42_LSI_CTL_VCT_BLT) - *cycle |= VME_BLT; - else - *cycle |= VME_SCT; - - if (ctl & CA91CX42_LSI_CTL_SUPER_SUPR) - *cycle |= VME_SUPER; - else - *cycle |= VME_USER; - - if (ctl & CA91CX42_LSI_CTL_PGM_PGM) - *cycle = VME_PROG; - else - *cycle = VME_DATA; - - /* Setup data width */ - switch (ctl & CA91CX42_LSI_CTL_VDW_M) { - case CA91CX42_LSI_CTL_VDW_D8: - *dwidth = VME_D8; - break; - case CA91CX42_LSI_CTL_VDW_D16: - *dwidth = VME_D16; - break; - case CA91CX42_LSI_CTL_VDW_D32: - *dwidth = VME_D32; - break; - case CA91CX42_LSI_CTL_VDW_D64: - *dwidth = VME_D64; - break; - } - - return 0; -} - -static int ca91cx42_master_get(struct vme_master_resource *image, int *enabled, - unsigned long long *vme_base, unsigned long long *size, u32 *aspace, - u32 *cycle, u32 *dwidth) -{ - int retval; - - spin_lock(&image->lock); - - retval = __ca91cx42_master_get(image, enabled, vme_base, size, aspace, - cycle, dwidth); - - spin_unlock(&image->lock); - - return retval; -} - -static ssize_t ca91cx42_master_read(struct vme_master_resource *image, - void *buf, size_t count, loff_t offset) -{ - ssize_t retval; - void __iomem *addr = image->kern_base + offset; - unsigned int done = 0; - unsigned int count32; - - if (count == 0) - return 0; - - spin_lock(&image->lock); - - /* The following code handles VME address alignment. We cannot use - * memcpy_xxx here because it may cut data transfers in to 8-bit - * cycles when D16 or D32 cycles are required on the VME bus. - * On the other hand, the bridge itself assures that the maximum data - * cycle configured for the transfer is used and splits it - * automatically for non-aligned addresses, so we don't want the - * overhead of needlessly forcing small transfers for the entire cycle. - */ - if ((uintptr_t)addr & 0x1) { - *(u8 *)buf = ioread8(addr); - done += 1; - if (done == count) - goto out; - } - if ((uintptr_t)(addr + done) & 0x2) { - if ((count - done) < 2) { - *(u8 *)(buf + done) = ioread8(addr + done); - done += 1; - goto out; - } else { - *(u16 *)(buf + done) = ioread16(addr + done); - done += 2; - } - } - - count32 = (count - done) & ~0x3; - while (done < count32) { - *(u32 *)(buf + done) = ioread32(addr + done); - done += 4; - } - - if ((count - done) & 0x2) { - *(u16 *)(buf + done) = ioread16(addr + done); - done += 2; - } - if ((count - done) & 0x1) { - *(u8 *)(buf + done) = ioread8(addr + done); - done += 1; - } -out: - retval = count; - spin_unlock(&image->lock); - - return retval; -} - -static ssize_t ca91cx42_master_write(struct vme_master_resource *image, - void *buf, size_t count, loff_t offset) -{ - ssize_t retval; - void __iomem *addr = image->kern_base + offset; - unsigned int done = 0; - unsigned int count32; - - if (count == 0) - return 0; - - spin_lock(&image->lock); - - /* Here we apply for the same strategy we do in master_read - * function in order to assure the correct cycles. - */ - if ((uintptr_t)addr & 0x1) { - iowrite8(*(u8 *)buf, addr); - done += 1; - if (done == count) - goto out; - } - if ((uintptr_t)(addr + done) & 0x2) { - if ((count - done) < 2) { - iowrite8(*(u8 *)(buf + done), addr + done); - done += 1; - goto out; - } else { - iowrite16(*(u16 *)(buf + done), addr + done); - done += 2; - } - } - - count32 = (count - done) & ~0x3; - while (done < count32) { - iowrite32(*(u32 *)(buf + done), addr + done); - done += 4; - } - - if ((count - done) & 0x2) { - iowrite16(*(u16 *)(buf + done), addr + done); - done += 2; - } - if ((count - done) & 0x1) { - iowrite8(*(u8 *)(buf + done), addr + done); - done += 1; - } -out: - retval = count; - - spin_unlock(&image->lock); - - return retval; -} - -static unsigned int ca91cx42_master_rmw(struct vme_master_resource *image, - unsigned int mask, unsigned int compare, unsigned int swap, - loff_t offset) -{ - u32 result; - uintptr_t pci_addr; - struct ca91cx42_driver *bridge; - struct device *dev; - - bridge = image->parent->driver_priv; - dev = image->parent->parent; - - /* Find the PCI address that maps to the desired VME address */ - - /* Locking as we can only do one of these at a time */ - mutex_lock(&bridge->vme_rmw); - - /* Lock image */ - spin_lock(&image->lock); - - pci_addr = (uintptr_t)image->kern_base + offset; - - /* Address must be 4-byte aligned */ - if (pci_addr & 0x3) { - dev_err(dev, "RMW Address not 4-byte aligned\n"); - result = -EINVAL; - goto out; - } - - /* Ensure RMW Disabled whilst configuring */ - iowrite32(0, bridge->base + SCYC_CTL); - - /* Configure registers */ - iowrite32(mask, bridge->base + SCYC_EN); - iowrite32(compare, bridge->base + SCYC_CMP); - iowrite32(swap, bridge->base + SCYC_SWP); - iowrite32(pci_addr, bridge->base + SCYC_ADDR); - - /* Enable RMW */ - iowrite32(CA91CX42_SCYC_CTL_CYC_RMW, bridge->base + SCYC_CTL); - - /* Kick process off with a read to the required address. */ - result = ioread32(image->kern_base + offset); - - /* Disable RMW */ - iowrite32(0, bridge->base + SCYC_CTL); - -out: - spin_unlock(&image->lock); - - mutex_unlock(&bridge->vme_rmw); - - return result; -} - -static int ca91cx42_dma_list_add(struct vme_dma_list *list, - struct vme_dma_attr *src, struct vme_dma_attr *dest, size_t count) -{ - struct ca91cx42_dma_entry *entry, *prev; - struct vme_dma_pci *pci_attr; - struct vme_dma_vme *vme_attr; - dma_addr_t desc_ptr; - int retval = 0; - struct device *dev; - - dev = list->parent->parent->parent; - - /* XXX descriptor must be aligned on 64-bit boundaries */ - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - retval = -ENOMEM; - goto err_mem; - } - - /* Test descriptor alignment */ - if ((unsigned long)&entry->descriptor & CA91CX42_DCPP_M) { - dev_err(dev, "Descriptor not aligned to 16 byte boundary as " - "required: %p\n", &entry->descriptor); - retval = -EINVAL; - goto err_align; - } - - memset(&entry->descriptor, 0, sizeof(entry->descriptor)); - - if (dest->type == VME_DMA_VME) { - entry->descriptor.dctl |= CA91CX42_DCTL_L2V; - vme_attr = dest->private; - pci_attr = src->private; - } else { - vme_attr = src->private; - pci_attr = dest->private; - } - - /* Check we can do fulfill required attributes */ - if ((vme_attr->aspace & ~(VME_A16 | VME_A24 | VME_A32 | VME_USER1 | - VME_USER2)) != 0) { - - dev_err(dev, "Unsupported cycle type\n"); - retval = -EINVAL; - goto err_aspace; - } - - if ((vme_attr->cycle & ~(VME_SCT | VME_BLT | VME_SUPER | VME_USER | - VME_PROG | VME_DATA)) != 0) { - - dev_err(dev, "Unsupported cycle type\n"); - retval = -EINVAL; - goto err_cycle; - } - - /* Check to see if we can fulfill source and destination */ - if (!(((src->type == VME_DMA_PCI) && (dest->type == VME_DMA_VME)) || - ((src->type == VME_DMA_VME) && (dest->type == VME_DMA_PCI)))) { - - dev_err(dev, "Cannot perform transfer with this " - "source-destination combination\n"); - retval = -EINVAL; - goto err_direct; - } - - /* Setup cycle types */ - if (vme_attr->cycle & VME_BLT) - entry->descriptor.dctl |= CA91CX42_DCTL_VCT_BLT; - - /* Setup data width */ - switch (vme_attr->dwidth) { - case VME_D8: - entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D8; - break; - case VME_D16: - entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D16; - break; - case VME_D32: - entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D32; - break; - case VME_D64: - entry->descriptor.dctl |= CA91CX42_DCTL_VDW_D64; - break; - default: - dev_err(dev, "Invalid data width\n"); - return -EINVAL; - } - - /* Setup address space */ - switch (vme_attr->aspace) { - case VME_A16: - entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A16; - break; - case VME_A24: - entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A24; - break; - case VME_A32: - entry->descriptor.dctl |= CA91CX42_DCTL_VAS_A32; - break; - case VME_USER1: - entry->descriptor.dctl |= CA91CX42_DCTL_VAS_USER1; - break; - case VME_USER2: - entry->descriptor.dctl |= CA91CX42_DCTL_VAS_USER2; - break; - default: - dev_err(dev, "Invalid address space\n"); - return -EINVAL; - break; - } - - if (vme_attr->cycle & VME_SUPER) - entry->descriptor.dctl |= CA91CX42_DCTL_SUPER_SUPR; - if (vme_attr->cycle & VME_PROG) - entry->descriptor.dctl |= CA91CX42_DCTL_PGM_PGM; - - entry->descriptor.dtbc = count; - entry->descriptor.dla = pci_attr->address; - entry->descriptor.dva = vme_attr->address; - entry->descriptor.dcpp = CA91CX42_DCPP_NULL; - - /* Add to list */ - list_add_tail(&entry->list, &list->entries); - - /* Fill out previous descriptors "Next Address" */ - if (entry->list.prev != &list->entries) { - prev = list_entry(entry->list.prev, struct ca91cx42_dma_entry, - list); - /* We need the bus address for the pointer */ - desc_ptr = virt_to_bus(&entry->descriptor); - prev->descriptor.dcpp = desc_ptr & ~CA91CX42_DCPP_M; - } - - return 0; - -err_cycle: -err_aspace: -err_direct: -err_align: - kfree(entry); -err_mem: - return retval; -} - -static int ca91cx42_dma_busy(struct vme_bridge *ca91cx42_bridge) -{ - u32 tmp; - struct ca91cx42_driver *bridge; - - bridge = ca91cx42_bridge->driver_priv; - - tmp = ioread32(bridge->base + DGCS); - - if (tmp & CA91CX42_DGCS_ACT) - return 0; - else - return 1; -} - -static int ca91cx42_dma_list_exec(struct vme_dma_list *list) -{ - struct vme_dma_resource *ctrlr; - struct ca91cx42_dma_entry *entry; - int retval; - dma_addr_t bus_addr; - u32 val; - struct device *dev; - struct ca91cx42_driver *bridge; - - ctrlr = list->parent; - - bridge = ctrlr->parent->driver_priv; - dev = ctrlr->parent->parent; - - mutex_lock(&ctrlr->mtx); - - if (!(list_empty(&ctrlr->running))) { - /* - * XXX We have an active DMA transfer and currently haven't - * sorted out the mechanism for "pending" DMA transfers. - * Return busy. - */ - /* Need to add to pending here */ - mutex_unlock(&ctrlr->mtx); - return -EBUSY; - } else { - list_add(&list->list, &ctrlr->running); - } - - /* Get first bus address and write into registers */ - entry = list_first_entry(&list->entries, struct ca91cx42_dma_entry, - list); - - bus_addr = virt_to_bus(&entry->descriptor); - - mutex_unlock(&ctrlr->mtx); - - iowrite32(0, bridge->base + DTBC); - iowrite32(bus_addr & ~CA91CX42_DCPP_M, bridge->base + DCPP); - - /* Start the operation */ - val = ioread32(bridge->base + DGCS); - - /* XXX Could set VMEbus On and Off Counters here */ - val &= (CA91CX42_DGCS_VON_M | CA91CX42_DGCS_VOFF_M); - - val |= (CA91CX42_DGCS_CHAIN | CA91CX42_DGCS_STOP | CA91CX42_DGCS_HALT | - CA91CX42_DGCS_DONE | CA91CX42_DGCS_LERR | CA91CX42_DGCS_VERR | - CA91CX42_DGCS_PERR); - - iowrite32(val, bridge->base + DGCS); - - val |= CA91CX42_DGCS_GO; - - iowrite32(val, bridge->base + DGCS); - - retval = wait_event_interruptible(bridge->dma_queue, - ca91cx42_dma_busy(ctrlr->parent)); - - if (retval) { - val = ioread32(bridge->base + DGCS); - iowrite32(val | CA91CX42_DGCS_STOP_REQ, bridge->base + DGCS); - /* Wait for the operation to abort */ - wait_event(bridge->dma_queue, - ca91cx42_dma_busy(ctrlr->parent)); - retval = -EINTR; - goto exit; - } - - /* - * Read status register, this register is valid until we kick off a - * new transfer. - */ - val = ioread32(bridge->base + DGCS); - - if (val & (CA91CX42_DGCS_LERR | CA91CX42_DGCS_VERR | - CA91CX42_DGCS_PERR)) { - - dev_err(dev, "ca91c042: DMA Error. DGCS=%08X\n", val); - val = ioread32(bridge->base + DCTL); - retval = -EIO; - } - -exit: - /* Remove list from running list */ - mutex_lock(&ctrlr->mtx); - list_del(&list->list); - mutex_unlock(&ctrlr->mtx); - - return retval; - -} - -static int ca91cx42_dma_list_empty(struct vme_dma_list *list) -{ - struct list_head *pos, *temp; - struct ca91cx42_dma_entry *entry; - - /* detach and free each entry */ - list_for_each_safe(pos, temp, &list->entries) { - list_del(pos); - entry = list_entry(pos, struct ca91cx42_dma_entry, list); - kfree(entry); - } - - return 0; -} - -/* - * All 4 location monitors reside at the same base - this is therefore a - * system wide configuration. - * - * This does not enable the LM monitor - that should be done when the first - * callback is attached and disabled when the last callback is removed. - */ -static int ca91cx42_lm_set(struct vme_lm_resource *lm, - unsigned long long lm_base, u32 aspace, u32 cycle) -{ - u32 temp_base, lm_ctl = 0; - int i; - struct ca91cx42_driver *bridge; - struct device *dev; - - bridge = lm->parent->driver_priv; - dev = lm->parent->parent; - - /* Check the alignment of the location monitor */ - temp_base = (u32)lm_base; - if (temp_base & 0xffff) { - dev_err(dev, "Location monitor must be aligned to 64KB " - "boundary"); - return -EINVAL; - } - - mutex_lock(&lm->mtx); - - /* If we already have a callback attached, we can't move it! */ - for (i = 0; i < lm->monitors; i++) { - if (bridge->lm_callback[i]) { - mutex_unlock(&lm->mtx); - dev_err(dev, "Location monitor callback attached, " - "can't reset\n"); - return -EBUSY; - } - } - - switch (aspace) { - case VME_A16: - lm_ctl |= CA91CX42_LM_CTL_AS_A16; - break; - case VME_A24: - lm_ctl |= CA91CX42_LM_CTL_AS_A24; - break; - case VME_A32: - lm_ctl |= CA91CX42_LM_CTL_AS_A32; - break; - default: - mutex_unlock(&lm->mtx); - dev_err(dev, "Invalid address space\n"); - return -EINVAL; - break; - } - - if (cycle & VME_SUPER) - lm_ctl |= CA91CX42_LM_CTL_SUPR; - if (cycle & VME_USER) - lm_ctl |= CA91CX42_LM_CTL_NPRIV; - if (cycle & VME_PROG) - lm_ctl |= CA91CX42_LM_CTL_PGM; - if (cycle & VME_DATA) - lm_ctl |= CA91CX42_LM_CTL_DATA; - - iowrite32(lm_base, bridge->base + LM_BS); - iowrite32(lm_ctl, bridge->base + LM_CTL); - - mutex_unlock(&lm->mtx); - - return 0; -} - -/* Get configuration of the callback monitor and return whether it is enabled - * or disabled. - */ -static int ca91cx42_lm_get(struct vme_lm_resource *lm, - unsigned long long *lm_base, u32 *aspace, u32 *cycle) -{ - u32 lm_ctl, enabled = 0; - struct ca91cx42_driver *bridge; - - bridge = lm->parent->driver_priv; - - mutex_lock(&lm->mtx); - - *lm_base = (unsigned long long)ioread32(bridge->base + LM_BS); - lm_ctl = ioread32(bridge->base + LM_CTL); - - if (lm_ctl & CA91CX42_LM_CTL_EN) - enabled = 1; - - if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A16) - *aspace = VME_A16; - if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A24) - *aspace = VME_A24; - if ((lm_ctl & CA91CX42_LM_CTL_AS_M) == CA91CX42_LM_CTL_AS_A32) - *aspace = VME_A32; - - *cycle = 0; - if (lm_ctl & CA91CX42_LM_CTL_SUPR) - *cycle |= VME_SUPER; - if (lm_ctl & CA91CX42_LM_CTL_NPRIV) - *cycle |= VME_USER; - if (lm_ctl & CA91CX42_LM_CTL_PGM) - *cycle |= VME_PROG; - if (lm_ctl & CA91CX42_LM_CTL_DATA) - *cycle |= VME_DATA; - - mutex_unlock(&lm->mtx); - - return enabled; -} - -/* - * Attach a callback to a specific location monitor. - * - * Callback will be passed the monitor triggered. - */ -static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor, - void (*callback)(void *), void *data) -{ - u32 lm_ctl, tmp; - struct ca91cx42_driver *bridge; - struct device *dev; - - bridge = lm->parent->driver_priv; - dev = lm->parent->parent; - - mutex_lock(&lm->mtx); - - /* Ensure that the location monitor is configured - need PGM or DATA */ - lm_ctl = ioread32(bridge->base + LM_CTL); - if ((lm_ctl & (CA91CX42_LM_CTL_PGM | CA91CX42_LM_CTL_DATA)) == 0) { - mutex_unlock(&lm->mtx); - dev_err(dev, "Location monitor not properly configured\n"); - return -EINVAL; - } - - /* Check that a callback isn't already attached */ - if (bridge->lm_callback[monitor]) { - mutex_unlock(&lm->mtx); - dev_err(dev, "Existing callback attached\n"); - return -EBUSY; - } - - /* Attach callback */ - bridge->lm_callback[monitor] = callback; - bridge->lm_data[monitor] = data; - - /* Enable Location Monitor interrupt */ - tmp = ioread32(bridge->base + LINT_EN); - tmp |= CA91CX42_LINT_LM[monitor]; - iowrite32(tmp, bridge->base + LINT_EN); - - /* Ensure that global Location Monitor Enable set */ - if ((lm_ctl & CA91CX42_LM_CTL_EN) == 0) { - lm_ctl |= CA91CX42_LM_CTL_EN; - iowrite32(lm_ctl, bridge->base + LM_CTL); - } - - mutex_unlock(&lm->mtx); - - return 0; -} - -/* - * Detach a callback function forn a specific location monitor. - */ -static int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor) -{ - u32 tmp; - struct ca91cx42_driver *bridge; - - bridge = lm->parent->driver_priv; - - mutex_lock(&lm->mtx); - - /* Disable Location Monitor and ensure previous interrupts are clear */ - tmp = ioread32(bridge->base + LINT_EN); - tmp &= ~CA91CX42_LINT_LM[monitor]; - iowrite32(tmp, bridge->base + LINT_EN); - - iowrite32(CA91CX42_LINT_LM[monitor], - bridge->base + LINT_STAT); - - /* Detach callback */ - bridge->lm_callback[monitor] = NULL; - bridge->lm_data[monitor] = NULL; - - /* If all location monitors disabled, disable global Location Monitor */ - if ((tmp & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 | - CA91CX42_LINT_LM3)) == 0) { - tmp = ioread32(bridge->base + LM_CTL); - tmp &= ~CA91CX42_LM_CTL_EN; - iowrite32(tmp, bridge->base + LM_CTL); - } - - mutex_unlock(&lm->mtx); - - return 0; -} - -static int ca91cx42_slot_get(struct vme_bridge *ca91cx42_bridge) -{ - u32 slot = 0; - struct ca91cx42_driver *bridge; - - bridge = ca91cx42_bridge->driver_priv; - - if (!geoid) { - slot = ioread32(bridge->base + VCSR_BS); - slot = ((slot & CA91CX42_VCSR_BS_SLOT_M) >> 27); - } else - slot = geoid; - - return (int)slot; - -} - -static void *ca91cx42_alloc_consistent(struct device *parent, size_t size, - dma_addr_t *dma) -{ - struct pci_dev *pdev; - - /* Find pci_dev container of dev */ - pdev = to_pci_dev(parent); - - return dma_alloc_coherent(&pdev->dev, size, dma, GFP_KERNEL); -} - -static void ca91cx42_free_consistent(struct device *parent, size_t size, - void *vaddr, dma_addr_t dma) -{ - struct pci_dev *pdev; - - /* Find pci_dev container of dev */ - pdev = to_pci_dev(parent); - - dma_free_coherent(&pdev->dev, size, vaddr, dma); -} - -/* - * Configure CR/CSR space - * - * Access to the CR/CSR can be configured at power-up. The location of the - * CR/CSR registers in the CR/CSR address space is determined by the boards - * Auto-ID or Geographic address. This function ensures that the window is - * enabled at an offset consistent with the boards geopgraphic address. - */ -static int ca91cx42_crcsr_init(struct vme_bridge *ca91cx42_bridge, - struct pci_dev *pdev) -{ - unsigned int crcsr_addr; - int tmp, slot; - struct ca91cx42_driver *bridge; - - bridge = ca91cx42_bridge->driver_priv; - - slot = ca91cx42_slot_get(ca91cx42_bridge); - - /* Write CSR Base Address if slot ID is supplied as a module param */ - if (geoid) - iowrite32(geoid << 27, bridge->base + VCSR_BS); - - dev_info(&pdev->dev, "CR/CSR Offset: %d\n", slot); - if (slot == 0) { - dev_err(&pdev->dev, "Slot number is unset, not configuring " - "CR/CSR space\n"); - return -EINVAL; - } - - /* Allocate mem for CR/CSR image */ - bridge->crcsr_kernel = dma_alloc_coherent(&pdev->dev, - VME_CRCSR_BUF_SIZE, - &bridge->crcsr_bus, GFP_KERNEL); - if (!bridge->crcsr_kernel) { - dev_err(&pdev->dev, "Failed to allocate memory for CR/CSR " - "image\n"); - return -ENOMEM; - } - - crcsr_addr = slot * (512 * 1024); - iowrite32(bridge->crcsr_bus - crcsr_addr, bridge->base + VCSR_TO); - - tmp = ioread32(bridge->base + VCSR_CTL); - tmp |= CA91CX42_VCSR_CTL_EN; - iowrite32(tmp, bridge->base + VCSR_CTL); - - return 0; -} - -static void ca91cx42_crcsr_exit(struct vme_bridge *ca91cx42_bridge, - struct pci_dev *pdev) -{ - u32 tmp; - struct ca91cx42_driver *bridge; - - bridge = ca91cx42_bridge->driver_priv; - - /* Turn off CR/CSR space */ - tmp = ioread32(bridge->base + VCSR_CTL); - tmp &= ~CA91CX42_VCSR_CTL_EN; - iowrite32(tmp, bridge->base + VCSR_CTL); - - /* Free image */ - iowrite32(0, bridge->base + VCSR_TO); - - dma_free_coherent(&pdev->dev, VME_CRCSR_BUF_SIZE, - bridge->crcsr_kernel, bridge->crcsr_bus); -} - -static int ca91cx42_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - int retval, i; - u32 data; - struct list_head *pos = NULL, *n; - struct vme_bridge *ca91cx42_bridge; - struct ca91cx42_driver *ca91cx42_device; - struct vme_master_resource *master_image; - struct vme_slave_resource *slave_image; - struct vme_dma_resource *dma_ctrlr; - struct vme_lm_resource *lm; - - /* We want to support more than one of each bridge so we need to - * dynamically allocate the bridge structure - */ - ca91cx42_bridge = kzalloc(sizeof(*ca91cx42_bridge), GFP_KERNEL); - if (!ca91cx42_bridge) { - retval = -ENOMEM; - goto err_struct; - } - vme_init_bridge(ca91cx42_bridge); - - ca91cx42_device = kzalloc(sizeof(*ca91cx42_device), GFP_KERNEL); - if (!ca91cx42_device) { - retval = -ENOMEM; - goto err_driver; - } - - ca91cx42_bridge->driver_priv = ca91cx42_device; - - /* Enable the device */ - retval = pci_enable_device(pdev); - if (retval) { - dev_err(&pdev->dev, "Unable to enable device\n"); - goto err_enable; - } - - /* Map Registers */ - retval = pci_request_regions(pdev, driver_name); - if (retval) { - dev_err(&pdev->dev, "Unable to reserve resources\n"); - goto err_resource; - } - - /* map registers in BAR 0 */ - ca91cx42_device->base = ioremap(pci_resource_start(pdev, 0), - 4096); - if (!ca91cx42_device->base) { - dev_err(&pdev->dev, "Unable to remap CRG region\n"); - retval = -EIO; - goto err_remap; - } - - /* Check to see if the mapping worked out */ - data = ioread32(ca91cx42_device->base + CA91CX42_PCI_ID) & 0x0000FFFF; - if (data != PCI_VENDOR_ID_TUNDRA) { - dev_err(&pdev->dev, "PCI_ID check failed\n"); - retval = -EIO; - goto err_test; - } - - /* Initialize wait queues & mutual exclusion flags */ - init_waitqueue_head(&ca91cx42_device->dma_queue); - init_waitqueue_head(&ca91cx42_device->iack_queue); - mutex_init(&ca91cx42_device->vme_int); - mutex_init(&ca91cx42_device->vme_rmw); - - ca91cx42_bridge->parent = &pdev->dev; - strcpy(ca91cx42_bridge->name, driver_name); - - /* Setup IRQ */ - retval = ca91cx42_irq_init(ca91cx42_bridge); - if (retval != 0) { - dev_err(&pdev->dev, "Chip Initialization failed.\n"); - goto err_irq; - } - - /* Add master windows to list */ - for (i = 0; i < CA91C142_MAX_MASTER; i++) { - master_image = kmalloc(sizeof(*master_image), GFP_KERNEL); - if (!master_image) { - retval = -ENOMEM; - goto err_master; - } - master_image->parent = ca91cx42_bridge; - spin_lock_init(&master_image->lock); - master_image->locked = 0; - master_image->number = i; - master_image->address_attr = VME_A16 | VME_A24 | VME_A32 | - VME_CRCSR | VME_USER1 | VME_USER2; - master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | - VME_SUPER | VME_USER | VME_PROG | VME_DATA; - master_image->width_attr = VME_D8 | VME_D16 | VME_D32 | VME_D64; - memset(&master_image->bus_resource, 0, - sizeof(master_image->bus_resource)); - master_image->kern_base = NULL; - list_add_tail(&master_image->list, - &ca91cx42_bridge->master_resources); - } - - /* Add slave windows to list */ - for (i = 0; i < CA91C142_MAX_SLAVE; i++) { - slave_image = kmalloc(sizeof(*slave_image), GFP_KERNEL); - if (!slave_image) { - retval = -ENOMEM; - goto err_slave; - } - slave_image->parent = ca91cx42_bridge; - mutex_init(&slave_image->mtx); - slave_image->locked = 0; - slave_image->number = i; - slave_image->address_attr = VME_A24 | VME_A32 | VME_USER1 | - VME_USER2; - - /* Only windows 0 and 4 support A16 */ - if (i == 0 || i == 4) - slave_image->address_attr |= VME_A16; - - slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | - VME_SUPER | VME_USER | VME_PROG | VME_DATA; - list_add_tail(&slave_image->list, - &ca91cx42_bridge->slave_resources); - } - - /* Add dma engines to list */ - for (i = 0; i < CA91C142_MAX_DMA; i++) { - dma_ctrlr = kmalloc(sizeof(*dma_ctrlr), GFP_KERNEL); - if (!dma_ctrlr) { - retval = -ENOMEM; - goto err_dma; - } - dma_ctrlr->parent = ca91cx42_bridge; - mutex_init(&dma_ctrlr->mtx); - dma_ctrlr->locked = 0; - dma_ctrlr->number = i; - dma_ctrlr->route_attr = VME_DMA_VME_TO_MEM | - VME_DMA_MEM_TO_VME; - INIT_LIST_HEAD(&dma_ctrlr->pending); - INIT_LIST_HEAD(&dma_ctrlr->running); - list_add_tail(&dma_ctrlr->list, - &ca91cx42_bridge->dma_resources); - } - - /* Add location monitor to list */ - lm = kmalloc(sizeof(*lm), GFP_KERNEL); - if (!lm) { - retval = -ENOMEM; - goto err_lm; - } - lm->parent = ca91cx42_bridge; - mutex_init(&lm->mtx); - lm->locked = 0; - lm->number = 1; - lm->monitors = 4; - list_add_tail(&lm->list, &ca91cx42_bridge->lm_resources); - - ca91cx42_bridge->slave_get = ca91cx42_slave_get; - ca91cx42_bridge->slave_set = ca91cx42_slave_set; - ca91cx42_bridge->master_get = ca91cx42_master_get; - ca91cx42_bridge->master_set = ca91cx42_master_set; - ca91cx42_bridge->master_read = ca91cx42_master_read; - ca91cx42_bridge->master_write = ca91cx42_master_write; - ca91cx42_bridge->master_rmw = ca91cx42_master_rmw; - ca91cx42_bridge->dma_list_add = ca91cx42_dma_list_add; - ca91cx42_bridge->dma_list_exec = ca91cx42_dma_list_exec; - ca91cx42_bridge->dma_list_empty = ca91cx42_dma_list_empty; - ca91cx42_bridge->irq_set = ca91cx42_irq_set; - ca91cx42_bridge->irq_generate = ca91cx42_irq_generate; - ca91cx42_bridge->lm_set = ca91cx42_lm_set; - ca91cx42_bridge->lm_get = ca91cx42_lm_get; - ca91cx42_bridge->lm_attach = ca91cx42_lm_attach; - ca91cx42_bridge->lm_detach = ca91cx42_lm_detach; - ca91cx42_bridge->slot_get = ca91cx42_slot_get; - ca91cx42_bridge->alloc_consistent = ca91cx42_alloc_consistent; - ca91cx42_bridge->free_consistent = ca91cx42_free_consistent; - - data = ioread32(ca91cx42_device->base + MISC_CTL); - dev_info(&pdev->dev, "Board is%s the VME system controller\n", - (data & CA91CX42_MISC_CTL_SYSCON) ? "" : " not"); - dev_info(&pdev->dev, "Slot ID is %d\n", - ca91cx42_slot_get(ca91cx42_bridge)); - - if (ca91cx42_crcsr_init(ca91cx42_bridge, pdev)) - dev_err(&pdev->dev, "CR/CSR configuration failed.\n"); - - /* Need to save ca91cx42_bridge pointer locally in link list for use in - * ca91cx42_remove() - */ - retval = vme_register_bridge(ca91cx42_bridge); - if (retval != 0) { - dev_err(&pdev->dev, "Chip Registration failed.\n"); - goto err_reg; - } - - pci_set_drvdata(pdev, ca91cx42_bridge); - - return 0; - -err_reg: - ca91cx42_crcsr_exit(ca91cx42_bridge, pdev); -err_lm: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &ca91cx42_bridge->lm_resources) { - lm = list_entry(pos, struct vme_lm_resource, list); - list_del(pos); - kfree(lm); - } -err_dma: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &ca91cx42_bridge->dma_resources) { - dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); - list_del(pos); - kfree(dma_ctrlr); - } -err_slave: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &ca91cx42_bridge->slave_resources) { - slave_image = list_entry(pos, struct vme_slave_resource, list); - list_del(pos); - kfree(slave_image); - } -err_master: - /* resources are stored in link list */ - list_for_each_safe(pos, n, &ca91cx42_bridge->master_resources) { - master_image = list_entry(pos, struct vme_master_resource, - list); - list_del(pos); - kfree(master_image); - } - - ca91cx42_irq_exit(ca91cx42_device, pdev); -err_irq: -err_test: - iounmap(ca91cx42_device->base); -err_remap: - pci_release_regions(pdev); -err_resource: - pci_disable_device(pdev); -err_enable: - kfree(ca91cx42_device); -err_driver: - kfree(ca91cx42_bridge); -err_struct: - return retval; - -} - -static void ca91cx42_remove(struct pci_dev *pdev) -{ - struct list_head *pos = NULL, *n; - struct vme_master_resource *master_image; - struct vme_slave_resource *slave_image; - struct vme_dma_resource *dma_ctrlr; - struct vme_lm_resource *lm; - struct ca91cx42_driver *bridge; - struct vme_bridge *ca91cx42_bridge = pci_get_drvdata(pdev); - - bridge = ca91cx42_bridge->driver_priv; - - - /* Turn off Ints */ - iowrite32(0, bridge->base + LINT_EN); - - /* Turn off the windows */ - iowrite32(0x00800000, bridge->base + LSI0_CTL); - iowrite32(0x00800000, bridge->base + LSI1_CTL); - iowrite32(0x00800000, bridge->base + LSI2_CTL); - iowrite32(0x00800000, bridge->base + LSI3_CTL); - iowrite32(0x00800000, bridge->base + LSI4_CTL); - iowrite32(0x00800000, bridge->base + LSI5_CTL); - iowrite32(0x00800000, bridge->base + LSI6_CTL); - iowrite32(0x00800000, bridge->base + LSI7_CTL); - iowrite32(0x00F00000, bridge->base + VSI0_CTL); - iowrite32(0x00F00000, bridge->base + VSI1_CTL); - iowrite32(0x00F00000, bridge->base + VSI2_CTL); - iowrite32(0x00F00000, bridge->base + VSI3_CTL); - iowrite32(0x00F00000, bridge->base + VSI4_CTL); - iowrite32(0x00F00000, bridge->base + VSI5_CTL); - iowrite32(0x00F00000, bridge->base + VSI6_CTL); - iowrite32(0x00F00000, bridge->base + VSI7_CTL); - - vme_unregister_bridge(ca91cx42_bridge); - - ca91cx42_crcsr_exit(ca91cx42_bridge, pdev); - - /* resources are stored in link list */ - list_for_each_safe(pos, n, &ca91cx42_bridge->lm_resources) { - lm = list_entry(pos, struct vme_lm_resource, list); - list_del(pos); - kfree(lm); - } - - /* resources are stored in link list */ - list_for_each_safe(pos, n, &ca91cx42_bridge->dma_resources) { - dma_ctrlr = list_entry(pos, struct vme_dma_resource, list); - list_del(pos); - kfree(dma_ctrlr); - } - - /* resources are stored in link list */ - list_for_each_safe(pos, n, &ca91cx42_bridge->slave_resources) { - slave_image = list_entry(pos, struct vme_slave_resource, list); - list_del(pos); - kfree(slave_image); - } - - /* resources are stored in link list */ - list_for_each_safe(pos, n, &ca91cx42_bridge->master_resources) { - master_image = list_entry(pos, struct vme_master_resource, - list); - list_del(pos); - kfree(master_image); - } - - ca91cx42_irq_exit(bridge, pdev); - - iounmap(bridge->base); - - pci_release_regions(pdev); - - pci_disable_device(pdev); - - kfree(ca91cx42_bridge); -} - -module_pci_driver(ca91cx42_driver); - -MODULE_PARM_DESC(geoid, "Override geographical addressing"); -module_param(geoid, int, 0); - -MODULE_DESCRIPTION("VME driver for the Tundra Universe II VME bridge"); -MODULE_LICENSE("GPL"); diff --git a/drivers/vme/bridges/vme_ca91cx42.h b/drivers/vme/bridges/vme_ca91cx42.h deleted file mode 100644 index 34a8c25de613..000000000000 --- a/drivers/vme/bridges/vme_ca91cx42.h +++ /dev/null @@ -1,579 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * ca91c042.h - * - * Support for the Tundra Universe 1 and Universe II VME bridge chips - * - * Author: Tom Armistead - * Updated by Ajit Prem - * Copyright 2004 Motorola Inc. - * - * Further updated by Martyn Welch - * Copyright 2009 GE Intelligent Platforms Embedded Systems, Inc. - * - * Derived from ca91c042.h by Michael Wyrick - */ - -#ifndef _CA91CX42_H -#define _CA91CX42_H - -#ifndef PCI_VENDOR_ID_TUNDRA -#define PCI_VENDOR_ID_TUNDRA 0x10e3 -#endif - -#ifndef PCI_DEVICE_ID_TUNDRA_CA91C142 -#define PCI_DEVICE_ID_TUNDRA_CA91C142 0x0000 -#endif - -/* - * Define the number of each that the CA91C142 supports. - */ -#define CA91C142_MAX_MASTER 8 /* Max Master Windows */ -#define CA91C142_MAX_SLAVE 8 /* Max Slave Windows */ -#define CA91C142_MAX_DMA 1 /* Max DMA Controllers */ -#define CA91C142_MAX_MAILBOX 4 /* Max Mail Box registers */ - -/* Structure used to hold driver specific information */ -struct ca91cx42_driver { - void __iomem *base; /* Base Address of device registers */ - wait_queue_head_t dma_queue; - wait_queue_head_t iack_queue; - wait_queue_head_t mbox_queue; - void (*lm_callback[4])(void *); /* Called in interrupt handler */ - void *lm_data[4]; - void *crcsr_kernel; - dma_addr_t crcsr_bus; - struct mutex vme_rmw; /* Only one RMW cycle at a time */ - struct mutex vme_int; /* - * Only one VME interrupt can be - * generated at a time, provide locking - */ -}; - -/* See Page 2-77 in the Universe User Manual */ -struct ca91cx42_dma_descriptor { - unsigned int dctl; /* DMA Control */ - unsigned int dtbc; /* Transfer Byte Count */ - unsigned int dla; /* PCI Address */ - unsigned int res1; /* Reserved */ - unsigned int dva; /* Vme Address */ - unsigned int res2; /* Reserved */ - unsigned int dcpp; /* Pointer to Numed Cmd Packet with rPN */ - unsigned int res3; /* Reserved */ -}; - -struct ca91cx42_dma_entry { - struct ca91cx42_dma_descriptor descriptor; - struct list_head list; -}; - -/* Universe Register Offsets */ -/* general PCI configuration registers */ -#define CA91CX42_PCI_ID 0x000 -#define CA91CX42_PCI_CSR 0x004 -#define CA91CX42_PCI_CLASS 0x008 -#define CA91CX42_PCI_MISC0 0x00C -#define CA91CX42_PCI_BS 0x010 -#define CA91CX42_PCI_MISC1 0x03C - -#define LSI0_CTL 0x0100 -#define LSI0_BS 0x0104 -#define LSI0_BD 0x0108 -#define LSI0_TO 0x010C - -#define LSI1_CTL 0x0114 -#define LSI1_BS 0x0118 -#define LSI1_BD 0x011C -#define LSI1_TO 0x0120 - -#define LSI2_CTL 0x0128 -#define LSI2_BS 0x012C -#define LSI2_BD 0x0130 -#define LSI2_TO 0x0134 - -#define LSI3_CTL 0x013C -#define LSI3_BS 0x0140 -#define LSI3_BD 0x0144 -#define LSI3_TO 0x0148 - -#define LSI4_CTL 0x01A0 -#define LSI4_BS 0x01A4 -#define LSI4_BD 0x01A8 -#define LSI4_TO 0x01AC - -#define LSI5_CTL 0x01B4 -#define LSI5_BS 0x01B8 -#define LSI5_BD 0x01BC -#define LSI5_TO 0x01C0 - -#define LSI6_CTL 0x01C8 -#define LSI6_BS 0x01CC -#define LSI6_BD 0x01D0 -#define LSI6_TO 0x01D4 - -#define LSI7_CTL 0x01DC -#define LSI7_BS 0x01E0 -#define LSI7_BD 0x01E4 -#define LSI7_TO 0x01E8 - -static const int CA91CX42_LSI_CTL[] = { LSI0_CTL, LSI1_CTL, LSI2_CTL, LSI3_CTL, - LSI4_CTL, LSI5_CTL, LSI6_CTL, LSI7_CTL }; - -static const int CA91CX42_LSI_BS[] = { LSI0_BS, LSI1_BS, LSI2_BS, LSI3_BS, - LSI4_BS, LSI5_BS, LSI6_BS, LSI7_BS }; - -static const int CA91CX42_LSI_BD[] = { LSI0_BD, LSI1_BD, LSI2_BD, LSI3_BD, - LSI4_BD, LSI5_BD, LSI6_BD, LSI7_BD }; - -static const int CA91CX42_LSI_TO[] = { LSI0_TO, LSI1_TO, LSI2_TO, LSI3_TO, - LSI4_TO, LSI5_TO, LSI6_TO, LSI7_TO }; - -#define SCYC_CTL 0x0170 -#define SCYC_ADDR 0x0174 -#define SCYC_EN 0x0178 -#define SCYC_CMP 0x017C -#define SCYC_SWP 0x0180 -#define LMISC 0x0184 -#define SLSI 0x0188 -#define L_CMDERR 0x018C -#define LAERR 0x0190 - -#define DCTL 0x0200 -#define DTBC 0x0204 -#define DLA 0x0208 -#define DVA 0x0210 -#define DCPP 0x0218 -#define DGCS 0x0220 -#define D_LLUE 0x0224 - -#define LINT_EN 0x0300 -#define LINT_STAT 0x0304 -#define LINT_MAP0 0x0308 -#define LINT_MAP1 0x030C -#define VINT_EN 0x0310 -#define VINT_STAT 0x0314 -#define VINT_MAP0 0x0318 -#define VINT_MAP1 0x031C -#define STATID 0x0320 - -#define V1_STATID 0x0324 -#define V2_STATID 0x0328 -#define V3_STATID 0x032C -#define V4_STATID 0x0330 -#define V5_STATID 0x0334 -#define V6_STATID 0x0338 -#define V7_STATID 0x033C - -static const int CA91CX42_V_STATID[8] = { 0, V1_STATID, V2_STATID, V3_STATID, - V4_STATID, V5_STATID, V6_STATID, - V7_STATID }; - -#define LINT_MAP2 0x0340 -#define VINT_MAP2 0x0344 - -#define MBOX0 0x0348 -#define MBOX1 0x034C -#define MBOX2 0x0350 -#define MBOX3 0x0354 -#define SEMA0 0x0358 -#define SEMA1 0x035C - -#define MAST_CTL 0x0400 -#define MISC_CTL 0x0404 -#define MISC_STAT 0x0408 -#define USER_AM 0x040C - -#define VSI0_CTL 0x0F00 -#define VSI0_BS 0x0F04 -#define VSI0_BD 0x0F08 -#define VSI0_TO 0x0F0C - -#define VSI1_CTL 0x0F14 -#define VSI1_BS 0x0F18 -#define VSI1_BD 0x0F1C -#define VSI1_TO 0x0F20 - -#define VSI2_CTL 0x0F28 -#define VSI2_BS 0x0F2C -#define VSI2_BD 0x0F30 -#define VSI2_TO 0x0F34 - -#define VSI3_CTL 0x0F3C -#define VSI3_BS 0x0F40 -#define VSI3_BD 0x0F44 -#define VSI3_TO 0x0F48 - -#define LM_CTL 0x0F64 -#define LM_BS 0x0F68 - -#define VRAI_CTL 0x0F70 - -#define VRAI_BS 0x0F74 -#define VCSR_CTL 0x0F80 -#define VCSR_TO 0x0F84 -#define V_AMERR 0x0F88 -#define VAERR 0x0F8C - -#define VSI4_CTL 0x0F90 -#define VSI4_BS 0x0F94 -#define VSI4_BD 0x0F98 -#define VSI4_TO 0x0F9C - -#define VSI5_CTL 0x0FA4 -#define VSI5_BS 0x0FA8 -#define VSI5_BD 0x0FAC -#define VSI5_TO 0x0FB0 - -#define VSI6_CTL 0x0FB8 -#define VSI6_BS 0x0FBC -#define VSI6_BD 0x0FC0 -#define VSI6_TO 0x0FC4 - -#define VSI7_CTL 0x0FCC -#define VSI7_BS 0x0FD0 -#define VSI7_BD 0x0FD4 -#define VSI7_TO 0x0FD8 - -static const int CA91CX42_VSI_CTL[] = { VSI0_CTL, VSI1_CTL, VSI2_CTL, VSI3_CTL, - VSI4_CTL, VSI5_CTL, VSI6_CTL, VSI7_CTL }; - -static const int CA91CX42_VSI_BS[] = { VSI0_BS, VSI1_BS, VSI2_BS, VSI3_BS, - VSI4_BS, VSI5_BS, VSI6_BS, VSI7_BS }; - -static const int CA91CX42_VSI_BD[] = { VSI0_BD, VSI1_BD, VSI2_BD, VSI3_BD, - VSI4_BD, VSI5_BD, VSI6_BD, VSI7_BD }; - -static const int CA91CX42_VSI_TO[] = { VSI0_TO, VSI1_TO, VSI2_TO, VSI3_TO, - VSI4_TO, VSI5_TO, VSI6_TO, VSI7_TO }; - -#define VCSR_CLR 0x0FF4 -#define VCSR_SET 0x0FF8 -#define VCSR_BS 0x0FFC - -/* - * PCI Class Register - * offset 008 - */ -#define CA91CX42_BM_PCI_CLASS_BASE 0xFF000000 -#define CA91CX42_OF_PCI_CLASS_BASE 24 -#define CA91CX42_BM_PCI_CLASS_SUB 0x00FF0000 -#define CA91CX42_OF_PCI_CLASS_SUB 16 -#define CA91CX42_BM_PCI_CLASS_PROG 0x0000FF00 -#define CA91CX42_OF_PCI_CLASS_PROG 8 -#define CA91CX42_BM_PCI_CLASS_RID 0x000000FF -#define CA91CX42_OF_PCI_CLASS_RID 0 - -#define CA91CX42_OF_PCI_CLASS_RID_UNIVERSE_I 0 -#define CA91CX42_OF_PCI_CLASS_RID_UNIVERSE_II 1 - -/* - * PCI Misc Register - * offset 00C - */ -#define CA91CX42_BM_PCI_MISC0_BISTC 0x80000000 -#define CA91CX42_BM_PCI_MISC0_SBIST 0x60000000 -#define CA91CX42_BM_PCI_MISC0_CCODE 0x0F000000 -#define CA91CX42_BM_PCI_MISC0_MFUNCT 0x00800000 -#define CA91CX42_BM_PCI_MISC0_LAYOUT 0x007F0000 -#define CA91CX42_BM_PCI_MISC0_LTIMER 0x0000FF00 -#define CA91CX42_OF_PCI_MISC0_LTIMER 8 - - -/* - * LSI Control Register - * offset 100 - */ -#define CA91CX42_LSI_CTL_EN (1<<31) -#define CA91CX42_LSI_CTL_PWEN (1<<30) - -#define CA91CX42_LSI_CTL_VDW_M (3<<22) -#define CA91CX42_LSI_CTL_VDW_D8 0 -#define CA91CX42_LSI_CTL_VDW_D16 (1<<22) -#define CA91CX42_LSI_CTL_VDW_D32 (1<<23) -#define CA91CX42_LSI_CTL_VDW_D64 (3<<22) - -#define CA91CX42_LSI_CTL_VAS_M (7<<16) -#define CA91CX42_LSI_CTL_VAS_A16 0 -#define CA91CX42_LSI_CTL_VAS_A24 (1<<16) -#define CA91CX42_LSI_CTL_VAS_A32 (1<<17) -#define CA91CX42_LSI_CTL_VAS_CRCSR (5<<16) -#define CA91CX42_LSI_CTL_VAS_USER1 (3<<17) -#define CA91CX42_LSI_CTL_VAS_USER2 (7<<16) - -#define CA91CX42_LSI_CTL_PGM_M (1<<14) -#define CA91CX42_LSI_CTL_PGM_DATA 0 -#define CA91CX42_LSI_CTL_PGM_PGM (1<<14) - -#define CA91CX42_LSI_CTL_SUPER_M (1<<12) -#define CA91CX42_LSI_CTL_SUPER_NPRIV 0 -#define CA91CX42_LSI_CTL_SUPER_SUPR (1<<12) - -#define CA91CX42_LSI_CTL_VCT_M (1<<8) -#define CA91CX42_LSI_CTL_VCT_BLT (1<<8) -#define CA91CX42_LSI_CTL_VCT_MBLT (1<<8) -#define CA91CX42_LSI_CTL_LAS (1<<0) - -/* - * SCYC_CTL Register - * offset 178 - */ -#define CA91CX42_SCYC_CTL_LAS_PCIMEM 0 -#define CA91CX42_SCYC_CTL_LAS_PCIIO (1<<2) - -#define CA91CX42_SCYC_CTL_CYC_M (3<<0) -#define CA91CX42_SCYC_CTL_CYC_RMW (1<<0) -#define CA91CX42_SCYC_CTL_CYC_ADOH (1<<1) - -/* - * LMISC Register - * offset 184 - */ -#define CA91CX42_BM_LMISC_CRT 0xF0000000 -#define CA91CX42_OF_LMISC_CRT 28 -#define CA91CX42_BM_LMISC_CWT 0x0F000000 -#define CA91CX42_OF_LMISC_CWT 24 - -/* - * SLSI Register - * offset 188 - */ -#define CA91CX42_BM_SLSI_EN 0x80000000 -#define CA91CX42_BM_SLSI_PWEN 0x40000000 -#define CA91CX42_BM_SLSI_VDW 0x00F00000 -#define CA91CX42_OF_SLSI_VDW 20 -#define CA91CX42_BM_SLSI_PGM 0x0000F000 -#define CA91CX42_OF_SLSI_PGM 12 -#define CA91CX42_BM_SLSI_SUPER 0x00000F00 -#define CA91CX42_OF_SLSI_SUPER 8 -#define CA91CX42_BM_SLSI_BS 0x000000F6 -#define CA91CX42_OF_SLSI_BS 2 -#define CA91CX42_BM_SLSI_LAS 0x00000003 -#define CA91CX42_OF_SLSI_LAS 0 -#define CA91CX42_BM_SLSI_RESERVED 0x3F0F0000 - -/* - * DCTL Register - * offset 200 - */ -#define CA91CX42_DCTL_L2V (1<<31) -#define CA91CX42_DCTL_VDW_M (3<<22) -#define CA91CX42_DCTL_VDW_D8 0 -#define CA91CX42_DCTL_VDW_D16 (1<<22) -#define CA91CX42_DCTL_VDW_D32 (1<<23) -#define CA91CX42_DCTL_VDW_D64 (3<<22) - -#define CA91CX42_DCTL_VAS_M (7<<16) -#define CA91CX42_DCTL_VAS_A16 0 -#define CA91CX42_DCTL_VAS_A24 (1<<16) -#define CA91CX42_DCTL_VAS_A32 (1<<17) -#define CA91CX42_DCTL_VAS_USER1 (3<<17) -#define CA91CX42_DCTL_VAS_USER2 (7<<16) - -#define CA91CX42_DCTL_PGM_M (1<<14) -#define CA91CX42_DCTL_PGM_DATA 0 -#define CA91CX42_DCTL_PGM_PGM (1<<14) - -#define CA91CX42_DCTL_SUPER_M (1<<12) -#define CA91CX42_DCTL_SUPER_NPRIV 0 -#define CA91CX42_DCTL_SUPER_SUPR (1<<12) - -#define CA91CX42_DCTL_VCT_M (1<<8) -#define CA91CX42_DCTL_VCT_BLT (1<<8) -#define CA91CX42_DCTL_LD64EN (1<<7) - -/* - * DCPP Register - * offset 218 - */ -#define CA91CX42_DCPP_M 0xf -#define CA91CX42_DCPP_NULL (1<<0) - -/* - * DMA General Control/Status Register (DGCS) - * offset 220 - */ -#define CA91CX42_DGCS_GO (1<<31) -#define CA91CX42_DGCS_STOP_REQ (1<<30) -#define CA91CX42_DGCS_HALT_REQ (1<<29) -#define CA91CX42_DGCS_CHAIN (1<<27) - -#define CA91CX42_DGCS_VON_M (7<<20) - -#define CA91CX42_DGCS_VOFF_M (0xf<<16) - -#define CA91CX42_DGCS_ACT (1<<15) -#define CA91CX42_DGCS_STOP (1<<14) -#define CA91CX42_DGCS_HALT (1<<13) -#define CA91CX42_DGCS_DONE (1<<11) -#define CA91CX42_DGCS_LERR (1<<10) -#define CA91CX42_DGCS_VERR (1<<9) -#define CA91CX42_DGCS_PERR (1<<8) -#define CA91CX42_DGCS_INT_STOP (1<<6) -#define CA91CX42_DGCS_INT_HALT (1<<5) -#define CA91CX42_DGCS_INT_DONE (1<<3) -#define CA91CX42_DGCS_INT_LERR (1<<2) -#define CA91CX42_DGCS_INT_VERR (1<<1) -#define CA91CX42_DGCS_INT_PERR (1<<0) - -/* - * PCI Interrupt Enable Register - * offset 300 - */ -#define CA91CX42_LINT_LM3 0x00800000 -#define CA91CX42_LINT_LM2 0x00400000 -#define CA91CX42_LINT_LM1 0x00200000 -#define CA91CX42_LINT_LM0 0x00100000 -#define CA91CX42_LINT_MBOX3 0x00080000 -#define CA91CX42_LINT_MBOX2 0x00040000 -#define CA91CX42_LINT_MBOX1 0x00020000 -#define CA91CX42_LINT_MBOX0 0x00010000 -#define CA91CX42_LINT_ACFAIL 0x00008000 -#define CA91CX42_LINT_SYSFAIL 0x00004000 -#define CA91CX42_LINT_SW_INT 0x00002000 -#define CA91CX42_LINT_SW_IACK 0x00001000 - -#define CA91CX42_LINT_VERR 0x00000400 -#define CA91CX42_LINT_LERR 0x00000200 -#define CA91CX42_LINT_DMA 0x00000100 -#define CA91CX42_LINT_VIRQ7 0x00000080 -#define CA91CX42_LINT_VIRQ6 0x00000040 -#define CA91CX42_LINT_VIRQ5 0x00000020 -#define CA91CX42_LINT_VIRQ4 0x00000010 -#define CA91CX42_LINT_VIRQ3 0x00000008 -#define CA91CX42_LINT_VIRQ2 0x00000004 -#define CA91CX42_LINT_VIRQ1 0x00000002 -#define CA91CX42_LINT_VOWN 0x00000001 - -static const int CA91CX42_LINT_VIRQ[] = { 0, CA91CX42_LINT_VIRQ1, - CA91CX42_LINT_VIRQ2, CA91CX42_LINT_VIRQ3, - CA91CX42_LINT_VIRQ4, CA91CX42_LINT_VIRQ5, - CA91CX42_LINT_VIRQ6, CA91CX42_LINT_VIRQ7 }; - -#define CA91CX42_LINT_MBOX 0x000F0000 - -static const int CA91CX42_LINT_LM[] = { CA91CX42_LINT_LM0, CA91CX42_LINT_LM1, - CA91CX42_LINT_LM2, CA91CX42_LINT_LM3 }; - -/* - * MAST_CTL Register - * offset 400 - */ -#define CA91CX42_BM_MAST_CTL_MAXRTRY 0xF0000000 -#define CA91CX42_OF_MAST_CTL_MAXRTRY 28 -#define CA91CX42_BM_MAST_CTL_PWON 0x0F000000 -#define CA91CX42_OF_MAST_CTL_PWON 24 -#define CA91CX42_BM_MAST_CTL_VRL 0x00C00000 -#define CA91CX42_OF_MAST_CTL_VRL 22 -#define CA91CX42_BM_MAST_CTL_VRM 0x00200000 -#define CA91CX42_BM_MAST_CTL_VREL 0x00100000 -#define CA91CX42_BM_MAST_CTL_VOWN 0x00080000 -#define CA91CX42_BM_MAST_CTL_VOWN_ACK 0x00040000 -#define CA91CX42_BM_MAST_CTL_PABS 0x00001000 -#define CA91CX42_BM_MAST_CTL_BUS_NO 0x0000000F -#define CA91CX42_OF_MAST_CTL_BUS_NO 0 - -/* - * MISC_CTL Register - * offset 404 - */ -#define CA91CX42_MISC_CTL_VBTO 0xF0000000 -#define CA91CX42_MISC_CTL_VARB 0x04000000 -#define CA91CX42_MISC_CTL_VARBTO 0x03000000 -#define CA91CX42_MISC_CTL_SW_LRST 0x00800000 -#define CA91CX42_MISC_CTL_SW_SRST 0x00400000 -#define CA91CX42_MISC_CTL_BI 0x00100000 -#define CA91CX42_MISC_CTL_ENGBI 0x00080000 -#define CA91CX42_MISC_CTL_RESCIND 0x00040000 -#define CA91CX42_MISC_CTL_SYSCON 0x00020000 -#define CA91CX42_MISC_CTL_V64AUTO 0x00010000 -#define CA91CX42_MISC_CTL_RESERVED 0x0820FFFF - -#define CA91CX42_OF_MISC_CTL_VARBTO 24 -#define CA91CX42_OF_MISC_CTL_VBTO 28 - -/* - * MISC_STAT Register - * offset 408 - */ -#define CA91CX42_BM_MISC_STAT_ENDIAN 0x80000000 -#define CA91CX42_BM_MISC_STAT_LCLSIZE 0x40000000 -#define CA91CX42_BM_MISC_STAT_DY4AUTO 0x08000000 -#define CA91CX42_BM_MISC_STAT_MYBBSY 0x00200000 -#define CA91CX42_BM_MISC_STAT_DY4DONE 0x00080000 -#define CA91CX42_BM_MISC_STAT_TXFE 0x00040000 -#define CA91CX42_BM_MISC_STAT_RXFE 0x00020000 -#define CA91CX42_BM_MISC_STAT_DY4AUTOID 0x0000FF00 -#define CA91CX42_OF_MISC_STAT_DY4AUTOID 8 - -/* - * VSI Control Register - * offset F00 - */ -#define CA91CX42_VSI_CTL_EN (1<<31) -#define CA91CX42_VSI_CTL_PWEN (1<<30) -#define CA91CX42_VSI_CTL_PREN (1<<29) - -#define CA91CX42_VSI_CTL_PGM_M (3<<22) -#define CA91CX42_VSI_CTL_PGM_DATA (1<<22) -#define CA91CX42_VSI_CTL_PGM_PGM (1<<23) - -#define CA91CX42_VSI_CTL_SUPER_M (3<<20) -#define CA91CX42_VSI_CTL_SUPER_NPRIV (1<<20) -#define CA91CX42_VSI_CTL_SUPER_SUPR (1<<21) - -#define CA91CX42_VSI_CTL_VAS_M (7<<16) -#define CA91CX42_VSI_CTL_VAS_A16 0 -#define CA91CX42_VSI_CTL_VAS_A24 (1<<16) -#define CA91CX42_VSI_CTL_VAS_A32 (1<<17) -#define CA91CX42_VSI_CTL_VAS_USER1 (3<<17) -#define CA91CX42_VSI_CTL_VAS_USER2 (7<<16) - -#define CA91CX42_VSI_CTL_LD64EN (1<<7) -#define CA91CX42_VSI_CTL_LLRMW (1<<6) - -#define CA91CX42_VSI_CTL_LAS_M (3<<0) -#define CA91CX42_VSI_CTL_LAS_PCI_MS 0 -#define CA91CX42_VSI_CTL_LAS_PCI_IO (1<<0) -#define CA91CX42_VSI_CTL_LAS_PCI_CONF (1<<1) - -/* LM_CTL Register - * offset F64 - */ -#define CA91CX42_LM_CTL_EN (1<<31) -#define CA91CX42_LM_CTL_PGM (1<<23) -#define CA91CX42_LM_CTL_DATA (1<<22) -#define CA91CX42_LM_CTL_SUPR (1<<21) -#define CA91CX42_LM_CTL_NPRIV (1<<20) -#define CA91CX42_LM_CTL_AS_M (7<<16) -#define CA91CX42_LM_CTL_AS_A16 0 -#define CA91CX42_LM_CTL_AS_A24 (1<<16) -#define CA91CX42_LM_CTL_AS_A32 (1<<17) - -/* - * VRAI_CTL Register - * offset F70 - */ -#define CA91CX42_BM_VRAI_CTL_EN 0x80000000 -#define CA91CX42_BM_VRAI_CTL_PGM 0x00C00000 -#define CA91CX42_OF_VRAI_CTL_PGM 22 -#define CA91CX42_BM_VRAI_CTL_SUPER 0x00300000 -#define CA91CX42_OF_VRAI_CTL_SUPER 20 -#define CA91CX42_BM_VRAI_CTL_VAS 0x00030000 -#define CA91CX42_OF_VRAI_CTL_VAS 16 - -/* VCSR_CTL Register - * offset F80 - */ -#define CA91CX42_VCSR_CTL_EN (1<<31) - -#define CA91CX42_VCSR_CTL_LAS_M (3<<0) -#define CA91CX42_VCSR_CTL_LAS_PCI_MS 0 -#define CA91CX42_VCSR_CTL_LAS_PCI_IO (1<<0) -#define CA91CX42_VCSR_CTL_LAS_PCI_CONF (1<<1) - -/* VCSR_BS Register - * offset FFC - */ -#define CA91CX42_VCSR_BS_SLOT_M (0x1F<<27) - -#endif /* _CA91CX42_H */ From 35ba63b8f6d07d353159505423cfca5a4378a11c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 6 Jun 2022 10:41:05 +0200 Subject: [PATCH 0287/1436] vme: move back to staging The VME subsystem graduated from staging into a top-level subsystem in 2012, with commit db3b9e990e75 ("Staging: VME: move VME drivers out of staging") stating: The VME device drivers have not moved out yet due to some API questions they are still working through, that should happen soon, hopefully. However, this never happened: maintenance of drivers/vme effectively stopped in 2017, with all subsequent changes being treewide cleanups. No hardware driver remains in staging, only the limited user-level access, and I just removed one of the two bridge drivers and the only remaining board. drivers/staging/vme/devices/ was recently moved to drivers/staging/vme_user/, but as the vme_user driver is the only one remaining for this subsystem, it is easier to just move the remaining three source files into this directory rather than keeping the original hierarchy. Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20220606084109.4108188-3-arnd@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/vme.rst | 4 +-- MAINTAINERS | 4 +-- drivers/Kconfig | 2 -- drivers/Makefile | 1 - drivers/staging/vme_user/Kconfig | 27 +++++++++++++++++++ drivers/staging/vme_user/Makefile | 3 +++ drivers/{vme => staging/vme_user}/vme.c | 2 +- .../linux => drivers/staging/vme_user}/vme.h | 0 .../{vme => staging/vme_user}/vme_bridge.h | 2 +- .../bridges => staging/vme_user}/vme_fake.c | 4 +-- .../bridges => staging/vme_user}/vme_tsi148.c | 4 +-- .../bridges => staging/vme_user}/vme_tsi148.h | 0 drivers/staging/vme_user/vme_user.c | 2 +- drivers/vme/Kconfig | 16 ----------- drivers/vme/Makefile | 7 ----- drivers/vme/bridges/Kconfig | 17 ------------ drivers/vme/bridges/Makefile | 3 --- 17 files changed, 40 insertions(+), 58 deletions(-) rename drivers/{vme => staging/vme_user}/vme.c (99%) rename {include/linux => drivers/staging/vme_user}/vme.h (100%) rename drivers/{vme => staging/vme_user}/vme_bridge.h (99%) rename drivers/{vme/bridges => staging/vme_user}/vme_fake.c (99%) rename drivers/{vme/bridges => staging/vme_user}/vme_tsi148.c (99%) rename drivers/{vme/bridges => staging/vme_user}/vme_tsi148.h (100%) delete mode 100644 drivers/vme/Kconfig delete mode 100644 drivers/vme/Makefile delete mode 100644 drivers/vme/bridges/Kconfig delete mode 100644 drivers/vme/bridges/Makefile diff --git a/Documentation/driver-api/vme.rst b/Documentation/driver-api/vme.rst index def139c13410..c0b475369de0 100644 --- a/Documentation/driver-api/vme.rst +++ b/Documentation/driver-api/vme.rst @@ -290,8 +290,8 @@ The function :c:func:`vme_bus_num` returns the bus ID of the provided bridge. VME API ------- -.. kernel-doc:: include/linux/vme.h +.. kernel-doc:: drivers/staging/vme_user/vme.h :internal: -.. kernel-doc:: drivers/vme/vme.c +.. kernel-doc:: drivers/staging/vme_user/vme.c :export: diff --git a/MAINTAINERS b/MAINTAINERS index 60e5e4007844..7097b824ba18 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -21230,12 +21230,10 @@ M: Martyn Welch M: Manohar Vanga M: Greg Kroah-Hartman L: linux-kernel@vger.kernel.org -S: Maintained +S: Odd fixes T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git F: Documentation/driver-api/vme.rst F: drivers/staging/vme_user/ -F: drivers/vme/ -F: include/linux/vme* VM SOCKETS (AF_VSOCK) M: Stefano Garzarella diff --git a/drivers/Kconfig b/drivers/Kconfig index b6a172d32a7d..19ee995bd0ae 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -183,8 +183,6 @@ source "drivers/iio/Kconfig" source "drivers/ntb/Kconfig" -source "drivers/vme/Kconfig" - source "drivers/pwm/Kconfig" source "drivers/irqchip/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 9a30842b22c5..dadf2678277f 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -165,7 +165,6 @@ obj-$(CONFIG_PM_DEVFREQ) += devfreq/ obj-$(CONFIG_EXTCON) += extcon/ obj-$(CONFIG_MEMORY) += memory/ obj-$(CONFIG_IIO) += iio/ -obj-$(CONFIG_VME_BUS) += vme/ obj-$(CONFIG_IPACK_BUS) += ipack/ obj-$(CONFIG_NTB) += ntb/ obj-$(CONFIG_POWERCAP) += powercap/ diff --git a/drivers/staging/vme_user/Kconfig b/drivers/staging/vme_user/Kconfig index e8b4461bf27f..c8eabf8f40f1 100644 --- a/drivers/staging/vme_user/Kconfig +++ b/drivers/staging/vme_user/Kconfig @@ -1,4 +1,29 @@ # SPDX-License-Identifier: GPL-2.0 +menuconfig VME_BUS + bool "VME bridge support" + depends on STAGING && PCI + help + If you say Y here you get support for the VME bridge Framework. + +if VME_BUS + +comment "VME Bridge Drivers" + +config VME_TSI148 + tristate "Tempe" + depends on HAS_DMA + help + If you say Y here you get support for the Tundra TSI148 VME bridge + chip. + +config VME_FAKE + tristate "Fake" + help + If you say Y here you get support for the fake VME bridge. This + provides a virtualised VME Bus for devices with no VME bridge. This + is mainly useful for VME development (in the absence of VME + hardware). + comment "VME Device Drivers" config VME_USER @@ -11,3 +36,5 @@ config VME_USER To compile this driver as a module, choose M here. The module will be called vme_user. If unsure, say N. + +endif diff --git a/drivers/staging/vme_user/Makefile b/drivers/staging/vme_user/Makefile index 5380115139b0..8dcc6938ce5c 100644 --- a/drivers/staging/vme_user/Makefile +++ b/drivers/staging/vme_user/Makefile @@ -3,4 +3,7 @@ # Makefile for the VME device drivers. # +obj-$(CONFIG_VME_BUS) += vme.o obj-$(CONFIG_VME_USER) += vme_user.o +obj-$(CONFIG_VME_TSI148) += vme_tsi148.o +obj-$(CONFIG_VME_FAKE) += vme_fake.o diff --git a/drivers/vme/vme.c b/drivers/staging/vme_user/vme.c similarity index 99% rename from drivers/vme/vme.c rename to drivers/staging/vme_user/vme.c index 8dba20186be3..b5555683a069 100644 --- a/drivers/vme/vme.c +++ b/drivers/staging/vme_user/vme.c @@ -26,8 +26,8 @@ #include #include #include -#include +#include "vme.h" #include "vme_bridge.h" /* Bitmask and list of registered buses both protected by common mutex */ diff --git a/include/linux/vme.h b/drivers/staging/vme_user/vme.h similarity index 100% rename from include/linux/vme.h rename to drivers/staging/vme_user/vme.h diff --git a/drivers/vme/vme_bridge.h b/drivers/staging/vme_user/vme_bridge.h similarity index 99% rename from drivers/vme/vme_bridge.h rename to drivers/staging/vme_user/vme_bridge.h index 42ecf961004e..0bbefe9851d7 100644 --- a/drivers/vme/vme_bridge.h +++ b/drivers/staging/vme_user/vme_bridge.h @@ -2,7 +2,7 @@ #ifndef _VME_BRIDGE_H_ #define _VME_BRIDGE_H_ -#include +#include "vme.h" #define VME_CRCSR_BUF_SIZE (508*1024) /* diff --git a/drivers/vme/bridges/vme_fake.c b/drivers/staging/vme_user/vme_fake.c similarity index 99% rename from drivers/vme/bridges/vme_fake.c rename to drivers/staging/vme_user/vme_fake.c index 6a1bc284f297..dd646b0c531d 100644 --- a/drivers/vme/bridges/vme_fake.c +++ b/drivers/staging/vme_user/vme_fake.c @@ -29,9 +29,9 @@ #include #include #include -#include -#include "../vme_bridge.h" +#include "vme.h" +#include "vme_bridge.h" /* * Define the number of each that the fake driver supports. diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/staging/vme_user/vme_tsi148.c similarity index 99% rename from drivers/vme/bridges/vme_tsi148.c rename to drivers/staging/vme_user/vme_tsi148.c index be9051b02f24..956476213241 100644 --- a/drivers/vme/bridges/vme_tsi148.c +++ b/drivers/staging/vme_user/vme_tsi148.c @@ -26,9 +26,9 @@ #include #include #include -#include -#include "../vme_bridge.h" +#include "vme.h" +#include "vme_bridge.h" #include "vme_tsi148.h" static int tsi148_probe(struct pci_dev *, const struct pci_device_id *); diff --git a/drivers/vme/bridges/vme_tsi148.h b/drivers/staging/vme_user/vme_tsi148.h similarity index 100% rename from drivers/vme/bridges/vme_tsi148.h rename to drivers/staging/vme_user/vme_tsi148.h diff --git a/drivers/staging/vme_user/vme_user.c b/drivers/staging/vme_user/vme_user.c index 859af797630c..4e533c0bfe6d 100644 --- a/drivers/staging/vme_user/vme_user.c +++ b/drivers/staging/vme_user/vme_user.c @@ -33,8 +33,8 @@ #include #include -#include +#include "vme.h" #include "vme_user.h" static const char driver_name[] = "vme_user"; diff --git a/drivers/vme/Kconfig b/drivers/vme/Kconfig deleted file mode 100644 index 26feabba19d2..000000000000 --- a/drivers/vme/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# VME configuration. -# - -menuconfig VME_BUS - bool "VME bridge support" - depends on PCI - help - If you say Y here you get support for the VME bridge Framework. - -if VME_BUS - -source "drivers/vme/bridges/Kconfig" - -endif # VME diff --git a/drivers/vme/Makefile b/drivers/vme/Makefile deleted file mode 100644 index 2dfb929a23de..000000000000 --- a/drivers/vme/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Makefile for the VME bridge device drivers. -# -obj-$(CONFIG_VME_BUS) += vme.o - -obj-y += bridges/ diff --git a/drivers/vme/bridges/Kconfig b/drivers/vme/bridges/Kconfig deleted file mode 100644 index 9493b22b5276..000000000000 --- a/drivers/vme/bridges/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -comment "VME Bridge Drivers" - -config VME_TSI148 - tristate "Tempe" - depends on HAS_DMA - help - If you say Y here you get support for the Tundra TSI148 VME bridge - chip. - -config VME_FAKE - tristate "Fake" - help - If you say Y here you get support for the fake VME bridge. This - provides a virtualised VME Bus for devices with no VME bridge. This - is mainly useful for VME development (in the absence of VME - hardware). diff --git a/drivers/vme/bridges/Makefile b/drivers/vme/bridges/Makefile deleted file mode 100644 index 043f9cd7a510..000000000000 --- a/drivers/vme/bridges/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VME_TSI148) += vme_tsi148.o -obj-$(CONFIG_VME_FAKE) += vme_fake.o From 5a46079a96451cfb15e4f5f01f73f7ba24ef851a Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:06:57 -0700 Subject: [PATCH 0288/1436] PM: domains: Delete usage of driver_deferred_probe_check_state() Now that fw_devlink=on by default and fw_devlink supports "power-domains" property, the execution will never get to the point where driver_deferred_probe_check_state() is called before the supplier has probed successfully or before deferred probe timeout has expired. So, delete the call and replace it with -ENODEV. Tested-by: Geert Uytterhoeven Reviewed-by: Ulf Hansson Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-2-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/power/domain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 739e52cd4aba..3e86772d5fac 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2730,7 +2730,7 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device *base_dev, mutex_unlock(&gpd_list_lock); dev_dbg(dev, "%s() failed to find PM domain: %ld\n", __func__, PTR_ERR(pd)); - return driver_deferred_probe_check_state(base_dev); + return -ENODEV; } dev_dbg(dev, "adding to PM domain %s\n", pd->name); From 24a026f85241a01bbcfe1b263caeeaa9a79bab40 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:06:58 -0700 Subject: [PATCH 0289/1436] pinctrl: devicetree: Delete usage of driver_deferred_probe_check_state() Now that fw_devlink=on by default and fw_devlink supports "pinctrl-[0-8]" property, the execution will never get to the point where driver_deferred_probe_check_state() is called before the supplier has probed successfully or before deferred probe timeout has expired. So, delete the call and replace it with -ENODEV. Tested-by: Geert Uytterhoeven Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-3-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/devicetree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index 3fb238714718..ef898ee8ca6b 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -129,7 +129,7 @@ static int dt_to_map_one_config(struct pinctrl *p, np_pctldev = of_get_next_parent(np_pctldev); if (!np_pctldev || of_node_is_root(np_pctldev)) { of_node_put(np_pctldev); - ret = driver_deferred_probe_check_state(p->dev); + ret = -ENODEV; /* keep deferring if modules are enabled */ if (IS_ENABLED(CONFIG_MODULES) && !allow_default && ret < 0) ret = -EPROBE_DEFER; From f8217275b57aa48d98cc42051c2aac34152718d6 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:06:59 -0700 Subject: [PATCH 0290/1436] net: mdio: Delete usage of driver_deferred_probe_check_state() Now that fw_devlink=on by default and fw_devlink supports interrupt properties, the execution will never get to the point where driver_deferred_probe_check_state() is called before the supplier has probed successfully or before deferred probe timeout has expired. So, delete the call and replace it with -ENODEV. Tested-by: Geert Uytterhoeven Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-4-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/net/mdio/fwnode_mdio.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c index 1c1584fca632..3e79c2c51929 100644 --- a/drivers/net/mdio/fwnode_mdio.c +++ b/drivers/net/mdio/fwnode_mdio.c @@ -47,9 +47,7 @@ int fwnode_mdiobus_phy_device_register(struct mii_bus *mdio, * just fall back to poll mode */ if (rc == -EPROBE_DEFER) - rc = driver_deferred_probe_check_state(&phy->mdio.dev); - if (rc == -EPROBE_DEFER) - return rc; + rc = -ENODEV; if (rc > 0) { phy->irq = rc; From 2f8c3ae8288e4a4018330ed5c4e758b878d9c555 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:07:00 -0700 Subject: [PATCH 0291/1436] driver core: Add wait_for_init_devices_probe helper function Some devices might need to be probed and bound successfully before the kernel boot sequence can finish and move on to init/userspace. For example, a network interface might need to be bound to be able to mount a NFS rootfs. With fw_devlink=on by default, some of these devices might be blocked from probing because they are waiting on a optional supplier that doesn't have a driver. While fw_devlink will eventually identify such devices and unblock the probing automatically, it might be too late by the time it unblocks the probing of devices. For example, the IP4 autoconfig might timeout before fw_devlink unblocks probing of the network interface. This function is available to temporarily try and probe all devices that have a driver even if some of their suppliers haven't been added or don't have drivers. The drivers can then decide which of the suppliers are optional vs mandatory and probe the device if possible. By the time this function returns, all such "best effort" probes are guaranteed to be completed. If a device successfully probes in this mode, we delete all fw_devlink discovered dependencies of that device where the supplier hasn't yet probed successfully because they have to be optional dependencies. This also means that some devices that aren't needed for init and could have waited for their optional supplier to probe (when the supplier's module is loaded later on) would end up probing prematurely with limited functionality. So call this function only when boot would fail without it. Tested-by: Geert Uytterhoeven Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-5-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/base.h | 1 + drivers/base/core.c | 100 ++++++++++++++++++++++++++++++++-- drivers/base/dd.c | 19 +++++-- include/linux/device/driver.h | 1 + 4 files changed, 110 insertions(+), 11 deletions(-) diff --git a/drivers/base/base.h b/drivers/base/base.h index ab71403d102f..b3a43a164dcd 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -160,6 +160,7 @@ extern int devres_release_all(struct device *dev); extern void device_block_probing(void); extern void device_unblock_probing(void); extern void deferred_probe_extend_timeout(void); +extern void driver_deferred_probe_trigger(void); /* /sys/devices directory */ extern struct kset *devices_kset; diff --git a/drivers/base/core.c b/drivers/base/core.c index 7cd789c4985d..61fdfe99b348 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -54,6 +54,7 @@ static unsigned int defer_sync_state_count = 1; static DEFINE_MUTEX(fwnode_link_lock); static bool fw_devlink_is_permissive(void); static bool fw_devlink_drv_reg_done; +static bool fw_devlink_best_effort; /** * fwnode_link_add - Create a link between two fwnode_handles. @@ -965,6 +966,11 @@ static void device_links_missing_supplier(struct device *dev) } } +static bool dev_is_best_effort(struct device *dev) +{ + return fw_devlink_best_effort && dev->can_match; +} + /** * device_links_check_suppliers - Check presence of supplier drivers. * @dev: Consumer device. @@ -984,7 +990,7 @@ static void device_links_missing_supplier(struct device *dev) int device_links_check_suppliers(struct device *dev) { struct device_link *link; - int ret = 0; + int ret = 0, fwnode_ret = 0; struct fwnode_handle *sup_fw; /* @@ -997,12 +1003,17 @@ int device_links_check_suppliers(struct device *dev) sup_fw = list_first_entry(&dev->fwnode->suppliers, struct fwnode_link, c_hook)->supplier; - dev_err_probe(dev, -EPROBE_DEFER, "wait for supplier %pfwP\n", - sup_fw); - mutex_unlock(&fwnode_link_lock); - return -EPROBE_DEFER; + if (!dev_is_best_effort(dev)) { + fwnode_ret = -EPROBE_DEFER; + dev_err_probe(dev, -EPROBE_DEFER, + "wait for supplier %pfwP\n", sup_fw); + } else { + fwnode_ret = -EAGAIN; + } } mutex_unlock(&fwnode_link_lock); + if (fwnode_ret == -EPROBE_DEFER) + return fwnode_ret; device_links_write_lock(); @@ -1012,6 +1023,14 @@ int device_links_check_suppliers(struct device *dev) if (link->status != DL_STATE_AVAILABLE && !(link->flags & DL_FLAG_SYNC_STATE_ONLY)) { + + if (dev_is_best_effort(dev) && + link->flags & DL_FLAG_INFERRED && + !link->supplier->can_match) { + ret = -EAGAIN; + continue; + } + device_links_missing_supplier(dev); dev_err_probe(dev, -EPROBE_DEFER, "supplier %s not ready\n", @@ -1024,7 +1043,8 @@ int device_links_check_suppliers(struct device *dev) dev->links.status = DL_DEV_PROBING; device_links_write_unlock(); - return ret; + + return ret ? ret : fwnode_ret; } /** @@ -1289,6 +1309,18 @@ void device_links_driver_bound(struct device *dev) * save to drop the managed link completely. */ device_link_drop_managed(link); + } else if (dev_is_best_effort(dev) && + link->flags & DL_FLAG_INFERRED && + link->status != DL_STATE_CONSUMER_PROBE && + !link->supplier->can_match) { + /* + * When dev_is_best_effort() is true, we ignore device + * links to suppliers that don't have a driver. If the + * consumer device still managed to probe, there's no + * point in maintaining a device link in a weird state + * (consumer probed before supplier). So delete it. + */ + device_link_drop_managed(link); } else { WARN_ON(link->status != DL_STATE_CONSUMER_PROBE); WRITE_ONCE(link->status, DL_STATE_ACTIVE); @@ -1655,6 +1687,62 @@ void fw_devlink_drivers_done(void) device_links_write_unlock(); } +/** + * wait_for_init_devices_probe - Try to probe any device needed for init + * + * Some devices might need to be probed and bound successfully before the kernel + * boot sequence can finish and move on to init/userspace. For example, a + * network interface might need to be bound to be able to mount a NFS rootfs. + * + * With fw_devlink=on by default, some of these devices might be blocked from + * probing because they are waiting on a optional supplier that doesn't have a + * driver. While fw_devlink will eventually identify such devices and unblock + * the probing automatically, it might be too late by the time it unblocks the + * probing of devices. For example, the IP4 autoconfig might timeout before + * fw_devlink unblocks probing of the network interface. + * + * This function is available to temporarily try and probe all devices that have + * a driver even if some of their suppliers haven't been added or don't have + * drivers. + * + * The drivers can then decide which of the suppliers are optional vs mandatory + * and probe the device if possible. By the time this function returns, all such + * "best effort" probes are guaranteed to be completed. If a device successfully + * probes in this mode, we delete all fw_devlink discovered dependencies of that + * device where the supplier hasn't yet probed successfully because they have to + * be optional dependencies. + * + * Any devices that didn't successfully probe go back to being treated as if + * this function was never called. + * + * This also means that some devices that aren't needed for init and could have + * waited for their optional supplier to probe (when the supplier's module is + * loaded later on) would end up probing prematurely with limited functionality. + * So call this function only when boot would fail without it. + */ +void __init wait_for_init_devices_probe(void) +{ + if (!fw_devlink_flags || fw_devlink_is_permissive()) + return; + + /* + * Wait for all ongoing probes to finish so that the "best effort" is + * only applied to devices that can't probe otherwise. + */ + wait_for_device_probe(); + + pr_info("Trying to probe devices needed for running init ...\n"); + fw_devlink_best_effort = true; + driver_deferred_probe_trigger(); + + /* + * Wait for all "best effort" probes to finish before going back to + * normal enforcement. + */ + wait_for_device_probe(); + fw_devlink_best_effort = false; +} + static void fw_devlink_unblock_consumers(struct device *dev) { struct device_link *link; diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 11b0fb6414d3..4a55fbb7e0da 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -172,7 +172,7 @@ static bool driver_deferred_probe_enable; * changes in the midst of a probe, then deferred processing should be triggered * again. */ -static void driver_deferred_probe_trigger(void) +void driver_deferred_probe_trigger(void) { if (!driver_deferred_probe_enable) return; @@ -580,7 +580,7 @@ static int really_probe(struct device *dev, struct device_driver *drv) { bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) && !drv->suppress_bind_attrs; - int ret; + int ret, link_ret; if (defer_all_probes) { /* @@ -592,9 +592,9 @@ static int really_probe(struct device *dev, struct device_driver *drv) return -EPROBE_DEFER; } - ret = device_links_check_suppliers(dev); - if (ret) - return ret; + link_ret = device_links_check_suppliers(dev); + if (link_ret == -EPROBE_DEFER) + return link_ret; pr_debug("bus: '%s': %s: probing driver %s with device %s\n", drv->bus->name, __func__, drv->name, dev_name(dev)); @@ -633,6 +633,15 @@ re_probe: ret = call_driver_probe(dev, drv); if (ret) { + /* + * If fw_devlink_best_effort is active (denoted by -EAGAIN), the + * device might actually probe properly once some of its missing + * suppliers have probed. So, treat this as if the driver + * returned -EPROBE_DEFER. + */ + if (link_ret == -EAGAIN) + ret = -EPROBE_DEFER; + /* * Return probe errors as positive values so that the callers * can distinguish them from other errors. diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index 700453017e1c..2114d65b862f 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -129,6 +129,7 @@ extern struct device_driver *driver_find(const char *name, struct bus_type *bus); extern int driver_probe_done(void); extern void wait_for_device_probe(void); +void __init wait_for_init_devices_probe(void); /* sysfs interface for exporting driver attributes */ From dd429036e778a3d789e6f6df6d1684764048fb50 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:07:01 -0700 Subject: [PATCH 0292/1436] net: ipconfig: Relax fw_devlink if we need to mount a network rootfs If there are network devices that could probe without some of their suppliers probing and those network devices are needed to mount a network rootfs, then fw_devlink=on might break that usecase by blocking the network devices from probing by the time IP auto config starts. So, if no network devices are available when IP auto config is enabled and we have a network rootfs, make sure fw_devlink doesn't block the probing of any device that has a driver and then retry finding a network device. Tested-by: Geert Uytterhoeven Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-6-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ipconfig.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 9d41d5d5cd1e..2342debd7066 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1434,6 +1434,7 @@ __be32 __init root_nfs_parse_addr(char *name) static int __init wait_for_devices(void) { int i; + bool try_init_devs = true; for (i = 0; i < DEVICE_WAIT_MAX; i++) { struct net_device *dev; @@ -1452,6 +1453,11 @@ static int __init wait_for_devices(void) rtnl_unlock(); if (found) return 0; + if (try_init_devs && + (ROOT_DEV == Root_NFS || ROOT_DEV == Root_CIFS)) { + try_init_devs = false; + wait_for_init_devices_probe(); + } ssleep(1); } return -ENODEV; From f516d01b9df2782b9399c44fa1d21c3d09211f8a Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:07:02 -0700 Subject: [PATCH 0293/1436] Revert "driver core: Set default deferred_probe_timeout back to 0." This reverts commit 11f7e7ef553b6b93ac1aa74a3c2011b9cc8aeb61. Let's take another shot at getting deferred_probe_timeout=10 to work. Tested-by: Geert Uytterhoeven Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-7-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 4a55fbb7e0da..335e71d3a618 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -256,7 +256,12 @@ static int deferred_devs_show(struct seq_file *s, void *data) } DEFINE_SHOW_ATTRIBUTE(deferred_devs); +#ifdef CONFIG_MODULES +int driver_deferred_probe_timeout = 10; +#else int driver_deferred_probe_timeout; +#endif + EXPORT_SYMBOL_GPL(driver_deferred_probe_timeout); static int __init deferred_probe_timeout_setup(char *str) From 71066545b48e4259f89481199a0bbc7c35457738 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:07:03 -0700 Subject: [PATCH 0294/1436] driver core: Set fw_devlink.strict=1 by default Now that deferred_probe_timeout is non-zero by default, fw_devlink will never permanently block the probing of devices. It'll try its best to probe the devices in the right order and then finally let devices probe even if their suppliers don't have any drivers. Tested-by: Geert Uytterhoeven Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-8-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 61fdfe99b348..977b379a495b 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1613,7 +1613,7 @@ static int __init fw_devlink_setup(char *arg) } early_param("fw_devlink", fw_devlink_setup); -static bool fw_devlink_strict; +static bool fw_devlink_strict = true; static int __init fw_devlink_strict_setup(char *arg) { return strtobool(arg, &fw_devlink_strict); From b09796d528bbf06e3e10a4a8f78038719da7ebc6 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:07:04 -0700 Subject: [PATCH 0295/1436] iommu/of: Delete usage of driver_deferred_probe_check_state() Now that fw_devlink=on and fw_devlink.strict=1 by default and fw_devlink supports iommu DT properties, the execution will never get to the point where driver_deferred_probe_check_state() is called before the supplier has probed successfully or before deferred probe timeout has expired. So, delete the call and replace it with -ENODEV. Tested-by: Geert Uytterhoeven Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-9-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/of_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 5696314ae69e..41f4eb005219 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -40,7 +40,7 @@ static int of_iommu_xlate(struct device *dev, * a proper probe-ordering dependency mechanism in future. */ if (!ops) - return driver_deferred_probe_check_state(dev); + return -ENODEV; if (!try_module_get(ops->owner)) return -ENODEV; From 9cbffc7a59561be950ecc675d19a3d2b45202b2b Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 1 Jun 2022 00:07:05 -0700 Subject: [PATCH 0296/1436] driver core: Delete driver_deferred_probe_check_state() The function is no longer used. So delete it. Tested-by: Geert Uytterhoeven Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220601070707.3946847-10-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 30 ------------------------------ include/linux/device/driver.h | 1 - 2 files changed, 31 deletions(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 335e71d3a618..e600dd2afc35 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -274,42 +274,12 @@ static int __init deferred_probe_timeout_setup(char *str) } __setup("deferred_probe_timeout=", deferred_probe_timeout_setup); -/** - * driver_deferred_probe_check_state() - Check deferred probe state - * @dev: device to check - * - * Return: - * * -ENODEV if initcalls have completed and modules are disabled. - * * -ETIMEDOUT if the deferred probe timeout was set and has expired - * and modules are enabled. - * * -EPROBE_DEFER in other cases. - * - * Drivers or subsystems can opt-in to calling this function instead of directly - * returning -EPROBE_DEFER. - */ -int driver_deferred_probe_check_state(struct device *dev) -{ - if (!IS_ENABLED(CONFIG_MODULES) && initcalls_done) { - dev_warn(dev, "ignoring dependency for device, assuming no driver\n"); - return -ENODEV; - } - - if (!driver_deferred_probe_timeout && initcalls_done) { - dev_warn(dev, "deferred probe timeout, ignoring dependency\n"); - return -ETIMEDOUT; - } - - return -EPROBE_DEFER; -} -EXPORT_SYMBOL_GPL(driver_deferred_probe_check_state); - static void deferred_probe_timeout_work_func(struct work_struct *work) { struct device_private *p; fw_devlink_drivers_done(); - driver_deferred_probe_timeout = 0; driver_deferred_probe_trigger(); flush_work(&deferred_probe_work); diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index 2114d65b862f..7acaabde5396 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -242,7 +242,6 @@ driver_find_device_by_acpi_dev(struct device_driver *drv, const void *adev) extern int driver_deferred_probe_timeout; void driver_deferred_probe_add(struct device *dev); -int driver_deferred_probe_check_state(struct device *dev); void driver_init(void); /** From 61d9c412d0416aa1f7914a732d424a9e8ff24c36 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 26 May 2022 21:08:10 +0000 Subject: [PATCH 0297/1436] KVM: x86: Grab regs_dirty in local 'unsigned long' Capture ctxt->regs_dirty in a local 'unsigned long' instead of casting it to an 'unsigned long *' for use in for_each_set_bit(). The bitops helpers really do read the entire 'unsigned long', even though the walking of the read value is capped at the specified size. I.e. 64-bit KVM is reading memory beyond ctxt->regs_dirty, which is a u32 and thus 4 bytes, whereas an unsigned long is 8 bytes. Functionally it's not an issue because regs_dirty is in the middle of x86_emulate_ctxt, i.e. KVM is just reading its own memory, but relying on that coincidence is gross and unsafe. Reviewed-by: Vitaly Kuznetsov Reviewed-by: Kees Cook Signed-off-by: Sean Christopherson Message-Id: <20220526210817.3428868-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 89b11e7dca8a..7226a127ccb4 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -269,9 +269,10 @@ static ulong *reg_rmw(struct x86_emulate_ctxt *ctxt, unsigned nr) static void writeback_registers(struct x86_emulate_ctxt *ctxt) { + unsigned long dirty = ctxt->regs_dirty; unsigned reg; - for_each_set_bit(reg, (ulong *)&ctxt->regs_dirty, 16) + for_each_set_bit(reg, &dirty, 16) ctxt->ops->write_gpr(ctxt, reg, ctxt->_regs[reg]); } From dfe21e6bc05af433308bc1842da28a8fe28faaa4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 26 May 2022 21:08:11 +0000 Subject: [PATCH 0298/1436] KVM: x86: Harden _regs accesses to guard against buggy input WARN and truncate the incoming GPR number/index when reading/writing GPRs in the emulator to guard against KVM bugs, e.g. to avoid out-of-bounds accesses to ctxt->_regs[] if KVM generates a bogus index. Truncate the index instead of returning e.g. zero, as reg_write() returns a pointer to the register, i.e. returning zero would result in a NULL pointer dereference. KVM could also force the index to any arbitrary GPR, but that's no better or worse, just different. Open code the restriction to 16 registers; RIP is handled via _eip and should never be accessed through reg_read() or reg_write(). See the comments above the declarations of reg_read() and reg_write(), and the behavior of writeback_registers(). The horrific open coded mess will be cleaned up in a future commit. There are no such bugs known to exist in the emulator, but determining that KVM is bug-free is not at all simple and requires a deep dive into the emulator. The code is so convoluted that GCC-12 with the recently enable -Warray-bounds spits out a false-positive due to a GCC bug: arch/x86/kvm/emulate.c:254:27: warning: array subscript 32 is above array bounds of 'long unsigned int[17]' [-Warray-bounds] 254 | return ctxt->_regs[nr]; | ~~~~~~~~~~~^~~~ In file included from arch/x86/kvm/emulate.c:23: arch/x86/kvm/kvm_emulate.h: In function 'reg_rmw': arch/x86/kvm/kvm_emulate.h:366:23: note: while referencing '_regs' 366 | unsigned long _regs[NR_VCPU_REGS]; | ^~~~~ Link: https://lore.kernel.org/all/YofQlBrlx18J7h9Y@google.com Link: https://bugzilla.kernel.org/show_bug.cgi?id=216026 Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105679 Reported-and-tested-by: Robert Dinse Reported-by: Kees Cook Reviewed-by: Kees Cook Signed-off-by: Sean Christopherson Message-Id: <20220526210817.3428868-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 7226a127ccb4..c58366ae4da2 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -247,6 +247,9 @@ enum x86_transfer_type { static ulong reg_read(struct x86_emulate_ctxt *ctxt, unsigned nr) { + if (WARN_ON_ONCE(nr >= 16)) + nr &= 16 - 1; + if (!(ctxt->regs_valid & (1 << nr))) { ctxt->regs_valid |= 1 << nr; ctxt->_regs[nr] = ctxt->ops->read_gpr(ctxt, nr); @@ -256,6 +259,9 @@ static ulong reg_read(struct x86_emulate_ctxt *ctxt, unsigned nr) static ulong *reg_write(struct x86_emulate_ctxt *ctxt, unsigned nr) { + if (WARN_ON_ONCE(nr >= 16)) + nr &= 16 - 1; + ctxt->regs_valid |= 1 << nr; ctxt->regs_dirty |= 1 << nr; return &ctxt->_regs[nr]; From a5ba67b42f07952ec45755bbdd66d7c6e49f555c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 26 May 2022 21:08:12 +0000 Subject: [PATCH 0299/1436] KVM: x86: Omit VCPU_REGS_RIP from emulator's _regs array Omit RIP from the emulator's _regs array, which is used only for GPRs, i.e. registers that can be referenced via ModRM and/or SIB bytes. The emulator uses the dedicated _eip field for RIP, and manually reads from _eip to handle RIP-relative addressing. To avoid an even bigger, slightly more dangerous change, hardcode the number of GPRs to 16 for the time being even though 32-bit KVM's emulator technically should only have 8 GPRs. Add a TODO to address that in a future commit. See also the comments above the read_gpr() and write_gpr() declarations, and obviously the handling in writeback_registers(). No functional change intended. Signed-off-by: Sean Christopherson Reviewed-by: Kees Cook Message-Id: <20220526210817.3428868-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 10 +++++----- arch/x86/kvm/kvm_emulate.h | 13 ++++++++++++- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index c58366ae4da2..c74c0fd3b860 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -247,8 +247,8 @@ enum x86_transfer_type { static ulong reg_read(struct x86_emulate_ctxt *ctxt, unsigned nr) { - if (WARN_ON_ONCE(nr >= 16)) - nr &= 16 - 1; + if (WARN_ON_ONCE(nr >= NR_EMULATOR_GPRS)) + nr &= NR_EMULATOR_GPRS - 1; if (!(ctxt->regs_valid & (1 << nr))) { ctxt->regs_valid |= 1 << nr; @@ -259,8 +259,8 @@ static ulong reg_read(struct x86_emulate_ctxt *ctxt, unsigned nr) static ulong *reg_write(struct x86_emulate_ctxt *ctxt, unsigned nr) { - if (WARN_ON_ONCE(nr >= 16)) - nr &= 16 - 1; + if (WARN_ON_ONCE(nr >= NR_EMULATOR_GPRS)) + nr &= NR_EMULATOR_GPRS - 1; ctxt->regs_valid |= 1 << nr; ctxt->regs_dirty |= 1 << nr; @@ -278,7 +278,7 @@ static void writeback_registers(struct x86_emulate_ctxt *ctxt) unsigned long dirty = ctxt->regs_dirty; unsigned reg; - for_each_set_bit(reg, &dirty, 16) + for_each_set_bit(reg, &dirty, NR_EMULATOR_GPRS) ctxt->ops->write_gpr(ctxt, reg, ctxt->_regs[reg]); } diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index 8dff25d267b7..bc3f8295c8c8 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -301,6 +301,17 @@ struct fastop; typedef void (*fastop_t)(struct fastop *); +/* + * The emulator's _regs array tracks only the GPRs, i.e. excludes RIP. RIP is + * tracked/accessed via _eip, and except for RIP relative addressing, which + * also uses _eip, RIP cannot be a register operand nor can it be an operand in + * a ModRM or SIB byte. + * + * TODO: this is technically wrong for 32-bit KVM, which only supports 8 GPRs; + * R8-R15 don't exist. + */ +#define NR_EMULATOR_GPRS 16 + struct x86_emulate_ctxt { void *vcpu; const struct x86_emulate_ops *ops; @@ -363,7 +374,7 @@ struct x86_emulate_ctxt { struct operand src2; struct operand dst; struct operand memop; - unsigned long _regs[NR_VCPU_REGS]; + unsigned long _regs[NR_EMULATOR_GPRS]; struct operand *memopp; struct fetch_cache fetch; struct read_cache io_read; From 0cbc60d44c35b1070eb4070b499164d27d050576 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 26 May 2022 21:08:13 +0000 Subject: [PATCH 0300/1436] KVM: x86: Use 16-bit fields to track dirty/valid emulator GPRs Use a u16 instead of a u32 to track the dirty/valid status of GPRs in the emulator. Unlike struct kvm_vcpu_arch, x86_emulate_ctxt tracks only the "true" GPRs, i.e. doesn't include RIP in its array, and so only needs to track 16 registers. Note, maxing out at 16 GPRs is a fundamental property of x86-64 and will not change barring a massive architecture update. Legacy x86 ModRM and SIB encodings use 3 bits for GPRs, i.e. support 8 registers. x86-64 uses a single bit in the REX prefix for each possible reference type to double the number of supported GPRs to 16 registers (4 bits). Reviewed-by: Kees Cook Signed-off-by: Sean Christopherson Message-Id: <20220526210817.3428868-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 3 +++ arch/x86/kvm/kvm_emulate.h | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index c74c0fd3b860..5aaf1d1200af 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -262,6 +262,9 @@ static ulong *reg_write(struct x86_emulate_ctxt *ctxt, unsigned nr) if (WARN_ON_ONCE(nr >= NR_EMULATOR_GPRS)) nr &= NR_EMULATOR_GPRS - 1; + BUILD_BUG_ON(sizeof(ctxt->regs_dirty) * BITS_PER_BYTE < NR_EMULATOR_GPRS); + BUILD_BUG_ON(sizeof(ctxt->regs_valid) * BITS_PER_BYTE < NR_EMULATOR_GPRS); + ctxt->regs_valid |= 1 << nr; ctxt->regs_dirty |= 1 << nr; return &ctxt->_regs[nr]; diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index bc3f8295c8c8..3a65d6ea7fe6 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -356,9 +356,9 @@ struct x86_emulate_ctxt { u8 lock_prefix; u8 rep_prefix; /* bitmaps of registers in _regs[] that can be read */ - u32 regs_valid; + u16 regs_valid; /* bitmaps of registers in _regs[] that have been written */ - u32 regs_dirty; + u16 regs_dirty; /* modrm */ u8 modrm; u8 modrm_mod; From b443183a25ab61840a12de92f8822849e017b9c8 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 26 May 2022 21:08:14 +0000 Subject: [PATCH 0301/1436] KVM: x86: Reduce the number of emulator GPRs to '8' for 32-bit KVM Reduce the number of GPRs emulated by 32-bit KVM from 16 to 8. KVM does not support emulating 64-bit mode on 32-bit host kernels, and so should never generate accesses to R8-15. Opportunistically use NR_EMULATOR_GPRS in rsm_load_state_{32,64}() now that it is precise and accurate for both flavors. Wrap the definition with full #ifdef ugliness; sadly, IS_ENABLED() doesn't guarantee a compile-time constant as far as BUILD_BUG_ON() is concerned. Signed-off-by: Sean Christopherson Reviewed-by: Kees Cook Message-Id: <20220526210817.3428868-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 4 ++-- arch/x86/kvm/kvm_emulate.h | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 5aaf1d1200af..77161f57c8d3 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2441,7 +2441,7 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, ctxt->eflags = GET_SMSTATE(u32, smstate, 0x7ff4) | X86_EFLAGS_FIXED; ctxt->_eip = GET_SMSTATE(u32, smstate, 0x7ff0); - for (i = 0; i < 8; i++) + for (i = 0; i < NR_EMULATOR_GPRS; i++) *reg_write(ctxt, i) = GET_SMSTATE(u32, smstate, 0x7fd0 + i * 4); val = GET_SMSTATE(u32, smstate, 0x7fcc); @@ -2498,7 +2498,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u16 selector; int i, r; - for (i = 0; i < 16; i++) + for (i = 0; i < NR_EMULATOR_GPRS; i++) *reg_write(ctxt, i) = GET_SMSTATE(u64, smstate, 0x7ff8 - i * 8); ctxt->_eip = GET_SMSTATE(u64, smstate, 0x7f78); diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index 3a65d6ea7fe6..034c845b3c63 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -306,11 +306,12 @@ typedef void (*fastop_t)(struct fastop *); * tracked/accessed via _eip, and except for RIP relative addressing, which * also uses _eip, RIP cannot be a register operand nor can it be an operand in * a ModRM or SIB byte. - * - * TODO: this is technically wrong for 32-bit KVM, which only supports 8 GPRs; - * R8-R15 don't exist. */ +#ifdef CONFIG_X86_64 #define NR_EMULATOR_GPRS 16 +#else +#define NR_EMULATOR_GPRS 8 +#endif struct x86_emulate_ctxt { void *vcpu; From 1cca2f8c501fa01e6c0d2aefbf97f8c3c89c0186 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 26 May 2022 21:08:15 +0000 Subject: [PATCH 0302/1436] KVM: x86: Bug the VM if the emulator accesses a non-existent GPR Bug the VM, i.e. kill it, if the emulator accesses a non-existent GPR, i.e. generates an out-of-bounds GPR index. Continuing on all but gaurantees some form of data corruption in the guest, e.g. even if KVM were to redirect to a dummy register, KVM would be incorrectly read zeros and drop writes. Note, bugging the VM doesn't completely prevent data corruption, e.g. the current round of emulation will complete before the vCPU bails out to userspace. But, the very act of killing the guest can also cause data corruption, e.g. due to lack of file writeback before termination, so taking on additional complexity to cleanly bail out of the emulator isn't justified, the goal is purely to stem the bleeding and alert userspace that something has gone horribly wrong, i.e. to avoid _silent_ data corruption. Signed-off-by: Sean Christopherson Reviewed-by: Kees Cook Reviewed-by: Vitaly Kuznetsov Message-Id: <20220526210817.3428868-7-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 4 ++-- arch/x86/kvm/kvm_emulate.h | 10 ++++++++++ arch/x86/kvm/x86.c | 9 +++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 77161f57c8d3..70a8e0cd9fdc 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -247,7 +247,7 @@ enum x86_transfer_type { static ulong reg_read(struct x86_emulate_ctxt *ctxt, unsigned nr) { - if (WARN_ON_ONCE(nr >= NR_EMULATOR_GPRS)) + if (KVM_EMULATOR_BUG_ON(nr >= NR_EMULATOR_GPRS, ctxt)) nr &= NR_EMULATOR_GPRS - 1; if (!(ctxt->regs_valid & (1 << nr))) { @@ -259,7 +259,7 @@ static ulong reg_read(struct x86_emulate_ctxt *ctxt, unsigned nr) static ulong *reg_write(struct x86_emulate_ctxt *ctxt, unsigned nr) { - if (WARN_ON_ONCE(nr >= NR_EMULATOR_GPRS)) + if (KVM_EMULATOR_BUG_ON(nr >= NR_EMULATOR_GPRS, ctxt)) nr &= NR_EMULATOR_GPRS - 1; BUILD_BUG_ON(sizeof(ctxt->regs_dirty) * BITS_PER_BYTE < NR_EMULATOR_GPRS); diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h index 034c845b3c63..89246446d6aa 100644 --- a/arch/x86/kvm/kvm_emulate.h +++ b/arch/x86/kvm/kvm_emulate.h @@ -89,6 +89,7 @@ struct x86_instruction_info { #define X86EMUL_INTERCEPTED 6 /* Intercepted by nested VMCB/VMCS */ struct x86_emulate_ops { + void (*vm_bugged)(struct x86_emulate_ctxt *ctxt); /* * read_gpr: read a general purpose register (rax - r15) * @@ -383,6 +384,15 @@ struct x86_emulate_ctxt { bool is_branch; }; +#define KVM_EMULATOR_BUG_ON(cond, ctxt) \ +({ \ + int __ret = (cond); \ + \ + if (WARN_ON_ONCE(__ret)) \ + ctxt->ops->vm_bugged(ctxt); \ + unlikely(__ret); \ +}) + /* Repeat String Operation Prefix */ #define REPE_PREFIX 0xf3 #define REPNE_PREFIX 0xf2 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e8177d8b378e..a0baf49bb00d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -7915,7 +7915,16 @@ static int emulator_set_xcr(struct x86_emulate_ctxt *ctxt, u32 index, u64 xcr) return __kvm_set_xcr(emul_to_vcpu(ctxt), index, xcr); } +static void emulator_vm_bugged(struct x86_emulate_ctxt *ctxt) +{ + struct kvm *kvm = emul_to_vcpu(ctxt)->kvm; + + if (!kvm->vm_bugged) + kvm_vm_bugged(kvm); +} + static const struct x86_emulate_ops emulate_ops = { + .vm_bugged = emulator_vm_bugged, .read_gpr = emulator_read_gpr, .write_gpr = emulator_write_gpr, .read_std = emulator_read_std, From 49a1431d3bea4092082b0082cd9f58f3ccdf57f4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 26 May 2022 21:08:16 +0000 Subject: [PATCH 0303/1436] KVM: x86: Bug the VM if the emulator generates a bogus exception vector Bug the VM if KVM's emulator attempts to inject a bogus exception vector. The guest is likely doomed even if KVM continues on, and propagating a bad vector to the rest of KVM runs the risk of breaking other assumptions in KVM and thus triggering a more egregious bug. All existing users of emulate_exception() have hardcoded vector numbers (__load_segment_descriptor() uses a few different vectors, but they're all hardcoded), and future users are likely to follow suit, i.e. the change to emulate_exception() is a glorified nop. As for the ctxt->exception.vector check in x86_emulate_insn(), the few known times the WARN has been triggered in the past is when the field was not set when synthesizing a fault, i.e. for all intents and purposes the check protects against consumption of uninitialized data. Signed-off-by: Sean Christopherson Reviewed-by: Kees Cook Reviewed-by: Vitaly Kuznetsov Message-Id: <20220526210817.3428868-8-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 70a8e0cd9fdc..2aa17462a9ac 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -624,7 +624,9 @@ static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg) static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec, u32 error, bool valid) { - WARN_ON(vec > 0x1f); + if (KVM_EMULATOR_BUG_ON(vec > 0x1f, ctxt)) + return X86EMUL_UNHANDLEABLE; + ctxt->exception.vector = vec; ctxt->exception.error_code = error; ctxt->exception.error_code_valid = valid; @@ -5728,7 +5730,8 @@ writeback: done: if (rc == X86EMUL_PROPAGATE_FAULT) { - WARN_ON(ctxt->exception.vector > 0x1f); + if (KVM_EMULATOR_BUG_ON(ctxt->exception.vector > 0x1f, ctxt)) + return EMULATION_FAILED; ctxt->have_exception = true; } if (rc == X86EMUL_INTERCEPTED) From d38ea9579ce34dfe22378788e99f26eab31ea064 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 26 May 2022 21:08:17 +0000 Subject: [PATCH 0304/1436] KVM: x86: Bug the VM on an out-of-bounds data read Bug the VM and terminate emulation if an out-of-bounds read into the emulator's data cache occurs. Knowingly contuining on all but guarantees that KVM will overwrite random kernel data, which is far, far worse than killing the VM. Signed-off-by: Sean Christopherson Reviewed-by: Kees Cook Reviewed-by: Vitaly Kuznetsov Message-Id: <20220526210817.3428868-9-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 2aa17462a9ac..39ea9138224c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1373,7 +1373,8 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt, if (mc->pos < mc->end) goto read_cached; - WARN_ON((mc->end + size) >= sizeof(mc->data)); + if (KVM_EMULATOR_BUG_ON((mc->end + size) >= sizeof(mc->data), ctxt)) + return X86EMUL_UNHANDLEABLE; rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, size, &ctxt->exception); From 82b070beae1ef55b0049768c8dc91d87565bb191 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 Jun 2022 15:02:18 +0300 Subject: [PATCH 0305/1436] driver core: Introduce device_find_any_child() helper There are several places in the kernel where this kind of functionality is being used. Provide a generic helper for such cases. Reviewed-by: Rafael J. Wysocki Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220610120219.18988-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 20 ++++++++++++++++++++ include/linux/device.h | 2 ++ 2 files changed, 22 insertions(+) diff --git a/drivers/base/core.c b/drivers/base/core.c index 977b379a495b..839f64485a55 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -3920,6 +3920,26 @@ struct device *device_find_child_by_name(struct device *parent, } EXPORT_SYMBOL_GPL(device_find_child_by_name); +static int match_any(struct device *dev, void *unused) +{ + return 1; +} + +/** + * device_find_any_child - device iterator for locating a child device, if any. + * @parent: parent struct device + * + * This is similar to the device_find_child() function above, but it + * returns a reference to a child device, if any. + * + * NOTE: you will need to drop the reference with put_device() after use. + */ +struct device *device_find_any_child(struct device *parent) +{ + return device_find_child(parent, NULL, match_any); +} +EXPORT_SYMBOL_GPL(device_find_any_child); + int __init devices_init(void) { devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); diff --git a/include/linux/device.h b/include/linux/device.h index dc941997795c..424b55df0272 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -905,6 +905,8 @@ struct device *device_find_child(struct device *dev, void *data, int (*match)(struct device *dev, void *data)); struct device *device_find_child_by_name(struct device *parent, const char *name); +struct device *device_find_any_child(struct device *parent); + int device_rename(struct device *dev, const char *new_name); int device_move(struct device *dev, struct device *new_parent, enum dpm_order dpm_order); From c21b0837983d3b00c4f73927dae8441bf478087f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 10 Jun 2022 15:02:19 +0300 Subject: [PATCH 0306/1436] spi: Use device_find_any_child() instead of custom approach We have already a helper to get the first child device, use it and drop custom approach. Reviewed-by: Rafael J. Wysocki Acked-by: Mark Brown Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220610120219.18988-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ea09d1b42bf6..b04be04dddfa 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -2613,11 +2613,6 @@ int spi_slave_abort(struct spi_device *spi) } EXPORT_SYMBOL_GPL(spi_slave_abort); -static int match_true(struct device *dev, void *data) -{ - return 1; -} - static ssize_t slave_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2625,7 +2620,7 @@ static ssize_t slave_show(struct device *dev, struct device_attribute *attr, dev); struct device *child; - child = device_find_child(&ctlr->dev, NULL, match_true); + child = device_find_any_child(&ctlr->dev); return sprintf(buf, "%s\n", child ? to_spi_device(child)->modalias : NULL); } @@ -2644,7 +2639,7 @@ static ssize_t slave_store(struct device *dev, struct device_attribute *attr, if (rc != 1 || !name[0]) return -EINVAL; - child = device_find_child(&ctlr->dev, NULL, match_true); + child = device_find_any_child(&ctlr->dev); if (child) { /* Remove registered slave */ device_unregister(child); From 8deb03e75f6048b33b80025b6475c92975670c5b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 1 Jun 2022 12:16:53 -0700 Subject: [PATCH 0307/1436] KVM: Fix references to non-existent KVM_CAP_TRIPLE_FAULT_EVENT The x86-only KVM_CAP_TRIPLE_FAULT_EVENT was (appropriately) renamed to KVM_CAP_X86_TRIPLE_FAULT_EVENT when the patches were applied, but the docs and selftests got left behind. Fix them. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 4 ++-- .../testing/selftests/kvm/x86_64/triple_fault_event_test.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 9cbbfdb663b6..84c486ce6279 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -1152,7 +1152,7 @@ The following bits are defined in the flags field: - KVM_VCPUEVENT_VALID_TRIPLE_FAULT may be set to signal that the triple_fault_pending field contains a valid state. This bit will - be set whenever KVM_CAP_TRIPLE_FAULT_EVENT is enabled. + be set whenever KVM_CAP_X86_TRIPLE_FAULT_EVENT is enabled. ARM64: ^^^^^^ @@ -1249,7 +1249,7 @@ can be set in the flags field to signal that the exception_has_payload, exception_payload, and exception.pending fields contain a valid state and shall be written into the VCPU. -If KVM_CAP_TRIPLE_FAULT_EVENT is enabled, KVM_VCPUEVENT_VALID_TRIPLE_FAULT +If KVM_CAP_X86_TRIPLE_FAULT_EVENT is enabled, KVM_VCPUEVENT_VALID_TRIPLE_FAULT can be set in flags field to signal that the triple_fault field contains a valid state and shall be written into the VCPU. diff --git a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c index 6e1de0631ce9..66378140764d 100644 --- a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c +++ b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c @@ -47,7 +47,7 @@ int main(void) struct ucall uc; struct kvm_enable_cap cap = { - .cap = KVM_CAP_TRIPLE_FAULT_EVENT, + .cap = KVM_CAP_X86_TRIPLE_FAULT_EVENT, .args = {1} }; @@ -56,8 +56,8 @@ int main(void) exit(KSFT_SKIP); } - if (!kvm_check_cap(KVM_CAP_TRIPLE_FAULT_EVENT)) { - print_skip("KVM_CAP_TRIPLE_FAULT_EVENT not supported"); + if (!kvm_check_cap(KVM_CAP_X86_TRIPLE_FAULT_EVENT)) { + print_skip("KVM_CAP_X86_TRIPLE_FAULT_EVENT not supported"); exit(KSFT_SKIP); } From 1ca378f65378864b33a0356478252bd49bf6ef86 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 23 Feb 2022 14:52:12 -0800 Subject: [PATCH 0308/1436] KVM: selftests: Fix buggy-but-benign check in test_v3_new_redist_regions() Update 'ret' with the return value of _kvm_device_access() prior to asserting that ret is non-zero. In the current code base, the flaw is benign as 'ret' is guaranteed to be -EBUSY from the previous run_vcpu(), which also means that errno==EBUSY prior to _kvm_device_access(), thus the "errno == EFAULT" part of the assert means that a false negative is impossible (unless the kernel is being truly mean and spuriously setting errno=EFAULT while returning success). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/vgic_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 34379c98d2f4..0f046e3e953d 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -381,8 +381,8 @@ static void test_v3_new_redist_regions(void) v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS); subtest_v3_redist_regions(&v); - _kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, dummy, true); + ret = _kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, dummy, true); TEST_ASSERT(ret && errno == EFAULT, "register a third region allowing to cover the 4 vcpus"); From ff624e57d8dfb6c66ff8118aca7bad61d75428f0 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 11:47:05 -0800 Subject: [PATCH 0309/1436] KVM: selftests: Fix typo in vgic_init test When iterating over vCPUs, invoke access_v3_redist_reg() on the "current" vCPU instead of vCPU0, which is presumably what was intended by iterating over all vCPUs. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/vgic_init.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 0f046e3e953d..defd196c69d2 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -426,8 +426,9 @@ static void test_v3_typer_accesses(void) KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); for (i = 0; i < NR_VCPUS ; i++) { - ret = access_v3_redist_reg(v.gic_fd, 0, GICR_TYPER, &val, false); - TEST_ASSERT(!ret && !val, "read GICR_TYPER before rdist region setting"); + ret = access_v3_redist_reg(v.gic_fd, i, GICR_TYPER, &val, false); + TEST_ASSERT(!ret && val == i * 0x100, + "read GICR_TYPER before rdist region setting"); } addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0); From d379749fdab68d0eee05e149a25f8ef45d2f19bc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 2 May 2022 15:25:35 -0700 Subject: [PATCH 0310/1436] KVM: selftests: Drop stale declarations from kvm_util_base.h Drop declarations for allocate_kvm_dirty_log() and vm_create_device(), which no longer have implementations. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/include/kvm_util_base.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 92cef0ffb19e..47b77ebda6a3 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -381,11 +381,6 @@ struct kvm_userspace_memory_region * kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end); -struct kvm_dirty_log * -allocate_kvm_dirty_log(struct kvm_userspace_memory_region *region); - -int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd); - #define sync_global_to_guest(vm, g) ({ \ typeof(g) *_p = addr_gva2hva(vm, (vm_vaddr_t)&(g)); \ memcpy(_p, &(g), sizeof(g)); \ From ccc82ba6bea45189a516c97480b2b70406832f35 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 14 Feb 2022 17:12:38 -0800 Subject: [PATCH 0311/1436] KVM: selftests: Always open VM file descriptors with O_RDWR Drop the @perm param from vm_create() and always open VM file descriptors with O_RDWR. There's no legitimate use case for other permissions, and if a selftest wants to do oddball negative testing it can open code the necessary bits instead of forcing a bunch of tests to provide useless information. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/get-reg-list.c | 2 +- .../testing/selftests/kvm/aarch64/psci_test.c | 2 +- .../selftests/kvm/aarch64/vcpu_width_config.c | 6 +++--- tools/testing/selftests/kvm/dirty_log_test.c | 2 +- .../selftests/kvm/hardware_disable_test.c | 2 +- .../selftests/kvm/include/kvm_util_base.h | 4 ++-- .../selftests/kvm/kvm_binary_stats_test.c | 2 +- .../selftests/kvm/kvm_create_max_vcpus.c | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 20 +++++++++---------- .../selftests/kvm/set_memory_region_test.c | 4 ++-- tools/testing/selftests/kvm/x86_64/amx_test.c | 2 +- .../testing/selftests/kvm/x86_64/evmcs_test.c | 2 +- .../kvm/x86_64/max_vcpuid_cap_test.c | 2 +- .../selftests/kvm/x86_64/set_boot_cpu_id.c | 2 +- .../selftests/kvm/x86_64/set_sregs_test.c | 2 +- .../selftests/kvm/x86_64/sev_migrate_tests.c | 8 ++++---- tools/testing/selftests/kvm/x86_64/smm_test.c | 2 +- .../testing/selftests/kvm/x86_64/state_test.c | 2 +- .../kvm/x86_64/vmx_preemption_timer_test.c | 2 +- 19 files changed, 34 insertions(+), 36 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index d3a7dbfcbb3d..dd549cc75869 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -416,7 +416,7 @@ static void run_test(struct vcpu_config *c) check_supported(c); - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); prepare_vcpu_init(c, &init); aarch64_vcpu_add_default(vm, 0, &init, NULL); finalize_vcpu(vm, 0, c); diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index 88541de21c41..de3b5e176d04 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -78,7 +78,7 @@ static struct kvm_vm *setup_vm(void *guest_code) struct kvm_vcpu_init init; struct kvm_vm *vm; - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); kvm_vm_elf_load(vm, program_invocation_name); ucall_init(vm, NULL); diff --git a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c index 6e9402679229..d48129349213 100644 --- a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c +++ b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c @@ -24,7 +24,7 @@ static int add_init_2vcpus(struct kvm_vcpu_init *init1, struct kvm_vm *vm; int ret; - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); vm_vcpu_add(vm, 0); ret = _vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); @@ -49,7 +49,7 @@ static int add_2vcpus_init_2vcpus(struct kvm_vcpu_init *init1, struct kvm_vm *vm; int ret; - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); vm_vcpu_add(vm, 0); vm_vcpu_add(vm, 1); @@ -86,7 +86,7 @@ int main(void) } /* Get the preferred target type and copy that to init2 for later use */ - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init1); kvm_vm_free(vm); init2 = init1; diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 3fcd89e195c7..11bf606e3165 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -679,7 +679,7 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode)); - vm = vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages, O_RDWR); + vm = vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); kvm_vm_elf_load(vm, program_invocation_name); #ifdef __x86_64__ vm_create_irqchip(vm); diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c index b21c69a56daa..1c9e2295c75b 100644 --- a/tools/testing/selftests/kvm/hardware_disable_test.c +++ b/tools/testing/selftests/kvm/hardware_disable_test.c @@ -104,7 +104,7 @@ static void run_test(uint32_t run) for (i = 0; i < VCPU_NUM; i++) CPU_SET(i, &cpu_set); - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); kvm_vm_elf_load(vm, program_invocation_name); vm_create_irqchip(vm); diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 47b77ebda6a3..89b633b40247 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -110,9 +110,9 @@ int vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size); const char *vm_guest_mode_string(uint32_t i); -struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); +struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages); void kvm_vm_free(struct kvm_vm *vmp); -void kvm_vm_restart(struct kvm_vm *vmp, int perm); +void kvm_vm_restart(struct kvm_vm *vmp); void kvm_vm_release(struct kvm_vm *vmp); void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log); void kvm_vm_clear_dirty_log(struct kvm_vm *vm, int slot, void *log, diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 17f65d514915..6217f4630e6c 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -230,7 +230,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(vms, "Allocate memory for storing VM pointers"); for (i = 0; i < max_vm; ++i) { vms[i] = vm_create(VM_MODE_DEFAULT, - DEFAULT_GUEST_PHY_PAGES, O_RDWR); + DEFAULT_GUEST_PHY_PAGES); for (j = 0; j < max_vcpu; ++j) vm_vcpu_add(vms[i], j); } diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c index aed9dc3ca1e9..bb69b75eac23 100644 --- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c +++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c @@ -28,7 +28,7 @@ void test_vcpu_creation(int first_vcpu_id, int num_vcpus) pr_info("Testing creating %d vCPUs, with IDs %d...%d.\n", num_vcpus, first_vcpu_id, first_vcpu_id + num_vcpus - 1); - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); for (i = first_vcpu_id; i < first_vcpu_id + num_vcpus; i++) /* This asserts that the vCPU was created. */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 1665a220abcb..da7e3369f4b8 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -173,9 +173,9 @@ void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size) vm->dirty_ring_size = ring_size; } -static void vm_open(struct kvm_vm *vm, int perm) +static void vm_open(struct kvm_vm *vm) { - vm->kvm_fd = _open_kvm_dev_path_or_exit(perm); + vm->kvm_fd = _open_kvm_dev_path_or_exit(O_RDWR); if (!kvm_check_cap(KVM_CAP_IMMEDIATE_EXIT)) { print_skip("immediate_exit not available"); @@ -240,7 +240,6 @@ _Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_params) * Input Args: * mode - VM Mode (e.g. VM_MODE_P52V48_4K) * phy_pages - Physical memory pages - * perm - permission * * Output Args: None * @@ -253,12 +252,12 @@ _Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_params) * descriptor to control the created VM is created with the permissions * given by perm (e.g. O_RDWR). */ -struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) +struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages) { struct kvm_vm *vm; - pr_debug("%s: mode='%s' pages='%ld' perm='%d'\n", __func__, - vm_guest_mode_string(mode), phy_pages, perm); + pr_debug("%s: mode='%s' pages='%ld'\n", __func__, + vm_guest_mode_string(mode), phy_pages); vm = calloc(1, sizeof(*vm)); TEST_ASSERT(vm != NULL, "Insufficient Memory"); @@ -340,7 +339,7 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) vm->type = KVM_VM_TYPE_ARM_IPA_SIZE(vm->pa_bits); #endif - vm_open(vm, perm); + vm_open(vm); /* Limit to VA-bit canonical virtual addresses. */ vm->vpages_valid = sparsebit_alloc(); @@ -366,7 +365,7 @@ struct kvm_vm *vm_create_without_vcpus(enum vm_guest_mode mode, uint64_t pages) { struct kvm_vm *vm; - vm = vm_create(mode, pages, O_RDWR); + vm = vm_create(mode, pages); kvm_vm_elf_load(vm, program_invocation_name); @@ -458,7 +457,6 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, * * Input Args: * vm - VM that has been released before - * perm - permission * * Output Args: None * @@ -466,12 +464,12 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, * global state, such as the irqchip and the memory regions that are mapped * into the guest. */ -void kvm_vm_restart(struct kvm_vm *vmp, int perm) +void kvm_vm_restart(struct kvm_vm *vmp) { int ctr; struct userspace_mem_region *region; - vm_open(vmp, perm); + vm_open(vmp); if (vmp->has_irqchip) vm_create_irqchip(vmp); diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index 73bc297dabe6..d97cfd6866c3 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -314,7 +314,7 @@ static void test_zero_memory_regions(void) pr_info("Testing KVM_RUN with zero added memory regions\n"); - vm = vm_create(VM_MODE_DEFAULT, 0, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, 0); vm_vcpu_add(vm, VCPU_ID); TEST_ASSERT(!ioctl(vm_get_fd(vm), KVM_SET_NR_MMU_PAGES, 64), @@ -354,7 +354,7 @@ static void test_add_max_memory_regions(void) "KVM_CAP_NR_MEMSLOTS should be greater than 0"); pr_info("Allowed number of memory slots: %i\n", max_mem_slots); - vm = vm_create(VM_MODE_DEFAULT, 0, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, 0); /* Check it can be added memory slots up to the maximum allowed */ pr_info("Adding slots 0..%i, each memory region with %dK size\n", diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index 76f65c22796f..2f01247da0b5 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -431,7 +431,7 @@ int main(int argc, char *argv[]) kvm_vm_release(vm); /* Restore state in a new VM. */ - kvm_vm_restart(vm, O_RDWR); + kvm_vm_restart(vm); vm_vcpu_add(vm, VCPU_ID); vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); vcpu_load_state(vm, VCPU_ID, state); diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c index e161c6dd7a02..78668605f673 100644 --- a/tools/testing/selftests/kvm/x86_64/evmcs_test.c +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c @@ -183,7 +183,7 @@ static void save_restore_vm(struct kvm_vm *vm) kvm_vm_release(vm); /* Restore state in a new VM. */ - kvm_vm_restart(vm, O_RDWR); + kvm_vm_restart(vm); vm_vcpu_add(vm, VCPU_ID); vcpu_set_hv_cpuid(vm, VCPU_ID); vcpu_enable_evmcs(vm, VCPU_ID); diff --git a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c index 3f6c1ad86cc6..28cc316c5dbe 100644 --- a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c +++ b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c @@ -18,7 +18,7 @@ int main(int argc, char *argv[]) struct kvm_enable_cap cap = { 0 }; int ret; - vm = vm_create(VM_MODE_DEFAULT, 0, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, 0); /* Get KVM_CAP_MAX_VCPU_ID cap supported in KVM */ ret = vm_check_cap(vm, KVM_CAP_MAX_VCPU_ID); diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index ae76436af0cc..2fe893ccedd0 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -88,7 +88,7 @@ static struct kvm_vm *create_vm(void) uint64_t pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages; pages = vm_adjust_num_guest_pages(VM_MODE_DEFAULT, pages); - vm = vm_create(VM_MODE_DEFAULT, pages, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, pages); kvm_vm_elf_load(vm, program_invocation_name); vm_create_irqchip(vm); diff --git a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c index 318be0bf77ab..44711ab735c3 100644 --- a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c +++ b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c @@ -95,7 +95,7 @@ int main(int argc, char *argv[]) * use it to verify all supported CR4 bits can be set prior to defining * the vCPU model, i.e. without doing KVM_SET_CPUID2. */ - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); vm_vcpu_add(vm, VCPU_ID); vcpu_sregs_get(vm, VCPU_ID, &sregs); diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index d1dc1acf997c..b0c052443c44 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -54,7 +54,7 @@ static struct kvm_vm *sev_vm_create(bool es) struct kvm_sev_launch_start start = { 0 }; int i; - vm = vm_create(VM_MODE_DEFAULT, 0, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, 0); sev_ioctl(vm->fd, es ? KVM_SEV_ES_INIT : KVM_SEV_INIT, NULL); for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i) vm_vcpu_add(vm, i); @@ -71,7 +71,7 @@ static struct kvm_vm *aux_vm_create(bool with_vcpus) struct kvm_vm *vm; int i; - vm = vm_create(VM_MODE_DEFAULT, 0, O_RDWR); + vm = vm_create(VM_MODE_DEFAULT, 0); if (!with_vcpus) return vm; @@ -174,7 +174,7 @@ static void test_sev_migrate_parameters(void) *sev_es_vm_no_vmsa; int ret; - vm_no_vcpu = vm_create(VM_MODE_DEFAULT, 0, O_RDWR); + vm_no_vcpu = vm_create(VM_MODE_DEFAULT, 0); vm_no_sev = aux_vm_create(true); ret = __sev_migrate_from(vm_no_vcpu->fd, vm_no_sev->fd); TEST_ASSERT(ret == -1 && errno == EINVAL, @@ -186,7 +186,7 @@ static void test_sev_migrate_parameters(void) sev_vm = sev_vm_create(/* es= */ false); sev_es_vm = sev_vm_create(/* es= */ true); - sev_es_vm_no_vmsa = vm_create(VM_MODE_DEFAULT, 0, O_RDWR); + sev_es_vm_no_vmsa = vm_create(VM_MODE_DEFAULT, 0); sev_ioctl(sev_es_vm_no_vmsa->fd, KVM_SEV_ES_INIT, NULL); vm_vcpu_add(sev_es_vm_no_vmsa, 1); diff --git a/tools/testing/selftests/kvm/x86_64/smm_test.c b/tools/testing/selftests/kvm/x86_64/smm_test.c index b4e0c860769e..dd2c1522ab90 100644 --- a/tools/testing/selftests/kvm/x86_64/smm_test.c +++ b/tools/testing/selftests/kvm/x86_64/smm_test.c @@ -204,7 +204,7 @@ int main(int argc, char *argv[]) state = vcpu_save_state(vm, VCPU_ID); kvm_vm_release(vm); - kvm_vm_restart(vm, O_RDWR); + kvm_vm_restart(vm); vm_vcpu_add(vm, VCPU_ID); vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); vcpu_load_state(vm, VCPU_ID, state); diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index 2e0a92da8ff5..41f7faaef2ac 100644 --- a/tools/testing/selftests/kvm/x86_64/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -213,7 +213,7 @@ int main(int argc, char *argv[]) kvm_vm_release(vm); /* Restore state in a new VM. */ - kvm_vm_restart(vm, O_RDWR); + kvm_vm_restart(vm); vm_vcpu_add(vm, VCPU_ID); vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); vcpu_load_state(vm, VCPU_ID, state); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c index ff92e25b6f1e..f5b4ae914131 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c @@ -239,7 +239,7 @@ int main(int argc, char *argv[]) kvm_vm_release(vm); /* Restore state in a new VM. */ - kvm_vm_restart(vm, O_RDWR); + kvm_vm_restart(vm); vm_vcpu_add(vm, VCPU_ID); vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); vcpu_load_state(vm, VCPU_ID, state); From 2b38a7398f20dbbfa88689819b21967489d284f5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 10:27:55 -0800 Subject: [PATCH 0312/1436] KVM: selftests: Add another underscore to inner ioctl() helpers Add a second underscore to inner ioctl() helpers to better align with commonly accepted kernel coding style, and to allow using a single underscore variant in the future for macro shenanigans. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/get-reg-list.c | 6 ++--- .../selftests/kvm/aarch64/hypercalls.c | 2 +- .../selftests/kvm/aarch64/vcpu_width_config.c | 8 +++---- .../testing/selftests/kvm/aarch64/vgic_init.c | 2 +- .../selftests/kvm/include/kvm_util_base.h | 8 +++---- tools/testing/selftests/kvm/lib/kvm_util.c | 24 +++++++++---------- .../selftests/kvm/lib/riscv/processor.c | 2 +- tools/testing/selftests/kvm/s390x/memop.c | 4 ++-- tools/testing/selftests/kvm/s390x/resets.c | 4 ++-- tools/testing/selftests/kvm/steal_time.c | 6 ++--- .../selftests/kvm/x86_64/hyperv_cpuid.c | 4 ++-- .../selftests/kvm/x86_64/set_boot_cpu_id.c | 6 ++--- .../kvm/x86_64/vmx_nested_tsc_scaling_test.c | 2 +- 13 files changed, 39 insertions(+), 39 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index dd549cc75869..441c98ffb812 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -457,7 +457,7 @@ static void run_test(struct vcpu_config *c) bool reject_reg = false; int ret; - ret = _vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, ®); + ret = __vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, ®); if (ret) { printf("%s: Failed to get ", config_name(c)); print_reg(c, reg.id); @@ -469,7 +469,7 @@ static void run_test(struct vcpu_config *c) for_each_sublist(c, s) { if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) { reject_reg = true; - ret = _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, ®); + ret = __vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, ®); if (ret != -1 || errno != EPERM) { printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno); print_reg(c, reg.id); @@ -481,7 +481,7 @@ static void run_test(struct vcpu_config *c) } if (!reject_reg) { - ret = _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, ®); + ret = __vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, ®); if (ret) { printf("%s: Failed to set ", config_name(c)); print_reg(c, reg.id); diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c index 41e0210b7a5e..1eb9738453b4 100644 --- a/tools/testing/selftests/kvm/aarch64/hypercalls.c +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c @@ -148,7 +148,7 @@ static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val) .addr = (uint64_t)&val, }; - return _vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, ®); + return __vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, ®); } static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr) diff --git a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c index d48129349213..271fa90e53fd 100644 --- a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c +++ b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c @@ -27,12 +27,12 @@ static int add_init_2vcpus(struct kvm_vcpu_init *init1, vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); vm_vcpu_add(vm, 0); - ret = _vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); + ret = __vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); if (ret) goto free_exit; vm_vcpu_add(vm, 1); - ret = _vcpu_ioctl(vm, 1, KVM_ARM_VCPU_INIT, init2); + ret = __vcpu_ioctl(vm, 1, KVM_ARM_VCPU_INIT, init2); free_exit: kvm_vm_free(vm); @@ -54,11 +54,11 @@ static int add_2vcpus_init_2vcpus(struct kvm_vcpu_init *init1, vm_vcpu_add(vm, 0); vm_vcpu_add(vm, 1); - ret = _vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); + ret = __vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); if (ret) goto free_exit; - ret = _vcpu_ioctl(vm, 1, KVM_ARM_VCPU_INIT, init2); + ret = __vcpu_ioctl(vm, 1, KVM_ARM_VCPU_INIT, init2); free_exit: kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index defd196c69d2..4b7e7ba43969 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -55,7 +55,7 @@ static void guest_code(void) static int run_vcpu(struct kvm_vm *vm, uint32_t vcpuid) { ucall_init(vm, NULL); - int ret = _vcpu_ioctl(vm, vcpuid, KVM_RUN, NULL); + int ret = __vcpu_ioctl(vm, vcpuid, KVM_RUN, NULL); if (ret) return -errno; return 0; diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 89b633b40247..662579a6358b 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -159,12 +159,12 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, void *arg); -int _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, - void *arg); +int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, + void *arg); void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); -int _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); +int __vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); void kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); -int _kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); +int __kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa); void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index da7e3369f4b8..03c1f885a98b 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1719,7 +1719,7 @@ struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid) struct kvm_reg_list reg_list_n = { .n = 0 }, *reg_list; int ret; - ret = _vcpu_ioctl(vm, vcpuid, KVM_GET_REG_LIST, ®_list_n); + ret = __vcpu_ioctl(vm, vcpuid, KVM_GET_REG_LIST, ®_list_n); TEST_ASSERT(ret == -1 && errno == E2BIG, "KVM_GET_REG_LIST n=0"); reg_list = calloc(1, sizeof(*reg_list) + reg_list_n.n * sizeof(__u64)); reg_list->n = reg_list_n.n; @@ -1905,7 +1905,7 @@ void vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_fpu *fpu) { int ret; - ret = _vcpu_ioctl(vm, vcpuid, KVM_GET_FPU, fpu); + ret = __vcpu_ioctl(vm, vcpuid, KVM_GET_FPU, fpu); TEST_ASSERT(ret == 0, "KVM_GET_FPU failed, rc: %i errno: %i (%s)", ret, errno, strerror(errno)); } @@ -1914,7 +1914,7 @@ void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_fpu *fpu) { int ret; - ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_FPU, fpu); + ret = __vcpu_ioctl(vm, vcpuid, KVM_SET_FPU, fpu); TEST_ASSERT(ret == 0, "KVM_SET_FPU failed, rc: %i errno: %i (%s)", ret, errno, strerror(errno)); } @@ -1923,7 +1923,7 @@ void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) { int ret; - ret = _vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, reg); + ret = __vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, reg); TEST_ASSERT(ret == 0, "KVM_GET_ONE_REG failed, rc: %i errno: %i (%s)", ret, errno, strerror(errno)); } @@ -1932,7 +1932,7 @@ void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) { int ret; - ret = _vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, reg); + ret = __vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, reg); TEST_ASSERT(ret == 0, "KVM_SET_ONE_REG failed, rc: %i errno: %i (%s)", ret, errno, strerror(errno)); } @@ -1955,13 +1955,13 @@ void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, { int ret; - ret = _vcpu_ioctl(vm, vcpuid, cmd, arg); + ret = __vcpu_ioctl(vm, vcpuid, cmd, arg); TEST_ASSERT(ret == 0, "vcpu ioctl %lu failed, rc: %i errno: %i (%s)", cmd, ret, errno, strerror(errno)); } -int _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, - unsigned long cmd, void *arg) +int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, + unsigned long cmd, void *arg) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); int ret; @@ -2025,12 +2025,12 @@ void vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) { int ret; - ret = _vm_ioctl(vm, cmd, arg); + ret = __vm_ioctl(vm, cmd, arg); TEST_ASSERT(ret == 0, "vm ioctl %lu failed, rc: %i errno: %i (%s)", cmd, ret, errno, strerror(errno)); } -int _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) +int __vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) { return ioctl(vm->fd, cmd, arg); } @@ -2056,7 +2056,7 @@ void kvm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) cmd, ret, errno, strerror(errno)); } -int _kvm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) +int __kvm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) { return ioctl(vm->kvm_fd, cmd, arg); } @@ -2185,7 +2185,7 @@ int _kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level) .level = level, }; - return _vm_ioctl(vm, KVM_IRQ_LINE, &irq_level); + return __vm_ioctl(vm, KVM_IRQ_LINE, &irq_level); } void kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level) diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index abc0ae5a4fe1..c89e6b1fbfb1 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -295,7 +295,7 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) * are powered-on using KVM_SET_MP_STATE ioctl(). */ mps.mp_state = KVM_MP_STATE_RUNNABLE; - r = _vcpu_ioctl(vm, vcpuid, KVM_SET_MP_STATE, &mps); + r = __vcpu_ioctl(vm, vcpuid, KVM_SET_MP_STATE, &mps); TEST_ASSERT(!r, "IOCTL KVM_SET_MP_STATE failed (error %d)", r); /* Setup global pointer of guest to be same as the host */ diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c index e704c6fa5758..230d4b6301e6 100644 --- a/tools/testing/selftests/kvm/s390x/memop.c +++ b/tools/testing/selftests/kvm/s390x/memop.c @@ -159,9 +159,9 @@ static void memop_ioctl(struct test_vcpu vcpu, struct kvm_s390_mem_op *ksmo) static int err_memop_ioctl(struct test_vcpu vcpu, struct kvm_s390_mem_op *ksmo) { if (vcpu.id == VM_VCPU_ID) - return _vm_ioctl(vcpu.vm, KVM_S390_MEM_OP, ksmo); + return __vm_ioctl(vcpu.vm, KVM_S390_MEM_OP, ksmo); else - return _vcpu_ioctl(vcpu.vm, vcpu.id, KVM_S390_MEM_OP, ksmo); + return __vcpu_ioctl(vcpu.vm, vcpu.id, KVM_S390_MEM_OP, ksmo); } #define MEMOP(err, vcpu_p, mop_target_p, access_mode_p, buf_p, size_p, ...) \ diff --git a/tools/testing/selftests/kvm/s390x/resets.c b/tools/testing/selftests/kvm/s390x/resets.c index 889449a22e7a..298bff3fd52e 100644 --- a/tools/testing/selftests/kvm/s390x/resets.c +++ b/tools/testing/selftests/kvm/s390x/resets.c @@ -77,7 +77,7 @@ static void assert_noirq(void) irq_state.len = sizeof(buf); irq_state.buf = (unsigned long)buf; - irqs = _vcpu_ioctl(vm, VCPU_ID, KVM_S390_GET_IRQ_STATE, &irq_state); + irqs = __vcpu_ioctl(vm, VCPU_ID, KVM_S390_GET_IRQ_STATE, &irq_state); /* * irqs contains the number of retrieved interrupts. Any interrupt * (notably, the emergency call interrupt we have injected) should @@ -197,7 +197,7 @@ static void inject_irq(int cpu_id) irq_state.buf = (unsigned long)buf; irq->type = KVM_S390_INT_EMERGENCY; irq->u.emerg.code = cpu_id; - irqs = _vcpu_ioctl(vm, cpu_id, KVM_S390_SET_IRQ_STATE, &irq_state); + irqs = __vcpu_ioctl(vm, cpu_id, KVM_S390_SET_IRQ_STATE, &irq_state); TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d\n", errno); } diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index 8c4e811bd586..75303fe8359d 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -166,7 +166,7 @@ static void steal_time_init(struct kvm_vm *vm) }; int i, ret; - ret = _vcpu_ioctl(vm, 0, KVM_HAS_DEVICE_ATTR, &dev); + ret = __vcpu_ioctl(vm, 0, KVM_HAS_DEVICE_ATTR, &dev); if (ret != 0 && errno == ENXIO) { print_skip("steal-time not supported"); exit(KSFT_SKIP); @@ -184,13 +184,13 @@ static void steal_time_init(struct kvm_vm *vm) sync_global_to_guest(vm, st_gva[i]); st_ipa = (ulong)st_gva[i] | 1; - ret = _vcpu_ioctl(vm, i, KVM_SET_DEVICE_ATTR, &dev); + ret = __vcpu_ioctl(vm, i, KVM_SET_DEVICE_ATTR, &dev); TEST_ASSERT(ret == -1 && errno == EINVAL, "Bad IPA didn't report EINVAL"); st_ipa = (ulong)st_gva[i]; vcpu_ioctl(vm, i, KVM_SET_DEVICE_ATTR, &dev); - ret = _vcpu_ioctl(vm, i, KVM_SET_DEVICE_ATTR, &dev); + ret = __vcpu_ioctl(vm, i, KVM_SET_DEVICE_ATTR, &dev); TEST_ASSERT(ret == -1 && errno == EEXIST, "Set IPA twice without EEXIST"); } diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c index 8c245ab2d98a..7e45a3df8f98 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c @@ -121,9 +121,9 @@ void test_hv_cpuid_e2big(struct kvm_vm *vm, bool system) int ret; if (!system) - ret = _vcpu_ioctl(vm, VCPU_ID, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); + ret = __vcpu_ioctl(vm, VCPU_ID, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); else - ret = _kvm_ioctl(vm, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); + ret = __kvm_ioctl(vm, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); TEST_ASSERT(ret == -1 && errno == E2BIG, "%s KVM_GET_SUPPORTED_HV_CPUID didn't fail with -E2BIG when" diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index 2fe893ccedd0..ee3d058a9fe1 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -42,7 +42,7 @@ static void test_set_boot_busy(struct kvm_vm *vm) { int res; - res = _vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID0); + res = __vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID0); TEST_ASSERT(res == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set while running vm"); } @@ -133,13 +133,13 @@ static void check_set_bsp_busy(void) add_x86_vcpu(vm, VCPU_ID0, true); add_x86_vcpu(vm, VCPU_ID1, false); - res = _vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1); + res = __vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1); TEST_ASSERT(res == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set after adding vcpu"); run_vcpu(vm, VCPU_ID0); run_vcpu(vm, VCPU_ID1); - res = _vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1); + res = __vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1); TEST_ASSERT(res == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set to a terminated vcpu"); kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c index 280c01fd2412..c35ada9f7f9c 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c @@ -186,7 +186,7 @@ int main(int argc, char *argv[]) vcpu_alloc_vmx(vm, &vmx_pages_gva); vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); - tsc_khz = _vcpu_ioctl(vm, VCPU_ID, KVM_GET_TSC_KHZ, NULL); + tsc_khz = __vcpu_ioctl(vm, VCPU_ID, KVM_GET_TSC_KHZ, NULL); TEST_ASSERT(tsc_khz != -1, "vcpu ioctl KVM_GET_TSC_KHZ failed"); /* scale down L1's TSC frequency */ From 02e04c15caeeb64a45d350a8fdeb32620b64a02d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 10:15:00 -0800 Subject: [PATCH 0313/1436] KVM: selftests: Make vcpu_ioctl() a wrapper to pretty print ioctl name Make vcpu_ioctl() a macro wrapper and pretty the _name_ of the ioctl on failure instead of the number. Add inner macros to allow handling cases where the name of the ioctl needs to be resolved higher up the stack, and to allow using the formatting for non-ioctl syscalls without being technically wrong. Deliberately do not use __stringify(), as that will expand the ioctl all the way down to its numerical sequence, again the intent is to print the name of the macro. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 13 ++++++-- tools/testing/selftests/kvm/lib/kvm_util.c | 31 +++++-------------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 662579a6358b..00f3103dc85e 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -157,10 +157,19 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, uint64_t guest_paddr, uint32_t slot, uint64_t npages, uint32_t flags); -void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, - void *arg); +#define __KVM_SYSCALL_ERROR(_name, _ret) \ + "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno) + +#define __KVM_IOCTL_ERROR(_name, _ret) __KVM_SYSCALL_ERROR(_name, _ret) +#define KVM_IOCTL_ERROR(_ioctl, _ret) __KVM_IOCTL_ERROR(#_ioctl, _ret) + +void _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, + const char *name, void *arg); int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, void *arg); +#define vcpu_ioctl(vm, vcpuid, ioctl, arg) \ + _vcpu_ioctl(vm, vcpuid, ioctl, #ioctl, arg) + void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); int __vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); void kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 03c1f885a98b..fdcaf74b5959 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1937,29 +1937,6 @@ void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) ret, errno, strerror(errno)); } -/* - * VCPU Ioctl - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * cmd - Ioctl number - * arg - Argument to pass to the ioctl - * - * Return: None - * - * Issues an arbitrary ioctl on a VCPU fd. - */ -void vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, - unsigned long cmd, void *arg) -{ - int ret; - - ret = __vcpu_ioctl(vm, vcpuid, cmd, arg); - TEST_ASSERT(ret == 0, "vcpu ioctl %lu failed, rc: %i errno: %i (%s)", - cmd, ret, errno, strerror(errno)); -} - int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, void *arg) { @@ -1973,6 +1950,14 @@ int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, return ret; } +void _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, + const char *name, void *arg) +{ + int ret = __vcpu_ioctl(vm, vcpuid, cmd, arg); + + TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); +} + void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid) { struct vcpu *vcpu; From 2ab2c307c734266e3c3e89d14d39c3b2327cb750 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 14 Feb 2022 17:20:17 -0800 Subject: [PATCH 0314/1436] KVM: selftests: Drop @mode from common vm_create() helper Drop @mode from vm_create() and have it use VM_MODE_DEFAULT. Add and use an inner helper, __vm_create(), to service the handful of tests that want something other than VM_MODE_DEFAULT. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/get-reg-list.c | 2 +- .../testing/selftests/kvm/aarch64/psci_test.c | 2 +- .../selftests/kvm/aarch64/vcpu_width_config.c | 6 +-- tools/testing/selftests/kvm/dirty_log_test.c | 2 +- .../selftests/kvm/hardware_disable_test.c | 2 +- .../selftests/kvm/include/kvm_util_base.h | 3 +- .../selftests/kvm/kvm_binary_stats_test.c | 3 +- .../selftests/kvm/kvm_create_max_vcpus.c | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 42 ++++++++++--------- .../selftests/kvm/set_memory_region_test.c | 4 +- .../kvm/x86_64/max_vcpuid_cap_test.c | 2 +- .../selftests/kvm/x86_64/set_boot_cpu_id.c | 2 +- .../selftests/kvm/x86_64/set_sregs_test.c | 2 +- .../selftests/kvm/x86_64/sev_migrate_tests.c | 8 ++-- 14 files changed, 42 insertions(+), 40 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index 441c98ffb812..ecfb773ec41e 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -416,7 +416,7 @@ static void run_test(struct vcpu_config *c) check_supported(c); - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); prepare_vcpu_init(c, &init); aarch64_vcpu_add_default(vm, 0, &init, NULL); finalize_vcpu(vm, 0, c); diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index de3b5e176d04..024a84064f1f 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -78,7 +78,7 @@ static struct kvm_vm *setup_vm(void *guest_code) struct kvm_vcpu_init init; struct kvm_vm *vm; - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); kvm_vm_elf_load(vm, program_invocation_name); ucall_init(vm, NULL); diff --git a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c index 271fa90e53fd..4145c28a245a 100644 --- a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c +++ b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c @@ -24,7 +24,7 @@ static int add_init_2vcpus(struct kvm_vcpu_init *init1, struct kvm_vm *vm; int ret; - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); vm_vcpu_add(vm, 0); ret = __vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); @@ -49,7 +49,7 @@ static int add_2vcpus_init_2vcpus(struct kvm_vcpu_init *init1, struct kvm_vm *vm; int ret; - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); vm_vcpu_add(vm, 0); vm_vcpu_add(vm, 1); @@ -86,7 +86,7 @@ int main(void) } /* Get the preferred target type and copy that to init2 for later use */ - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init1); kvm_vm_free(vm); init2 = init1; diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 11bf606e3165..01c01d40201f 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -679,7 +679,7 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode)); - vm = vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); + vm = __vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); kvm_vm_elf_load(vm, program_invocation_name); #ifdef __x86_64__ vm_create_irqchip(vm); diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c index 1c9e2295c75b..81ba8645772a 100644 --- a/tools/testing/selftests/kvm/hardware_disable_test.c +++ b/tools/testing/selftests/kvm/hardware_disable_test.c @@ -104,7 +104,7 @@ static void run_test(uint32_t run) for (i = 0; i < VCPU_NUM; i++) CPU_SET(i, &cpu_set); - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); kvm_vm_elf_load(vm, program_invocation_name); vm_create_irqchip(vm); diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 00f3103dc85e..f6984b0c3816 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -110,7 +110,8 @@ int vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size); const char *vm_guest_mode_string(uint32_t i); -struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages); +struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t phy_pages); +struct kvm_vm *vm_create(uint64_t phy_pages); void kvm_vm_free(struct kvm_vm *vmp); void kvm_vm_restart(struct kvm_vm *vmp); void kvm_vm_release(struct kvm_vm *vmp); diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 6217f4630e6c..4b149b383678 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -229,8 +229,7 @@ int main(int argc, char *argv[]) vms = malloc(sizeof(vms[0]) * max_vm); TEST_ASSERT(vms, "Allocate memory for storing VM pointers"); for (i = 0; i < max_vm; ++i) { - vms[i] = vm_create(VM_MODE_DEFAULT, - DEFAULT_GUEST_PHY_PAGES); + vms[i] = vm_create(DEFAULT_GUEST_PHY_PAGES); for (j = 0; j < max_vcpu; ++j) vm_vcpu_add(vms[i], j); } diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c index bb69b75eac23..9de5e1376c49 100644 --- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c +++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c @@ -28,7 +28,7 @@ void test_vcpu_creation(int first_vcpu_id, int num_vcpus) pr_info("Testing creating %d vCPUs, with IDs %d...%d.\n", num_vcpus, first_vcpu_id, first_vcpu_id + num_vcpus - 1); - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); for (i = first_vcpu_id; i < first_vcpu_id + num_vcpus; i++) /* This asserts that the vCPU was created. */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index fdcaf74b5959..bab4ab297fcc 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -234,25 +234,7 @@ const struct vm_guest_mode_params vm_guest_mode_params[] = { _Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_params) == NUM_VM_MODES, "Missing new mode params?"); -/* - * VM Create - * - * Input Args: - * mode - VM Mode (e.g. VM_MODE_P52V48_4K) - * phy_pages - Physical memory pages - * - * Output Args: None - * - * Return: - * Pointer to opaque structure that describes the created VM. - * - * Creates a VM with the mode specified by mode (e.g. VM_MODE_P52V48_4K). - * When phy_pages is non-zero, a memory region of phy_pages physical pages - * is created and mapped starting at guest physical address 0. The file - * descriptor to control the created VM is created with the permissions - * given by perm (e.g. O_RDWR). - */ -struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages) +struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t phy_pages) { struct kvm_vm *vm; @@ -361,11 +343,31 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages) return vm; } +/* + * VM Create + * + * Input Args: + * phy_pages - Physical memory pages + * + * Output Args: None + * + * Return: + * Pointer to opaque structure that describes the created VM. + * + * Creates a VM with the default physical/virtual address widths and page size. + * When phy_pages is non-zero, a memory region of phy_pages physical pages + * is created and mapped starting at guest physical address 0. + */ +struct kvm_vm *vm_create(uint64_t phy_pages) +{ + return __vm_create(VM_MODE_DEFAULT, phy_pages); +} + struct kvm_vm *vm_create_without_vcpus(enum vm_guest_mode mode, uint64_t pages) { struct kvm_vm *vm; - vm = vm_create(mode, pages); + vm = __vm_create(mode, pages); kvm_vm_elf_load(vm, program_invocation_name); diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index d97cfd6866c3..89b13f23c3ac 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -314,7 +314,7 @@ static void test_zero_memory_regions(void) pr_info("Testing KVM_RUN with zero added memory regions\n"); - vm = vm_create(VM_MODE_DEFAULT, 0); + vm = vm_create(0); vm_vcpu_add(vm, VCPU_ID); TEST_ASSERT(!ioctl(vm_get_fd(vm), KVM_SET_NR_MMU_PAGES, 64), @@ -354,7 +354,7 @@ static void test_add_max_memory_regions(void) "KVM_CAP_NR_MEMSLOTS should be greater than 0"); pr_info("Allowed number of memory slots: %i\n", max_mem_slots); - vm = vm_create(VM_MODE_DEFAULT, 0); + vm = vm_create(0); /* Check it can be added memory slots up to the maximum allowed */ pr_info("Adding slots 0..%i, each memory region with %dK size\n", diff --git a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c index 28cc316c5dbe..e83afd4bb4cf 100644 --- a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c +++ b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c @@ -18,7 +18,7 @@ int main(int argc, char *argv[]) struct kvm_enable_cap cap = { 0 }; int ret; - vm = vm_create(VM_MODE_DEFAULT, 0); + vm = vm_create(0); /* Get KVM_CAP_MAX_VCPU_ID cap supported in KVM */ ret = vm_check_cap(vm, KVM_CAP_MAX_VCPU_ID); diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index ee3d058a9fe1..b4da92ddc1c6 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -88,7 +88,7 @@ static struct kvm_vm *create_vm(void) uint64_t pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages; pages = vm_adjust_num_guest_pages(VM_MODE_DEFAULT, pages); - vm = vm_create(VM_MODE_DEFAULT, pages); + vm = vm_create(pages); kvm_vm_elf_load(vm, program_invocation_name); vm_create_irqchip(vm); diff --git a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c index 44711ab735c3..4dc7fd925023 100644 --- a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c +++ b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c @@ -95,7 +95,7 @@ int main(int argc, char *argv[]) * use it to verify all supported CR4 bits can be set prior to defining * the vCPU model, i.e. without doing KVM_SET_CPUID2. */ - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); vm_vcpu_add(vm, VCPU_ID); vcpu_sregs_get(vm, VCPU_ID, &sregs); diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index b0c052443c44..7424bec5ae23 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -54,7 +54,7 @@ static struct kvm_vm *sev_vm_create(bool es) struct kvm_sev_launch_start start = { 0 }; int i; - vm = vm_create(VM_MODE_DEFAULT, 0); + vm = vm_create(0); sev_ioctl(vm->fd, es ? KVM_SEV_ES_INIT : KVM_SEV_INIT, NULL); for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i) vm_vcpu_add(vm, i); @@ -71,7 +71,7 @@ static struct kvm_vm *aux_vm_create(bool with_vcpus) struct kvm_vm *vm; int i; - vm = vm_create(VM_MODE_DEFAULT, 0); + vm = vm_create(0); if (!with_vcpus) return vm; @@ -174,7 +174,7 @@ static void test_sev_migrate_parameters(void) *sev_es_vm_no_vmsa; int ret; - vm_no_vcpu = vm_create(VM_MODE_DEFAULT, 0); + vm_no_vcpu = vm_create(0); vm_no_sev = aux_vm_create(true); ret = __sev_migrate_from(vm_no_vcpu->fd, vm_no_sev->fd); TEST_ASSERT(ret == -1 && errno == EINVAL, @@ -186,7 +186,7 @@ static void test_sev_migrate_parameters(void) sev_vm = sev_vm_create(/* es= */ false); sev_es_vm = sev_vm_create(/* es= */ true); - sev_es_vm_no_vmsa = vm_create(VM_MODE_DEFAULT, 0); + sev_es_vm_no_vmsa = vm_create(0); sev_ioctl(sev_es_vm_no_vmsa->fd, KVM_SEV_ES_INIT, NULL); vm_vcpu_add(sev_es_vm_no_vmsa, 1); From 1d438b3bc25e7ea2e7af95b9c07d88a287346df1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 10:08:45 -0800 Subject: [PATCH 0315/1436] KVM: selftests: Split vcpu_set_nested_state() into two helpers Split vcpu_nested_state_set() into a wrapper that asserts, and an inner helper that does not. Passing a bool is all kinds of awful as it's unintuitive for readers and requires returning an 'int' from a function that for most users can never return anything other than "success". Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 6 ++++-- tools/testing/selftests/kvm/lib/kvm_util.c | 20 +++++++++---------- .../kvm/x86_64/vmx_set_nested_state_test.c | 4 ++-- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index f6984b0c3816..314d971c1f06 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -261,8 +261,10 @@ void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, #ifdef __x86_64__ void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_nested_state *state); -int vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_nested_state *state, bool ignore_error); +int __vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_nested_state *state); +void vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_nested_state *state); #endif void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index bab4ab297fcc..7b339f98070b 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1826,22 +1826,22 @@ void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid, ret, errno); } -int vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_nested_state *state, bool ignore_error) +int __vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_nested_state *state) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); - int ret; TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - ret = ioctl(vcpu->fd, KVM_SET_NESTED_STATE, state); - if (!ignore_error) { - TEST_ASSERT(ret == 0, - "KVM_SET_NESTED_STATE failed, ret: %i errno: %i", - ret, errno); - } + return ioctl(vcpu->fd, KVM_SET_NESTED_STATE, state); +} - return ret; +void vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_nested_state *state) +{ + int ret = __vcpu_nested_state_set(vm, vcpuid, state); + + TEST_ASSERT(!ret, "KVM_SET_NESTED_STATE failed, ret: %i errno: %i", ret, errno); } #endif diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c index 5827b9bae468..af3b60eb35ec 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c @@ -29,7 +29,7 @@ bool have_evmcs; void test_nested_state(struct kvm_vm *vm, struct kvm_nested_state *state) { - vcpu_nested_state_set(vm, VCPU_ID, state, false); + vcpu_nested_state_set(vm, VCPU_ID, state); } void test_nested_state_expect_errno(struct kvm_vm *vm, @@ -38,7 +38,7 @@ void test_nested_state_expect_errno(struct kvm_vm *vm, { int rv; - rv = vcpu_nested_state_set(vm, VCPU_ID, state, true); + rv = __vcpu_nested_state_set(vm, VCPU_ID, state); TEST_ASSERT(rv == -1 && errno == expected_errno, "Expected %s (%d) from vcpu_nested_state_set but got rv: %i errno: %s (%d)", strerror(expected_errno), expected_errno, rv, strerror(errno), From ffb7c77fd5039a01b2534465a2cdf7514f7fc9df Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 11:05:21 -0800 Subject: [PATCH 0316/1436] KVM: sefltests: Use vcpu_ioctl() and __vcpu_ioctl() helpers Use the recently introduced vCPU-specific ioctl() helpers instead of open coding calls to ioctl() just to pretty print the ioctl name. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 142 ++++++--- .../selftests/kvm/include/x86_64/processor.h | 28 +- .../selftests/kvm/kvm_binary_stats_test.c | 6 +- tools/testing/selftests/kvm/lib/kvm_util.c | 286 +----------------- .../selftests/kvm/lib/x86_64/processor.c | 112 +------ 5 files changed, 135 insertions(+), 439 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 314d971c1f06..4f18f03c537f 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -105,8 +105,6 @@ int open_kvm_dev_path_or_exit(void); int kvm_check_cap(long cap); int vm_check_cap(struct kvm_vm *vm, long cap); int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap); -int vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, - struct kvm_enable_cap *cap); void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size); const char *vm_guest_mode_string(uint32_t i); @@ -212,13 +210,112 @@ void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); int vcpu_get_fd(struct kvm_vm *vm, uint32_t vcpuid); void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid); -void vcpu_set_guest_debug(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_guest_debug *debug); -void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_mp_state *mp_state); struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid); -void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs); -void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs); + +static inline void vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, + struct kvm_enable_cap *cap) +{ + vcpu_ioctl(vm, vcpu_id, KVM_ENABLE_CAP, cap); +} + +static inline void vcpu_set_guest_debug(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_guest_debug *debug) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_GUEST_DEBUG, debug); +} + +static inline void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_mp_state *mp_state) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_MP_STATE, mp_state); +} + +static inline void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_regs *regs) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_REGS, regs); +} + +static inline void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_regs *regs) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_REGS, regs); +} +static inline void vcpu_sregs_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_sregs *sregs) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_SREGS, sregs); + +} +static inline void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_sregs *sregs) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_SREGS, sregs); +} +static inline int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_sregs *sregs) +{ + return __vcpu_ioctl(vm, vcpuid, KVM_SET_SREGS, sregs); +} +static inline void vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_fpu *fpu) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_FPU, fpu); +} +static inline void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_fpu *fpu) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_FPU, fpu); +} +static inline void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_one_reg *reg) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, reg); +} +static inline void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_one_reg *reg) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, reg); +} +#ifdef __KVM_HAVE_VCPU_EVENTS +static inline void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_vcpu_events *events) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_VCPU_EVENTS, events); +} +static inline void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_vcpu_events *events) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_VCPU_EVENTS, events); +} +#endif +#ifdef __x86_64__ +static inline void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_nested_state *state) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_NESTED_STATE, state); +} +static inline int __vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_nested_state *state) +{ + return __vcpu_ioctl(vm, vcpuid, KVM_SET_NESTED_STATE, state); +} + +static inline void vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_nested_state *state) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_NESTED_STATE, state); +} +#endif +static inline int vcpu_get_stats_fd(struct kvm_vm *vm, uint32_t vcpuid) +{ + int fd = __vcpu_ioctl(vm, vcpuid, KVM_GET_STATS_FD, NULL); + + TEST_ASSERT(fd >= 0, KVM_IOCTL_ERROR(KVM_GET_STATS_FD, fd)); + return fd; +} + +void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid); /* * VM VCPU Args Set @@ -240,34 +337,6 @@ void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs); */ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); -void vcpu_sregs_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_sregs *sregs); -void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_sregs *sregs); -int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_sregs *sregs); -void vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_fpu *fpu); -void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_fpu *fpu); -void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg); -void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg); -#ifdef __KVM_HAVE_VCPU_EVENTS -void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_vcpu_events *events); -void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_vcpu_events *events); -#endif -#ifdef __x86_64__ -void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_nested_state *state); -int __vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_nested_state *state); -void vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_nested_state *state); -#endif -void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid); - int _kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr); int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr); int _kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test, int *fd); @@ -406,7 +475,6 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid); int vm_get_stats_fd(struct kvm_vm *vm); -int vcpu_get_stats_fd(struct kvm_vm *vm, uint32_t vcpuid); uint32_t guest_get_vcpuid(void); diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 1c0419c4786d..583754bf18c3 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -430,12 +430,19 @@ void kvm_x86_state_cleanup(struct kvm_x86_state *state); struct kvm_msr_list *kvm_get_msr_index_list(void); uint64_t kvm_get_feature_msr(uint64_t msr_index); struct kvm_cpuid2 *kvm_get_supported_cpuid(void); - struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid); -int __vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_cpuid2 *cpuid); -void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_cpuid2 *cpuid); + +static inline int __vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_cpuid2 *cpuid) +{ + return __vcpu_ioctl(vm, vcpuid, KVM_SET_CPUID2, cpuid); +} + +static inline void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_cpuid2 *cpuid) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_CPUID2, cpuid); +} struct kvm_cpuid_entry2 * kvm_get_supported_cpuid_index(uint32_t function, uint32_t index); @@ -449,8 +456,15 @@ kvm_get_supported_cpuid_entry(uint32_t function) uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index); int _vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, uint64_t msr_value); -void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, - uint64_t msr_value); + +static inline void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, + uint64_t msr_index, uint64_t msr_value) +{ + int r = _vcpu_set_msr(vm, vcpuid, msr_index, msr_value); + + TEST_ASSERT(r == 1, KVM_IOCTL_ERROR(KVM_SET_MSRS, r)); +} + uint32_t kvm_get_cpuid_max_basic(void); uint32_t kvm_get_cpuid_max_extended(void); diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 4b149b383678..bab8b49b52da 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -178,11 +178,7 @@ static void vm_stats_test(struct kvm_vm *vm) static void vcpu_stats_test(struct kvm_vm *vm, int vcpu_id) { - int stats_fd; - - /* Get fd for VCPU stats */ - stats_fd = vcpu_get_stats_fd(vm, vcpu_id); - TEST_ASSERT(stats_fd >= 0, "Get VCPU stats fd"); + int stats_fd = vcpu_get_stats_fd(vm, vcpu_id); stats_test(stats_fd); close(stats_fd); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 7b339f98070b..7ac4516d764c 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -135,34 +135,6 @@ int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) return ret; } -/* VCPU Enable Capability - * - * Input Args: - * vm - Virtual Machine - * vcpu_id - VCPU - * cap - Capability - * - * Output Args: None - * - * Return: On success, 0. On failure a TEST_ASSERT failure is produced. - * - * Enables a capability (KVM_CAP_*) on the VCPU. - */ -int vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, - struct kvm_enable_cap *cap) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpu_id); - int r; - - TEST_ASSERT(vcpu, "cannot find vcpu %d", vcpu_id); - - r = ioctl(vcpu->fd, KVM_ENABLE_CAP, cap); - TEST_ASSERT(!r, "KVM_ENABLE_CAP vCPU ioctl failed,\n" - " rc: %i, errno: %i", r, errno); - - return r; -} - void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size) { struct kvm_enable_cap cap = { 0 }; @@ -1619,8 +1591,8 @@ struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) { int ret = _vcpu_run(vm, vcpuid); - TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " - "rc: %i errno: %i", ret, errno); + + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_RUN, ret)); } int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) @@ -1663,43 +1635,6 @@ void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid) ret, errno); } -void vcpu_set_guest_debug(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_guest_debug *debug) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - int ret = ioctl(vcpu->fd, KVM_SET_GUEST_DEBUG, debug); - - TEST_ASSERT(ret == 0, "KVM_SET_GUEST_DEBUG failed: %d", ret); -} - -/* - * VM VCPU Set MP State - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * mp_state - mp_state to be set - * - * Output Args: None - * - * Return: None - * - * Sets the MP state of the VCPU given by vcpuid, to the state given - * by mp_state. - */ -void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_mp_state *mp_state) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - int ret; - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - ret = ioctl(vcpu->fd, KVM_SET_MP_STATE, mp_state); - TEST_ASSERT(ret == 0, "KVM_SET_MP_STATE IOCTL failed, " - "rc: %i errno: %i", ret, errno); -} - /* * VM VCPU Get Reg List * @@ -1729,216 +1664,6 @@ struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid) return reg_list; } -/* - * VM VCPU Regs Get - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * - * Output Args: - * regs - current state of VCPU regs - * - * Return: None - * - * Obtains the current register state for the VCPU specified by vcpuid - * and stores it at the location given by regs. - */ -void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - int ret; - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - ret = ioctl(vcpu->fd, KVM_GET_REGS, regs); - TEST_ASSERT(ret == 0, "KVM_GET_REGS failed, rc: %i errno: %i", - ret, errno); -} - -/* - * VM VCPU Regs Set - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * regs - Values to set VCPU regs to - * - * Output Args: None - * - * Return: None - * - * Sets the regs of the VCPU specified by vcpuid to the values - * given by regs. - */ -void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_regs *regs) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - int ret; - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - ret = ioctl(vcpu->fd, KVM_SET_REGS, regs); - TEST_ASSERT(ret == 0, "KVM_SET_REGS failed, rc: %i errno: %i", - ret, errno); -} - -#ifdef __KVM_HAVE_VCPU_EVENTS -void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_vcpu_events *events) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - int ret; - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - ret = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, events); - TEST_ASSERT(ret == 0, "KVM_GET_VCPU_EVENTS, failed, rc: %i errno: %i", - ret, errno); -} - -void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_vcpu_events *events) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - int ret; - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - ret = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, events); - TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i", - ret, errno); -} -#endif - -#ifdef __x86_64__ -void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_nested_state *state) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - int ret; - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - ret = ioctl(vcpu->fd, KVM_GET_NESTED_STATE, state); - TEST_ASSERT(ret == 0, - "KVM_SET_NESTED_STATE failed, ret: %i errno: %i", - ret, errno); -} - -int __vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_nested_state *state) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - return ioctl(vcpu->fd, KVM_SET_NESTED_STATE, state); -} - -void vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_nested_state *state) -{ - int ret = __vcpu_nested_state_set(vm, vcpuid, state); - - TEST_ASSERT(!ret, "KVM_SET_NESTED_STATE failed, ret: %i errno: %i", ret, errno); -} -#endif - -/* - * VM VCPU System Regs Get - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * - * Output Args: - * sregs - current state of VCPU system regs - * - * Return: None - * - * Obtains the current system register state for the VCPU specified by - * vcpuid and stores it at the location given by sregs. - */ -void vcpu_sregs_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - int ret; - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - ret = ioctl(vcpu->fd, KVM_GET_SREGS, sregs); - TEST_ASSERT(ret == 0, "KVM_GET_SREGS failed, rc: %i errno: %i", - ret, errno); -} - -/* - * VM VCPU System Regs Set - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * sregs - Values to set VCPU system regs to - * - * Output Args: None - * - * Return: None - * - * Sets the system regs of the VCPU specified by vcpuid to the values - * given by sregs. - */ -void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) -{ - int ret = _vcpu_sregs_set(vm, vcpuid, sregs); - TEST_ASSERT(ret == 0, "KVM_SET_SREGS IOCTL failed, " - "rc: %i errno: %i", ret, errno); -} - -int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_sregs *sregs) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); -} - -void vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_fpu *fpu) -{ - int ret; - - ret = __vcpu_ioctl(vm, vcpuid, KVM_GET_FPU, fpu); - TEST_ASSERT(ret == 0, "KVM_GET_FPU failed, rc: %i errno: %i (%s)", - ret, errno, strerror(errno)); -} - -void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_fpu *fpu) -{ - int ret; - - ret = __vcpu_ioctl(vm, vcpuid, KVM_SET_FPU, fpu); - TEST_ASSERT(ret == 0, "KVM_SET_FPU failed, rc: %i errno: %i (%s)", - ret, errno, strerror(errno)); -} - -void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) -{ - int ret; - - ret = __vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, reg); - TEST_ASSERT(ret == 0, "KVM_GET_ONE_REG failed, rc: %i errno: %i (%s)", - ret, errno, strerror(errno)); -} - -void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_one_reg *reg) -{ - int ret; - - ret = __vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, reg); - TEST_ASSERT(ret == 0, "KVM_SET_ONE_REG failed, rc: %i errno: %i (%s)", - ret, errno, strerror(errno)); -} - int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, void *arg) { @@ -2534,10 +2259,3 @@ int vm_get_stats_fd(struct kvm_vm *vm) { return ioctl(vm->fd, KVM_GET_STATS_FD, NULL); } - -int vcpu_get_stats_fd(struct kvm_vm *vm, uint32_t vcpuid) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - - return ioctl(vcpu->fd, KVM_GET_STATS_FD, NULL); -} diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index ead7011ee8f6..af2bf114249d 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -802,18 +802,15 @@ uint64_t kvm_get_feature_msr(uint64_t msr_index) */ struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); struct kvm_cpuid2 *cpuid; int max_ent; int rc = -1; - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - cpuid = allocate_kvm_cpuid2(); max_ent = cpuid->nent; for (cpuid->nent = 1; cpuid->nent <= max_ent; cpuid->nent++) { - rc = ioctl(vcpu->fd, KVM_GET_CPUID2, cpuid); + rc = __vcpu_ioctl(vm, vcpuid, KVM_GET_CPUID2, cpuid); if (!rc) break; @@ -822,9 +819,7 @@ struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid) rc, errno); } - TEST_ASSERT(rc == 0, "KVM_GET_CPUID2 failed, rc: %i errno: %i", - rc, errno); - + TEST_ASSERT(!rc, KVM_IOCTL_ERROR(KVM_GET_CPUID2, rc)); return cpuid; } @@ -862,132 +857,37 @@ kvm_get_supported_cpuid_index(uint32_t function, uint32_t index) return entry; } - -int __vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_cpuid2 *cpuid) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - return ioctl(vcpu->fd, KVM_SET_CPUID2, cpuid); -} - -/* - * VM VCPU CPUID Set - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU id - * cpuid - The CPUID values to set. - * - * Output Args: None - * - * Return: void - * - * Set the VCPU's CPUID. - */ -void vcpu_set_cpuid(struct kvm_vm *vm, - uint32_t vcpuid, struct kvm_cpuid2 *cpuid) -{ - int rc; - - rc = __vcpu_set_cpuid(vm, vcpuid, cpuid); - TEST_ASSERT(rc == 0, "KVM_SET_CPUID2 failed, rc: %i errno: %i", - rc, errno); - -} - -/* - * VCPU Get MSR - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * msr_index - Index of MSR - * - * Output Args: None - * - * Return: On success, value of the MSR. On failure a TEST_ASSERT is produced. - * - * Get value of MSR for VCPU. - */ uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); struct { struct kvm_msrs header; struct kvm_msr_entry entry; } buffer = {}; int r; - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); buffer.header.nmsrs = 1; buffer.entry.index = msr_index; - r = ioctl(vcpu->fd, KVM_GET_MSRS, &buffer.header); - TEST_ASSERT(r == 1, "KVM_GET_MSRS IOCTL failed,\n" - " rc: %i errno: %i", r, errno); + + r = __vcpu_ioctl(vm, vcpuid, KVM_GET_MSRS, &buffer.header); + TEST_ASSERT(r == 1, KVM_IOCTL_ERROR(KVM_GET_MSRS, r)); return buffer.entry.data; } -/* - * _VCPU Set MSR - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * msr_index - Index of MSR - * msr_value - New value of MSR - * - * Output Args: None - * - * Return: The result of KVM_SET_MSRS. - * - * Sets the value of an MSR for the given VCPU. - */ int _vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, uint64_t msr_value) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); struct { struct kvm_msrs header; struct kvm_msr_entry entry; } buffer = {}; - int r; - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); memset(&buffer, 0, sizeof(buffer)); buffer.header.nmsrs = 1; buffer.entry.index = msr_index; buffer.entry.data = msr_value; - r = ioctl(vcpu->fd, KVM_SET_MSRS, &buffer.header); - return r; -} -/* - * VCPU Set MSR - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * msr_index - Index of MSR - * msr_value - New value of MSR - * - * Output Args: None - * - * Return: On success, nothing. On failure a TEST_ASSERT is produced. - * - * Set value of MSR for VCPU. - */ -void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, - uint64_t msr_value) -{ - int r; - - r = _vcpu_set_msr(vm, vcpuid, msr_index, msr_value); - TEST_ASSERT(r == 1, "KVM_SET_MSRS IOCTL failed,\n" - " rc: %i errno: %i", r, errno); + return __vcpu_ioctl(vm, vcpuid, KVM_SET_MSRS, &buffer.header); } void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) From 38d4a385a345d807652f748822630f309786b658 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 11:49:42 -0800 Subject: [PATCH 0317/1436] KVM: selftests: Add __vcpu_run() helper Add __vcpu_run() so that tests that want to avoid asserts on KVM_RUN failures don't need to open code the ioctl() call. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/vgic_init.c | 6 ++---- tools/testing/selftests/kvm/dirty_log_test.c | 6 ++---- tools/testing/selftests/kvm/include/kvm_util_base.h | 6 ++++++ tools/testing/selftests/kvm/lib/kvm_util.c | 6 ++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 4b7e7ba43969..42c9209f7786 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -55,10 +55,8 @@ static void guest_code(void) static int run_vcpu(struct kvm_vm *vm, uint32_t vcpuid) { ucall_init(vm, NULL); - int ret = __vcpu_ioctl(vm, vcpuid, KVM_RUN, NULL); - if (ret) - return -errno; - return 0; + + return __vcpu_run(vm, vcpuid) ? -errno : 0; } static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type, uint32_t nr_vcpus) diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 01c01d40201f..5752486764c9 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -509,7 +509,7 @@ static void generate_random_array(uint64_t *guest_array, uint64_t size) static void *vcpu_worker(void *data) { - int ret, vcpu_fd; + int ret; struct kvm_vm *vm = data; uint64_t *guest_array; uint64_t pages_count = 0; @@ -517,8 +517,6 @@ static void *vcpu_worker(void *data) + sizeof(sigset_t)); sigset_t *sigset = (sigset_t *) &sigmask->sigset; - vcpu_fd = vcpu_get_fd(vm, VCPU_ID); - /* * SIG_IPI is unblocked atomically while in KVM_RUN. It causes the * ioctl to return with -EINTR, but it is still pending and we need @@ -539,7 +537,7 @@ static void *vcpu_worker(void *data) generate_random_array(guest_array, TEST_PAGES_PER_LOOP); pages_count += TEST_PAGES_PER_LOOP; /* Let the guest dirty the random pages */ - ret = ioctl(vcpu_fd, KVM_RUN, NULL); + ret = __vcpu_run(vm, VCPU_ID); if (ret == -1 && errno == EINTR) { int sig = -1; sigwait(sigset, &sig); diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 4f18f03c537f..6b7a5297053e 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -208,6 +208,12 @@ vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva); struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid); void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); + +static inline int __vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) +{ + return __vcpu_ioctl(vm, vcpuid, KVM_RUN, NULL); +} + int vcpu_get_fd(struct kvm_vm *vm, uint32_t vcpuid); void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid); struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 7ac4516d764c..45895c9ca35a 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1597,12 +1597,10 @@ void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); int rc; - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); do { - rc = ioctl(vcpu->fd, KVM_RUN, NULL); + rc = __vcpu_run(vm, vcpuid); } while (rc == -1 && errno == EINTR); assert_on_unhandled_exception(vm, vcpuid); @@ -1627,7 +1625,7 @@ void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid) TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); vcpu->state->immediate_exit = 1; - ret = ioctl(vcpu->fd, KVM_RUN, NULL); + ret = __vcpu_run(vm, vcpuid); vcpu->state->immediate_exit = 0; TEST_ASSERT(ret == -1 && errno == EINTR, From caf12f3b1d629c06634b059acc7b18d05bb5fb94 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 11:23:34 -0800 Subject: [PATCH 0318/1436] KVM: selftests: Use vcpu_access_device_attr() in arm64 code Use vcpu_access_device_attr() in arm's arch_timer test instead of manually retrieving the vCPU's fd. This will allow dropping vcpu_get_fd() in a future patch. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/arch_timer.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index 3b940a101bc0..f55c4c20d8b3 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -349,12 +349,10 @@ static void test_run(struct kvm_vm *vm) static void test_init_timer_irq(struct kvm_vm *vm) { /* Timer initid should be same for all the vCPUs, so query only vCPU-0 */ - int vcpu0_fd = vcpu_get_fd(vm, 0); - - kvm_device_access(vcpu0_fd, KVM_ARM_VCPU_TIMER_CTRL, - KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq, false); - kvm_device_access(vcpu0_fd, KVM_ARM_VCPU_TIMER_CTRL, - KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq, false); + vcpu_access_device_attr(vm, 0, KVM_ARM_VCPU_TIMER_CTRL, + KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq, false); + vcpu_access_device_attr(vm, 0, KVM_ARM_VCPU_TIMER_CTRL, + KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq, false); sync_global_to_guest(vm, ptimer_irq); sync_global_to_guest(vm, vtimer_irq); From 21c6ee2b3ac25b36cba22a2c725382ff7706dc95 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 11:24:01 -0800 Subject: [PATCH 0319/1436] KVM: selftests: Remove vcpu_get_fd() Drop vcpu_get_fd(), it no longer has any users, and really should not exist as the framework has failed if tests need to manually operate on a vCPU fd. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/include/kvm_util_base.h | 1 - tools/testing/selftests/kvm/lib/kvm_util.c | 9 --------- 2 files changed, 10 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 6b7a5297053e..c2dfc4341b31 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -214,7 +214,6 @@ static inline int __vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) return __vcpu_ioctl(vm, vcpuid, KVM_RUN, NULL); } -int vcpu_get_fd(struct kvm_vm *vm, uint32_t vcpuid); void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid); struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 45895c9ca35a..73123b9d9625 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1608,15 +1608,6 @@ int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) return rc; } -int vcpu_get_fd(struct kvm_vm *vm, uint32_t vcpuid) -{ - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - return vcpu->fd; -} - void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid) { struct vcpu *vcpu = vcpu_find(vm, vcpuid); From 47a7c924b62de4b9d1752c1f5bc111c847229799 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 11:31:16 -0800 Subject: [PATCH 0320/1436] KVM: selftests: Add vcpu_get() to retrieve and assert on vCPU existence Add vcpu_get() to wrap vcpu_find() and deduplicate a pile of code that asserts the requested vCPU exists. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/kvm_util.c | 56 ++++++------------- .../selftests/kvm/lib/kvm_util_internal.h | 2 +- .../selftests/kvm/lib/s390x/processor.c | 5 +- .../selftests/kvm/lib/x86_64/processor.c | 4 +- 4 files changed, 20 insertions(+), 47 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 73123b9d9625..940decfaa633 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -561,23 +561,7 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, return ®ion->region; } -/* - * VCPU Find - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * - * Output Args: None - * - * Return: - * Pointer to VCPU structure - * - * Locates a vcpu structure that describes the VCPU specified by vcpuid and - * returns a pointer to it. Returns NULL if the VM doesn't contain a VCPU - * for the specified vcpuid. - */ -struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid) +static struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid) { struct vcpu *vcpu; @@ -589,6 +573,14 @@ struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid) return NULL; } +struct vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + + TEST_ASSERT(vcpu, "vCPU %d does not exist", vcpuid); + return vcpu; +} + /* * VM VCPU Remove * @@ -1568,8 +1560,7 @@ void vm_create_irqchip(struct kvm_vm *vm) */ struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + struct vcpu *vcpu = vcpu_get(vm, vcpuid); return vcpu->state; } @@ -1610,11 +1601,9 @@ int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); + struct vcpu *vcpu = vcpu_get(vm, vcpuid); int ret; - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - vcpu->state->immediate_exit = 1; ret = __vcpu_run(vm, vcpuid); vcpu->state->immediate_exit = 0; @@ -1656,14 +1645,9 @@ struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid) int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, void *arg) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - int ret; + struct vcpu *vcpu = vcpu_get(vm, vcpuid); - TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); - - ret = ioctl(vcpu->fd, cmd, arg); - - return ret; + return ioctl(vcpu->fd, cmd, arg); } void _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, @@ -1676,15 +1660,11 @@ void _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid) { - struct vcpu *vcpu; + struct vcpu *vcpu = vcpu_get(vm, vcpuid); uint32_t size = vm->dirty_ring_size; TEST_ASSERT(size > 0, "Should enable dirty ring first"); - vcpu = vcpu_find(vm, vcpuid); - - TEST_ASSERT(vcpu, "Cannot find vcpu %u", vcpuid); - if (!vcpu->dirty_gfns) { void *addr; @@ -1840,9 +1820,7 @@ int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, int _vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, uint64_t attr) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - - TEST_ASSERT(vcpu, "nonexistent vcpu id: %d", vcpuid); + struct vcpu *vcpu = vcpu_get(vm, vcpuid); return _kvm_device_check_attr(vcpu->fd, group, attr); } @@ -1859,9 +1837,7 @@ int vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, int _vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, uint64_t attr, void *val, bool write) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - - TEST_ASSERT(vcpu, "nonexistent vcpu id: %d", vcpuid); + struct vcpu *vcpu = vcpu_get(vm, vcpuid); return _kvm_device_access(vcpu->fd, group, attr, val, write); } diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h index a03febc24ba6..0c7c44499129 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util_internal.h +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h @@ -69,7 +69,7 @@ struct kvm_vm { uint32_t dirty_ring_size; }; -struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid); +struct vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid); /* * Virtual Translation Tables Dump diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index f87c7137598e..7cc1051c4b71 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -208,10 +208,7 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); - - if (!vcpu) - return; + struct vcpu *vcpu = vcpu_get(vm, vcpuid); fprintf(stream, "%*spstate: psw: 0x%.16llx:0x%.16llx\n", indent, "", vcpu->state->psw_mask, vcpu->state->psw_addr); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index af2bf114249d..723cb49d1994 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -995,7 +995,7 @@ static int vcpu_save_xsave_state(struct kvm_vm *vm, struct vcpu *vcpu, struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); + struct vcpu *vcpu = vcpu_get(vm, vcpuid); struct kvm_msr_list *list; struct kvm_x86_state *state; int nmsrs, r, i; @@ -1078,7 +1078,7 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *state) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); + struct vcpu *vcpu = vcpu_get(vm, vcpuid); int r; r = ioctl(vcpu->fd, KVM_SET_SREGS, &state->sregs); From 71ab5a6fea49875290e6ca035ff1d3e3ef3813f7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 12:06:02 -0800 Subject: [PATCH 0321/1436] KVM: selftests: Make vm_ioctl() a wrapper to pretty print ioctl name Make vm_ioctl() a macro wrapper and print the _name_ of the ioctl on failure instead of the number. Deliberately do not use __stringify(), as that will expand the ioctl all the way down to its numerical sequence. Again the intent is to print the name of the macro. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 38 ++++++++++--------- tools/testing/selftests/kvm/lib/kvm_util.c | 28 ++++---------- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index c2dfc4341b31..39e1971e5d65 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -105,6 +105,27 @@ int open_kvm_dev_path_or_exit(void); int kvm_check_cap(long cap); int vm_check_cap(struct kvm_vm *vm, long cap); int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap); + +#define __KVM_SYSCALL_ERROR(_name, _ret) \ + "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno) + +#define __KVM_IOCTL_ERROR(_name, _ret) __KVM_SYSCALL_ERROR(_name, _ret) +#define KVM_IOCTL_ERROR(_ioctl, _ret) __KVM_IOCTL_ERROR(#_ioctl, _ret) + +int __kvm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); +void kvm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); + +int __vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); +void _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, const char *name, void *arg); +#define vm_ioctl(vm, cmd, arg) _vm_ioctl(vm, cmd, #cmd, arg) + +int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, + void *arg); +void _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, + const char *name, void *arg); +#define vcpu_ioctl(vm, vcpuid, cmd, arg) \ + _vcpu_ioctl(vm, vcpuid, cmd, #cmd, arg) + void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size); const char *vm_guest_mode_string(uint32_t i); @@ -156,23 +177,6 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, uint64_t guest_paddr, uint32_t slot, uint64_t npages, uint32_t flags); -#define __KVM_SYSCALL_ERROR(_name, _ret) \ - "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno) - -#define __KVM_IOCTL_ERROR(_name, _ret) __KVM_SYSCALL_ERROR(_name, _ret) -#define KVM_IOCTL_ERROR(_ioctl, _ret) __KVM_IOCTL_ERROR(#_ioctl, _ret) - -void _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, - const char *name, void *arg); -int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long ioctl, - void *arg); -#define vcpu_ioctl(vm, vcpuid, ioctl, arg) \ - _vcpu_ioctl(vm, vcpuid, ioctl, #ioctl, arg) - -void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); -int __vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); -void kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); -int __kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa); void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 940decfaa633..7eedd9ff20fa 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1690,32 +1690,18 @@ void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid) return vcpu->dirty_gfns; } -/* - * VM Ioctl - * - * Input Args: - * vm - Virtual Machine - * cmd - Ioctl number - * arg - Argument to pass to the ioctl - * - * Return: None - * - * Issues an arbitrary ioctl on a VM fd. - */ -void vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) -{ - int ret; - - ret = __vm_ioctl(vm, cmd, arg); - TEST_ASSERT(ret == 0, "vm ioctl %lu failed, rc: %i errno: %i (%s)", - cmd, ret, errno, strerror(errno)); -} - int __vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) { return ioctl(vm->fd, cmd, arg); } +void _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, const char *name, void *arg) +{ + int ret = __vm_ioctl(vm, cmd, arg); + + TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); +} + /* * KVM system ioctl * From 10825b55b9d5a402294095a3d5fc9d0ea39cc282 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 12:09:56 -0800 Subject: [PATCH 0322/1436] KVM: sefltests: Use vm_ioctl() and __vm_ioctl() helpers Use the recently introduced VM-specific ioctl() helpers instead of open coding calls to ioctl() just to pretty print the ioctl name. Keep a few open coded assertions that provide additional info. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 60 +++++++-- .../selftests/kvm/kvm_binary_stats_test.c | 6 +- .../testing/selftests/kvm/lib/aarch64/vgic.c | 6 +- tools/testing/selftests/kvm/lib/kvm_util.c | 116 ++---------------- .../selftests/kvm/set_memory_region_test.c | 3 +- .../kvm/x86_64/pmu_event_filter_test.c | 2 +- 6 files changed, 67 insertions(+), 126 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 39e1971e5d65..1ccb91103e74 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -103,8 +103,6 @@ extern const struct vm_guest_mode_params vm_guest_mode_params[]; int open_path_or_exit(const char *path, int flags); int open_kvm_dev_path_or_exit(void); int kvm_check_cap(long cap); -int vm_check_cap(struct kvm_vm *vm, long cap); -int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap); #define __KVM_SYSCALL_ERROR(_name, _ret) \ "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno) @@ -126,6 +124,23 @@ void _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, #define vcpu_ioctl(vm, vcpuid, cmd, arg) \ _vcpu_ioctl(vm, vcpuid, cmd, #cmd, arg) +/* + * Looks up and returns the value corresponding to the capability + * (KVM_CAP_*) given by cap. + */ +static inline int vm_check_cap(struct kvm_vm *vm, long cap) +{ + int ret = __vm_ioctl(vm, KVM_CHECK_EXTENSION, (void *)cap); + + TEST_ASSERT(ret >= 0, KVM_IOCTL_ERROR(KVM_CHECK_EXTENSION, ret)); + return ret; +} + +static inline void vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) +{ + vm_ioctl(vm, KVM_ENABLE_CAP, cap); +} + void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size); const char *vm_guest_mode_string(uint32_t i); @@ -134,19 +149,46 @@ struct kvm_vm *vm_create(uint64_t phy_pages); void kvm_vm_free(struct kvm_vm *vmp); void kvm_vm_restart(struct kvm_vm *vmp); void kvm_vm_release(struct kvm_vm *vmp); -void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log); -void kvm_vm_clear_dirty_log(struct kvm_vm *vm, int slot, void *log, - uint64_t first_page, uint32_t num_pages); -uint32_t kvm_vm_reset_dirty_ring(struct kvm_vm *vm); - int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, const vm_vaddr_t gva, size_t len); - void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename); int kvm_memfd_alloc(size_t size, bool hugepages); void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); +static inline void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log) +{ + struct kvm_dirty_log args = { .dirty_bitmap = log, .slot = slot }; + + vm_ioctl(vm, KVM_GET_DIRTY_LOG, &args); +} + +static inline void kvm_vm_clear_dirty_log(struct kvm_vm *vm, int slot, void *log, + uint64_t first_page, uint32_t num_pages) +{ + struct kvm_clear_dirty_log args = { + .dirty_bitmap = log, + .slot = slot, + .first_page = first_page, + .num_pages = num_pages + }; + + vm_ioctl(vm, KVM_CLEAR_DIRTY_LOG, &args); +} + +static inline uint32_t kvm_vm_reset_dirty_ring(struct kvm_vm *vm) +{ + return __vm_ioctl(vm, KVM_RESET_DIRTY_RINGS, NULL); +} + +static inline int vm_get_stats_fd(struct kvm_vm *vm) +{ + int fd = __vm_ioctl(vm, KVM_GET_STATS_FD, NULL); + + TEST_ASSERT(fd >= 0, KVM_IOCTL_ERROR(KVM_GET_STATS_FD, fd)); + return fd; +} + /* * VM VCPU Dump * @@ -483,8 +525,6 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid); -int vm_get_stats_fd(struct kvm_vm *vm); - uint32_t guest_get_vcpuid(void); #endif /* SELFTEST_KVM_UTIL_BASE_H */ diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index bab8b49b52da..0a27b0f85009 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -165,11 +165,7 @@ static void stats_test(int stats_fd) static void vm_stats_test(struct kvm_vm *vm) { - int stats_fd; - - /* Get fd for VM stats */ - stats_fd = vm_get_stats_fd(vm); - TEST_ASSERT(stats_fd >= 0, "Get VM stats fd"); + int stats_fd = vm_get_stats_fd(vm); stats_test(stats_fd); close(stats_fd); diff --git a/tools/testing/selftests/kvm/lib/aarch64/vgic.c b/tools/testing/selftests/kvm/lib/aarch64/vgic.c index 5d45046c1b80..25d1ec65621d 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/vgic.c +++ b/tools/testing/selftests/kvm/lib/aarch64/vgic.c @@ -104,8 +104,7 @@ void kvm_irq_set_level_info(int gic_fd, uint32_t intid, int level) { int ret = _kvm_irq_set_level_info(gic_fd, intid, level); - TEST_ASSERT(ret == 0, "KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO failed, " - "rc: %i errno: %i", ret, errno); + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO, ret)); } int _kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level) @@ -127,8 +126,7 @@ void kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level) { int ret = _kvm_arm_irq_line(vm, intid, level); - TEST_ASSERT(ret == 0, "KVM_IRQ_LINE failed, rc: %i errno: %i", - ret, errno); + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_IRQ_LINE, ret)); } static void vgic_poke_irq(int gic_fd, uint32_t intid, diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 7eedd9ff20fa..339d524a0399 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -85,56 +85,6 @@ int kvm_check_cap(long cap) return ret; } -/* VM Check Capability - * - * Input Args: - * vm - Virtual Machine - * cap - Capability - * - * Output Args: None - * - * Return: - * On success, the Value corresponding to the capability (KVM_CAP_*) - * specified by the value of cap. On failure a TEST_ASSERT failure - * is produced. - * - * Looks up and returns the value corresponding to the capability - * (KVM_CAP_*) given by cap. - */ -int vm_check_cap(struct kvm_vm *vm, long cap) -{ - int ret; - - ret = ioctl(vm->fd, KVM_CHECK_EXTENSION, cap); - TEST_ASSERT(ret >= 0, "KVM_CHECK_EXTENSION VM IOCTL failed,\n" - " rc: %i errno: %i", ret, errno); - - return ret; -} - -/* VM Enable Capability - * - * Input Args: - * vm - Virtual Machine - * cap - Capability - * - * Output Args: None - * - * Return: On success, 0. On failure a TEST_ASSERT failure is produced. - * - * Enables a capability (KVM_CAP_*) on the VM. - */ -int vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) -{ - int ret; - - ret = ioctl(vm->fd, KVM_ENABLE_CAP, cap); - TEST_ASSERT(ret == 0, "KVM_ENABLE_CAP IOCTL failed,\n" - " rc: %i errno: %i", ret, errno); - - return ret; -} - void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size) { struct kvm_enable_cap cap = { 0 }; @@ -460,36 +410,6 @@ void kvm_vm_restart(struct kvm_vm *vmp) } } -void kvm_vm_get_dirty_log(struct kvm_vm *vm, int slot, void *log) -{ - struct kvm_dirty_log args = { .dirty_bitmap = log, .slot = slot }; - int ret; - - ret = ioctl(vm->fd, KVM_GET_DIRTY_LOG, &args); - TEST_ASSERT(ret == 0, "%s: KVM_GET_DIRTY_LOG failed: %s", - __func__, strerror(-ret)); -} - -void kvm_vm_clear_dirty_log(struct kvm_vm *vm, int slot, void *log, - uint64_t first_page, uint32_t num_pages) -{ - struct kvm_clear_dirty_log args = { - .dirty_bitmap = log, .slot = slot, - .first_page = first_page, - .num_pages = num_pages - }; - int ret; - - ret = ioctl(vm->fd, KVM_CLEAR_DIRTY_LOG, &args); - TEST_ASSERT(ret == 0, "%s: KVM_CLEAR_DIRTY_LOG failed: %s", - __func__, strerror(-ret)); -} - -uint32_t kvm_vm_reset_dirty_ring(struct kvm_vm *vm) -{ - return ioctl(vm->fd, KVM_RESET_DIRTY_RINGS); -} - /* * Userspace Memory Region Find * @@ -645,9 +565,7 @@ static void __vm_mem_region_delete(struct kvm_vm *vm, } region->region.memory_size = 0; - ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); - TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed, " - "rc: %i errno: %i", ret, errno); + vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION, ®ion->region); sparsebit_free(®ion->unused_phy_pages); ret = munmap(region->mmap_start, region->mmap_size); @@ -993,7 +911,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, region->region.guest_phys_addr = guest_paddr; region->region.memory_size = npages * vm->page_size; region->region.userspace_addr = (uintptr_t) region->host_mem; - ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); + ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION, ®ion->region); TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" " rc: %i errno: %i\n" " slot: %u flags: 0x%x\n" @@ -1076,7 +994,7 @@ void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) region->region.flags = flags; - ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); + ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION, ®ion->region); TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" " rc: %i errno: %i slot: %u flags: 0x%x", @@ -1106,7 +1024,7 @@ void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa) region->region.guest_phys_addr = new_gpa; - ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); + ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION, ®ion->region); TEST_ASSERT(!ret, "KVM_SET_USER_MEMORY_REGION failed\n" "ret: %i errno: %i slot: %u new_gpa: 0x%lx", @@ -1190,10 +1108,10 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) /* Allocate and initialize new vcpu structure. */ vcpu = calloc(1, sizeof(*vcpu)); TEST_ASSERT(vcpu != NULL, "Insufficient Memory"); + vcpu->id = vcpuid; - vcpu->fd = ioctl(vm->fd, KVM_CREATE_VCPU, vcpuid); - TEST_ASSERT(vcpu->fd >= 0, "KVM_CREATE_VCPU failed, rc: %i errno: %i", - vcpu->fd, errno); + vcpu->fd = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)(unsigned long)vcpuid); + TEST_ASSERT(vcpu->fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, vcpu->fd)); TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->state), "vcpu mmap size " "smaller than expected, vcpu_mmap_sz: %i expected_min: %zi", @@ -1534,11 +1452,7 @@ void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa) */ void vm_create_irqchip(struct kvm_vm *vm) { - int ret; - - ret = ioctl(vm->fd, KVM_CREATE_IRQCHIP, 0); - TEST_ASSERT(ret == 0, "KVM_CREATE_IRQCHIP IOCTL failed, " - "rc: %i errno: %i", ret, errno); + vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL); vm->has_irqchip = true; } @@ -1759,7 +1673,7 @@ int _kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test, int *fd) create_dev.type = type; create_dev.fd = -1; create_dev.flags = test ? KVM_CREATE_DEVICE_TEST : 0; - ret = ioctl(vm_get_fd(vm), KVM_CREATE_DEVICE, &create_dev); + ret = __vm_ioctl(vm, KVM_CREATE_DEVICE, &create_dev); *fd = create_dev.fd; return ret; } @@ -1855,7 +1769,7 @@ void kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level) { int ret = _kvm_irq_line(vm, irq, level); - TEST_ASSERT(ret >= 0, "KVM_IRQ_LINE failed, rc: %i errno: %i", ret, errno); + TEST_ASSERT(ret >= 0, KVM_IOCTL_ERROR(KVM_IRQ_LINE, ret)); } struct kvm_irq_routing *kvm_gsi_routing_create(void) @@ -1894,7 +1808,7 @@ int _kvm_gsi_routing_write(struct kvm_vm *vm, struct kvm_irq_routing *routing) int ret; assert(routing); - ret = ioctl(vm_get_fd(vm), KVM_SET_GSI_ROUTING, routing); + ret = __vm_ioctl(vm, KVM_SET_GSI_ROUTING, routing); free(routing); return ret; @@ -1905,8 +1819,7 @@ void kvm_gsi_routing_write(struct kvm_vm *vm, struct kvm_irq_routing *routing) int ret; ret = _kvm_gsi_routing_write(vm, routing); - TEST_ASSERT(ret == 0, "KVM_SET_GSI_ROUTING failed, rc: %i errno: %i", - ret, errno); + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_SET_GSI_ROUTING, ret)); } /* @@ -2205,8 +2118,3 @@ unsigned int vm_calc_num_guest_pages(enum vm_guest_mode mode, size_t size) n = DIV_ROUND_UP(size, vm_guest_mode_params[mode].page_size); return vm_adjust_num_guest_pages(mode, n); } - -int vm_get_stats_fd(struct kvm_vm *vm) -{ - return ioctl(vm->fd, KVM_GET_STATS_FD, NULL); -} diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index 89b13f23c3ac..e66deb8ba7e0 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -317,8 +317,7 @@ static void test_zero_memory_regions(void) vm = vm_create(0); vm_vcpu_add(vm, VCPU_ID); - TEST_ASSERT(!ioctl(vm_get_fd(vm), KVM_SET_NR_MMU_PAGES, 64), - "KVM_SET_NR_MMU_PAGES failed, errno = %d\n", errno); + vm_ioctl(vm, KVM_SET_NR_MMU_PAGES, (void *)64ul); vcpu_run(vm, VCPU_ID); run = vcpu_state(vm, VCPU_ID); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 93d77574b255..84cd5e717fcf 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -370,7 +370,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) cap.cap = KVM_CAP_PMU_CAPABILITY; cap.args[0] = KVM_PMU_CAP_DISABLE; - TEST_ASSERT(!vm_enable_cap(vm, &cap), "Failed to set KVM_PMU_CAP_DISABLE."); + vm_enable_cap(vm, &cap); vm_vcpu_add_default(vm, VCPU_ID, guest_code); vm_init_descriptor_tables(vm); From 2de1b7b127da0e87d278af172fa37ebfe04c8675 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 17 Feb 2022 10:21:36 -0800 Subject: [PATCH 0323/1436] KVM: selftests: Make kvm_ioctl() a wrapper to pretty print ioctl name Make kvm_ioctl() a macro wrapper and print the _name_ of the ioctl on failure instead of the number. Deliberately do not use __stringify(), as that will expand the ioctl all the way down to its numerical sequence, again the intent is to print the name of the macro. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 16 ++++++++-- tools/testing/selftests/kvm/lib/kvm_util.c | 31 +++---------------- .../selftests/kvm/x86_64/hyperv_cpuid.c | 2 +- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 1ccb91103e74..f5bfdf0b4548 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -110,8 +110,19 @@ int kvm_check_cap(long cap); #define __KVM_IOCTL_ERROR(_name, _ret) __KVM_SYSCALL_ERROR(_name, _ret) #define KVM_IOCTL_ERROR(_ioctl, _ret) __KVM_IOCTL_ERROR(#_ioctl, _ret) -int __kvm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); -void kvm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); +#define __kvm_ioctl(kvm_fd, cmd, arg) \ + ioctl(kvm_fd, cmd, arg) + +static inline void _kvm_ioctl(int kvm_fd, unsigned long cmd, const char *name, + void *arg) +{ + int ret = __kvm_ioctl(kvm_fd, cmd, arg); + + TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); +} + +#define kvm_ioctl(kvm_fd, cmd, arg) \ + _kvm_ioctl(kvm_fd, cmd, #cmd, arg) int __vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); void _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, const char *name, void *arg); @@ -492,6 +503,7 @@ unsigned int vm_get_page_size(struct kvm_vm *vm); unsigned int vm_get_page_shift(struct kvm_vm *vm); unsigned long vm_compute_max_gfn(struct kvm_vm *vm); uint64_t vm_get_max_gfn(struct kvm_vm *vm); +int vm_get_kvm_fd(struct kvm_vm *vm); int vm_get_fd(struct kvm_vm *vm); unsigned int vm_calc_num_guest_pages(enum vm_guest_mode mode, size_t size); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 339d524a0399..ac8faf072288 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1616,32 +1616,6 @@ void _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, const char *name, void *arg TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); } -/* - * KVM system ioctl - * - * Input Args: - * vm - Virtual Machine - * cmd - Ioctl number - * arg - Argument to pass to the ioctl - * - * Return: None - * - * Issues an arbitrary ioctl on a KVM fd. - */ -void kvm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) -{ - int ret; - - ret = ioctl(vm->kvm_fd, cmd, arg); - TEST_ASSERT(ret == 0, "KVM ioctl %lu failed, rc: %i errno: %i (%s)", - cmd, ret, errno, strerror(errno)); -} - -int __kvm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) -{ - return ioctl(vm->kvm_fd, cmd, arg); -} - /* * Device Ioctl */ @@ -2074,6 +2048,11 @@ uint64_t vm_get_max_gfn(struct kvm_vm *vm) return vm->max_gfn; } +int vm_get_kvm_fd(struct kvm_vm *vm) +{ + return vm->kvm_fd; +} + int vm_get_fd(struct kvm_vm *vm) { return vm->fd; diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c index 7e45a3df8f98..896e1e7c1df7 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c @@ -123,7 +123,7 @@ void test_hv_cpuid_e2big(struct kvm_vm *vm, bool system) if (!system) ret = __vcpu_ioctl(vm, VCPU_ID, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); else - ret = __kvm_ioctl(vm, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); + ret = __kvm_ioctl(vm_get_kvm_fd(vm), KVM_GET_SUPPORTED_HV_CPUID, &cpuid); TEST_ASSERT(ret == -1 && errno == E2BIG, "%s KVM_GET_SUPPORTED_HV_CPUID didn't fail with -E2BIG when" From f9725f89dc5027c7d94f8fdfbac8bbad846a0891 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 12:39:12 -0800 Subject: [PATCH 0324/1436] KVM: selftests: Use kvm_ioctl() helpers Use the recently introduced KVM-specific ioctl() helpers instead of open coding calls to ioctl() just to pretty print the ioctl name. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/lib/aarch64/processor.c | 4 +-- tools/testing/selftests/kvm/lib/guest_modes.c | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 13 +++---- .../selftests/kvm/lib/x86_64/processor.c | 34 ++++++------------- .../kvm/x86_64/get_msr_index_features.c | 16 +++------ .../selftests/kvm/x86_64/mmio_warning_test.c | 6 ++-- 6 files changed, 26 insertions(+), 49 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 6a041289fa80..d28cc12cea1d 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -469,8 +469,8 @@ void aarch64_get_supported_page_sizes(uint32_t ipa, }; kvm_fd = open_kvm_dev_path_or_exit(); - vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, ipa); - TEST_ASSERT(vm_fd >= 0, "Can't create VM"); + vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, ipa); + TEST_ASSERT(vm_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, vm_fd)); vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0); TEST_ASSERT(vcpu_fd >= 0, "Can't create vcpu"); diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c index 8784013b747c..9ab27b4169bf 100644 --- a/tools/testing/selftests/kvm/lib/guest_modes.c +++ b/tools/testing/selftests/kvm/lib/guest_modes.c @@ -65,7 +65,7 @@ void guest_modes_append_default(void) struct kvm_s390_vm_cpu_processor info; kvm_fd = open_kvm_dev_path_or_exit(); - vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, 0); + vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, 0); kvm_device_access(vm_fd, KVM_S390_VM_CPU_MODEL, KVM_S390_VM_CPU_PROCESSOR, &info, false); close(vm_fd); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index ac8faf072288..4d2748e8428a 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -76,9 +76,8 @@ int kvm_check_cap(long cap) int kvm_fd; kvm_fd = open_kvm_dev_path_or_exit(); - ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, cap); - TEST_ASSERT(ret >= 0, "KVM_CHECK_EXTENSION IOCTL failed,\n" - " rc: %i errno: %i", ret, errno); + ret = __kvm_ioctl(kvm_fd, KVM_CHECK_EXTENSION, cap); + TEST_ASSERT(ret >= 0, KVM_IOCTL_ERROR(KVM_CHECK_EXTENSION, ret)); close(kvm_fd); @@ -104,9 +103,8 @@ static void vm_open(struct kvm_vm *vm) exit(KSFT_SKIP); } - vm->fd = ioctl(vm->kvm_fd, KVM_CREATE_VM, vm->type); - TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " - "rc: %i errno: %i", vm->fd, errno); + vm->fd = __kvm_ioctl(vm->kvm_fd, KVM_CREATE_VM, vm->type); + TEST_ASSERT(vm->fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, vm->fd)); } const char *vm_guest_mode_string(uint32_t i) @@ -1070,8 +1068,7 @@ static int vcpu_mmap_sz(void) ret = ioctl(dev_fd, KVM_GET_VCPU_MMAP_SIZE, NULL); TEST_ASSERT(ret >= sizeof(struct kvm_run), - "%s KVM_GET_VCPU_MMAP_SIZE ioctl failed, rc: %i errno: %i", - __func__, ret, errno); + KVM_IOCTL_ERROR(KVM_GET_VCPU_MMAP_SIZE, ret)); close(dev_fd); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 723cb49d1994..852274d64483 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -638,7 +638,7 @@ void vm_xsave_req_perm(int bit) }; kvm_fd = open_kvm_dev_path_or_exit(); - rc = ioctl(kvm_fd, KVM_GET_DEVICE_ATTR, &attr); + rc = __kvm_ioctl(kvm_fd, KVM_GET_DEVICE_ATTR, &attr); close(kvm_fd); if (rc == -1 && (errno == ENXIO || errno == EINVAL)) exit(KSFT_SKIP); @@ -738,7 +738,6 @@ static struct kvm_cpuid2 *allocate_kvm_cpuid2(void) struct kvm_cpuid2 *kvm_get_supported_cpuid(void) { static struct kvm_cpuid2 *cpuid; - int ret; int kvm_fd; if (cpuid) @@ -747,9 +746,7 @@ struct kvm_cpuid2 *kvm_get_supported_cpuid(void) cpuid = allocate_kvm_cpuid2(); kvm_fd = open_kvm_dev_path_or_exit(); - ret = ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); - TEST_ASSERT(ret == 0, "KVM_GET_SUPPORTED_CPUID failed %d %d\n", - ret, errno); + kvm_ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); close(kvm_fd); return cpuid; @@ -779,9 +776,8 @@ uint64_t kvm_get_feature_msr(uint64_t msr_index) buffer.entry.index = msr_index; kvm_fd = open_kvm_dev_path_or_exit(); - r = ioctl(kvm_fd, KVM_GET_MSRS, &buffer.header); - TEST_ASSERT(r == 1, "KVM_GET_MSRS IOCTL failed,\n" - " rc: %i errno: %i", r, errno); + r = __kvm_ioctl(kvm_fd, KVM_GET_MSRS, &buffer.header); + TEST_ASSERT(r == 1, KVM_IOCTL_ERROR(KVM_GET_MSRS, r)); close(kvm_fd); return buffer.entry.data; @@ -946,9 +942,9 @@ static int kvm_get_num_msrs_fd(int kvm_fd) int r; nmsrs.nmsrs = 0; - r = ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, &nmsrs); - TEST_ASSERT(r == -1 && errno == E2BIG, "Unexpected result from KVM_GET_MSR_INDEX_LIST probe, r: %i", - r); + r = __kvm_ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, &nmsrs); + TEST_ASSERT(r == -1 && errno == E2BIG, + "Unexpected result from KVM_GET_MSR_INDEX_LIST probe, r: %i", r); return nmsrs.nmsrs; } @@ -961,19 +957,16 @@ static int kvm_get_num_msrs(struct kvm_vm *vm) struct kvm_msr_list *kvm_get_msr_index_list(void) { struct kvm_msr_list *list; - int nmsrs, r, kvm_fd; + int nmsrs, kvm_fd; kvm_fd = open_kvm_dev_path_or_exit(); nmsrs = kvm_get_num_msrs_fd(kvm_fd); list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0])); list->nmsrs = nmsrs; - r = ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list); + kvm_ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list); close(kvm_fd); - TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_MSR_INDEX_LIST, r: %i", - r); - return list; } @@ -1019,9 +1012,7 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) nmsrs = kvm_get_num_msrs(vm); list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0])); list->nmsrs = nmsrs; - r = ioctl(vm->kvm_fd, KVM_GET_MSR_INDEX_LIST, list); - TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_MSR_INDEX_LIST, r: %i", - r); + kvm_ioctl(vm->kvm_fd, KVM_GET_MSR_INDEX_LIST, list); state = malloc(sizeof(*state) + nmsrs * sizeof(state->msrs.entries[0])); r = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, &state->events); @@ -1329,7 +1320,6 @@ uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void) { static struct kvm_cpuid2 *cpuid; - int ret; int kvm_fd; if (cpuid) @@ -1338,9 +1328,7 @@ struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void) cpuid = allocate_kvm_cpuid2(); kvm_fd = open_kvm_dev_path_or_exit(); - ret = ioctl(kvm_fd, KVM_GET_SUPPORTED_HV_CPUID, cpuid); - TEST_ASSERT(ret == 0, "KVM_GET_SUPPORTED_HV_CPUID failed %d %d\n", - ret, errno); + kvm_ioctl(kvm_fd, KVM_GET_SUPPORTED_HV_CPUID, cpuid); close(kvm_fd); return cpuid; diff --git a/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c b/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c index 8aed0db1331d..4ef60adbe108 100644 --- a/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c +++ b/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c @@ -34,7 +34,7 @@ static int kvm_num_index_msrs(int kvm_fd, int nmsrs) static void test_get_msr_index(void) { - int old_res, res, kvm_fd, r; + int old_res, res, kvm_fd; struct kvm_msr_list *list; kvm_fd = open_kvm_dev_path_or_exit(); @@ -50,11 +50,8 @@ static void test_get_msr_index(void) list = malloc(sizeof(*list) + old_res * sizeof(list->indices[0])); list->nmsrs = old_res; - r = ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list); + kvm_ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list); - TEST_ASSERT(r == 0, - "Unexpected result from KVM_GET_MSR_FEATURE_INDEX_LIST, r: %i", - r); TEST_ASSERT(list->nmsrs == old_res, "Expecting nmsrs to be identical"); free(list); @@ -68,7 +65,7 @@ static int kvm_num_feature_msrs(int kvm_fd, int nmsrs) list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0])); list->nmsrs = nmsrs; - r = ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list); + r = __kvm_ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list); TEST_ASSERT(r == -1 && errno == E2BIG, "Unexpected result from KVM_GET_MSR_FEATURE_INDEX_LIST probe, r: %i", r); @@ -81,15 +78,10 @@ static int kvm_num_feature_msrs(int kvm_fd, int nmsrs) struct kvm_msr_list *kvm_get_msr_feature_list(int kvm_fd, int nmsrs) { struct kvm_msr_list *list; - int r; list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0])); list->nmsrs = nmsrs; - r = ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list); - - TEST_ASSERT(r == 0, - "Unexpected result from KVM_GET_MSR_FEATURE_INDEX_LIST, r: %i", - r); + kvm_ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list); return list; } diff --git a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c index 9f55ccd169a1..31ae837fedb1 100644 --- a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c +++ b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c @@ -59,10 +59,10 @@ void test(void) kvm = open("/dev/kvm", O_RDWR); TEST_ASSERT(kvm != -1, "failed to open /dev/kvm"); - kvmvm = ioctl(kvm, KVM_CREATE_VM, 0); - TEST_ASSERT(kvmvm != -1, "KVM_CREATE_VM failed"); + kvmvm = __kvm_ioctl(kvm, KVM_CREATE_VM, 0); + TEST_ASSERT(kvmvm > 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, kvmvm)); kvmcpu = ioctl(kvmvm, KVM_CREATE_VCPU, 0); - TEST_ASSERT(kvmcpu != -1, "KVM_CREATE_VCPU failed"); + TEST_ASSERT(kvmcpu != -1, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, kvmcpu)); run = (struct kvm_run *)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, kvmcpu, 0); tc.kvmcpu = kvmcpu; From f17cf5674a1e70c142cb3acb5eb7667560e62012 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 4 May 2022 09:44:49 -0700 Subject: [PATCH 0325/1436] KVM: selftests: Use __KVM_SYSCALL_ERROR() to handle non-KVM syscall errors Use __KVM_SYSCALL_ERROR() to report and pretty print non-KVM syscall and ioctl errors, e.g. for mmap(), munmap(), uffd ioctls, etc... Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/vgic_irq.c | 5 ++- .../selftests/kvm/demand_paging_test.c | 12 +++---- tools/testing/selftests/kvm/lib/kvm_util.c | 34 ++++++++----------- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_irq.c b/tools/testing/selftests/kvm/aarch64/vgic_irq.c index 554ca649d470..87e41895b385 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_irq.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_irq.c @@ -630,8 +630,7 @@ static void kvm_routing_and_irqfd_check(struct kvm_vm *vm, for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) { fd[f] = eventfd(0, 0); - TEST_ASSERT(fd[f] != -1, - "eventfd failed, errno: %i\n", errno); + TEST_ASSERT(fd[f] != -1, __KVM_SYSCALL_ERROR("eventfd()", fd[f])); } for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) { @@ -647,7 +646,7 @@ static void kvm_routing_and_irqfd_check(struct kvm_vm *vm, val = 1; ret = write(fd[f], &val, sizeof(uint64_t)); TEST_ASSERT(ret == sizeof(uint64_t), - "Write to KVM_IRQFD failed with ret: %d\n", ret); + __KVM_SYSCALL_ERROR("write()", ret)); } for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index 6a719d065599..d8db0a37e973 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -223,6 +223,7 @@ static void setup_demand_paging(struct kvm_vm *vm, struct uffdio_api uffdio_api; struct uffdio_register uffdio_register; uint64_t expected_ioctls = ((uint64_t) 1) << _UFFDIO_COPY; + int ret; PER_PAGE_DEBUG("Userfaultfd %s mode, faults resolved with %s\n", is_minor ? "MINOR" : "MISSING", @@ -242,19 +243,18 @@ static void setup_demand_paging(struct kvm_vm *vm, } uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); - TEST_ASSERT(uffd >= 0, "uffd creation failed, errno: %d", errno); + TEST_ASSERT(uffd >= 0, __KVM_SYSCALL_ERROR("userfaultfd()", uffd)); uffdio_api.api = UFFD_API; uffdio_api.features = 0; - TEST_ASSERT(ioctl(uffd, UFFDIO_API, &uffdio_api) != -1, - "ioctl UFFDIO_API failed: %" PRIu64, - (uint64_t)uffdio_api.api); + ret = ioctl(uffd, UFFDIO_API, &uffdio_api); + TEST_ASSERT(ret != -1, __KVM_SYSCALL_ERROR("UFFDIO_API", ret)); uffdio_register.range.start = (uint64_t)hva; uffdio_register.range.len = len; uffdio_register.mode = uffd_mode; - TEST_ASSERT(ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) != -1, - "ioctl UFFDIO_REGISTER failed"); + ret = ioctl(uffd, UFFDIO_REGISTER, &uffdio_register); + TEST_ASSERT(ret != -1, __KVM_SYSCALL_ERROR("UFFDIO_REGISTER", ret)); TEST_ASSERT((uffdio_register.ioctls & expected_ioctls) == expected_ioctls, "missing userfaultfd ioctls"); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 4d2748e8428a..c7df8ba04ec5 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -517,17 +517,15 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct vcpu *vcpu) if (vcpu->dirty_gfns) { ret = munmap(vcpu->dirty_gfns, vm->dirty_ring_size); - TEST_ASSERT(ret == 0, "munmap of VCPU dirty ring failed, " - "rc: %i errno: %i", ret, errno); + TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); vcpu->dirty_gfns = NULL; } ret = munmap(vcpu->state, vcpu_mmap_sz()); - TEST_ASSERT(ret == 0, "munmap of VCPU fd failed, rc: %i " - "errno: %i", ret, errno); + TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); + ret = close(vcpu->fd); - TEST_ASSERT(ret == 0, "Close of VCPU fd failed, rc: %i " - "errno: %i", ret, errno); + TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("close()", ret)); list_del(&vcpu->list); free(vcpu); @@ -542,12 +540,10 @@ void kvm_vm_release(struct kvm_vm *vmp) vm_vcpu_rm(vmp, vcpu); ret = close(vmp->fd); - TEST_ASSERT(ret == 0, "Close of vm fd failed,\n" - " vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno); + TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("close()", ret)); ret = close(vmp->kvm_fd); - TEST_ASSERT(ret == 0, "Close of /dev/kvm fd failed,\n" - " vmp->kvm_fd: %i rc: %i errno: %i", vmp->kvm_fd, ret, errno); + TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("close()", ret)); } static void __vm_mem_region_delete(struct kvm_vm *vm, @@ -567,7 +563,7 @@ static void __vm_mem_region_delete(struct kvm_vm *vm, sparsebit_free(®ion->unused_phy_pages); ret = munmap(region->mmap_start, region->mmap_size); - TEST_ASSERT(ret == 0, "munmap failed, rc: %i errno: %i", ret, errno); + TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); free(region); } @@ -607,14 +603,13 @@ int kvm_memfd_alloc(size_t size, bool hugepages) memfd_flags |= MFD_HUGETLB; fd = memfd_create("kvm_selftest", memfd_flags); - TEST_ASSERT(fd != -1, "memfd_create() failed, errno: %i (%s)", - errno, strerror(errno)); + TEST_ASSERT(fd != -1, __KVM_SYSCALL_ERROR("memfd_create()", fd)); r = ftruncate(fd, size); - TEST_ASSERT(!r, "ftruncate() failed, errno: %i (%s)", errno, strerror(errno)); + TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("ftruncate()", r)); r = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, size); - TEST_ASSERT(!r, "fallocate() failed, errno: %i (%s)", errno, strerror(errno)); + TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("fallocate()", r)); return fd; } @@ -880,8 +875,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, vm_mem_backing_src_alias(src_type)->flag, region->fd, 0); TEST_ASSERT(region->mmap_start != MAP_FAILED, - "test_malloc failed, mmap_start: %p errno: %i", - region->mmap_start, errno); + __KVM_SYSCALL_ERROR("mmap()", (int)(unsigned long)MAP_FAILED)); TEST_ASSERT(!is_backing_src_hugetlb(src_type) || region->mmap_start == align_ptr_up(region->mmap_start, backing_src_pagesz), @@ -929,7 +923,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, vm_mem_backing_src_alias(src_type)->flag, region->fd, 0); TEST_ASSERT(region->mmap_alias != MAP_FAILED, - "mmap of alias failed, errno: %i", errno); + __KVM_SYSCALL_ERROR("mmap()", (int)(unsigned long)MAP_FAILED)); /* Align host alias address */ region->host_alias = align_ptr_up(region->mmap_alias, alignment); @@ -1115,8 +1109,8 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) vcpu_mmap_sz(), sizeof(*vcpu->state)); vcpu->state = (struct kvm_run *) mmap(NULL, vcpu_mmap_sz(), PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, 0); - TEST_ASSERT(vcpu->state != MAP_FAILED, "mmap vcpu_state failed, " - "vcpu id: %u errno: %i", vcpuid, errno); + TEST_ASSERT(vcpu->state != MAP_FAILED, + __KVM_SYSCALL_ERROR("mmap()", (int)(unsigned long)MAP_FAILED)); /* Add to linked-list of VCPUs. */ list_add(&vcpu->list, &vm->vcpus); From b938cafdde4e2dac94154bd2a345f2baa68919dc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 09:14:17 -0800 Subject: [PATCH 0326/1436] KVM: selftests: Make x86-64's register dump helpers static Make regs_dump() and sregs_dump() static, they're only implemented by x86 and only used internally. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/lib/kvm_util_internal.h | 34 ------------------ .../selftests/kvm/lib/x86_64/processor.c | 36 ++----------------- 2 files changed, 2 insertions(+), 68 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h index 0c7c44499129..544b90df2f80 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util_internal.h +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h @@ -88,40 +88,6 @@ struct vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid); */ void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); -/* - * Register Dump - * - * Input Args: - * stream - Output FILE stream - * regs - Registers - * indent - Left margin indent amount - * - * Output Args: None - * - * Return: None - * - * Dumps the state of the registers given by @regs, to the FILE stream - * given by @stream. - */ -void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent); - -/* - * System Register Dump - * - * Input Args: - * stream - Output FILE stream - * sregs - System registers - * indent - Left margin indent amount - * - * Output Args: None - * - * Return: None - * - * Dumps the state of the system registers given by @sregs, to the FILE stream - * given by @stream. - */ -void sregs_dump(FILE *stream, struct kvm_sregs *sregs, uint8_t indent); - struct userspace_mem_region * memslot2region(struct kvm_vm *vm, uint32_t memslot); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 852274d64483..31293dbe10ec 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -19,8 +19,7 @@ vm_vaddr_t exception_handlers; -void regs_dump(FILE *stream, struct kvm_regs *regs, - uint8_t indent) +static void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent) { fprintf(stream, "%*srax: 0x%.16llx rbx: 0x%.16llx " "rcx: 0x%.16llx rdx: 0x%.16llx\n", @@ -43,21 +42,6 @@ void regs_dump(FILE *stream, struct kvm_regs *regs, regs->rip, regs->rflags); } -/* - * Segment Dump - * - * Input Args: - * stream - Output FILE stream - * segment - KVM segment - * indent - Left margin indent amount - * - * Output Args: None - * - * Return: None - * - * Dumps the state of the KVM segment given by @segment, to the FILE stream - * given by @stream. - */ static void segment_dump(FILE *stream, struct kvm_segment *segment, uint8_t indent) { @@ -75,21 +59,6 @@ static void segment_dump(FILE *stream, struct kvm_segment *segment, segment->unusable, segment->padding); } -/* - * dtable Dump - * - * Input Args: - * stream - Output FILE stream - * dtable - KVM dtable - * indent - Left margin indent amount - * - * Output Args: None - * - * Return: None - * - * Dumps the state of the KVM dtable given by @dtable, to the FILE stream - * given by @stream. - */ static void dtable_dump(FILE *stream, struct kvm_dtable *dtable, uint8_t indent) { @@ -99,8 +68,7 @@ static void dtable_dump(FILE *stream, struct kvm_dtable *dtable, dtable->padding[0], dtable->padding[1], dtable->padding[2]); } -void sregs_dump(FILE *stream, struct kvm_sregs *sregs, - uint8_t indent) +static void sregs_dump(FILE *stream, struct kvm_sregs *sregs, uint8_t indent) { unsigned int i; From b530eba14c7001882ab517c8408878ef2de97863 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 13:21:19 -0800 Subject: [PATCH 0327/1436] KVM: selftests: Get rid of kvm_util_internal.h Fold kvm_util_internal.h into kvm_util_base.h, i.e. make all KVM utility stuff "public". Hiding struct implementations from tests has been a massive failure, as it has led to pointless and poorly named wrappers, unnecessarily opaque code, etc... Not to mention that the approach was a complete failure as evidenced by the non-zero number of tests that were including kvm_util_internal.h. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 99 +++++++++++++++++-- .../selftests/kvm/lib/aarch64/processor.c | 1 - .../testing/selftests/kvm/lib/aarch64/ucall.c | 1 - .../testing/selftests/kvm/lib/aarch64/vgic.c | 1 - tools/testing/selftests/kvm/lib/elf.c | 1 - tools/testing/selftests/kvm/lib/kvm_util.c | 1 - .../selftests/kvm/lib/kvm_util_internal.h | 94 ------------------ .../selftests/kvm/lib/riscv/processor.c | 1 - tools/testing/selftests/kvm/lib/riscv/ucall.c | 1 - .../selftests/kvm/lib/s390x/processor.c | 1 - .../selftests/kvm/lib/x86_64/perf_test_util.c | 1 - .../selftests/kvm/lib/x86_64/processor.c | 1 - tools/testing/selftests/kvm/lib/x86_64/svm.c | 1 - tools/testing/selftests/kvm/lib/x86_64/vmx.c | 1 - .../kvm/x86_64/max_vcpuid_cap_test.c | 1 - .../selftests/kvm/x86_64/sev_migrate_tests.c | 1 - .../kvm/x86_64/svm_nested_soft_inject_test.c | 1 - 17 files changed, 91 insertions(+), 117 deletions(-) delete mode 100644 tools/testing/selftests/kvm/lib/kvm_util_internal.h diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index f5bfdf0b4548..c0199f3b59bb 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -9,9 +9,13 @@ #include "test_util.h" -#include "asm/kvm.h" +#include +#include "linux/hashtable.h" #include "linux/list.h" -#include "linux/kvm.h" +#include +#include +#include "linux/rbtree.h" + #include #include "sparsebit.h" @@ -21,15 +25,94 @@ #define NSEC_PER_SEC 1000000000L -/* - * Callers of kvm_util only have an incomplete/opaque description of the - * structure kvm_util is using to maintain the state of a VM. - */ -struct kvm_vm; - typedef uint64_t vm_paddr_t; /* Virtual Machine (Guest) physical address */ typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ +struct userspace_mem_region { + struct kvm_userspace_memory_region region; + struct sparsebit *unused_phy_pages; + int fd; + off_t offset; + void *host_mem; + void *host_alias; + void *mmap_start; + void *mmap_alias; + size_t mmap_size; + struct rb_node gpa_node; + struct rb_node hva_node; + struct hlist_node slot_node; +}; + +struct vcpu { + struct list_head list; + uint32_t id; + int fd; + struct kvm_run *state; + struct kvm_dirty_gfn *dirty_gfns; + uint32_t fetch_index; + uint32_t dirty_gfns_count; +}; + +struct userspace_mem_regions { + struct rb_root gpa_tree; + struct rb_root hva_tree; + DECLARE_HASHTABLE(slot_hash, 9); +}; + +struct kvm_vm { + int mode; + unsigned long type; + int kvm_fd; + int fd; + unsigned int pgtable_levels; + unsigned int page_size; + unsigned int page_shift; + unsigned int pa_bits; + unsigned int va_bits; + uint64_t max_gfn; + struct list_head vcpus; + struct userspace_mem_regions regions; + struct sparsebit *vpages_valid; + struct sparsebit *vpages_mapped; + bool has_irqchip; + bool pgd_created; + vm_paddr_t pgd; + vm_vaddr_t gdt; + vm_vaddr_t tss; + vm_vaddr_t idt; + vm_vaddr_t handlers; + uint32_t dirty_ring_size; +}; + + +#define kvm_for_each_vcpu(vm, i, vcpu) \ + for ((i) = 0; (i) <= (vm)->last_vcpu_id; (i)++) \ + if (!((vcpu) = vm->vcpus[i])) \ + continue; \ + else + +struct vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid); + +/* + * Virtual Translation Tables Dump + * + * Input Args: + * stream - Output FILE stream + * vm - Virtual Machine + * indent - Left margin indent amount + * + * Output Args: None + * + * Return: None + * + * Dumps to the FILE stream given by @stream, the contents of all the + * virtual translation tables for the VM given by @vm. + */ +void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); + +struct userspace_mem_region * +memslot2region(struct kvm_vm *vm, uint32_t memslot); + /* Minimum allocated guest virtual and physical addresses */ #define KVM_UTIL_MIN_VADDR 0x2000 #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index d28cc12cea1d..388bd7d87c02 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -10,7 +10,6 @@ #include "guest_modes.h" #include "kvm_util.h" -#include "../kvm_util_internal.h" #include "processor.h" #define DEFAULT_ARM64_GUEST_STACK_VADDR_MIN 0xac0000 diff --git a/tools/testing/selftests/kvm/lib/aarch64/ucall.c b/tools/testing/selftests/kvm/lib/aarch64/ucall.c index 00be3ef195ca..868ebab5369e 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/ucall.c +++ b/tools/testing/selftests/kvm/lib/aarch64/ucall.c @@ -5,7 +5,6 @@ * Copyright (C) 2018, Red Hat, Inc. */ #include "kvm_util.h" -#include "../kvm_util_internal.h" static vm_vaddr_t *ucall_exit_mmio_addr; diff --git a/tools/testing/selftests/kvm/lib/aarch64/vgic.c b/tools/testing/selftests/kvm/lib/aarch64/vgic.c index 25d1ec65621d..c34f0f116f39 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/vgic.c +++ b/tools/testing/selftests/kvm/lib/aarch64/vgic.c @@ -9,7 +9,6 @@ #include #include "kvm_util.h" -#include "../kvm_util_internal.h" #include "vgic.h" #include "gic.h" #include "gic_v3.h" diff --git a/tools/testing/selftests/kvm/lib/elf.c b/tools/testing/selftests/kvm/lib/elf.c index 13e8e3dcf984..9f54c098d9d0 100644 --- a/tools/testing/selftests/kvm/lib/elf.c +++ b/tools/testing/selftests/kvm/lib/elf.c @@ -11,7 +11,6 @@ #include #include "kvm_util.h" -#include "kvm_util_internal.h" static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp) { diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index c7df8ba04ec5..a57958a39c1b 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -8,7 +8,6 @@ #define _GNU_SOURCE /* for program_invocation_name */ #include "test_util.h" #include "kvm_util.h" -#include "kvm_util_internal.h" #include "processor.h" #include diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h deleted file mode 100644 index 544b90df2f80..000000000000 --- a/tools/testing/selftests/kvm/lib/kvm_util_internal.h +++ /dev/null @@ -1,94 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * tools/testing/selftests/kvm/lib/kvm_util_internal.h - * - * Copyright (C) 2018, Google LLC. - */ - -#ifndef SELFTEST_KVM_UTIL_INTERNAL_H -#define SELFTEST_KVM_UTIL_INTERNAL_H - -#include "linux/hashtable.h" -#include "linux/rbtree.h" - -#include "sparsebit.h" - -struct userspace_mem_region { - struct kvm_userspace_memory_region region; - struct sparsebit *unused_phy_pages; - int fd; - off_t offset; - void *host_mem; - void *host_alias; - void *mmap_start; - void *mmap_alias; - size_t mmap_size; - struct rb_node gpa_node; - struct rb_node hva_node; - struct hlist_node slot_node; -}; - -struct vcpu { - struct list_head list; - uint32_t id; - int fd; - struct kvm_run *state; - struct kvm_dirty_gfn *dirty_gfns; - uint32_t fetch_index; - uint32_t dirty_gfns_count; -}; - -struct userspace_mem_regions { - struct rb_root gpa_tree; - struct rb_root hva_tree; - DECLARE_HASHTABLE(slot_hash, 9); -}; - -struct kvm_vm { - int mode; - unsigned long type; - int kvm_fd; - int fd; - unsigned int pgtable_levels; - unsigned int page_size; - unsigned int page_shift; - unsigned int pa_bits; - unsigned int va_bits; - uint64_t max_gfn; - struct list_head vcpus; - struct userspace_mem_regions regions; - struct sparsebit *vpages_valid; - struct sparsebit *vpages_mapped; - bool has_irqchip; - bool pgd_created; - vm_paddr_t pgd; - vm_vaddr_t gdt; - vm_vaddr_t tss; - vm_vaddr_t idt; - vm_vaddr_t handlers; - uint32_t dirty_ring_size; -}; - -struct vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid); - -/* - * Virtual Translation Tables Dump - * - * Input Args: - * stream - Output FILE stream - * vm - Virtual Machine - * indent - Left margin indent amount - * - * Output Args: None - * - * Return: None - * - * Dumps to the FILE stream given by @stream, the contents of all the - * virtual translation tables for the VM given by @vm. - */ -void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); - -struct userspace_mem_region * -memslot2region(struct kvm_vm *vm, uint32_t memslot); - -#endif /* SELFTEST_KVM_UTIL_INTERNAL_H */ diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index c89e6b1fbfb1..5ee8250dd74c 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -9,7 +9,6 @@ #include #include "kvm_util.h" -#include "../kvm_util_internal.h" #include "processor.h" #define DEFAULT_RISCV_GUEST_STACK_VADDR_MIN 0xac0000 diff --git a/tools/testing/selftests/kvm/lib/riscv/ucall.c b/tools/testing/selftests/kvm/lib/riscv/ucall.c index c2ed59f5783d..48d91b77fa1d 100644 --- a/tools/testing/selftests/kvm/lib/riscv/ucall.c +++ b/tools/testing/selftests/kvm/lib/riscv/ucall.c @@ -8,7 +8,6 @@ #include #include "kvm_util.h" -#include "../kvm_util_internal.h" #include "processor.h" void ucall_init(struct kvm_vm *vm, void *arg) diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index 7cc1051c4b71..53c413932f64 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -7,7 +7,6 @@ #include "processor.h" #include "kvm_util.h" -#include "../kvm_util_internal.h" #define PAGES_PER_REGION 4 diff --git a/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c b/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c index e258524435a0..f525427a37c4 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c @@ -12,7 +12,6 @@ #include "test_util.h" #include "kvm_util.h" #include "perf_test_util.h" -#include "../kvm_util_internal.h" #include "processor.h" #include "vmx.h" diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 31293dbe10ec..02266b8123df 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -7,7 +7,6 @@ #include "test_util.h" #include "kvm_util.h" -#include "../kvm_util_internal.h" #include "processor.h" #ifndef NUM_INTERRUPTS diff --git a/tools/testing/selftests/kvm/lib/x86_64/svm.c b/tools/testing/selftests/kvm/lib/x86_64/svm.c index 736ee4a23df6..01a9d831da13 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/svm.c +++ b/tools/testing/selftests/kvm/lib/x86_64/svm.c @@ -9,7 +9,6 @@ #include "test_util.h" #include "kvm_util.h" -#include "../kvm_util_internal.h" #include "processor.h" #include "svm_util.h" diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c index b77a01d0a271..fdca123397e4 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c @@ -7,7 +7,6 @@ #include "test_util.h" #include "kvm_util.h" -#include "../kvm_util_internal.h" #include "processor.h" #include "vmx.h" diff --git a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c index e83afd4bb4cf..419fbdc51246 100644 --- a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c +++ b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c @@ -8,7 +8,6 @@ */ #include "kvm_util.h" -#include "../lib/kvm_util_internal.h" #define MAX_VCPU_ID 2 diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index 7424bec5ae23..5b565aa11e32 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -12,7 +12,6 @@ #include "processor.h" #include "svm_util.h" #include "kselftest.h" -#include "../lib/kvm_util_internal.h" #define SEV_POLICY_ES 0b100 diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c index f94f1b449aef..18061677154f 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -17,7 +17,6 @@ #include "processor.h" #include "svm_util.h" #include "test_util.h" -#include "../lib/kvm_util_internal.h" #define VCPU_ID 0 #define INT_NR 0x20 From a78593fd8717349852fa9a3f7292516edc5b50ea Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 17 Feb 2022 10:57:06 -0800 Subject: [PATCH 0328/1436] KVM: selftests: Use KVM_IOCTL_ERROR() for one-off arm64 ioctls Use the KVM_IOCTL_ERROR() macro to generate error messages for a handful of one-off arm64 ioctls. The calls in question are made without an associated struct kvm_vm/kvm_vcpu as they are used to configure those structs, i.e. can't be easily converted to e.g. vcpu_ioctl(). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/aarch64/processor.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 388bd7d87c02..2e73853f485e 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -472,15 +472,15 @@ void aarch64_get_supported_page_sizes(uint32_t ipa, TEST_ASSERT(vm_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, vm_fd)); vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0); - TEST_ASSERT(vcpu_fd >= 0, "Can't create vcpu"); + TEST_ASSERT(vcpu_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, vcpu_fd)); err = ioctl(vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init); - TEST_ASSERT(err == 0, "Can't get target"); + TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_ARM_PREFERRED_TARGET, err)); err = ioctl(vcpu_fd, KVM_ARM_VCPU_INIT, &preferred_init); - TEST_ASSERT(err == 0, "Can't get init vcpu"); + TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_ARM_VCPU_INIT, err)); err = ioctl(vcpu_fd, KVM_GET_ONE_REG, ®); - TEST_ASSERT(err == 0, "Can't get MMFR0"); + TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd)); *ps4k = ((val >> 28) & 0xf) != 0xf; *ps64k = ((val >> 24) & 0xf) == 0; From f3165dc02212e8eaf5cb675f105aac89c6de431c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 17 Feb 2022 12:09:28 -0800 Subject: [PATCH 0329/1436] KVM: selftests: Drop @test param from kvm_create_device() Remove the two calls that pass @test=true to kvm_create_device() and drop the @test param entirely. The two removed calls don't check the return value of kvm_create_device(), so other than verifying KVM doesn't explode, which is extremely unlikely given that the non-test variant was _just_ called, they are pointless and provide no validation coverage. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/vgic_init.c | 14 ++++++-------- .../testing/selftests/kvm/include/kvm_util_base.h | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 12 ++++-------- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 42c9209f7786..4928cb43c8a7 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -65,7 +65,7 @@ static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type, uint32_t nr v.gic_dev_type = gic_dev_type; v.vm = vm_create_default_with_vcpus(nr_vcpus, 0, 0, guest_code, NULL); - v.gic_fd = kvm_create_device(v.vm, gic_dev_type, false); + v.gic_fd = kvm_create_device(v.vm, gic_dev_type); return v; } @@ -406,7 +406,7 @@ static void test_v3_typer_accesses(void) v.vm = vm_create_default(0, 0, guest_code); - v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3, false); + v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); vm_vcpu_add_default(v.vm, 3, guest_code); @@ -487,7 +487,7 @@ static void test_v3_last_bit_redist_regions(void) v.vm = vm_create_default_with_vcpus(6, 0, 0, guest_code, vcpuids); - v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3, false); + v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); @@ -536,7 +536,7 @@ static void test_v3_last_bit_single_rdist(void) v.vm = vm_create_default_with_vcpus(6, 0, 0, guest_code, vcpuids); - v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3, false); + v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); @@ -603,7 +603,7 @@ static void test_v3_its_region(void) int its_fd, ret; v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS); - its_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_ITS, false); + its_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_ITS); addr = 0x401000; ret = _kvm_device_access(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, @@ -656,13 +656,11 @@ int test_kvm_device(uint32_t gic_dev_type) ret = _kvm_create_device(v.vm, gic_dev_type, true, &fd); if (ret) return ret; - v.gic_fd = kvm_create_device(v.vm, gic_dev_type, false); + v.gic_fd = kvm_create_device(v.vm, gic_dev_type); ret = _kvm_create_device(v.vm, gic_dev_type, false, &fd); TEST_ASSERT(ret && errno == EEXIST, "create GIC device twice"); - kvm_create_device(v.vm, gic_dev_type, true); - /* try to create the other gic_dev_type */ other = VGIC_DEV_IS_V2(gic_dev_type) ? KVM_DEV_TYPE_ARM_VGIC_V3 : KVM_DEV_TYPE_ARM_VGIC_V2; diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index c0199f3b59bb..6e1926abb248 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -485,7 +485,7 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); int _kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr); int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr); int _kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test, int *fd); -int kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test); +int kvm_create_device(struct kvm_vm *vm, uint64_t type); int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, void *val, bool write); int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index a57958a39c1b..cb2e42aa1c03 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1642,18 +1642,14 @@ int _kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test, int *fd) return ret; } -int kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test) +int kvm_create_device(struct kvm_vm *vm, uint64_t type) { int fd, ret; - ret = _kvm_create_device(vm, type, test, &fd); + ret = _kvm_create_device(vm, type, false, &fd); - if (!test) { - TEST_ASSERT(!ret, - "KVM_CREATE_DEVICE IOCTL failed, rc: %i errno: %i", ret, errno); - return fd; - } - return ret; + TEST_ASSERT(!ret, "KVM_CREATE_DEVICE IOCTL failed, rc: %i errno: %i", ret, errno); + return fd; } int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, From 98f94ce42ac672b2abdcf38cfc0e60fd52e04995 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 17 Feb 2022 12:16:20 -0800 Subject: [PATCH 0330/1436] KVM: selftests: Move KVM_CREATE_DEVICE_TEST code to separate helper Move KVM_CREATE_DEVICE_TEST to its own helper, identifying "real" versus "test" device creation based on a hardcoded boolean buried in the middle of a param list is painful for readers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/vgic_init.c | 10 ++++---- .../selftests/kvm/include/kvm_util_base.h | 3 ++- .../testing/selftests/kvm/lib/aarch64/vgic.c | 3 +-- tools/testing/selftests/kvm/lib/kvm_util.c | 23 ++++++++++++++----- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 4928cb43c8a7..18054b94207f 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -649,24 +649,24 @@ int test_kvm_device(uint32_t gic_dev_type) v.vm = vm_create_default_with_vcpus(NR_VCPUS, 0, 0, guest_code, NULL); /* try to create a non existing KVM device */ - ret = _kvm_create_device(v.vm, 0, true, &fd); + ret = __kvm_test_create_device(v.vm, 0); TEST_ASSERT(ret && errno == ENODEV, "unsupported device"); /* trial mode */ - ret = _kvm_create_device(v.vm, gic_dev_type, true, &fd); + ret = __kvm_test_create_device(v.vm, gic_dev_type); if (ret) return ret; v.gic_fd = kvm_create_device(v.vm, gic_dev_type); - ret = _kvm_create_device(v.vm, gic_dev_type, false, &fd); + ret = __kvm_create_device(v.vm, gic_dev_type, &fd); TEST_ASSERT(ret && errno == EEXIST, "create GIC device twice"); /* try to create the other gic_dev_type */ other = VGIC_DEV_IS_V2(gic_dev_type) ? KVM_DEV_TYPE_ARM_VGIC_V3 : KVM_DEV_TYPE_ARM_VGIC_V2; - if (!_kvm_create_device(v.vm, other, true, &fd)) { - ret = _kvm_create_device(v.vm, other, false, &fd); + if (!__kvm_test_create_device(v.vm, other)) { + ret = __kvm_test_create_device(v.vm, other); TEST_ASSERT(ret && errno == EINVAL, "create GIC device while other version exists"); } diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 6e1926abb248..8795f4624c2c 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -484,7 +484,8 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); int _kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr); int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr); -int _kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test, int *fd); +int __kvm_test_create_device(struct kvm_vm *vm, uint64_t type); +int __kvm_create_device(struct kvm_vm *vm, uint64_t type, int *fd); int kvm_create_device(struct kvm_vm *vm, uint64_t type); int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, void *val, bool write); diff --git a/tools/testing/selftests/kvm/lib/aarch64/vgic.c b/tools/testing/selftests/kvm/lib/aarch64/vgic.c index c34f0f116f39..74b4bcaffcfa 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/vgic.c +++ b/tools/testing/selftests/kvm/lib/aarch64/vgic.c @@ -51,8 +51,7 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs, nr_vcpus, nr_vcpus_created); /* Distributor setup */ - if (_kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3, - false, &gic_fd) != 0) + if (__kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3, &gic_fd)) return -1; kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index cb2e42aa1c03..9c0122b0e393 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1629,14 +1629,25 @@ int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr) return ret; } -int _kvm_create_device(struct kvm_vm *vm, uint64_t type, bool test, int *fd) +int __kvm_test_create_device(struct kvm_vm *vm, uint64_t type) { - struct kvm_create_device create_dev; + struct kvm_create_device create_dev = { + .type = type, + .flags = KVM_CREATE_DEVICE_TEST, + }; + + return __vm_ioctl(vm, KVM_CREATE_DEVICE, &create_dev); +} + +int __kvm_create_device(struct kvm_vm *vm, uint64_t type, int *fd) +{ + struct kvm_create_device create_dev = { + .type = type, + .fd = -1, + .flags = 0, + }; int ret; - create_dev.type = type; - create_dev.fd = -1; - create_dev.flags = test ? KVM_CREATE_DEVICE_TEST : 0; ret = __vm_ioctl(vm, KVM_CREATE_DEVICE, &create_dev); *fd = create_dev.fd; return ret; @@ -1646,7 +1657,7 @@ int kvm_create_device(struct kvm_vm *vm, uint64_t type) { int fd, ret; - ret = _kvm_create_device(vm, type, false, &fd); + ret = __kvm_create_device(vm, type, &fd); TEST_ASSERT(!ret, "KVM_CREATE_DEVICE IOCTL failed, rc: %i errno: %i", ret, errno); return fd; From 279eacbefad5d163a20f8fcde2fd9362bc24f7c7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 17 Feb 2022 12:21:33 -0800 Subject: [PATCH 0331/1436] KVM: selftests: Multiplex return code and fd in __kvm_create_device() Multiplex the return value and fd (on success) in __kvm_create_device() to mimic common library helpers that return file descriptors, e.g. open(). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/vgic_init.c | 6 +++--- .../selftests/kvm/include/kvm_util_base.h | 2 +- tools/testing/selftests/kvm/lib/aarch64/vgic.c | 5 +++-- tools/testing/selftests/kvm/lib/kvm_util.c | 16 +++++++--------- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 18054b94207f..77d6c09e0f80 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -643,8 +643,8 @@ static void test_v3_its_region(void) int test_kvm_device(uint32_t gic_dev_type) { struct vm_gic v; - int ret, fd; uint32_t other; + int ret; v.vm = vm_create_default_with_vcpus(NR_VCPUS, 0, 0, guest_code, NULL); @@ -658,8 +658,8 @@ int test_kvm_device(uint32_t gic_dev_type) return ret; v.gic_fd = kvm_create_device(v.vm, gic_dev_type); - ret = __kvm_create_device(v.vm, gic_dev_type, &fd); - TEST_ASSERT(ret && errno == EEXIST, "create GIC device twice"); + ret = __kvm_create_device(v.vm, gic_dev_type); + TEST_ASSERT(ret < 0 && errno == EEXIST, "create GIC device twice"); /* try to create the other gic_dev_type */ other = VGIC_DEV_IS_V2(gic_dev_type) ? KVM_DEV_TYPE_ARM_VGIC_V3 diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 8795f4624c2c..1ccf44805fa0 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -485,7 +485,7 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); int _kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr); int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr); int __kvm_test_create_device(struct kvm_vm *vm, uint64_t type); -int __kvm_create_device(struct kvm_vm *vm, uint64_t type, int *fd); +int __kvm_create_device(struct kvm_vm *vm, uint64_t type); int kvm_create_device(struct kvm_vm *vm, uint64_t type); int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, void *val, bool write); diff --git a/tools/testing/selftests/kvm/lib/aarch64/vgic.c b/tools/testing/selftests/kvm/lib/aarch64/vgic.c index 74b4bcaffcfa..7925b4c5dad0 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/vgic.c +++ b/tools/testing/selftests/kvm/lib/aarch64/vgic.c @@ -51,8 +51,9 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs, nr_vcpus, nr_vcpus_created); /* Distributor setup */ - if (__kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3, &gic_fd)) - return -1; + gic_fd = __kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3); + if (gic_fd < 0) + return gic_fd; kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, &nr_irqs, true); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 9c0122b0e393..17e226107b65 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1639,27 +1639,25 @@ int __kvm_test_create_device(struct kvm_vm *vm, uint64_t type) return __vm_ioctl(vm, KVM_CREATE_DEVICE, &create_dev); } -int __kvm_create_device(struct kvm_vm *vm, uint64_t type, int *fd) +int __kvm_create_device(struct kvm_vm *vm, uint64_t type) { struct kvm_create_device create_dev = { .type = type, .fd = -1, .flags = 0, }; - int ret; + int err; - ret = __vm_ioctl(vm, KVM_CREATE_DEVICE, &create_dev); - *fd = create_dev.fd; - return ret; + err = __vm_ioctl(vm, KVM_CREATE_DEVICE, &create_dev); + TEST_ASSERT(err <= 0, "KVM_CREATE_DEVICE shouldn't return a positive value"); + return err ? : create_dev.fd; } int kvm_create_device(struct kvm_vm *vm, uint64_t type) { - int fd, ret; + int fd = __kvm_create_device(vm, type); - ret = __kvm_create_device(vm, type, &fd); - - TEST_ASSERT(!ret, "KVM_CREATE_DEVICE IOCTL failed, rc: %i errno: %i", ret, errno); + TEST_ASSERT(fd >= 0, "KVM_CREATE_DEVICE IOCTL failed, rc: %i errno: %i", fd, errno); return fd; } From 9367504f77ebb47d09847993aae01f8a38d5b4f6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 2 Mar 2022 19:49:16 -0800 Subject: [PATCH 0332/1436] KVM: selftests: Rename KVM_HAS_DEVICE_ATTR helpers for consistency Rename kvm_device_check_attr() and its variants to kvm_has_device_attr() to be consistent with the ioctl names and with other helpers in the KVM selftests framework. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/vgic_init.c | 12 +++++------- tools/testing/selftests/kvm/include/kvm_util_base.h | 6 +++--- tools/testing/selftests/kvm/lib/kvm_util.c | 12 ++++++------ .../selftests/kvm/system_counter_offset_test.c | 2 +- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 77d6c09e0f80..3013b4f522e7 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -127,14 +127,12 @@ static void subtest_dist_rdist(struct vm_gic *v) : gic_v2_dist_region; /* Check existing group/attributes */ - kvm_device_check_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - dist.attr); + kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, dist.attr); - kvm_device_check_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - rdist.attr); + kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, rdist.attr); /* check non existing attribute */ - ret = _kvm_device_check_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, -1); + ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, -1); TEST_ASSERT(ret && errno == ENXIO, "attribute not supported"); /* misaligned DIST and REDIST address settings */ @@ -176,7 +174,7 @@ static void subtest_dist_rdist(struct vm_gic *v) rdist.attr, &addr, true); TEST_ASSERT(ret && errno == EEXIST, "GIC redist base set again"); - ret = _kvm_device_check_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST); if (!ret) { /* Attempt to mix legacy and new redistributor regions */ @@ -203,7 +201,7 @@ static void subtest_v3_redist_regions(struct vm_gic *v) uint64_t addr, expected_addr; int ret; - ret = kvm_device_check_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + ret = kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST); TEST_ASSERT(!ret, "Multiple redist regions advertised"); diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 1ccf44805fa0..66d896c8e19b 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -482,8 +482,8 @@ void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid); */ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); -int _kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr); -int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr); +int __kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr); +int kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr); int __kvm_test_create_device(struct kvm_vm *vm, uint64_t type); int __kvm_create_device(struct kvm_vm *vm, uint64_t type); int kvm_create_device(struct kvm_vm *vm, uint64_t type); @@ -494,7 +494,7 @@ int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, void kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level); int _kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level); -int _vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, +int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, uint64_t attr); int vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, uint64_t attr); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 17e226107b65..ca313dc8b37a 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1610,7 +1610,7 @@ void _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, const char *name, void *arg * Device Ioctl */ -int _kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr) +int __kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr) { struct kvm_device_attr attribute = { .group = group, @@ -1621,9 +1621,9 @@ int _kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr) return ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attribute); } -int kvm_device_check_attr(int dev_fd, uint32_t group, uint64_t attr) +int kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr) { - int ret = _kvm_device_check_attr(dev_fd, group, attr); + int ret = __kvm_has_device_attr(dev_fd, group, attr); TEST_ASSERT(!ret, "KVM_HAS_DEVICE_ATTR failed, rc: %i errno: %i", ret, errno); return ret; @@ -1686,18 +1686,18 @@ int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, return ret; } -int _vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, +int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, uint64_t attr) { struct vcpu *vcpu = vcpu_get(vm, vcpuid); - return _kvm_device_check_attr(vcpu->fd, group, attr); + return __kvm_has_device_attr(vcpu->fd, group, attr); } int vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, uint64_t attr) { - int ret = _vcpu_has_device_attr(vm, vcpuid, group, attr); + int ret = __vcpu_has_device_attr(vm, vcpuid, group, attr); TEST_ASSERT(!ret, "KVM_HAS_DEVICE_ATTR IOCTL failed, rc: %i errno: %i", ret, errno); return ret; diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c b/tools/testing/selftests/kvm/system_counter_offset_test.c index b337bbbfa41f..2b10c53abf4f 100644 --- a/tools/testing/selftests/kvm/system_counter_offset_test.c +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c @@ -30,7 +30,7 @@ static struct test_case test_cases[] = { static void check_preconditions(struct kvm_vm *vm) { - if (!_vcpu_has_device_attr(vm, VCPU_ID, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET)) + if (!__vcpu_has_device_attr(vm, VCPU_ID, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET)) return; print_skip("KVM_VCPU_TSC_OFFSET not supported; skipping test"); From d2752e2eb331cbbed6f51f901f2685654e1cafa7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 17 Feb 2022 16:33:21 -0800 Subject: [PATCH 0333/1436] KVM: selftests: Drop 'int' return from asserting *_has_device_attr() Drop 'int' returns from *_device_has_attr() helpers that assert the return is '0', there's no point in returning '0' and "requiring" the caller to perform a redundant assertion. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/vgic_init.c | 4 ++-- .../selftests/kvm/include/kvm_util_base.h | 20 ++++++++++++++++--- tools/testing/selftests/kvm/lib/kvm_util.c | 17 ---------------- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 3013b4f522e7..fe3d0259a9f4 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -201,8 +201,8 @@ static void subtest_v3_redist_regions(struct vm_gic *v) uint64_t addr, expected_addr; int ret; - ret = kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST); + ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST); TEST_ASSERT(!ret, "Multiple redist regions advertised"); addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 2, 0); diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 66d896c8e19b..f9aeac540699 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -483,7 +483,14 @@ void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid); void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); int __kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr); -int kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr); + +static inline void kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr) +{ + int ret = __kvm_has_device_attr(dev_fd, group, attr); + + TEST_ASSERT(!ret, "KVM_HAS_DEVICE_ATTR failed, rc: %i errno: %i", ret, errno); +} + int __kvm_test_create_device(struct kvm_vm *vm, uint64_t type); int __kvm_create_device(struct kvm_vm *vm, uint64_t type); int kvm_create_device(struct kvm_vm *vm, uint64_t type); @@ -496,8 +503,15 @@ int _kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level); int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, uint64_t attr); -int vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr); + +static inline void vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, + uint32_t group, uint64_t attr) +{ + int ret = __vcpu_has_device_attr(vm, vcpuid, group, attr); + + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_HAS_DEVICE_ATTR, ret)); +} + int _vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, uint64_t attr, void *val, bool write); int vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index ca313dc8b37a..a7bc6b623871 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1621,14 +1621,6 @@ int __kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr) return ioctl(dev_fd, KVM_HAS_DEVICE_ATTR, &attribute); } -int kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr) -{ - int ret = __kvm_has_device_attr(dev_fd, group, attr); - - TEST_ASSERT(!ret, "KVM_HAS_DEVICE_ATTR failed, rc: %i errno: %i", ret, errno); - return ret; -} - int __kvm_test_create_device(struct kvm_vm *vm, uint64_t type) { struct kvm_create_device create_dev = { @@ -1694,15 +1686,6 @@ int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, return __kvm_has_device_attr(vcpu->fd, group, attr); } -int vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr) -{ - int ret = __vcpu_has_device_attr(vm, vcpuid, group, attr); - - TEST_ASSERT(!ret, "KVM_HAS_DEVICE_ATTR IOCTL failed, rc: %i errno: %i", ret, errno); - return ret; -} - int _vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, uint64_t attr, void *val, bool write) { From 4091818426d98f4e7093808264caf86ad90287c8 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Jun 2022 13:06:57 -0700 Subject: [PATCH 0334/1436] KVM: selftests: Split get/set device_attr helpers Split the get/set device_attr helpers instead of using a boolean param to select between get and set. Duplicating upper level wrappers is a very, very small price to pay for improved readability, and having constant (at compile time) inputs will allow the selftests framework to sanity check ioctl() invocations. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/arch_timer.c | 8 +- .../testing/selftests/kvm/aarch64/vgic_init.c | 246 +++++++++--------- .../selftests/kvm/include/kvm_util_base.h | 91 ++++--- .../testing/selftests/kvm/lib/aarch64/vgic.c | 31 ++- tools/testing/selftests/kvm/lib/guest_modes.c | 4 +- tools/testing/selftests/kvm/lib/kvm_util.c | 70 +++-- .../kvm/system_counter_offset_test.c | 4 +- 7 files changed, 237 insertions(+), 217 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index f55c4c20d8b3..f04ca07c7f14 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -349,10 +349,10 @@ static void test_run(struct kvm_vm *vm) static void test_init_timer_irq(struct kvm_vm *vm) { /* Timer initid should be same for all the vCPUs, so query only vCPU-0 */ - vcpu_access_device_attr(vm, 0, KVM_ARM_VCPU_TIMER_CTRL, - KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq, false); - vcpu_access_device_attr(vm, 0, KVM_ARM_VCPU_TIMER_CTRL, - KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq, false); + vcpu_device_attr_get(vm, 0, KVM_ARM_VCPU_TIMER_CTRL, + KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq); + vcpu_device_attr_get(vm, 0, KVM_ARM_VCPU_TIMER_CTRL, + KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq); sync_global_to_guest(vm, ptimer_irq); sync_global_to_guest(vm, vtimer_irq); diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index fe3d0259a9f4..4da1524cc49c 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -33,13 +33,10 @@ struct vm_gic { static uint64_t max_phys_size; /* helper to access a redistributor register */ -static int access_v3_redist_reg(int gicv3_fd, int vcpu, int offset, - uint32_t *val, bool write) +static int v3_redist_reg_get(int gicv3_fd, int vcpu, int offset, uint32_t *val) { - uint64_t attr = REG_OFFSET(vcpu, offset); - - return _kvm_device_access(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, - attr, val, write); + return __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, + REG_OFFSET(vcpu, offset), val); } /* dummy guest code */ @@ -137,41 +134,41 @@ static void subtest_dist_rdist(struct vm_gic *v) /* misaligned DIST and REDIST address settings */ addr = dist.alignment / 0x10; - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - dist.attr, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + dist.attr, &addr); TEST_ASSERT(ret && errno == EINVAL, "GIC dist base not aligned"); addr = rdist.alignment / 0x10; - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - rdist.attr, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + rdist.attr, &addr); TEST_ASSERT(ret && errno == EINVAL, "GIC redist/cpu base not aligned"); /* out of range address */ addr = max_phys_size; - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - dist.attr, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + dist.attr, &addr); TEST_ASSERT(ret && errno == E2BIG, "dist address beyond IPA limit"); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - rdist.attr, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + rdist.attr, &addr); TEST_ASSERT(ret && errno == E2BIG, "redist address beyond IPA limit"); /* Space for half a rdist (a rdist is: 2 * rdist.alignment). */ addr = max_phys_size - dist.alignment; - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - rdist.attr, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + rdist.attr, &addr); TEST_ASSERT(ret && errno == E2BIG, "half of the redist is beyond IPA limit"); /* set REDIST base address @0x0*/ addr = 0x00000; - kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - rdist.attr, &addr, true); + kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + rdist.attr, &addr); /* Attempt to create a second legacy redistributor region */ addr = 0xE0000; - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - rdist.attr, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + rdist.attr, &addr); TEST_ASSERT(ret && errno == EEXIST, "GIC redist base set again"); ret = __kvm_has_device_attr(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, @@ -179,9 +176,8 @@ static void subtest_dist_rdist(struct vm_gic *v) if (!ret) { /* Attempt to mix legacy and new redistributor regions */ addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 0, 0); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, - &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "attempt to mix GICv3 REDIST and REDIST_REGION"); } @@ -191,8 +187,8 @@ static void subtest_dist_rdist(struct vm_gic *v) * on first vcpu run instead. */ addr = rdist.size - rdist.alignment; - kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - dist.attr, &addr, true); + kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + dist.attr, &addr); } /* Test the new REDIST region API */ @@ -206,66 +202,66 @@ static void subtest_v3_redist_regions(struct vm_gic *v) TEST_ASSERT(!ret, "Multiple redist regions advertised"); addr = REDIST_REGION_ATTR_ADDR(NR_VCPUS, 0x100000, 2, 0); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with flags != 0"); addr = REDIST_REGION_ATTR_ADDR(0, 0x100000, 0, 0); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "redist region attr value with count== 0"); addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "attempt to register the first rdist region with index != 0"); addr = REDIST_REGION_ATTR_ADDR(2, 0x201000, 0, 1); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "rdist region with misaligned address"); addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0); - kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 1); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "register an rdist region with already used index"); addr = REDIST_REGION_ATTR_ADDR(1, 0x210000, 0, 2); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "register an rdist region overlapping with another one"); addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 2); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "register redist region with index not +1"); addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1); - kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); addr = REDIST_REGION_ATTR_ADDR(1, max_phys_size, 0, 2); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == E2BIG, "register redist region with base address beyond IPA range"); /* The last redist is above the pa range. */ addr = REDIST_REGION_ATTR_ADDR(2, max_phys_size - 0x30000, 0, 2); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == E2BIG, "register redist region with top address beyond IPA range"); addr = 0x260000; - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr); TEST_ASSERT(ret && errno == EINVAL, "Mix KVM_VGIC_V3_ADDR_TYPE_REDIST and REDIST_REGION"); @@ -278,28 +274,28 @@ static void subtest_v3_redist_regions(struct vm_gic *v) addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 0); expected_addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, false); + ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #0"); addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 1); expected_addr = REDIST_REGION_ATTR_ADDR(1, 0x240000, 0, 1); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, false); + ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(!ret && addr == expected_addr, "read characteristics of region #1"); addr = REDIST_REGION_ATTR_ADDR(0, 0, 0, 2); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, false); + ret = __kvm_device_attr_get(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == ENOENT, "read characteristics of non existing region"); addr = 0x260000; - kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_DIST, &addr, true); + kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_DIST, &addr); addr = REDIST_REGION_ATTR_ADDR(1, 0x260000, 0, 2); - ret = _kvm_device_access(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v->gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "register redist region colliding with dist"); } @@ -351,8 +347,8 @@ static void test_v3_new_redist_regions(void) v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS); subtest_v3_redist_regions(&v); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); ret = run_vcpu(v.vm, 3); TEST_ASSERT(ret == -ENXIO, "running without sufficient number of rdists"); @@ -364,8 +360,8 @@ static void test_v3_new_redist_regions(void) subtest_v3_redist_regions(&v); addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); ret = run_vcpu(v.vm, 3); TEST_ASSERT(ret == -EBUSY, "running without vgic explicit init"); @@ -377,17 +373,17 @@ static void test_v3_new_redist_regions(void) v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS); subtest_v3_redist_regions(&v); - ret = _kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, dummy, true); + ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, dummy); TEST_ASSERT(ret && errno == EFAULT, "register a third region allowing to cover the 4 vcpus"); addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); ret = run_vcpu(v.vm, 3); TEST_ASSERT(!ret, "vcpu run"); @@ -408,57 +404,57 @@ static void test_v3_typer_accesses(void) vm_vcpu_add_default(v.vm, 3, guest_code); - ret = access_v3_redist_reg(v.gic_fd, 1, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); TEST_ASSERT(ret && errno == EINVAL, "attempting to read GICR_TYPER of non created vcpu"); vm_vcpu_add_default(v.vm, 1, guest_code); - ret = access_v3_redist_reg(v.gic_fd, 1, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); TEST_ASSERT(ret && errno == EBUSY, "read GICR_TYPER before GIC initialized"); vm_vcpu_add_default(v.vm, 2, guest_code); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); for (i = 0; i < NR_VCPUS ; i++) { - ret = access_v3_redist_reg(v.gic_fd, i, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, &val); TEST_ASSERT(!ret && val == i * 0x100, "read GICR_TYPER before rdist region setting"); } addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); /* The 2 first rdists should be put there (vcpu 0 and 3) */ - ret = access_v3_redist_reg(v.gic_fd, 0, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, &val); TEST_ASSERT(!ret && !val, "read typer of rdist #0"); - ret = access_v3_redist_reg(v.gic_fd, 3, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x310, "read typer of rdist #1"); addr = REDIST_REGION_ATTR_ADDR(10, 0x100000, 0, 1); - ret = _kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "collision with previous rdist region"); - ret = access_v3_redist_reg(v.gic_fd, 1, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x100, "no redist region attached to vcpu #1 yet, last cannot be returned"); - ret = access_v3_redist_reg(v.gic_fd, 2, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x200, "no redist region attached to vcpu #2, last cannot be returned"); addr = REDIST_REGION_ATTR_ADDR(10, 0x20000, 0, 1); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); - ret = access_v3_redist_reg(v.gic_fd, 1, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x100, "read typer of rdist #1"); - ret = access_v3_redist_reg(v.gic_fd, 2, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x210, "read typer of rdist #1, last properly returned"); @@ -487,37 +483,37 @@ static void test_v3_last_bit_redist_regions(void) v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); addr = REDIST_REGION_ATTR_ADDR(2, 0x100000, 0, 0); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); addr = REDIST_REGION_ATTR_ADDR(2, 0x240000, 0, 1); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 2); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); - ret = access_v3_redist_reg(v.gic_fd, 0, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x000, "read typer of rdist #0"); - ret = access_v3_redist_reg(v.gic_fd, 1, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x100, "read typer of rdist #1"); - ret = access_v3_redist_reg(v.gic_fd, 2, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x200, "read typer of rdist #2"); - ret = access_v3_redist_reg(v.gic_fd, 3, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x310, "read typer of rdist #3"); - ret = access_v3_redist_reg(v.gic_fd, 5, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x500, "read typer of rdist #5"); - ret = access_v3_redist_reg(v.gic_fd, 4, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 4, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x410, "read typer of rdist #4"); vm_gic_destroy(&v); @@ -536,26 +532,26 @@ static void test_v3_last_bit_single_rdist(void) v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); addr = 0x10000; - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr); - ret = access_v3_redist_reg(v.gic_fd, 0, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x000, "read typer of rdist #0"); - ret = access_v3_redist_reg(v.gic_fd, 3, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x300, "read typer of rdist #1"); - ret = access_v3_redist_reg(v.gic_fd, 5, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x500, "read typer of rdist #2"); - ret = access_v3_redist_reg(v.gic_fd, 1, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x100, "read typer of rdist #3"); - ret = access_v3_redist_reg(v.gic_fd, 2, GICR_TYPER, &val, false); + ret = v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, &val); TEST_ASSERT(!ret && val == 0x210, "read typer of rdist #3"); vm_gic_destroy(&v); @@ -572,19 +568,19 @@ static void test_v3_redist_ipa_range_check_at_vcpu_run(void) /* Set space for 3 redists, we have 1 vcpu, so this succeeds. */ addr = max_phys_size - (3 * 2 * 0x10000); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr); addr = 0x00000; - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_DIST, &addr, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_DIST, &addr); /* Add the rest of the VCPUs */ for (i = 1; i < NR_VCPUS; ++i) vm_vcpu_add_default(v.vm, i, guest_code); - kvm_device_access(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); /* Attempt to run a vcpu without enough redist space. */ ret = run_vcpu(v.vm, 2); @@ -604,31 +600,31 @@ static void test_v3_its_region(void) its_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_ITS); addr = 0x401000; - ret = _kvm_device_access(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_ITS_ADDR_TYPE, &addr, true); + ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_ITS_ADDR_TYPE, &addr); TEST_ASSERT(ret && errno == EINVAL, "ITS region with misaligned address"); addr = max_phys_size; - ret = _kvm_device_access(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_ITS_ADDR_TYPE, &addr, true); + ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_ITS_ADDR_TYPE, &addr); TEST_ASSERT(ret && errno == E2BIG, "register ITS region with base address beyond IPA range"); addr = max_phys_size - 0x10000; - ret = _kvm_device_access(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_ITS_ADDR_TYPE, &addr, true); + ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_ITS_ADDR_TYPE, &addr); TEST_ASSERT(ret && errno == E2BIG, "Half of ITS region is beyond IPA range"); /* This one succeeds setting the ITS base */ addr = 0x400000; - kvm_device_access(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_ITS_ADDR_TYPE, &addr, true); + kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_ITS_ADDR_TYPE, &addr); addr = 0x300000; - ret = _kvm_device_access(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_ITS_ADDR_TYPE, &addr, true); + ret = __kvm_device_attr_set(its_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_ITS_ADDR_TYPE, &addr); TEST_ASSERT(ret && errno == EEXIST, "ITS base set again"); close(its_fd); diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index f9aeac540699..6e63e7e57752 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -460,6 +460,65 @@ static inline int vcpu_get_stats_fd(struct kvm_vm *vm, uint32_t vcpuid) return fd; } +int __kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr); + +static inline void kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr) +{ + int ret = __kvm_has_device_attr(dev_fd, group, attr); + + TEST_ASSERT(!ret, "KVM_HAS_DEVICE_ATTR failed, rc: %i errno: %i", ret, errno); +} + +int __kvm_device_attr_get(int dev_fd, uint32_t group, uint64_t attr, void *val); + +static inline void kvm_device_attr_get(int dev_fd, uint32_t group, + uint64_t attr, void *val) +{ + int ret = __kvm_device_attr_get(dev_fd, group, attr, val); + + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_GET_DEVICE_ATTR, ret)); +} + +int __kvm_device_attr_set(int dev_fd, uint32_t group, uint64_t attr, void *val); + +static inline void kvm_device_attr_set(int dev_fd, uint32_t group, + uint64_t attr, void *val) +{ + int ret = __kvm_device_attr_set(dev_fd, group, attr, val); + + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret)); +} + +int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr); + +static inline void vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, + uint32_t group, uint64_t attr) +{ + int ret = __vcpu_has_device_attr(vm, vcpuid, group, attr); + + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_HAS_DEVICE_ATTR, ret)); +} + +int __vcpu_device_attr_get(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val); +void vcpu_device_attr_get(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val); +int __vcpu_device_attr_set(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val); +void vcpu_device_attr_set(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val); +int __kvm_test_create_device(struct kvm_vm *vm, uint64_t type); +int __kvm_create_device(struct kvm_vm *vm, uint64_t type); + +static inline int kvm_create_device(struct kvm_vm *vm, uint64_t type) +{ + int fd = __kvm_create_device(vm, type); + + TEST_ASSERT(fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_DEVICE, fd)); + return fd; +} + void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid); /* @@ -482,41 +541,9 @@ void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid); */ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); -int __kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr); - -static inline void kvm_has_device_attr(int dev_fd, uint32_t group, uint64_t attr) -{ - int ret = __kvm_has_device_attr(dev_fd, group, attr); - - TEST_ASSERT(!ret, "KVM_HAS_DEVICE_ATTR failed, rc: %i errno: %i", ret, errno); -} - -int __kvm_test_create_device(struct kvm_vm *vm, uint64_t type); -int __kvm_create_device(struct kvm_vm *vm, uint64_t type); -int kvm_create_device(struct kvm_vm *vm, uint64_t type); -int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, - void *val, bool write); -int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, - void *val, bool write); void kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level); int _kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level); -int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr); - -static inline void vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, - uint32_t group, uint64_t attr) -{ - int ret = __vcpu_has_device_attr(vm, vcpuid, group, attr); - - TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_HAS_DEVICE_ATTR, ret)); -} - -int _vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val, bool write); -int vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val, bool write); - #define KVM_MAX_IRQ_ROUTES 4096 struct kvm_irq_routing *kvm_gsi_routing_create(void); diff --git a/tools/testing/selftests/kvm/lib/aarch64/vgic.c b/tools/testing/selftests/kvm/lib/aarch64/vgic.c index 7925b4c5dad0..cfe3067efbf0 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/vgic.c +++ b/tools/testing/selftests/kvm/lib/aarch64/vgic.c @@ -55,27 +55,26 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs, if (gic_fd < 0) return gic_fd; - kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, - 0, &nr_irqs, true); + kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 0, &nr_irqs); - kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); - kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_DIST, &gicd_base_gpa, true); + kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_DIST, &gicd_base_gpa); nr_gic_pages = vm_calc_num_guest_pages(vm->mode, KVM_VGIC_V3_DIST_SIZE); virt_map(vm, gicd_base_gpa, gicd_base_gpa, nr_gic_pages); /* Redistributor setup */ redist_attr = REDIST_REGION_ATTR_ADDR(nr_vcpus, gicr_base_gpa, 0, 0); - kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, - KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &redist_attr, true); + kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, + KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &redist_attr); nr_gic_pages = vm_calc_num_guest_pages(vm->mode, KVM_VGIC_V3_REDIST_SIZE * nr_vcpus); virt_map(vm, gicr_base_gpa, gicr_base_gpa, nr_gic_pages); - kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, - KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); + kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, + KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); return gic_fd; } @@ -88,14 +87,14 @@ int _kvm_irq_set_level_info(int gic_fd, uint32_t intid, int level) uint64_t val; int ret; - ret = _kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO, - attr, &val, false); + ret = __kvm_device_attr_get(gic_fd, KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO, + attr, &val); if (ret != 0) return ret; val |= 1U << index; - ret = _kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO, - attr, &val, true); + ret = __kvm_device_attr_set(gic_fd, KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO, + attr, &val); return ret; } @@ -155,9 +154,9 @@ static void vgic_poke_irq(int gic_fd, uint32_t intid, * intid will just make the read/writes point to above the intended * register space (i.e., ICPENDR after ISPENDR). */ - kvm_device_access(gic_fd, group, attr, &val, false); + kvm_device_attr_get(gic_fd, group, attr, &val); val |= 1ULL << index; - kvm_device_access(gic_fd, group, attr, &val, true); + kvm_device_attr_set(gic_fd, group, attr, &val); } void kvm_irq_write_ispendr(int gic_fd, uint32_t intid, uint32_t vcpu) diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c index 9ab27b4169bf..0be56c63aed6 100644 --- a/tools/testing/selftests/kvm/lib/guest_modes.c +++ b/tools/testing/selftests/kvm/lib/guest_modes.c @@ -66,8 +66,8 @@ void guest_modes_append_default(void) kvm_fd = open_kvm_dev_path_or_exit(); vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, 0); - kvm_device_access(vm_fd, KVM_S390_VM_CPU_MODEL, - KVM_S390_VM_CPU_PROCESSOR, &info, false); + kvm_device_attr_get(vm_fd, KVM_S390_VM_CPU_MODEL, + KVM_S390_VM_CPU_PROCESSOR, &info); close(vm_fd); close(kvm_fd); /* Starting with z13 we have 47bits of physical address */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index a7bc6b623871..220e079dc749 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1645,16 +1645,7 @@ int __kvm_create_device(struct kvm_vm *vm, uint64_t type) return err ? : create_dev.fd; } -int kvm_create_device(struct kvm_vm *vm, uint64_t type) -{ - int fd = __kvm_create_device(vm, type); - - TEST_ASSERT(fd >= 0, "KVM_CREATE_DEVICE IOCTL failed, rc: %i errno: %i", fd, errno); - return fd; -} - -int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, - void *val, bool write) +int __kvm_device_attr_get(int dev_fd, uint32_t group, uint64_t attr, void *val) { struct kvm_device_attr kvmattr = { .group = group, @@ -1662,20 +1653,44 @@ int _kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, .flags = 0, .addr = (uintptr_t)val, }; - int ret; - ret = ioctl(dev_fd, write ? KVM_SET_DEVICE_ATTR : KVM_GET_DEVICE_ATTR, - &kvmattr); - return ret; + return __kvm_ioctl(dev_fd, KVM_GET_DEVICE_ATTR, &kvmattr); } -int kvm_device_access(int dev_fd, uint32_t group, uint64_t attr, - void *val, bool write) +int __kvm_device_attr_set(int dev_fd, uint32_t group, uint64_t attr, void *val) { - int ret = _kvm_device_access(dev_fd, group, attr, val, write); + struct kvm_device_attr kvmattr = { + .group = group, + .attr = attr, + .flags = 0, + .addr = (uintptr_t)val, + }; - TEST_ASSERT(!ret, "KVM_SET|GET_DEVICE_ATTR IOCTL failed, rc: %i errno: %i", ret, errno); - return ret; + return __kvm_ioctl(dev_fd, KVM_SET_DEVICE_ATTR, &kvmattr); +} + +int __vcpu_device_attr_get(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val) +{ + return __kvm_device_attr_get(vcpu_get(vm, vcpuid)->fd, group, attr, val); +} + +void vcpu_device_attr_get(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val) +{ + kvm_device_attr_get(vcpu_get(vm, vcpuid)->fd, group, attr, val); +} + +int __vcpu_device_attr_set(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val) +{ + return __kvm_device_attr_set(vcpu_get(vm, vcpuid)->fd, group, attr, val); +} + +void vcpu_device_attr_set(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, + uint64_t attr, void *val) +{ + kvm_device_attr_set(vcpu_get(vm, vcpuid)->fd, group, attr, val); } int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, @@ -1686,23 +1701,6 @@ int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, return __kvm_has_device_attr(vcpu->fd, group, attr); } -int _vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val, bool write) -{ - struct vcpu *vcpu = vcpu_get(vm, vcpuid); - - return _kvm_device_access(vcpu->fd, group, attr, val, write); -} - -int vcpu_access_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val, bool write) -{ - int ret = _vcpu_access_device_attr(vm, vcpuid, group, attr, val, write); - - TEST_ASSERT(!ret, "KVM_SET|GET_DEVICE_ATTR IOCTL failed, rc: %i errno: %i", ret, errno); - return ret; -} - /* * IRQ related functions. */ diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c b/tools/testing/selftests/kvm/system_counter_offset_test.c index 2b10c53abf4f..5dd9d28efb97 100644 --- a/tools/testing/selftests/kvm/system_counter_offset_test.c +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c @@ -39,8 +39,8 @@ static void check_preconditions(struct kvm_vm *vm) static void setup_system_counter(struct kvm_vm *vm, struct test_case *test) { - vcpu_access_device_attr(vm, VCPU_ID, KVM_VCPU_TSC_CTRL, - KVM_VCPU_TSC_OFFSET, &test->tsc_offset, true); + vcpu_device_attr_set(vm, VCPU_ID, KVM_VCPU_TSC_CTRL, + KVM_VCPU_TSC_OFFSET, &test->tsc_offset); } static uint64_t guest_read_system_counter(struct test_case *test) From 114eef6e461a6a0810d6ed354b4ce7f3b74fe547 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Jun 2022 13:20:53 -0700 Subject: [PATCH 0335/1436] KVM: selftests: Dedup vgic_init's asserts and improve error messages Move the asserts for the many REDIST_REGS accesses into common helpers instead of copy+pasting the same, unhelpful asserts over and over. Not providing the actual (or expected) value makes it unnecessarily painful to debug failures, especially since test_assert() prints the errno unconditionally, e.g. on success, it may print a stale, misleading errno. Use kvm_device_attr_get() to handle the "success" check so that the "success" and "expected == actual" asserts are separated, which will make it far less likely that a user incorrectly assumes the ioctl() failed. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/vgic_init.c | 112 ++++++++---------- 1 file changed, 47 insertions(+), 65 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 4da1524cc49c..c5866c3f4516 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -32,11 +32,28 @@ struct vm_gic { static uint64_t max_phys_size; -/* helper to access a redistributor register */ -static int v3_redist_reg_get(int gicv3_fd, int vcpu, int offset, uint32_t *val) +/* + * Helpers to access a redistributor register and verify the ioctl() failed or + * succeeded as expected, and provided the correct value on success. + */ +static void v3_redist_reg_get_errno(int gicv3_fd, int vcpu, int offset, + int want, const char *msg) { - return __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, - REG_OFFSET(vcpu, offset), val); + uint32_t ignored_val; + int ret = __kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, + REG_OFFSET(vcpu, offset), &ignored_val); + + TEST_ASSERT(ret && errno == want, "%s; want errno = %d", msg, want); +} + +static void v3_redist_reg_get(int gicv3_fd, int vcpu, int offset, uint32_t want, + const char *msg) +{ + uint32_t val; + + kvm_device_attr_get(gicv3_fd, KVM_DEV_ARM_VGIC_GRP_REDIST_REGS, + REG_OFFSET(vcpu, offset), &val); + TEST_ASSERT(val == want, "%s; want '0x%x', got '0x%x'", msg, want, val); } /* dummy guest code */ @@ -395,7 +412,6 @@ static void test_v3_typer_accesses(void) { struct vm_gic v; uint64_t addr; - uint32_t val; int ret, i; v.vm = vm_create_default(0, 0, guest_code); @@ -404,13 +420,13 @@ static void test_v3_typer_accesses(void) vm_vcpu_add_default(v.vm, 3, guest_code); - ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); - TEST_ASSERT(ret && errno == EINVAL, "attempting to read GICR_TYPER of non created vcpu"); + v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EINVAL, + "attempting to read GICR_TYPER of non created vcpu"); vm_vcpu_add_default(v.vm, 1, guest_code); - ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); - TEST_ASSERT(ret && errno == EBUSY, "read GICR_TYPER before GIC initialized"); + v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EBUSY, + "read GICR_TYPER before GIC initialized"); vm_vcpu_add_default(v.vm, 2, guest_code); @@ -418,9 +434,8 @@ static void test_v3_typer_accesses(void) KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); for (i = 0; i < NR_VCPUS ; i++) { - ret = v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == i * 0x100, - "read GICR_TYPER before rdist region setting"); + v3_redist_reg_get(v.gic_fd, i, GICR_TYPER, i * 0x100, + "read GICR_TYPER before rdist region setting"); } addr = REDIST_REGION_ATTR_ADDR(2, 0x200000, 0, 0); @@ -428,35 +443,26 @@ static void test_v3_typer_accesses(void) KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); /* The 2 first rdists should be put there (vcpu 0 and 3) */ - ret = v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, &val); - TEST_ASSERT(!ret && !val, "read typer of rdist #0"); - - ret = v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x310, "read typer of rdist #1"); + v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x0, "read typer of rdist #0"); + v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #1"); addr = REDIST_REGION_ATTR_ADDR(10, 0x100000, 0, 1); ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); TEST_ASSERT(ret && errno == EINVAL, "collision with previous rdist region"); - ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x100, - "no redist region attached to vcpu #1 yet, last cannot be returned"); - - ret = v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x200, - "no redist region attached to vcpu #2, last cannot be returned"); + v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, + "no redist region attached to vcpu #1 yet, last cannot be returned"); + v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200, + "no redist region attached to vcpu #2, last cannot be returned"); addr = REDIST_REGION_ATTR_ADDR(10, 0x20000, 0, 1); kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); - ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x100, "read typer of rdist #1"); - - ret = v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x210, - "read typer of rdist #1, last properly returned"); + v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1"); + v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210, + "read typer of rdist #1, last properly returned"); vm_gic_destroy(&v); } @@ -476,8 +482,6 @@ static void test_v3_last_bit_redist_regions(void) uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 }; struct vm_gic v; uint64_t addr; - uint32_t val; - int ret; v.vm = vm_create_default_with_vcpus(6, 0, 0, guest_code, vcpuids); @@ -498,23 +502,12 @@ static void test_v3_last_bit_redist_regions(void) kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); - ret = v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x000, "read typer of rdist #0"); - - ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x100, "read typer of rdist #1"); - - ret = v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x200, "read typer of rdist #2"); - - ret = v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x310, "read typer of rdist #3"); - - ret = v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x500, "read typer of rdist #5"); - - ret = v3_redist_reg_get(v.gic_fd, 4, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x410, "read typer of rdist #4"); + v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0"); + v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #1"); + v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x200, "read typer of rdist #2"); + v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x310, "read typer of rdist #3"); + v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #5"); + v3_redist_reg_get(v.gic_fd, 4, GICR_TYPER, 0x410, "read typer of rdist #4"); vm_gic_destroy(&v); } @@ -525,8 +518,6 @@ static void test_v3_last_bit_single_rdist(void) uint32_t vcpuids[] = { 0, 3, 5, 4, 1, 2 }; struct vm_gic v; uint64_t addr; - uint32_t val; - int ret; v.vm = vm_create_default_with_vcpus(6, 0, 0, guest_code, vcpuids); @@ -539,20 +530,11 @@ static void test_v3_last_bit_single_rdist(void) kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST, &addr); - ret = v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x000, "read typer of rdist #0"); - - ret = v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x300, "read typer of rdist #1"); - - ret = v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x500, "read typer of rdist #2"); - - ret = v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x100, "read typer of rdist #3"); - - ret = v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, &val); - TEST_ASSERT(!ret && val == 0x210, "read typer of rdist #3"); + v3_redist_reg_get(v.gic_fd, 0, GICR_TYPER, 0x000, "read typer of rdist #0"); + v3_redist_reg_get(v.gic_fd, 3, GICR_TYPER, 0x300, "read typer of rdist #1"); + v3_redist_reg_get(v.gic_fd, 5, GICR_TYPER, 0x500, "read typer of rdist #2"); + v3_redist_reg_get(v.gic_fd, 1, GICR_TYPER, 0x100, "read typer of rdist #3"); + v3_redist_reg_get(v.gic_fd, 2, GICR_TYPER, 0x210, "read typer of rdist #3"); vm_gic_destroy(&v); } From c472df1ac318c1120f32cd4a70d202806be30c43 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 15:14:29 -0800 Subject: [PATCH 0336/1436] KVM: selftests: Add a VM backpointer to 'struct vcpu' Add a backpointer to 'struct vcpu' so that tests can get at the owning VM when passing around a vCPU object. Long term, this will be little more than a nice-to-have feature, but in the short term it is a critical step toward purging the VM+vcpu_id ioctl mess without introducing even more churn. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/include/kvm_util_base.h | 1 + tools/testing/selftests/kvm/lib/kvm_util.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 6e63e7e57752..2e1453cb0511 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -47,6 +47,7 @@ struct vcpu { struct list_head list; uint32_t id; int fd; + struct kvm_vm *vm; struct kvm_run *state; struct kvm_dirty_gfn *dirty_gfns; uint32_t fetch_index; diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 220e079dc749..2d82b5720737 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1099,6 +1099,7 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) vcpu = calloc(1, sizeof(*vcpu)); TEST_ASSERT(vcpu != NULL, "Insufficient Memory"); + vcpu->vm = vm; vcpu->id = vcpuid; vcpu->fd = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)(unsigned long)vcpuid); TEST_ASSERT(vcpu->fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, vcpu->fd)); From ac71220934a9240864ec485932308866500b1e61 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 2 Jun 2022 12:55:59 -0700 Subject: [PATCH 0337/1436] KVM: selftests: Consolidate KVM_ENABLE_CAP usage Add __vm_enable_cap() and use it for negative tests that expect KVM_ENABLE_CAP to fail. Opportunistically clean up the MAX_VCPU_ID test error messages. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 4 + tools/testing/selftests/kvm/lib/x86_64/vmx.c | 2 +- .../kvm/x86_64/max_vcpuid_cap_test.c | 19 ++--- .../selftests/kvm/x86_64/sev_migrate_tests.c | 78 +++++++++---------- 4 files changed, 52 insertions(+), 51 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 2e1453cb0511..f0afc1dce8ba 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -231,6 +231,10 @@ static inline int vm_check_cap(struct kvm_vm *vm, long cap) return ret; } +static inline int __vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) +{ + return __vm_ioctl(vm, KVM_ENABLE_CAP, cap); +} static inline void vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) { vm_ioctl(vm, KVM_ENABLE_CAP, cap); diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c index fdca123397e4..dbfca8ed79aa 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c @@ -51,7 +51,7 @@ int vcpu_enable_evmcs(struct kvm_vm *vm, int vcpu_id) .args[0] = (unsigned long)&evmcs_ver }; - vcpu_ioctl(vm, vcpu_id, KVM_ENABLE_CAP, &enable_evmcs_cap); + vcpu_enable_cap(vm, vcpu_id, &enable_evmcs_cap); /* KVM should return supported EVMCS version range */ TEST_ASSERT(((evmcs_ver >> 8) >= (evmcs_ver & 0xff)) && diff --git a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c index 419fbdc51246..c6fd36a31c8c 100644 --- a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c +++ b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c @@ -25,28 +25,25 @@ int main(int argc, char *argv[]) /* Try to set KVM_CAP_MAX_VCPU_ID beyond KVM cap */ cap.cap = KVM_CAP_MAX_VCPU_ID; cap.args[0] = ret + 1; - ret = ioctl(vm->fd, KVM_ENABLE_CAP, &cap); + ret = __vm_enable_cap(vm, &cap); TEST_ASSERT(ret < 0, - "Unexpected success to enable KVM_CAP_MAX_VCPU_ID" - "beyond KVM cap!\n"); + "Setting KVM_CAP_MAX_VCPU_ID beyond KVM cap should fail"); /* Set KVM_CAP_MAX_VCPU_ID */ cap.cap = KVM_CAP_MAX_VCPU_ID; cap.args[0] = MAX_VCPU_ID; - ret = ioctl(vm->fd, KVM_ENABLE_CAP, &cap); - TEST_ASSERT(ret == 0, - "Unexpected failure to enable KVM_CAP_MAX_VCPU_ID!\n"); + vm_enable_cap(vm, &cap); + /* Try to set KVM_CAP_MAX_VCPU_ID again */ cap.args[0] = MAX_VCPU_ID + 1; - ret = ioctl(vm->fd, KVM_ENABLE_CAP, &cap); + ret = __vm_enable_cap(vm, &cap); TEST_ASSERT(ret < 0, - "Unexpected success to enable KVM_CAP_MAX_VCPU_ID again\n"); + "Setting KVM_CAP_MAX_VCPU_ID multiple times should fail"); /* Create vCPU with id beyond KVM_CAP_MAX_VCPU_ID cap*/ - ret = ioctl(vm->fd, KVM_CREATE_VCPU, MAX_VCPU_ID); - TEST_ASSERT(ret < 0, - "Unexpected success in creating a vCPU with VCPU ID out of range\n"); + ret = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)MAX_VCPU_ID); + TEST_ASSERT(ret < 0, "Creating vCPU with ID > MAX_VCPU_ID should fail"); kvm_vm_free(vm); return 0; diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index 5b565aa11e32..f127f2fccca6 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -80,22 +80,22 @@ static struct kvm_vm *aux_vm_create(bool with_vcpus) return vm; } -static int __sev_migrate_from(int dst_fd, int src_fd) +static int __sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src) { struct kvm_enable_cap cap = { .cap = KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM, - .args = { src_fd } + .args = { src->fd } }; - return ioctl(dst_fd, KVM_ENABLE_CAP, &cap); + return __vm_enable_cap(dst, &cap); } -static void sev_migrate_from(int dst_fd, int src_fd) +static void sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src) { int ret; - ret = __sev_migrate_from(dst_fd, src_fd); + ret = __sev_migrate_from(dst, src); TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d\n", ret, errno); } @@ -110,13 +110,13 @@ static void test_sev_migrate_from(bool es) dst_vms[i] = aux_vm_create(true); /* Initial migration from the src to the first dst. */ - sev_migrate_from(dst_vms[0]->fd, src_vm->fd); + sev_migrate_from(dst_vms[0], src_vm); for (i = 1; i < NR_MIGRATE_TEST_VMS; i++) - sev_migrate_from(dst_vms[i]->fd, dst_vms[i - 1]->fd); + sev_migrate_from(dst_vms[i], dst_vms[i - 1]); /* Migrate the guest back to the original VM. */ - ret = __sev_migrate_from(src_vm->fd, dst_vms[NR_MIGRATE_TEST_VMS - 1]->fd); + ret = __sev_migrate_from(src_vm, dst_vms[NR_MIGRATE_TEST_VMS - 1]); TEST_ASSERT(ret == -1 && errno == EIO, "VM that was migrated from should be dead. ret %d, errno: %d\n", ret, errno); @@ -128,7 +128,7 @@ static void test_sev_migrate_from(bool es) struct locking_thread_input { struct kvm_vm *vm; - int source_fds[NR_LOCK_TESTING_THREADS]; + struct kvm_vm *source_vms[NR_LOCK_TESTING_THREADS]; }; static void *locking_test_thread(void *arg) @@ -138,7 +138,7 @@ static void *locking_test_thread(void *arg) for (i = 0; i < NR_LOCK_TESTING_ITERATIONS; ++i) { j = i % NR_LOCK_TESTING_THREADS; - __sev_migrate_from(input->vm->fd, input->source_fds[j]); + __sev_migrate_from(input->vm, input->source_vms[j]); } return NULL; @@ -152,11 +152,11 @@ static void test_sev_migrate_locking(void) for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i) { input[i].vm = sev_vm_create(/* es= */ false); - input[0].source_fds[i] = input[i].vm->fd; + input[0].source_vms[i] = input[i].vm; } for (i = 1; i < NR_LOCK_TESTING_THREADS; ++i) - memcpy(input[i].source_fds, input[0].source_fds, - sizeof(input[i].source_fds)); + memcpy(input[i].source_vms, input[0].source_vms, + sizeof(input[i].source_vms)); for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i) pthread_create(&pt[i], NULL, locking_test_thread, &input[i]); @@ -175,7 +175,7 @@ static void test_sev_migrate_parameters(void) vm_no_vcpu = vm_create(0); vm_no_sev = aux_vm_create(true); - ret = __sev_migrate_from(vm_no_vcpu->fd, vm_no_sev->fd); + ret = __sev_migrate_from(vm_no_vcpu, vm_no_sev); TEST_ASSERT(ret == -1 && errno == EINVAL, "Migrations require SEV enabled. ret %d, errno: %d\n", ret, errno); @@ -189,25 +189,25 @@ static void test_sev_migrate_parameters(void) sev_ioctl(sev_es_vm_no_vmsa->fd, KVM_SEV_ES_INIT, NULL); vm_vcpu_add(sev_es_vm_no_vmsa, 1); - ret = __sev_migrate_from(sev_vm->fd, sev_es_vm->fd); + ret = __sev_migrate_from(sev_vm, sev_es_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, "Should not be able migrate to SEV enabled VM. ret: %d, errno: %d\n", ret, errno); - ret = __sev_migrate_from(sev_es_vm->fd, sev_vm->fd); + ret = __sev_migrate_from(sev_es_vm, sev_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, "Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d\n", ret, errno); - ret = __sev_migrate_from(vm_no_vcpu->fd, sev_es_vm->fd); + ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, "SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d\n", ret, errno); - ret = __sev_migrate_from(vm_no_vcpu->fd, sev_es_vm_no_vmsa->fd); + ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm_no_vmsa); TEST_ASSERT( ret == -1 && errno == EINVAL, "SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d\n", @@ -221,22 +221,22 @@ out: kvm_vm_free(vm_no_sev); } -static int __sev_mirror_create(int dst_fd, int src_fd) +static int __sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src) { struct kvm_enable_cap cap = { .cap = KVM_CAP_VM_COPY_ENC_CONTEXT_FROM, - .args = { src_fd } + .args = { src->fd } }; - return ioctl(dst_fd, KVM_ENABLE_CAP, &cap); + return __vm_enable_cap(dst, &cap); } -static void sev_mirror_create(int dst_fd, int src_fd) +static void sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src) { int ret; - ret = __sev_mirror_create(dst_fd, src_fd); + ret = __sev_mirror_create(dst, src); TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d\n", ret, errno); } @@ -284,7 +284,7 @@ static void test_sev_mirror(bool es) src_vm = sev_vm_create(es); dst_vm = aux_vm_create(false); - sev_mirror_create(dst_vm->fd, src_vm->fd); + sev_mirror_create(dst_vm, src_vm); /* Check that we can complete creation of the mirror VM. */ for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i) @@ -308,18 +308,18 @@ static void test_sev_mirror_parameters(void) vm_with_vcpu = aux_vm_create(true); vm_no_vcpu = aux_vm_create(false); - ret = __sev_mirror_create(sev_vm->fd, sev_vm->fd); + ret = __sev_mirror_create(sev_vm, sev_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, "Should not be able copy context to self. ret: %d, errno: %d\n", ret, errno); - ret = __sev_mirror_create(vm_no_vcpu->fd, vm_with_vcpu->fd); + ret = __sev_mirror_create(vm_no_vcpu, vm_with_vcpu); TEST_ASSERT(ret == -1 && errno == EINVAL, "Copy context requires SEV enabled. ret %d, errno: %d\n", ret, errno); - ret = __sev_mirror_create(vm_with_vcpu->fd, sev_vm->fd); + ret = __sev_mirror_create(vm_with_vcpu, sev_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, "SEV copy context requires no vCPUS on the destination. ret: %d, errno: %d\n", @@ -329,13 +329,13 @@ static void test_sev_mirror_parameters(void) goto out; sev_es_vm = sev_vm_create(/* es= */ true); - ret = __sev_mirror_create(sev_vm->fd, sev_es_vm->fd); + ret = __sev_mirror_create(sev_vm, sev_es_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, "Should not be able copy context to SEV enabled VM. ret: %d, errno: %d\n", ret, errno); - ret = __sev_mirror_create(sev_es_vm->fd, sev_vm->fd); + ret = __sev_mirror_create(sev_es_vm, sev_vm); TEST_ASSERT( ret == -1 && errno == EINVAL, "Should not be able copy context to SEV-ES enabled VM. ret: %d, errno: %d\n", @@ -363,16 +363,16 @@ static void test_sev_move_copy(void) dst2_mirror_vm = aux_vm_create(false); dst3_mirror_vm = aux_vm_create(false); - sev_mirror_create(mirror_vm->fd, sev_vm->fd); + sev_mirror_create(mirror_vm, sev_vm); - sev_migrate_from(dst_mirror_vm->fd, mirror_vm->fd); - sev_migrate_from(dst_vm->fd, sev_vm->fd); + sev_migrate_from(dst_mirror_vm, mirror_vm); + sev_migrate_from(dst_vm, sev_vm); - sev_migrate_from(dst2_vm->fd, dst_vm->fd); - sev_migrate_from(dst2_mirror_vm->fd, dst_mirror_vm->fd); + sev_migrate_from(dst2_vm, dst_vm); + sev_migrate_from(dst2_mirror_vm, dst_mirror_vm); - sev_migrate_from(dst3_mirror_vm->fd, dst2_mirror_vm->fd); - sev_migrate_from(dst3_vm->fd, dst2_vm->fd); + sev_migrate_from(dst3_mirror_vm, dst2_mirror_vm); + sev_migrate_from(dst3_vm, dst2_vm); kvm_vm_free(dst_vm); kvm_vm_free(sev_vm); @@ -392,10 +392,10 @@ static void test_sev_move_copy(void) mirror_vm = aux_vm_create(false); dst_mirror_vm = aux_vm_create(false); - sev_mirror_create(mirror_vm->fd, sev_vm->fd); + sev_mirror_create(mirror_vm, sev_vm); - sev_migrate_from(dst_mirror_vm->fd, mirror_vm->fd); - sev_migrate_from(dst_vm->fd, sev_vm->fd); + sev_migrate_from(dst_mirror_vm, mirror_vm); + sev_migrate_from(dst_vm, sev_vm); kvm_vm_free(mirror_vm); kvm_vm_free(dst_mirror_vm); From a12c86c447f4bce6d2725c3fab426aba6630b376 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 2 Jun 2022 13:19:09 -0700 Subject: [PATCH 0338/1436] KVM: selftests: Simplify KVM_ENABLE_CAP helper APIs Rework the KVM_ENABLE_CAP helpers to take the cap and arg0; literally every current user, and likely every future user, wants to set 0 or 1 arguments and nothing else. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/psci_test.c | 11 +------ .../selftests/kvm/dirty_log_perf_test.c | 9 ++---- tools/testing/selftests/kvm/dirty_log_test.c | 5 +-- .../selftests/kvm/include/kvm_util_base.h | 18 +++++++---- tools/testing/selftests/kvm/lib/kvm_util.c | 6 +--- tools/testing/selftests/kvm/lib/x86_64/vmx.c | 8 ++--- .../kvm/x86_64/emulator_error_test.c | 6 +--- .../selftests/kvm/x86_64/fix_hypercall_test.c | 6 ++-- .../selftests/kvm/x86_64/hyperv_features.c | 16 ++-------- .../selftests/kvm/x86_64/kvm_pv_test.c | 5 +-- .../kvm/x86_64/max_vcpuid_cap_test.c | 12 ++----- .../selftests/kvm/x86_64/platform_info_test.c | 14 ++------- .../kvm/x86_64/pmu_event_filter_test.c | 5 +-- .../selftests/kvm/x86_64/sev_migrate_tests.c | 14 ++------- .../kvm/x86_64/triple_fault_event_test.c | 7 +---- .../kvm/x86_64/userspace_msr_exit_test.c | 31 +++++++------------ 16 files changed, 47 insertions(+), 126 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index 024a84064f1f..1a351f3f443d 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -156,15 +156,6 @@ static void host_test_cpu_on(void) kvm_vm_free(vm); } -static void enable_system_suspend(struct kvm_vm *vm) -{ - struct kvm_enable_cap cap = { - .cap = KVM_CAP_ARM_SYSTEM_SUSPEND, - }; - - vm_enable_cap(vm, &cap); -} - static void guest_test_system_suspend(void) { uint64_t ret; @@ -183,7 +174,7 @@ static void host_test_system_suspend(void) struct kvm_vm *vm; vm = setup_vm(guest_test_system_suspend); - enable_system_suspend(vm); + vm_enable_cap(vm, KVM_CAP_ARM_SYSTEM_SUSPEND, 0); vcpu_power_off(vm, VCPU_ID_TARGET); run = vcpu_state(vm, VCPU_ID_SOURCE); diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c index d60a34cdfaee..8aaa0949707a 100644 --- a/tools/testing/selftests/kvm/dirty_log_perf_test.c +++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c @@ -213,7 +213,6 @@ static void run_test(enum vm_guest_mode mode, void *arg) struct timespec get_dirty_log_total = (struct timespec){0}; struct timespec vcpu_dirty_total = (struct timespec){0}; struct timespec avg; - struct kvm_enable_cap cap = {}; struct timespec clear_dirty_log_total = (struct timespec){0}; vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size, @@ -229,11 +228,9 @@ static void run_test(enum vm_guest_mode mode, void *arg) bitmaps = alloc_bitmaps(p->slots, pages_per_slot); - if (dirty_log_manual_caps) { - cap.cap = KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2; - cap.args[0] = dirty_log_manual_caps; - vm_enable_cap(vm, &cap); - } + if (dirty_log_manual_caps) + vm_enable_cap(vm, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, + dirty_log_manual_caps); arch_setup_vm(vm, nr_vcpus); diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 5752486764c9..9dfc861a3cf3 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -217,16 +217,13 @@ static bool clear_log_supported(void) static void clear_log_create_vm_done(struct kvm_vm *vm) { - struct kvm_enable_cap cap = {}; u64 manual_caps; manual_caps = kvm_check_cap(KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2); TEST_ASSERT(manual_caps, "MANUAL_CAPS is zero!"); manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | KVM_DIRTY_LOG_INITIALLY_SET); - cap.cap = KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2; - cap.args[0] = manual_caps; - vm_enable_cap(vm, &cap); + vm_enable_cap(vm, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, manual_caps); } static void dirty_log_collect_dirty_pages(struct kvm_vm *vm, int slot, diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index f0afc1dce8ba..c9d94c9f2031 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -231,13 +231,17 @@ static inline int vm_check_cap(struct kvm_vm *vm, long cap) return ret; } -static inline int __vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) +static inline int __vm_enable_cap(struct kvm_vm *vm, uint32_t cap, uint64_t arg0) { - return __vm_ioctl(vm, KVM_ENABLE_CAP, cap); + struct kvm_enable_cap enable_cap = { .cap = cap, .args = { arg0 } }; + + return __vm_ioctl(vm, KVM_ENABLE_CAP, &enable_cap); } -static inline void vm_enable_cap(struct kvm_vm *vm, struct kvm_enable_cap *cap) +static inline void vm_enable_cap(struct kvm_vm *vm, uint32_t cap, uint64_t arg0) { - vm_ioctl(vm, KVM_ENABLE_CAP, cap); + struct kvm_enable_cap enable_cap = { .cap = cap, .args = { arg0 } }; + + vm_ioctl(vm, KVM_ENABLE_CAP, &enable_cap); } void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size); @@ -363,9 +367,11 @@ void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid); struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid); static inline void vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, - struct kvm_enable_cap *cap) + uint32_t cap, uint64_t arg0) { - vcpu_ioctl(vm, vcpu_id, KVM_ENABLE_CAP, cap); + struct kvm_enable_cap enable_cap = { .cap = cap, .args = { arg0 } }; + + vcpu_ioctl(vm, vcpu_id, KVM_ENABLE_CAP, &enable_cap); } static inline void vcpu_set_guest_debug(struct kvm_vm *vm, uint32_t vcpuid, diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 2d82b5720737..8f670cef6faa 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -85,11 +85,7 @@ int kvm_check_cap(long cap) void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size) { - struct kvm_enable_cap cap = { 0 }; - - cap.cap = KVM_CAP_DIRTY_LOG_RING; - cap.args[0] = ring_size; - vm_enable_cap(vm, &cap); + vm_enable_cap(vm, KVM_CAP_DIRTY_LOG_RING, ring_size); vm->dirty_ring_size = ring_size; } diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c index dbfca8ed79aa..a12c0e1224af 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c @@ -46,12 +46,8 @@ int vcpu_enable_evmcs(struct kvm_vm *vm, int vcpu_id) { uint16_t evmcs_ver; - struct kvm_enable_cap enable_evmcs_cap = { - .cap = KVM_CAP_HYPERV_ENLIGHTENED_VMCS, - .args[0] = (unsigned long)&evmcs_ver - }; - - vcpu_enable_cap(vm, vcpu_id, &enable_evmcs_cap); + vcpu_enable_cap(vm, vcpu_id, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, + (unsigned long)&evmcs_ver); /* KVM should return supported EVMCS version range */ TEST_ASSERT(((evmcs_ver >> 8) >= (evmcs_ver & 0xff)) && diff --git a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c index aeb3850f81bd..9c156f9cfa15 100644 --- a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c +++ b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c @@ -161,10 +161,6 @@ static uint64_t process_ucall(struct kvm_vm *vm) int main(int argc, char *argv[]) { - struct kvm_enable_cap emul_failure_cap = { - .cap = KVM_CAP_EXIT_ON_EMULATION_FAILURE, - .args[0] = 1, - }; struct kvm_cpuid_entry2 *entry; struct kvm_cpuid2 *cpuid; struct kvm_vm *vm; @@ -192,7 +188,7 @@ int main(int argc, char *argv[]) rc = kvm_check_cap(KVM_CAP_EXIT_ON_EMULATION_FAILURE); TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable"); - vm_enable_cap(vm, &emul_failure_cap); + vm_enable_cap(vm, KVM_CAP_EXIT_ON_EMULATION_FAILURE, 1); vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, MEM_REGION_GPA, MEM_REGION_SLOT, diff --git a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c index 1f5c32146f3d..81f9f5b1f655 100644 --- a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c @@ -140,15 +140,13 @@ static void test_fix_hypercall(void) static void test_fix_hypercall_disabled(void) { - struct kvm_enable_cap cap = {0}; struct kvm_vm *vm; vm = vm_create_default(VCPU_ID, 0, guest_main); setup_ud_vector(vm); - cap.cap = KVM_CAP_DISABLE_QUIRKS2; - cap.args[0] = KVM_X86_QUIRK_FIX_HYPERCALL_INSN; - vm_enable_cap(vm, &cap); + vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, + KVM_X86_QUIRK_FIX_HYPERCALL_INSN); ud_expected = true; sync_global_to_guest(vm, ud_expected); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index 672915ce73d8..7ff6e4d70333 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -182,10 +182,6 @@ static void guest_test_msrs_access(void) }; struct kvm_cpuid2 *best; vm_vaddr_t msr_gva; - struct kvm_enable_cap cap = { - .cap = KVM_CAP_HYPERV_ENFORCE_CPUID, - .args = {1} - }; struct msr_data *msr; while (true) { @@ -196,7 +192,7 @@ static void guest_test_msrs_access(void) msr = addr_gva2hva(vm, msr_gva); vcpu_args_set(vm, VCPU_ID, 1, msr_gva); - vcpu_enable_cap(vm, VCPU_ID, &cap); + vcpu_enable_cap(vm, VCPU_ID, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); vcpu_set_hv_cpuid(vm, VCPU_ID); @@ -337,9 +333,7 @@ static void guest_test_msrs_access(void) * Remains unavailable even with KVM_CAP_HYPERV_SYNIC2 * capability enabled and guest visible CPUID bit unset. */ - cap.cap = KVM_CAP_HYPERV_SYNIC2; - cap.args[0] = 0; - vcpu_enable_cap(vm, VCPU_ID, &cap); + vcpu_enable_cap(vm, VCPU_ID, KVM_CAP_HYPERV_SYNIC2, 0); break; case 22: feat.eax |= HV_MSR_SYNIC_AVAILABLE; @@ -518,10 +512,6 @@ static void guest_test_hcalls_access(void) struct kvm_cpuid_entry2 dbg = { .function = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES }; - struct kvm_enable_cap cap = { - .cap = KVM_CAP_HYPERV_ENFORCE_CPUID, - .args = {1} - }; vm_vaddr_t hcall_page, hcall_params; struct hcall_data *hcall; struct kvm_cpuid2 *best; @@ -542,7 +532,7 @@ static void guest_test_hcalls_access(void) memset(addr_gva2hva(vm, hcall_params), 0x0, getpagesize()); vcpu_args_set(vm, VCPU_ID, 2, addr_gva2gpa(vm, hcall_page), hcall_params); - vcpu_enable_cap(vm, VCPU_ID, &cap); + vcpu_enable_cap(vm, VCPU_ID, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); vcpu_set_hv_cpuid(vm, VCPU_ID); diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index 04ed975662c9..5eea3ac7958e 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -206,7 +206,6 @@ static void enter_guest(struct kvm_vm *vm) int main(void) { - struct kvm_enable_cap cap = {0}; struct kvm_cpuid2 *best; struct kvm_vm *vm; @@ -217,9 +216,7 @@ int main(void) vm = vm_create_default(VCPU_ID, 0, guest_main); - cap.cap = KVM_CAP_ENFORCE_PV_FEATURE_CPUID; - cap.args[0] = 1; - vcpu_enable_cap(vm, VCPU_ID, &cap); + vcpu_enable_cap(vm, VCPU_ID, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 1); best = kvm_get_supported_cpuid(); clear_kvm_cpuid_features(best); diff --git a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c index c6fd36a31c8c..7211fd8d5d24 100644 --- a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c +++ b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c @@ -14,7 +14,6 @@ int main(int argc, char *argv[]) { struct kvm_vm *vm; - struct kvm_enable_cap cap = { 0 }; int ret; vm = vm_create(0); @@ -23,21 +22,16 @@ int main(int argc, char *argv[]) ret = vm_check_cap(vm, KVM_CAP_MAX_VCPU_ID); /* Try to set KVM_CAP_MAX_VCPU_ID beyond KVM cap */ - cap.cap = KVM_CAP_MAX_VCPU_ID; - cap.args[0] = ret + 1; - ret = __vm_enable_cap(vm, &cap); + ret = __vm_enable_cap(vm, KVM_CAP_MAX_VCPU_ID, ret + 1); TEST_ASSERT(ret < 0, "Setting KVM_CAP_MAX_VCPU_ID beyond KVM cap should fail"); /* Set KVM_CAP_MAX_VCPU_ID */ - cap.cap = KVM_CAP_MAX_VCPU_ID; - cap.args[0] = MAX_VCPU_ID; - vm_enable_cap(vm, &cap); + vm_enable_cap(vm, KVM_CAP_MAX_VCPU_ID, MAX_VCPU_ID); /* Try to set KVM_CAP_MAX_VCPU_ID again */ - cap.args[0] = MAX_VCPU_ID + 1; - ret = __vm_enable_cap(vm, &cap); + ret = __vm_enable_cap(vm, KVM_CAP_MAX_VCPU_ID, MAX_VCPU_ID + 1); TEST_ASSERT(ret < 0, "Setting KVM_CAP_MAX_VCPU_ID multiple times should fail"); diff --git a/tools/testing/selftests/kvm/x86_64/platform_info_test.c b/tools/testing/selftests/kvm/x86_64/platform_info_test.c index 1e89688cbbbf..e79c04581ca8 100644 --- a/tools/testing/selftests/kvm/x86_64/platform_info_test.c +++ b/tools/testing/selftests/kvm/x86_64/platform_info_test.c @@ -35,22 +35,12 @@ static void guest_code(void) } } -static void set_msr_platform_info_enabled(struct kvm_vm *vm, bool enable) -{ - struct kvm_enable_cap cap = {}; - - cap.cap = KVM_CAP_MSR_PLATFORM_INFO; - cap.flags = 0; - cap.args[0] = (int)enable; - vm_enable_cap(vm, &cap); -} - static void test_msr_platform_info_enabled(struct kvm_vm *vm) { struct kvm_run *run = vcpu_state(vm, VCPU_ID); struct ucall uc; - set_msr_platform_info_enabled(vm, true); + vm_enable_cap(vm, KVM_CAP_MSR_PLATFORM_INFO, true); vcpu_run(vm, VCPU_ID); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Exit_reason other than KVM_EXIT_IO: %u (%s),\n", @@ -69,7 +59,7 @@ static void test_msr_platform_info_disabled(struct kvm_vm *vm) { struct kvm_run *run = vcpu_state(vm, VCPU_ID); - set_msr_platform_info_enabled(vm, false); + vm_enable_cap(vm, KVM_CAP_MSR_PLATFORM_INFO, false); vcpu_run(vm, VCPU_ID); TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN, "Exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s)\n", diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 84cd5e717fcf..9ec6ba2ad89b 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -360,7 +360,6 @@ static void test_pmu_config_disable(void (*guest_code)(void)) { int r; struct kvm_vm *vm; - struct kvm_enable_cap cap = { 0 }; r = kvm_check_cap(KVM_CAP_PMU_CAPABILITY); if (!(r & KVM_PMU_CAP_DISABLE)) @@ -368,9 +367,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) vm = vm_create_without_vcpus(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); - cap.cap = KVM_CAP_PMU_CAPABILITY; - cap.args[0] = KVM_PMU_CAP_DISABLE; - vm_enable_cap(vm, &cap); + vm_enable_cap(vm, KVM_CAP_PMU_CAPABILITY, KVM_PMU_CAP_DISABLE); vm_vcpu_add_default(vm, VCPU_ID, guest_code); vm_init_descriptor_tables(vm); diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index f127f2fccca6..e814748bf7ba 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -82,12 +82,7 @@ static struct kvm_vm *aux_vm_create(bool with_vcpus) static int __sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src) { - struct kvm_enable_cap cap = { - .cap = KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM, - .args = { src->fd } - }; - - return __vm_enable_cap(dst, &cap); + return __vm_enable_cap(dst, KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM, src->fd); } @@ -223,12 +218,7 @@ out: static int __sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src) { - struct kvm_enable_cap cap = { - .cap = KVM_CAP_VM_COPY_ENC_CONTEXT_FROM, - .args = { src->fd } - }; - - return __vm_enable_cap(dst, &cap); + return __vm_enable_cap(dst, KVM_CAP_VM_COPY_ENC_CONTEXT_FROM, src->fd); } diff --git a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c index 66378140764d..68e0f1c5ec5a 100644 --- a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c +++ b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c @@ -46,11 +46,6 @@ int main(void) vm_vaddr_t vmx_pages_gva; struct ucall uc; - struct kvm_enable_cap cap = { - .cap = KVM_CAP_X86_TRIPLE_FAULT_EVENT, - .args = {1} - }; - if (!nested_vmx_supported()) { print_skip("Nested VMX not supported"); exit(KSFT_SKIP); @@ -62,7 +57,7 @@ int main(void) } vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); - vm_enable_cap(vm, &cap); + vm_enable_cap(vm, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 1); run = vcpu_state(vm, VCPU_ID); vcpu_alloc_vmx(vm, &vmx_pages_gva); diff --git a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c index e3e20e8848d0..23e9292580c9 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c @@ -550,11 +550,8 @@ static void run_guest_then_process_ucall_done(struct kvm_vm *vm) process_ucall_done(vm); } -static void test_msr_filter_allow(void) { - struct kvm_enable_cap cap = { - .cap = KVM_CAP_X86_USER_SPACE_MSR, - .args[0] = KVM_MSR_EXIT_REASON_FILTER, - }; +static void test_msr_filter_allow(void) +{ struct kvm_vm *vm; int rc; @@ -564,7 +561,7 @@ static void test_msr_filter_allow(void) { rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available"); - vm_enable_cap(vm, &cap); + vm_enable_cap(vm, KVM_CAP_X86_USER_SPACE_MSR, KVM_MSR_EXIT_REASON_FILTER); rc = kvm_check_cap(KVM_CAP_X86_MSR_FILTER); TEST_ASSERT(rc, "KVM_CAP_X86_MSR_FILTER is available"); @@ -673,13 +670,8 @@ static void handle_wrmsr(struct kvm_run *run) } } -static void test_msr_filter_deny(void) { - struct kvm_enable_cap cap = { - .cap = KVM_CAP_X86_USER_SPACE_MSR, - .args[0] = KVM_MSR_EXIT_REASON_INVAL | - KVM_MSR_EXIT_REASON_UNKNOWN | - KVM_MSR_EXIT_REASON_FILTER, - }; +static void test_msr_filter_deny(void) +{ struct kvm_vm *vm; struct kvm_run *run; int rc; @@ -691,7 +683,9 @@ static void test_msr_filter_deny(void) { rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available"); - vm_enable_cap(vm, &cap); + vm_enable_cap(vm, KVM_CAP_X86_USER_SPACE_MSR, KVM_MSR_EXIT_REASON_INVAL | + KVM_MSR_EXIT_REASON_UNKNOWN | + KVM_MSR_EXIT_REASON_FILTER); rc = kvm_check_cap(KVM_CAP_X86_MSR_FILTER); TEST_ASSERT(rc, "KVM_CAP_X86_MSR_FILTER is available"); @@ -726,11 +720,8 @@ done: kvm_vm_free(vm); } -static void test_msr_permission_bitmap(void) { - struct kvm_enable_cap cap = { - .cap = KVM_CAP_X86_USER_SPACE_MSR, - .args[0] = KVM_MSR_EXIT_REASON_FILTER, - }; +static void test_msr_permission_bitmap(void) +{ struct kvm_vm *vm; int rc; @@ -740,7 +731,7 @@ static void test_msr_permission_bitmap(void) { rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available"); - vm_enable_cap(vm, &cap); + vm_enable_cap(vm, KVM_CAP_X86_USER_SPACE_MSR, KVM_MSR_EXIT_REASON_FILTER); rc = kvm_check_cap(KVM_CAP_X86_MSR_FILTER); TEST_ASSERT(rc, "KVM_CAP_X86_MSR_FILTER is available"); From c095cb609b3aa56fd24e2907556c24fef88b9180 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 2 Jun 2022 14:12:14 -0700 Subject: [PATCH 0339/1436] KVM: selftests: Cache list of MSRs to save/restore Cache the list of MSRs to save restore, mostly to justify not freeing the list in the caller, which simplifies consumption of the list. Opportunistically move the XSS test's so called is_supported_msr() to common code as kvm_msr_is_in_save_restore_list(). The XSS is "supported" by KVM, it's simply not in the save/restore list because KVM doesn't yet allow a non-zero value. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/x86_64/processor.h | 4 +- .../selftests/kvm/lib/x86_64/processor.c | 83 +++++++++---------- .../selftests/kvm/x86_64/xss_msr_test.c | 27 ++---- 3 files changed, 46 insertions(+), 68 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 583754bf18c3..b8023c30bded 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -427,8 +427,10 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *state); void kvm_x86_state_cleanup(struct kvm_x86_state *state); -struct kvm_msr_list *kvm_get_msr_index_list(void); +const struct kvm_msr_list *kvm_get_msr_index_list(void); +bool kvm_msr_is_in_save_restore_list(uint32_t msr_index); uint64_t kvm_get_feature_msr(uint64_t msr_index); + struct kvm_cpuid2 *kvm_get_supported_cpuid(void); struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 02266b8123df..3f83857009a3 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -719,18 +719,6 @@ struct kvm_cpuid2 *kvm_get_supported_cpuid(void) return cpuid; } -/* - * KVM Get MSR - * - * Input Args: - * msr_index - Index of MSR - * - * Output Args: None - * - * Return: On success, value of the MSR. On failure a TEST_ASSERT is produced. - * - * Get value of MSR for VCPU. - */ uint64_t kvm_get_feature_msr(uint64_t msr_index) { struct { @@ -903,40 +891,49 @@ void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) sregs_dump(stream, &sregs, indent + 4); } -static int kvm_get_num_msrs_fd(int kvm_fd) +const struct kvm_msr_list *kvm_get_msr_index_list(void) { + static struct kvm_msr_list *list; struct kvm_msr_list nmsrs; - int r; + int kvm_fd, r; + + if (list) + return list; + + kvm_fd = open_kvm_dev_path_or_exit(); nmsrs.nmsrs = 0; r = __kvm_ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, &nmsrs); TEST_ASSERT(r == -1 && errno == E2BIG, - "Unexpected result from KVM_GET_MSR_INDEX_LIST probe, r: %i", r); + "Expected -E2BIG, got rc: %i errno: %i (%s)", + r, errno, strerror(errno)); - return nmsrs.nmsrs; -} + list = malloc(sizeof(*list) + nmsrs.nmsrs * sizeof(list->indices[0])); + TEST_ASSERT(list, "-ENOMEM when allocating MSR index list"); + list->nmsrs = nmsrs.nmsrs; -static int kvm_get_num_msrs(struct kvm_vm *vm) -{ - return kvm_get_num_msrs_fd(vm->kvm_fd); -} - -struct kvm_msr_list *kvm_get_msr_index_list(void) -{ - struct kvm_msr_list *list; - int nmsrs, kvm_fd; - - kvm_fd = open_kvm_dev_path_or_exit(); - - nmsrs = kvm_get_num_msrs_fd(kvm_fd); - list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0])); - list->nmsrs = nmsrs; kvm_ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list); close(kvm_fd); + TEST_ASSERT(list->nmsrs == nmsrs.nmsrs, + "Number of save/restore MSRs changed, was %d, now %d", + nmsrs.nmsrs, list->nmsrs); return list; } +bool kvm_msr_is_in_save_restore_list(uint32_t msr_index) +{ + const struct kvm_msr_list *list = kvm_get_msr_index_list(); + int i; + + for (i = 0; i < list->nmsrs; ++i) { + if (list->indices[i] == msr_index) + return true; + } + + return false; +} + static int vcpu_save_xsave_state(struct kvm_vm *vm, struct vcpu *vcpu, struct kvm_x86_state *state) { @@ -955,10 +952,10 @@ static int vcpu_save_xsave_state(struct kvm_vm *vm, struct vcpu *vcpu, struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) { + const struct kvm_msr_list *msr_list = kvm_get_msr_index_list(); struct vcpu *vcpu = vcpu_get(vm, vcpuid); - struct kvm_msr_list *list; struct kvm_x86_state *state; - int nmsrs, r, i; + int r, i; static int nested_size = -1; if (nested_size == -1) { @@ -976,12 +973,7 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) */ vcpu_run_complete_io(vm, vcpuid); - nmsrs = kvm_get_num_msrs(vm); - list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0])); - list->nmsrs = nmsrs; - kvm_ioctl(vm->kvm_fd, KVM_GET_MSR_INDEX_LIST, list); - - state = malloc(sizeof(*state) + nmsrs * sizeof(state->msrs.entries[0])); + state = malloc(sizeof(*state) + msr_list->nmsrs * sizeof(state->msrs.entries[0])); r = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, &state->events); TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_VCPU_EVENTS, r: %i", r); @@ -1019,18 +1011,17 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) } else state->nested.size = 0; - state->msrs.nmsrs = nmsrs; - for (i = 0; i < nmsrs; i++) - state->msrs.entries[i].index = list->indices[i]; + state->msrs.nmsrs = msr_list->nmsrs; + for (i = 0; i < msr_list->nmsrs; i++) + state->msrs.entries[i].index = msr_list->indices[i]; r = ioctl(vcpu->fd, KVM_GET_MSRS, &state->msrs); - TEST_ASSERT(r == nmsrs, "Unexpected result from KVM_GET_MSRS, r: %i (failed MSR was 0x%x)", - r, r == nmsrs ? -1 : list->indices[r]); + TEST_ASSERT(r == msr_list->nmsrs, "Unexpected result from KVM_GET_MSRS, r: %i (failed MSR was 0x%x)", + r, r == msr_list->nmsrs ? -1 : msr_list->indices[r]); r = ioctl(vcpu->fd, KVM_GET_DEBUGREGS, &state->debugregs); TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_DEBUGREGS, r: %i", r); - free(list); return state; } diff --git a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c index 3529376747c2..7bd15f8a805c 100644 --- a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c +++ b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c @@ -17,28 +17,11 @@ #define X86_FEATURE_XSAVES (1<<3) -bool is_supported_msr(u32 msr_index) -{ - struct kvm_msr_list *list; - bool found = false; - int i; - - list = kvm_get_msr_index_list(); - for (i = 0; i < list->nmsrs; ++i) { - if (list->indices[i] == msr_index) { - found = true; - break; - } - } - - free(list); - return found; -} - int main(int argc, char *argv[]) { struct kvm_cpuid_entry2 *entry; bool xss_supported = false; + bool xss_in_msr_list; struct kvm_vm *vm; uint64_t xss_val; int i, r; @@ -64,12 +47,14 @@ int main(int argc, char *argv[]) * At present, KVM only supports a guest IA32_XSS value of 0. Verify * that trying to set the guest IA32_XSS to an unsupported value fails. * Also, in the future when a non-zero value succeeds check that - * IA32_XSS is in the KVM_GET_MSR_INDEX_LIST. + * IA32_XSS is in the list of MSRs to save/restore. */ + xss_in_msr_list = kvm_msr_is_in_save_restore_list(MSR_IA32_XSS); for (i = 0; i < MSR_BITS; ++i) { r = _vcpu_set_msr(vm, VCPU_ID, MSR_IA32_XSS, 1ull << i); - TEST_ASSERT(r == 0 || is_supported_msr(MSR_IA32_XSS), - "IA32_XSS was able to be set, but was not found in KVM_GET_MSR_INDEX_LIST.\n"); + + TEST_ASSERT(r == 0 || xss_in_msr_list, + "IA32_XSS was able to be set, but was not in save/restore list"); } kvm_vm_free(vm); From 0ce74180f306981534d023199017a90b77a92004 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 2 Jun 2022 14:12:22 -0700 Subject: [PATCH 0340/1436] KVM: selftests: Harden and comment XSS / KVM_SET_MSRS interaction Assert that KVM_SET_MSRS returns '0' or '1' when setting XSS to a non-zero value. The ioctl() itself should "succeed", its only the setting of the XSS MSR that should fail/fault. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/x86_64/xss_msr_test.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c index 7bd15f8a805c..a6abcb559e7c 100644 --- a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c +++ b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c @@ -53,7 +53,12 @@ int main(int argc, char *argv[]) for (i = 0; i < MSR_BITS; ++i) { r = _vcpu_set_msr(vm, VCPU_ID, MSR_IA32_XSS, 1ull << i); - TEST_ASSERT(r == 0 || xss_in_msr_list, + /* + * Setting a list of MSRs returns the entry that "faulted", or + * the last entry +1 if all MSRs were successfully written. + */ + TEST_ASSERT(!r || r == 1, KVM_IOCTL_ERROR(KVM_SET_MSRS, r)); + TEST_ASSERT(r != 1 || xss_in_msr_list, "IA32_XSS was able to be set, but was not in save/restore list"); } From 2128e30b01867a4d5e41bbaba8e35bcca7537f3b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 2 Jun 2022 12:24:18 -0700 Subject: [PATCH 0341/1436] KVM: selftests: Dedup MSR index list helpers, simplify dedicated test Consolidate the helper for retrieving the list of save/restore MSRs and the list of feature MSRs, and use the common helpers in the related get_msr_index_features test. Switching to the common helpers eliminates the testcase that KVM returns the same -E2BIG result if the input number of MSRs is '1' versus '0', but considered that testcase isn't very interesting, e.g. '0' and '1' are equally arbitrary, and certainly not worth the additional code. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/x86_64/processor.h | 1 + .../selftests/kvm/lib/x86_64/processor.c | 39 ++++-- .../kvm/x86_64/get_msr_index_features.c | 118 +++--------------- 3 files changed, 49 insertions(+), 109 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index b8023c30bded..9145da0bc61e 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -428,6 +428,7 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, void kvm_x86_state_cleanup(struct kvm_x86_state *state); const struct kvm_msr_list *kvm_get_msr_index_list(void); +const struct kvm_msr_list *kvm_get_feature_msr_index_list(void); bool kvm_msr_is_in_save_restore_list(uint32_t msr_index); uint64_t kvm_get_feature_msr(uint64_t msr_index); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 3f83857009a3..18fce5e8a5e5 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -891,19 +891,20 @@ void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) sregs_dump(stream, &sregs, indent + 4); } -const struct kvm_msr_list *kvm_get_msr_index_list(void) +static struct kvm_msr_list *__kvm_get_msr_index_list(bool feature_msrs) { - static struct kvm_msr_list *list; + struct kvm_msr_list *list; struct kvm_msr_list nmsrs; int kvm_fd, r; - if (list) - return list; - kvm_fd = open_kvm_dev_path_or_exit(); nmsrs.nmsrs = 0; - r = __kvm_ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, &nmsrs); + if (!feature_msrs) + r = __kvm_ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, &nmsrs); + else + r = __kvm_ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, &nmsrs); + TEST_ASSERT(r == -1 && errno == E2BIG, "Expected -E2BIG, got rc: %i errno: %i (%s)", r, errno, strerror(errno)); @@ -912,15 +913,37 @@ const struct kvm_msr_list *kvm_get_msr_index_list(void) TEST_ASSERT(list, "-ENOMEM when allocating MSR index list"); list->nmsrs = nmsrs.nmsrs; - kvm_ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list); + if (!feature_msrs) + kvm_ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list); + else + kvm_ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list); close(kvm_fd); TEST_ASSERT(list->nmsrs == nmsrs.nmsrs, - "Number of save/restore MSRs changed, was %d, now %d", + "Number of MSRs in list changed, was %d, now %d", nmsrs.nmsrs, list->nmsrs); return list; } +const struct kvm_msr_list *kvm_get_msr_index_list(void) +{ + static const struct kvm_msr_list *list; + + if (!list) + list = __kvm_get_msr_index_list(false); + return list; +} + + +const struct kvm_msr_list *kvm_get_feature_msr_index_list(void) +{ + static const struct kvm_msr_list *list; + + if (!list) + list = __kvm_get_msr_index_list(true); + return list; +} + bool kvm_msr_is_in_save_restore_list(uint32_t msr_index) { const struct kvm_msr_list *list = kvm_get_msr_index_list(); diff --git a/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c b/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c index 4ef60adbe108..1e366fdfe7be 100644 --- a/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c +++ b/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c @@ -15,108 +15,24 @@ #include "kvm_util.h" #include "processor.h" -static int kvm_num_index_msrs(int kvm_fd, int nmsrs) -{ - struct kvm_msr_list *list; - int r; - - list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0])); - list->nmsrs = nmsrs; - r = ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list); - TEST_ASSERT(r == -1 && errno == E2BIG, - "Unexpected result from KVM_GET_MSR_INDEX_LIST probe, r: %i", - r); - - r = list->nmsrs; - free(list); - return r; -} - -static void test_get_msr_index(void) -{ - int old_res, res, kvm_fd; - struct kvm_msr_list *list; - - kvm_fd = open_kvm_dev_path_or_exit(); - - old_res = kvm_num_index_msrs(kvm_fd, 0); - TEST_ASSERT(old_res != 0, "Expecting nmsrs to be > 0"); - - if (old_res != 1) { - res = kvm_num_index_msrs(kvm_fd, 1); - TEST_ASSERT(res > 1, "Expecting nmsrs to be > 1"); - TEST_ASSERT(res == old_res, "Expecting nmsrs to be identical"); - } - - list = malloc(sizeof(*list) + old_res * sizeof(list->indices[0])); - list->nmsrs = old_res; - kvm_ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list); - - TEST_ASSERT(list->nmsrs == old_res, "Expecting nmsrs to be identical"); - free(list); - - close(kvm_fd); -} - -static int kvm_num_feature_msrs(int kvm_fd, int nmsrs) -{ - struct kvm_msr_list *list; - int r; - - list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0])); - list->nmsrs = nmsrs; - r = __kvm_ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list); - TEST_ASSERT(r == -1 && errno == E2BIG, - "Unexpected result from KVM_GET_MSR_FEATURE_INDEX_LIST probe, r: %i", - r); - - r = list->nmsrs; - free(list); - return r; -} - -struct kvm_msr_list *kvm_get_msr_feature_list(int kvm_fd, int nmsrs) -{ - struct kvm_msr_list *list; - - list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0])); - list->nmsrs = nmsrs; - kvm_ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list); - - return list; -} - -static void test_get_msr_feature(void) -{ - int res, old_res, i, kvm_fd; - struct kvm_msr_list *feature_list; - - kvm_fd = open_kvm_dev_path_or_exit(); - - old_res = kvm_num_feature_msrs(kvm_fd, 0); - TEST_ASSERT(old_res != 0, "Expecting nmsrs to be > 0"); - - if (old_res != 1) { - res = kvm_num_feature_msrs(kvm_fd, 1); - TEST_ASSERT(res > 1, "Expecting nmsrs to be > 1"); - TEST_ASSERT(res == old_res, "Expecting nmsrs to be identical"); - } - - feature_list = kvm_get_msr_feature_list(kvm_fd, old_res); - TEST_ASSERT(old_res == feature_list->nmsrs, - "Unmatching number of msr indexes"); - - for (i = 0; i < feature_list->nmsrs; i++) - kvm_get_feature_msr(feature_list->indices[i]); - - free(feature_list); - close(kvm_fd); -} - int main(int argc, char *argv[]) { - if (kvm_check_cap(KVM_CAP_GET_MSR_FEATURES)) - test_get_msr_feature(); + const struct kvm_msr_list *feature_list; + int i; - test_get_msr_index(); + /* + * Skip the entire test if MSR_FEATURES isn't supported, other tests + * will cover the "regular" list of MSRs, the coverage here is purely + * opportunistic and not interesting on its own. + */ + if (!kvm_check_cap(KVM_CAP_GET_MSR_FEATURES)) { + print_skip("KVM_CAP_GET_MSR_FEATURES not supported"); + exit(KSFT_SKIP); + } + + (void)kvm_get_msr_index_list(); + + feature_list = kvm_get_feature_msr_index_list(); + for (i = 0; i < feature_list->nmsrs; i++) + kvm_get_feature_msr(feature_list->indices[i]); } From 877bd3997c508691b30054524353d574a3597cd9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 2 Jun 2022 10:25:56 -0700 Subject: [PATCH 0342/1436] KVM: selftests: Rename MP_STATE and GUEST_DEBUG helpers for consistency Move the get/set part of the MP_STATE and GUEST_DEBUG helpers to the end to align with the many other ioctl() wrappers/helpers. Note, this is not an endorsement of the predominant style, the goal is purely to provide consistency in the selftests. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/psci_test.c | 2 +- tools/testing/selftests/kvm/include/kvm_util_base.h | 9 +++++++-- tools/testing/selftests/kvm/lib/x86_64/processor.c | 2 +- tools/testing/selftests/kvm/x86_64/debug_regs.c | 2 +- .../selftests/kvm/x86_64/svm_nested_soft_inject_test.c | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index 1a351f3f443d..1485d0b05b66 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -70,7 +70,7 @@ static void vcpu_power_off(struct kvm_vm *vm, uint32_t vcpuid) .mp_state = KVM_MP_STATE_STOPPED, }; - vcpu_set_mp_state(vm, vcpuid, &mp_state); + vcpu_mp_state_set(vm, vcpuid, &mp_state); } static struct kvm_vm *setup_vm(void *guest_code) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index c9d94c9f2031..edbbbbe4cd5d 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -374,13 +374,18 @@ static inline void vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, vcpu_ioctl(vm, vcpu_id, KVM_ENABLE_CAP, &enable_cap); } -static inline void vcpu_set_guest_debug(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_guest_debug_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_guest_debug *debug) { vcpu_ioctl(vm, vcpuid, KVM_SET_GUEST_DEBUG, debug); } -static inline void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_mp_state_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_mp_state *mp_state) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_MP_STATE, mp_state); +} +static inline void vcpu_mp_state_set(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_mp_state *mp_state) { vcpu_ioctl(vm, vcpuid, KVM_SET_MP_STATE, mp_state); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 18fce5e8a5e5..8dfe40eeceac 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -654,7 +654,7 @@ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) /* Setup the MP state */ mp_state.mp_state = 0; - vcpu_set_mp_state(vm, vcpuid, &mp_state); + vcpu_mp_state_set(vm, vcpuid, &mp_state); } /* diff --git a/tools/testing/selftests/kvm/x86_64/debug_regs.c b/tools/testing/selftests/kvm/x86_64/debug_regs.c index 5f078db1bcba..f726645bb9c3 100644 --- a/tools/testing/selftests/kvm/x86_64/debug_regs.c +++ b/tools/testing/selftests/kvm/x86_64/debug_regs.c @@ -67,7 +67,7 @@ static void guest_code(void) } #define CLEAR_DEBUG() memset(&debug, 0, sizeof(debug)) -#define APPLY_DEBUG() vcpu_set_guest_debug(vm, VCPU_ID, &debug) +#define APPLY_DEBUG() vcpu_guest_debug_set(vm, VCPU_ID, &debug) #define CAST_TO_RIP(v) ((unsigned long long)&(v)) #define SET_RIP(v) do { \ vcpu_regs_get(vm, VCPU_ID, ®s); \ diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c index 18061677154f..f834b9a1a7fa 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -166,7 +166,7 @@ static void run_test(bool is_nmi) vcpu_args_set(vm, VCPU_ID, 3, svm_gva, (uint64_t)is_nmi, (uint64_t)idt_alt_vm); memset(&debug, 0, sizeof(debug)); - vcpu_set_guest_debug(vm, VCPU_ID, &debug); + vcpu_guest_debug_set(vm, VCPU_ID, &debug); struct kvm_run *run = vcpu_state(vm, VCPU_ID); struct ucall uc; From 6ebfef83f03f216b25b09a386bef16d05796cdaa Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 2 Jun 2022 10:30:06 -0700 Subject: [PATCH 0343/1436] KVM: selftest: Add proper helpers for x86-specific save/restore ioctls Add helpers for the various one-off helpers used by x86's vCPU state save/restore helpers, and convert the other open coded ioctl()s to use existing helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/x86_64/processor.h | 54 ++++++++ .../selftests/kvm/lib/x86_64/processor.c | 126 +++++------------- 2 files changed, 91 insertions(+), 89 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 9145da0bc61e..0bb9ba955d18 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -432,6 +432,60 @@ const struct kvm_msr_list *kvm_get_feature_msr_index_list(void); bool kvm_msr_is_in_save_restore_list(uint32_t msr_index); uint64_t kvm_get_feature_msr(uint64_t msr_index); +static inline void vcpu_msrs_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_msrs *msrs) +{ + int r = __vcpu_ioctl(vm, vcpuid, KVM_GET_MSRS, msrs); + + TEST_ASSERT(r == msrs->nmsrs, + "KVM_GET_MSRS failed, r: %i (failed on MSR %x)", + r, r < 0 || r >= msrs->nmsrs ? -1 : msrs->entries[r].index); +} +static inline void vcpu_msrs_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_msrs *msrs) +{ + int r = __vcpu_ioctl(vm, vcpuid, KVM_SET_MSRS, msrs); + + TEST_ASSERT(r == msrs->nmsrs, + "KVM_GET_MSRS failed, r: %i (failed on MSR %x)", + r, r < 0 || r >= msrs->nmsrs ? -1 : msrs->entries[r].index); +} +static inline void vcpu_debugregs_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_debugregs *debugregs) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_DEBUGREGS, debugregs); +} +static inline void vcpu_debugregs_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_debugregs *debugregs) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_DEBUGREGS, debugregs); +} +static inline void vcpu_xsave_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_xsave *xsave) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_XSAVE, xsave); +} +static inline void vcpu_xsave2_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_xsave *xsave) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_XSAVE2, xsave); +} +static inline void vcpu_xsave_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_xsave *xsave) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_XSAVE, xsave); +} +static inline void vcpu_xcrs_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_xcrs *xcrs) +{ + vcpu_ioctl(vm, vcpuid, KVM_GET_XCRS, xcrs); +} +static inline void vcpu_xcrs_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_xcrs *xcrs) +{ + vcpu_ioctl(vm, vcpuid, KVM_SET_XCRS, xcrs); +} + struct kvm_cpuid2 *kvm_get_supported_cpuid(void); struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 8dfe40eeceac..47bc84d1aeb0 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -814,13 +814,11 @@ uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index) struct kvm_msrs header; struct kvm_msr_entry entry; } buffer = {}; - int r; buffer.header.nmsrs = 1; buffer.entry.index = msr_index; - r = __vcpu_ioctl(vm, vcpuid, KVM_GET_MSRS, &buffer.header); - TEST_ASSERT(r == 1, KVM_IOCTL_ERROR(KVM_GET_MSRS, r)); + vcpu_msrs_get(vm, vcpuid, &buffer.header); return buffer.entry.data; } @@ -957,28 +955,26 @@ bool kvm_msr_is_in_save_restore_list(uint32_t msr_index) return false; } -static int vcpu_save_xsave_state(struct kvm_vm *vm, struct vcpu *vcpu, - struct kvm_x86_state *state) +static void vcpu_save_xsave_state(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_x86_state *state) { - int size; + int size = vm_check_cap(vm, KVM_CAP_XSAVE2); - size = vm_check_cap(vm, KVM_CAP_XSAVE2); - if (!size) - size = sizeof(struct kvm_xsave); - - state->xsave = malloc(size); - if (size == sizeof(struct kvm_xsave)) - return ioctl(vcpu->fd, KVM_GET_XSAVE, state->xsave); - else - return ioctl(vcpu->fd, KVM_GET_XSAVE2, state->xsave); + if (size) { + state->xsave = malloc(size); + vcpu_xsave2_get(vm, vcpuid, state->xsave); + } else { + state->xsave = malloc(sizeof(struct kvm_xsave)); + vcpu_xsave_get(vm, vcpuid, state->xsave); + } } struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) { const struct kvm_msr_list *msr_list = kvm_get_msr_index_list(); - struct vcpu *vcpu = vcpu_get(vm, vcpuid); struct kvm_x86_state *state; - int r, i; + int i; + static int nested_size = -1; if (nested_size == -1) { @@ -997,102 +993,54 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) vcpu_run_complete_io(vm, vcpuid); state = malloc(sizeof(*state) + msr_list->nmsrs * sizeof(state->msrs.entries[0])); - r = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, &state->events); - TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_VCPU_EVENTS, r: %i", - r); - r = ioctl(vcpu->fd, KVM_GET_MP_STATE, &state->mp_state); - TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_MP_STATE, r: %i", - r); + vcpu_events_get(vm, vcpuid, &state->events); + vcpu_mp_state_get(vm, vcpuid, &state->mp_state); + vcpu_regs_get(vm, vcpuid, &state->regs); + vcpu_save_xsave_state(vm, vcpuid, state); - r = ioctl(vcpu->fd, KVM_GET_REGS, &state->regs); - TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_REGS, r: %i", - r); + if (kvm_check_cap(KVM_CAP_XCRS)) + vcpu_xcrs_get(vm, vcpuid, &state->xcrs); - r = vcpu_save_xsave_state(vm, vcpu, state); - TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_XSAVE, r: %i", - r); - - if (kvm_check_cap(KVM_CAP_XCRS)) { - r = ioctl(vcpu->fd, KVM_GET_XCRS, &state->xcrs); - TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_XCRS, r: %i", - r); - } - - r = ioctl(vcpu->fd, KVM_GET_SREGS, &state->sregs); - TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_SREGS, r: %i", - r); + vcpu_sregs_get(vm, vcpuid, &state->sregs); if (nested_size) { state->nested.size = sizeof(state->nested_); - r = ioctl(vcpu->fd, KVM_GET_NESTED_STATE, &state->nested); - TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_NESTED_STATE, r: %i", - r); + + vcpu_nested_state_get(vm, vcpuid, &state->nested); TEST_ASSERT(state->nested.size <= nested_size, "Nested state size too big, %i (KVM_CHECK_CAP gave %i)", state->nested.size, nested_size); - } else + } else { state->nested.size = 0; + } state->msrs.nmsrs = msr_list->nmsrs; for (i = 0; i < msr_list->nmsrs; i++) state->msrs.entries[i].index = msr_list->indices[i]; - r = ioctl(vcpu->fd, KVM_GET_MSRS, &state->msrs); - TEST_ASSERT(r == msr_list->nmsrs, "Unexpected result from KVM_GET_MSRS, r: %i (failed MSR was 0x%x)", - r, r == msr_list->nmsrs ? -1 : msr_list->indices[r]); + vcpu_msrs_get(vm, vcpuid, &state->msrs); - r = ioctl(vcpu->fd, KVM_GET_DEBUGREGS, &state->debugregs); - TEST_ASSERT(r == 0, "Unexpected result from KVM_GET_DEBUGREGS, r: %i", - r); + vcpu_debugregs_get(vm, vcpuid, &state->debugregs); return state; } void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *state) { - struct vcpu *vcpu = vcpu_get(vm, vcpuid); - int r; + vcpu_sregs_set(vm, vcpuid, &state->sregs); + vcpu_msrs_set(vm, vcpuid, &state->msrs); - r = ioctl(vcpu->fd, KVM_SET_SREGS, &state->sregs); - TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_SREGS, r: %i", - r); + if (kvm_check_cap(KVM_CAP_XCRS)) + vcpu_xcrs_set(vm, vcpuid, &state->xcrs); - r = ioctl(vcpu->fd, KVM_SET_MSRS, &state->msrs); - TEST_ASSERT(r == state->msrs.nmsrs, - "Unexpected result from KVM_SET_MSRS, r: %i (failed at %x)", - r, r == state->msrs.nmsrs ? -1 : state->msrs.entries[r].index); + vcpu_xsave_set(vm, vcpuid, state->xsave); + vcpu_events_set(vm, vcpuid, &state->events); + vcpu_mp_state_set(vm, vcpuid, &state->mp_state); + vcpu_debugregs_set(vm, vcpuid, &state->debugregs); + vcpu_regs_set(vm, vcpuid, &state->regs); - if (kvm_check_cap(KVM_CAP_XCRS)) { - r = ioctl(vcpu->fd, KVM_SET_XCRS, &state->xcrs); - TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XCRS, r: %i", - r); - } - - r = ioctl(vcpu->fd, KVM_SET_XSAVE, state->xsave); - TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_XSAVE, r: %i", - r); - - r = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, &state->events); - TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_VCPU_EVENTS, r: %i", - r); - - r = ioctl(vcpu->fd, KVM_SET_MP_STATE, &state->mp_state); - TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_MP_STATE, r: %i", - r); - - r = ioctl(vcpu->fd, KVM_SET_DEBUGREGS, &state->debugregs); - TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_DEBUGREGS, r: %i", - r); - - r = ioctl(vcpu->fd, KVM_SET_REGS, &state->regs); - TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_REGS, r: %i", - r); - - if (state->nested.size) { - r = ioctl(vcpu->fd, KVM_SET_NESTED_STATE, &state->nested); - TEST_ASSERT(r == 0, "Unexpected result from KVM_SET_NESTED_STATE, r: %i", - r); - } + if (state->nested.size) + vcpu_nested_state_set(vm, vcpuid, &state->nested); } void kvm_x86_state_cleanup(struct kvm_x86_state *state) From f17686aac61fb23c08efba56ee3f3ceb89572d08 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 15:14:51 -0800 Subject: [PATCH 0344/1436] KVM: selftests: Add vm_create_*() variants to expose/return 'struct vcpu' Add VM creation helpers to expose/return 'struct vcpu' so that tests don't have to hardcode a VCPU_ID or make assumptions about what vCPU ID is used by the framework just to retrieve a vCPU the test created. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 16 ++++++++++++++++ tools/testing/selftests/kvm/lib/kvm_util.c | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index edbbbbe4cd5d..c46c03750043 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -628,6 +628,22 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, /* Create a default VM without any vcpus. */ struct kvm_vm *vm_create_without_vcpus(enum vm_guest_mode mode, uint64_t pages); +/* + * Create a VM with a single vCPU with reasonable defaults and @extra_mem_pages + * additional pages of guest memory. Returns the VM and vCPU (via out param). + */ +struct kvm_vm *__vm_create_with_one_vcpu(struct vcpu **vcpu, + uint64_t extra_mem_pages, + void *guest_code); + +static inline struct kvm_vm *vm_create_with_one_vcpu(struct vcpu **vcpu, + void *guest_code) +{ + return __vm_create_with_one_vcpu(vcpu, 0, guest_code); +} + +struct vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm); + /* * Adds a vCPU with reasonable defaults (e.g. a stack) * diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 8f670cef6faa..1c5caf2ddca4 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -369,6 +369,16 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, (uint32_t []){ vcpuid }); } +struct kvm_vm *__vm_create_with_one_vcpu(struct vcpu **vcpu, + uint64_t extra_mem_pages, + void *guest_code) +{ + struct kvm_vm *vm = vm_create_default(0, extra_mem_pages, guest_code); + + *vcpu = vcpu_get(vm, 0); + return vm; +} + /* * VM Restart * @@ -403,6 +413,14 @@ void kvm_vm_restart(struct kvm_vm *vmp) } } +struct vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm) +{ + kvm_vm_restart(vm); + + vm_vcpu_add(vm, 0); + return vcpu_get(vm, 0); +} + /* * Userspace Memory Region Find * From 0c276ff22c7eb1a6ebf889b25d631f4cd358a482 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 12:58:44 -0700 Subject: [PATCH 0345/1436] KVM: selftests: Push vm_adjust_num_guest_pages() into "w/o vCPUs" helper Move the call to vm_adjust_num_guest_pages() from vm_create_with_vcpus() down into vm_create_without_vcpus(). This will allow a future patch to make the "w/o vCPUs" variant the common inner helper, e.g. so that the "with_vcpus" helper calls the "without_vcpus" helper, instead of having them be separate paths. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/kvm_util.c | 4 ++-- .../selftests/kvm/x86_64/monitor_mwait_test | Bin 0 -> 1485656 bytes 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100755 tools/testing/selftests/kvm/x86_64/monitor_mwait_test diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 1c5caf2ddca4..8c0310094d73 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -282,6 +282,8 @@ struct kvm_vm *vm_create_without_vcpus(enum vm_guest_mode mode, uint64_t pages) { struct kvm_vm *vm; + pages = vm_adjust_num_guest_pages(mode, pages); + vm = __vm_create(mode, pages); kvm_vm_elf_load(vm, program_invocation_name); @@ -341,8 +343,6 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, "nr_vcpus = %d too large for host, max-vcpus = %d", nr_vcpus, kvm_check_cap(KVM_CAP_MAX_VCPUS)); - pages = vm_adjust_num_guest_pages(mode, pages); - vm = vm_create_without_vcpus(mode, pages); for (i = 0; i < nr_vcpus; ++i) { diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test new file mode 100755 index 0000000000000000000000000000000000000000..598b597e1eec1b15296043e2e174d1e0a1164ec7 GIT binary patch literal 1485656 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. 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�DK7o(W3$ZwSZv%9=`Vv``8s$|8l|os{r>w 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 Q{;v~mUJGI|T7ymDZ`lq~d5p2s04AUg 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%0AGT2PDnEWC!gJ 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�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%0D3PNLk?8@ z0aQJ#zHSAHgX)oHNH~Db?*_SlGANxeu`_H~4)O0pkRSsC!$PQf^z^e1Dy|R@NhdJ> z9s-Gj%ICX~eEJ<~&K;0AsN9Hv*sBT^ufY+&PoU}?=_2T-F@PD8L2{+JsERd9%KB!(3V@OyBX-~rDzs$hmTnr6=A>j#Y*Dd3L z;zypmMSa;xEuRJ4osaNE{T8tPpc7q3NH)01^%gb`bTjc4kErBpf!Nm8;kC zAmRnkc{E6BVPKF0nFA`%q2oWW^r>k8iWdon18D17ZJ_EMERF-bSqvsV84}Kg&<3csAt-)D7&s2Wrn4m_Yp733bnoLP+>K>`ahP;(MgA@)LAH4F^fK;oc! z4cZTarMG<`aZrBT0ZCV|_Vz`PIH-K&F(9 zLEL%36yh&fz070;3O7N94bXMzuy6xiBnPg)_CnkPyC6oz2x5*w4MZGz%mago5hT7E zK0v}}8}#B+XQ+4qTDvy{Bn~Q1d?EgVt(VRNyN8Qm1KRquHjsKy_(0p$u=&~LIQrdv zAoU>g7ema4h4UPcIH;a=f}|hV`Jy|(_KGlwK-bShi#LX&Q1t>gpyebqoj(Gr7i2h4 z4oPpYc`ncefuL|}=!B@B3^fRJF&#)8z5gy`3<bYM;cBo6AQ%z%Wm0n}bQ z&^Q37f2t0N$5+tu2Xvtx$ovORkaP$ux8saK@higMfR-;RLFR+P(*}}0ZJ_D7AF5se zP5lOA&>aLHLDvsJZG=!~pzc`!P0z6P$)NRIpnlDT8<6maT{QCmq#hJ6&~`7Z-Sr0Q zo`wpDe_{K5KsOSB{Pn>X;xATcIM_nV+W=cgdIPPK2DwPm1QMPN(0l~D7)sfMfdS+m z0ciS%p|j75)1~={wB=)!yt1&{lrK} zIER7)fq{YHG)NqjPV^w*13M@AB~)CY50XBoL)HHPg%7Cx22F>sa+t{!5}pQ^A?ll; z=~)3PegLgsW)2m1@PgE*p!*U)R(P0#!c&AH02*$v@SIWrF<&4O62Gu@T=7tIHbCzS zfcf{U3uGJseZ30kf#hZfgYsiGB%ERE`Xs^_7{nO(7+~`~(BNU%YYItk1!(nJMiiv{ynxo8 zISMu3!55PL1EKZuC6G9%eKj8v{;+s?4H5^{%hMt5f!&Yu6C@7G*A9?$1)FzZF@x0a z==(7R%pmQG12K?tzyfNo5=b0mFLeCV3|jGML&Yz=gt*5T>S0T$xWf{N_yMRn-cWId z{}A(;p$R$`Dqg@2ac3&D{K)p!N)OoDeo{pq&Z{=MDEE@d#Ug zH36g^)bD_%XIOe$1QG|;r^S$PgSErAfW$%LoF^dpMH%XzLuR0K%f)a2x}F@C9&Uov zgYum}qU=AdGLYrL-A7Y{IhnD{^^LOY##L>q+nn30-u`>inLE<+ZdXe`e zb5Q-l#lX-A=^sI@Wtb0A4~nlH5O>1nF?X9o;@#maq@01(BgdiY1N1w?tDBVghJV5Ig?}w^C;0np7uyX7MNIioDLju}-(;JX_P`v|HzYR9PY6bCcz(q(n zgOA%~U|^82g3L#pKpR(7w*t9Ggy9EtUJsUE96{!Q>fb_0_`}*cQ6ODk_j~@ z0Il6s237Ci3`x(+p&8~-E~H(7e!f8~NIhu0B?l7zuyPVKZ2_9^Q-ID>!`i(wLFz&2 z8JgZ;_1zkfI4C`oK+J)Z5)2FnK;oeOICT60rv5Bc{DB}O++gS2K7)xv+b6K{_6tZH zH2<{#l5Sz~#byl(PsBN>pg0F%A!|syY%qtUH(zLdrvw%MP!CBz_Rx%N01^kKLukJV zwm!iYBn}z}2!Z6UW6*@|0TKtzC+>uZ{{dObz`zg<6>osf2f^ld(m~>&_QnTD{62%K zZ-$C16hPu@H&na}D*j<7Bz$1*nE@5Q0A05Lo5x%L5(l{ln!jM_Y7;_02l+L01+WtcQ`x+z;3jcD5f77AjUqRxa^f?(4FED$z`asI75229o zhbBV?VH-%iFjzyxVfWFfg2X}f^*o6Av!Lc%+koO%g5eG{|3agS!3(4wR1OzH)E|YG zC$UiR3DEO!VCf{Y0a6|=@P?$%AgKAdQ1u_6^Iz+r;WG&&4oVNub`B)9FfgnFiG%vr zOc4KuLC5+1LLmN~5D9V54XF8hq3SO{*Vn<;fn0)$PuK)e4_lWm0;(@S`4O$$y9-r+ zpaGJ8oO-uOu`)RiNq_ zN+9;0g_@%S6<=@(5|2xv`O6F{z5#k};csYodfS5Hk&EHMHAu@r0%}e?RJ{On9s!nq z8ld6_k|5=IA9P}@0XiPF0Ih#96{`M0EF>T4LCs$d5(kYBL+5{C>%r1np#q@d8=&hRVfiT14it|f3?69pP68~`1&HKF%0Fy#{^FWaK3?d8;Q&Ia_2_W^L`eF%0y#};H)c_I)m8;P3 zf#_mjm;e<|h=Zh0WoScl1ytMsIQR{{cFG1al{|0|SEqvl#rGQfM+{ka2*hKLG8Iz{WQ=L_)+j zG(gfPEIp_=K-|Be5|Z9v`P3LHu5b^M-WZ@63^c6<8s|y)28ow_(0p_n+CMEon`aLO zxd&9fLGRatxd(J@F=(BbLj@$pVemqd-`R4`L1jv|j@or*Z(959+5sf%pryUMmbL?f_i}4m;NrWF07e8=&oB z*!rakka|!!*FyXYn+NQGihqFCcc6QVLGC$T4RH_p`jAB+^`LfX3?#n@Ld)CrP;moM zNdATGQ`-d<|8O0WZXvxV28O+$@d{9T5?T(!+I#1r>Nh~=@nQ2Upkuv3{Z;|!xw5c& zncE5CP6s83zhLv-svvPtI)UE%04)X>3_;?cel!!r{jhtQ9GyVpEtuo^pktgt_AaQ0 zm=EjkWP!{9nZF*Ak6`iD2oeYN%b@;+wV$UuLDEA5^#0ao(DD;>{4yxM45}gd0=AC~ zv@8K6E^rG{j@d!mjpsq;gT}9*=L^C5=}(~I3DA58$(0NY-=X3g{2}JU_7{|9L&9wX zbbcAO-kZZ2w7x}xAp?4jJv3V|fR5P&x#z)0NI3%uJq89)^8h4%0Xm)r%P*i~@j&7V zUm@v12AWP%ogwxvaDs#<>|VSL!I1Jzp&w#CZ2Z3jq#jhi#G$&s4I~blPrnZ7@4)7> zW`e{)`6V2p{xUS2S3&*+$b{cG+Xb(*NWk|XOt$POLi!(5BXu5)}Te}Gr zM_=#s2r6Ds2{8vYkMk8I4(cylgoMLkXh5?<*CS1Ut`mc$TX7diym+9EGw8cO($xfL z`wg}(+8$&MsGSCF|G?%YJwf82buSAb?wJd<_eut&zmI;tVhmJ0`ueDJs5tt#N;$|q zp!rtleK)Z2;a-q>&^m`{ko*EmC*Pp!VHTjRGg%5!4{AT7&5MDKfl_3UV7P&H-r8oE zdT9Fu){Z(3au2Bgg4S=n1XV8p9XGxWid@h=)KKvQ&~XV^`SaO@fk6t?{z2Op{0FLD z0J;th+6-jibA_by0<>{FDUdkGJsyzohqX7(LFWO{=M7a|LG_UsgTi`9j)v82xd%Ew4oeS5LE@l(RvIK< zz{=I@AaPK*1wh<+8X8}=p!p7vf6>zU2dMf9`jGN-HPm1GpzW~+=>BV1KjlA2Jt)21 zgv1MM{0h`;2F+)|>QR_GLB|P#>V<}15cf=n&Ierr)%&1+lRu=sJ_mItsQ40OkYI>F z%fH2LkZ^8Lfs~W?pz1-(Q9$MAgACjg7&i>K>PKucC|9p90h1Q91@!h3?S!$ z!oLG8{5_%S4emqiErr?(y4D;N{u_KD@dB&A^4vk;&&8nd3z9Ej`LPo!?tnJmu>@*9 zlOQBLe}m?iRbcfJ3=Pov1<-k3pr}6pRWAU&ClRWg0o2?DrMCd+I)B)F>obsgPAR15)oSfQB2aA7Ka`$5TKX z|Fi(9XOdu80Bt`*qn*JOEH23K0J^RQCLRT{7nI+j?KjwY$Qe-a562)W&=eXFMNsho zXgj|O6le?#46Pt>Q2B5M;;)@h^?lHJkOk2GDXiT)!2^=6(C0_yg3JN+_tDl5ysd?( zcd&-!uUu%mVkuPp1?ajyNG@Pt*ai{@jdLD?xW5MKo&z9pQ2TQw#2hPVKjHyM9Hia| zA`VMeAHd-z!LR{3uLLW9>}x>r$jZPV07+NSU|{$OHRpm8BphJpbg_Ga)Uz`r@IuT_ zftH72o{;qX0J;tn);>3cs^4%Gl7pblPX=eG_=Hl3IP6}P5Rf?x5)2m5^bB)n9!Nc? zUVzq*&|qKy4NHRZmxBkyog&Z#0XpUaG>?GZ|84b#v~$qKr-1Bb5@fgmO;<2`*MjT? z^~a&<1U8?z6C{qMzBmCA2jv&&K3v$m%q6J!fy0n`L;@P`?FNwcQUdfGZ`ipXpkhrB zG%j=(Qa-@iU2J9$_2}yjK10o4un48{4?4e`0IHZ67#Lvf zz4&}c`uqT0rwuC)b)e=jNJCoeQ=$19w9E+<{u7|)K$8Ols5=P~XIKe|7ufyj8BlZ3 z*HspR#6j(FX#B#$zX>D`s^4WH;Q-s$GZQK<09}^?Yqu{4iG%v-S0U-y3K|ZZpyCNd z5OLT#($k=Io}hjx+W7xnFHm}xV0Zy7e_-x;1u_RzKA^etCscevD@SiY+OiG%VH+WcuVR2)5D^nk=c<2L^x;Rf61vJ4~+iZ5vY1=haW zBN0u?VHbI|7p1!5uj z0{z@|P9ISCOECOE3pX_%Ncc~H?mL4XH^pEH5(o9iq3gq8@$L>Xhk=Vh0Tke%dnKU` ziUFx-U}xYJgM<&X7-l#GT^BmR3XH)dzS(${zt}x$zDveqa`)ym}2y(0sno@~Q<=ZgfJ; z2OS#)igyQSe;k^<7(mCZfW!-+=D_xAq(JNI257quHZBC(o(xj&0BvtTT*bhU4Yl_H z+PKp#XnzWQy=4tlJ^K2h#so+>pr7N^3Q`ZMFQDNMD{m)*)+vGJsh2_WDa@VoK=aWy2p!Oo)-^@F671JHB7Vf~}CAoZa72vi_5FfhQ@CEoT0v}dmFa@h1CxdUklnH;;{CKFjO4fJ@R024u%WR zb2#~->0!DXq})L7kDK~|+$q8E0NQTZ0Zk8HU~||R6oeq<=PhVP4F`#X#*Lx-Mq&51 zXM@B+`A#3=&TY^G8I>v_;fCI>TNMuR*9K_$49mZbAag+FCv<$Z09xUJhG9YF_5$d7 z2G~CO`d~;ovp@?HU$FMT5|BBdb_I05>Q-oZvJWbLzyXpT`k?*=E&B(h+XK+@6IL%P zWkB5D0IE-zR46uHxG)NpY z4r31qXDO(A4E-VT;sSCo186Ti!~@FEeir&XkveGH64XA2))%nxC})s43=#|((0&0l z8X3Z&_I}t72{+hyV>(D2lrPZs&sKrNLE~W1dKp#@`$5<9ps(Ya08$S!2U ze1Q`r-$_H`cR5rXeLijj$o)(b3g02)AMU|{HnIy40;?f~644I2-c3SD2P0KI1c7S1(L^$Wrv z^`j*;!*qefLE|21^R|;g;vn}x_qo8%dsz+@FW3Od*FMnrS`S?pk$|?IVH;F^g9^l6 z*uLNkQ1J)Q@n_h$(;KMxfhLIg@1Xwu2NDO3&qK$ZVEz>fgybWIX^{F?3tGM@fy6=S z^9V#d5$aAokT|G)1)cYS)aDEfHi4l0CCIP>tv})lQV&WeyCCM|L9!h~Bvf3W0Fqx| z^Zt1tanO7*biYh7w4UvRiYL@V(v>LGJ<~wqp!GJokns5rHGeKh9JC(kHzYm7_E)Zf ziZ?*l1;NI zXuBQOe)}KDz#zs18!blMrzR2vjTf|e0fit)e^8(e5}vSd(1Y&tMPFBG3^ixMT1ff4 z7Fv&ZLB&7FL&Rb2?SvpmJU+;WjJv|_gDZlnKLG8g!~EL>5(lM!D@b{(0PQDE1)C$m zFaxdJSPN1Qs^5bk?uX3_>;s8|>cIj?PaKv$uS3NJ_CeIUL(}u)AV_(FeoxSQka|#i z54xYu9-1C_p!HgSH6)$*L(P#0295J@F*w|Z^mi6O)vJNjgVvcuK-%FJPQy&JgcLCI$wIFfO zco(!@hK z1_`wFnH?pNdi;VFBwxVpJG%%q2fdyA0VED`4|IM9w!f7n1k&Eva1G+$c~JLDK*iD5 zv8aK>LFL0rNI2I*!^biNly12g9zf$U11jzXRgb>jEEuGoL4u(Itsc(>sRyM)=zJ@5 zn3iEORJ=hBQeM?T&7Thv2i41uA@TbN8g6T$;^^i1R**QTyb6Sb8|eKE;uBgR>S6O5KcV6WenZ@I1?o=bP)K?50lJQQGPL{@0*N!Q zGZ?Ia_-h)}{Ys&r@DyR_Ks(n(7c4Hp;BgdEKET>Pwjgsr=@2^Z3UmL=T1fmpkb;;G zUFOfQ0M?F$s)vmm_(9DPkb~4Luzh(sp^*Od1nB*?&}72U2vt7;x=tR}AL)#Og28rJV z(Dik&dk3tc;^^zgoWnrzE68vFt-cP1s#k#4v#|DIDpWk68RAapF+vQFq3e{;=ljY) z>Ot-BFi1GV)_L}T?Ui7-0!=@#aGM8JkACjQL8y2FXu%Hy0|V^*#%myPP`)?~N$01a z;r0Y14(cyJ!ylF&K0(DDpzAGR?OPw{xA>|?ZJ`^jEdQg6co?o#antuGD;^^&!gm7rOg^sVn=LMkZA3*2nVELs1Bo10< zdlXV{nn5$()Nn}rE~tW}z#C9|mqFc$-cQ^FH75bOpB=W|<}^qgls=*12{Da<;V#r1 z2I&51*t)gnQ1uLskoLd>X!-L4Bo1niLC;Zv^(zG;AnA631Ek#rJ1^oUv>krnFC>0n zLF4yN6(pPs(D(I2&G`V`U$YXb-WDp3zOK?c0u(+X3>IkXGZR7TLFEIq{D-B7I;i*s z==vg9`(y%098~__g1FNinxN;TL&jCm&$}+Ihqyn$9a0X!)}_ybnsY%F(msLp7j}Zg zLG>ou`6@?1;-Gd8+WN^$AaPK9ordI7Sh?{SD((P12LP6SK0?LO&-3{S5(k-&)~;ra zgp}tS(856iDxLsZILE-iPy{XCPD1B}8DQs7LDQikRDHuth&#KW;+7zBP`}9#k{(V$ z#e+fOpmOyZq(2B-N0$%@8i&EGr|LlJLFFfO-7>7b)BzF)l@HK$O0axAEfSO-BpC$G zK~gxZURw)QkG}qJ7f2iw@6hu%T%hSq$`TU4==+HdgVclO*`f1gu=Q8BpyCI5A>jZ! z$LR-198|y5Kv#0^2HsJi@Z@4p01bdMFfc$$CkBQzs5$8S zUJF3tp!O}aUkNEa7#NyB^*G3#(ED3q?ZydU^Tik*tbxQAY&>u^$Q)3;0Ge1~U|@i) z?>z(+-vAx2fYsyIq2eDNLekYusJ~u9#SNhAW^JJ2pFs99NH8=&+l|oTje$8D8ZXdw zKCpZz1r`4QZKuK7lLk<60noxl1_lObx01mYBo2y4OGv#59cEw%2Z@97V-cjBNro=; zOoNI~KwH;Q2s-Zzq#o^jp+>0s1v4S(3O29N9t~<=i7_NV&mV?*mq85F-^9{iSQrh8 zUqOZjwEK*fgUko@gL)zE*M+9rtx)j|&~S`*u({2Ubp8O^-iCxK1H%W9deFSaS%?dv z-8BZr7-+eNc7Bm?45S~5ejc3^NIfXuLEE>`YMDVl1{7{$3=h!OHF-kS8$?3Nz5P&k z20_IepyOJw^AA%&;-GK_Eih(aV1S*2T?Y~ewFk~a`t`7Lc#NR=`T%I*A_D^hY`t_B zNIl3LXuATI-cEzokAc>yqOBiW5(62pfW;Gx-VHJb)L(|C=k?Hf@DkX+Tnq`Ukp49T zG(ca%)PIBccRsYfV2Fk0BWSw|7H&V?A@Q{U8lJHFi!T<^UP7NolZ^$1GZ({w0LV&F zSUb%SWIiZ8L+eLaJJ1~@4st&&6==U38k`Kfpz0l<`;=kxr>8;Upmrwo z{5{xu-8&$0P(27*2*kj^04wL;LB$o&_G|xvilfi7ABL`zM?a@dI1UnD2cYBduyJx7 zs5tsQsW;GboDQf$+CQ-Q4l}5F1?av-*gifNs5k?3ybiWr*B2`80Nob`i5&)pB&hg= z!;lOA#(~mc2qu6T#YhvqAg6K=}o2 z|NBa)`U`017G4Fdp8@szpywsR&IvpNb`KXrf;c37!p76?L(SO$J<*BU9XE? zAAJU!Bgnwe2k{r|d}D@qNO>gyT^|U$uag%f4oVN3A>|wFUL;AVIC^=j4iX2|%g}S} zVC%X~K;ocrt;LXdd<=D`Upy$BMHn>D_V0v2#U;?%+j%f^(Dv=tK*bB7?KfEeq5~uj zDwm+^*kR|P%>bJ($glvdKf4$#F2NuGo%ey2SL;FMfXc}>NXmhwx1CV&08L2x>426? z$D!s#pyl7&AoZaBLMf!aTMe!6UV+3x?GWgBeXwy4mIP>iafO827ihSNLB$zB3tvI) zXK4Aa0u@hy-b)L+&&U#*ZqfHy+MNz`(!&+lO1904ZOuKJ84?b#{riT{aqzU^zfc70oFrbg; z9DvOWqs=F-0+|mgC(-ih7LYioy#!r%4T&`dhNDn%^zp-sAaPK=U2eyXP1KQ6=Z0D z-U|s^|FAm|6z`b(O>Th90gdZI`}MH;^fgEv-=0eJ6*g0~=V0UscY&Z`Y z7llsaFmyoGFMy7#!`3y;fr!GwqM%|G=2!$-+?xM*Z|$P$N;UsVB-%FAag+J{4%7!83m1(RFF7m zeioWeVEbnqK;oc$y# zOdM@LT@zH?0lFRl+KpzI3bl6vbp0yyxG9EL&~$zQI&T6i$5w*O0fmn}Bz$1^2OR*3 zgTe zSAd?g2MdQ}kT|G(fVKl+;uRoqQ2vG9dsPT6&!^ThFeosHFgyS)^n!|ksEHu;pz;v9 z&L1}3xDX@`Y6n8k_kitVJqi_P(1p1F6SQ4%6)GOE7&5Y_23<(;5-Pp{t^DBxwU=#0 zP&`8S$HC@VE`rr_F+70o-+_+CFuZ}P4}h+Ng6$*z4;6o~6;fWo&NJu8fW(&pv^ibc>+pP237w7ZM{l4RQv$+ybf4B(g+owkOC1TrDIvx%^7aHmd24|3Z1_=fSXnzM9%nYF*anSyq zhmext1$3f424pX&euR$Or$Ft^1&M?5qZ-6LE1}_E4l;*9f*}B{pVgNIIUg04USakw zgqrgJIv)z_zpRCd3qbeLL%ZV)N1);#W<%l~b|3vEkT|H`hqjks`}^L3#6jiBK1jY^ z2@Ow%Y*2qtgnJLr4>PG+l?ngWSum_|bRF9zT2b=~H2bB-=A?XcvPRLr2IH(?h?xXnut?%|h#Sff= z#QR}rdN>0TXJBUtm;o_oBh;ODz~LaqkgyTb&VkL-y#}cVogH9tc0woB-(hd04wz86*xG_k*sZhBjvy^g!aEaszsw5u{dP zVDJHzlc4m2cCKbPNIj@u4Bh7fGba%$J^@+C61x2Z@8)!_aXU zXfukzJ{0ONXgdLB&Ws#TeivczKpS6O12P8`{tF@DzZe?+XQ1K@(DrQ@RQwr8925@F z@>v`z&YlY?X9C601iP_bN)y%G!wXyd3_Q1us}3OL50|kgn0-*Wg7F2uzT7T*}NE|fY=m!}u z`T)%@zo6m@NsyFw1S&3-2kA$kuQSobF^*~uQV%MJq5Y9Ms5#zH@dMCvQDEuE1lmqG zfY$Cx0jUS2f9O6k*myz+spoje(0K5RUH zZ2>5~2{J4wgw%tub1Y9n=jGA&7iWOhZ-D9xXul8E-q;5vX75@O8uY}!W$N*ix_W?T34r`ykfx45SAL33}y~zj~-vH(JfSvxV&+ zOn{1`&u?Zx#RINE+9$AkUP?gXp!($iBwp;H>9YuOogy8{n-8F0- z*E^_s^m8g^!^(5C{wa46q`Y#t3CX#zb7Ezn;tQbTsIdK&#vpM}yyQZ{2X>!`Csh0b zbYB~6{Ry8D$iI>d3efd(&}d{xDFTI?1VaO~T!qDdG1MG|I}r0>;}R1<;-GRY8d9F@ zg@(f{kT@tGLC?>D^=sCE?qvhzQ?z|FJ3;C}^`I~$U%<-Yqfl}5d)zKU#nJCSeF!oi zRQ{v&qu)T)GeG;HFn|4niYuIh^sv@L+XFn%^&t*W^|1UUS_}!F1JM2#Y}`hx7*g+} z@82;8iG$L=4kR97^^Pl4+yQ$2Fswd}hT4lhFPscg4=U%;&VergyGMk92ilH;I-j8d zq#o4%zXT0WXuNbn#T(Qh?l}k5Fas)%e$U_{sQC(L^Zxrm>OuWAwDqXBK;oeFT4?KP zo)v@A8#_bKK}h<6rMK@O^`LSdZ9hJ12_*d&K<}M_jhhLB#6k5DC!`#M#iKe%9F%^x zK>U>eZBSa4K;kO^ZCud_s{X?SNPP!eHy8mD2f61u#GOXaa7%)U2Y?QuWME)`=we_f zf{Hsp??HeTs|;-*anO7>+Wwk8uzN%p8dgHeXV`j=1yJ>D%LiC_D_jcc?<|1s?1pyMR4dn@vw<}g6ZC0IVH2Z@8yKXm>MHh<9t75@O;*9=QP^FiXE z@(Ma14Xc0mfy6=WTj=?vvC#Z72YQYZ`o7(>AoZa3Gqn8)8-HF0olitxhkPHT9yFfN z2}#etpys~=`&WWt12o=Y;rtJ(9(}(&cNrv{3!wD^Y`uyqNF01Fh4RV8}o_XTuYu9#k)b4(wuJU=V{A^w}VBkiF1$ z3oO3cpyB~&>kQ{X#nJCITV4ighww2NK+_*A9K0JL{$+rUXTsL28~~XEYImWXgK-rk z4r;IRLE05tpb6_WRD6RTBz$1!OE5#nb3`iVQ@1UJa&|v#6ja!(DVOc_bvVeyHk)M0lHrmR-bZLK;jquyc!9pI0JMY6fD21gTz7O zJZzAXnFU&ITZ6{-NVMuzB!#AoZa5g8B=#UTzsk9F$I=>jz-> zGVFkgI|M<(6INdwgNg@0_cg%A2@j<}`a1<^>jch$)PvGF+BnH0u)jnY7|`w(SZuB?WH&j;u{ z6s-Jrgs%TbAJ5zXHKzf3Pxo19I4^>ZW1z3sIs{S=O3%=80M;(LSPg0qh%iim#yiYk zFG1=-IGoB(zY7sG;oko*NH)fpI8gT*BnPN0=DgVcliWzg{-XtBXy0}=<-Q)ufILC5QX@ApJIf6@)Aegm{$*#a%F z0zu-S_6FKKV+KeZRIfqLM}plmRRa}AKYwF#EvSErx!z_0NIfY11VQ4Z02&Um(0j=R zp!ExEe10uRJ!l*Tdapg~WRR^OaZot}tuJ8p)FG(&0krj~m!aYbX!{Oypy%JB-*b8k zq#hJs(0xy^{P-Fq4$6;c=YM_$iG#{d4M;iD4fPjC9i)B<$cLl{m^m_akot%Lnr>m^ zTB;y%CP@Yf=r|Hgy*0=jQ2s)@*R>JaPjo=*mwAEIgW6-zcI+ysdlI4IA0#39^b54U zCGEWP+aOX#gF6hNb^3s5u*;?LZG`hA)PSqwkw;gNi>8fTTCrzT=rt@egS8YdfLh z53(TT(qd@+dl4iKO3%>wJ6JpRRz0X(5@bk#-tP<>XLt!x4+^(Bh`q4(>Q9*XE=c{p z7wUd)(7jrqe6$Xd4q^Qcaj5tK=sI55ejj6yI4Inp{a@Jph(`m+Jt7Pa(D6E0_@_hF zCwM~An*-EerBLw+g%EMr`l24NIT8#z(8dSYp!-S=pzTkY*8oXZ=ht0PpLGSHCpV#OCsR#KN zI$sYfKUYA-4WReWPJ=GM-2)XzKkxk*R6GG%pTgSJSD@ks&~@y~pyBxhBn~QPpyTkc zbo(774(fM+4#EZ99{`O=jwVR?kKWE#g^C+M=fPp?avhr>;V%IVe^`3<1E~jv8}vQ` z*gRk?R2+T%Kw1-|J$V3aJx>`(J!pLe+Wd|k=p0>;`OxwQnoSuRKp#fTt!0zom3>8Oj_g)5>0~%j~)|if^celuPYU@i34$ zXnY>JPZqWwBe@wAUtA0hXzkJ&(DTg%(9Vmf1FIKg*nw6K%m$ecawl}12E?@t49h{{ zpmG?x4hME$)pn@30(5@?wE4`i3wn+aM!y@XK4CA!U$A}9m%;84V_2{ObzJK?NIhuY z0lF>}*1lqDfuv`K2@n?+K+9DHsJKEOq~4TDz zJXrMoca_lfB>G%o$Qja|_}@nu@V1Fknc@EH21N ztc)*8%u9zFmY9-)Rj~!cuHu56%o3~$EFlVtQd3HkQ?aTrV@S#@i7!qq(JM$SD$z5* zs>l?qC^;uJu?U|sW2~ADEfL`r4>lt{uQV5*IVMONic?DnDL2IKXhSpX&M`$YJuS1S z7~=cn{2c6IY-obr7#yB8$FAA}yRZ>$Ci%SyIQyDVz(~@)Yi&H_F#M3`MFSR@#Dgd@WGe0dYr?fZ& zDh=hpq|#GMieWNfHcX-@H8BMy0cOJ_%8N2fV0NWJI8dpAQn*=QCRn&UEi)%IzW`XZ3my%kPmXlu&^-oGxX>mz>d1gv#d`e|GX_}s+Gq}2G_+{6Ox(jbYn zg3^*?y?h1;4YnU-6vzqj#i^;;`DtnB=757MGba_@O(2Wni&AqF3*wVAQj@d6mO>1w z%u9y2BPBH%B_@dO3(xN<=0=NJ~S#e2Gd`W(MZb2R_f9EA-mK5t5GJvf~0b2uR<{+`t42>+n zG6hAMc_nG_X$5-u3>k^Z+3_iv>7bG=)6gOhR0<@e7R48(f@7Q^J|3<*9-7YK0vV|l zpoD`^0TKYmMP@!IVqi%D!iGwur@bl_>#n=oK%L=^7zcW;*!LiocQGYypq(4l6XU`f{@?>rRw<9 zyyX0p)Rg$L#GKMp223G{($tF75p3M)`h z73&#*bfT(&Xp9d92XlN-VrFrwYejNuK}lwQUVK1CVsWYw172BF1Kje9l2cQlrlD!a zB8RHkJ+;I=2vsN;Q^+MXsWjaqKR+9XyHE`XN-ZwUg%+}Ke}Ki}^NZqxQcE(5U_}v3 z+9@$PyQC;F8LA7B0(H|;Qgu@@L75~i1ypLlQc!Y!Zb4#EDgz`^Qu535GEx%@pj;5M zIKQX_OA3oG&n(FR*8+GYAwEh^Es0OgOob%d%)E4l@(l`23`-)Z~)*{Ib-d z__UPNV%#zilR%Cy&df{CK^PVf_d-f)JPtX8=G@GR)D*ZwQ1oJ#f@n=lNrAWz#()Ut zWagzN7R48*CKe@UKonpKL6pLx$g?E1D6u3pAS0#7IWZ?EDKR-47TPIA@yUtF8L9CZ zsfj5Ji76?dLJ$%$88A79;?ksIJw(FBVjRRisGA@G%uteAl$)8CSdw3)XUveBSd^Vw zq-Vl_q6VT3qCP&iv?R5Hp){{JH8l?!NyQ9_d9Vm824&35;*!*&)D(DHcFW95iFb2x zg%|`)d!Tv^)K-YkPlJRyywt)f3eg)MpPrl?UyxcliNz)HMXAN5IVB9mC5a`O$?-|0X$+upgdsj9CoMTI zJ|jOryO<$2KQFT+zbHPpJTbE*z9h96)Fw|aO)V~ohe?5C7$8ERk`~mQFD@xfOVdkc zh>v&mh<6Ke^mUDQa&`Cgi;rhWNi9lE2M0%dNp5^{PJUi0sHL8gAD^C+pOlyrpHh-v zR2-jJTEPHHtU0MAsVRD(1{)R?@oAZPnemB5MTwR1sd*(umC)3YQkt7v$pDESPzwuM zvVw)OyhO*pvkTIYd zJTou7SkIIJWKeujYGQGIUU7VOUVeEVLlL;^19KzPQQ-PGKCvt@GY3>V#)I+)$gbj| z$wjH4CUI#& zL26NaK}jlDBd8QBE-fg?FDgk*iO(pDPcA6UOo90y!ZF065+VcbDnU4=4Dn^Tpyon+ zL1H?zApnhSkURBE7{HV0n+wPX2=0GFwIQ#lELu~W~3Gs<>l+<QudC21urcGvbR&@(ZAX;BH!8X#qn{W>T_laS5nrn9l$Tv*i5T-26Of z(UzH)25P5)oE%@3k(ghRna2Qic4BS{vii)tl+5JRV!dRf$N?FbT2Ydk2WtFaQvmA3 zxA8=+^wkegTm?L&a`bwOfsYJ6fc zsK_pY3qT8w_+qeZZej)0e5jeA(n-${8klQiQ zPK+-~O-s%zDPqV35rw6hB@D^noEHyCq(uw`uxby&fcMrJ%F>FH6Z6t^LCF~0ea{DH zagYKAP^tmdfoZ8l@t}rFaZY|YLs=TQj78CrUX)*20PQV-yNnsBIiR8s)Gh;cctOdq zxC9(OX{C9|FpuY#mOw?5^YhA5!Q~>jI}8zJfLIh?kYAh$DnJr*7_v%p3!wd;;*!(? zlX#E-s4UMb&BRAC&U4L5-F)s1QSDenDbNo?bpfQchxCb}>U$ zYEgb_F+*m4SutD_sQ(V?*d}LWgB!QtKtvXV*qfQ31`02|e1@{(Jao-@2%X@e5O@h& zRGJr`1}bQaOX5M@MsR+H_%a@pWx?4Wl#fA`2t!J0VopvzxGj{HT2#zXoLC0#ih--v zQpm7GXcq1?$ro<4N5Fk~2#4vLUq& z18BS}KCvh@FOdOa3S>kfwWx@pBp)^^lbKf%50V8}5bk7lfCanwyxDnVtvL z4fh+!r!bd*ioK%DT$Gx%G!K*jN*wZnSn}Kh(-pm4?#^WBbfDhV4>ppoXp(J5tS#=cR)Sn;g(|1Eeid0vdFNYRFB^g_r|jAVhQX%fLgrkoHS%YA#3s zAzhFR_FOzD{6K7|OmPW_0~)c5hcMydMahZ9smZwo;BiH;ci;k0H6Ry24F%;=2p1|> zlvobpg9AT49?pZxg2FPRD6bSWW(qMH%!A72CKW*fF*m8GB)=TgX)aGLD#-`eMY&1E zU_nsPSe^`G=O#hfpx_4kq&&G8#D*GIo?M)pR16w`*UM)p$&W8j29dc*3~-~sUM#LG zPR`Fu0~-KkL$YmraY1S_XpW#fFH;XRiB(*XSe}gtG8ay`z z8Z873jDlt%GK-56^$b9rgW}3!Q2QF>eQ<6CjkYk9Wag$8mn7zbx^LhD0W{(a8V1la zWB~OaAtPe>2zETAdBc#BqYG)XgBYcGpyocvS;1T_*g=mlxx!%J&WyA@&|O0@tn5h4+vS^-Lr z5Fv22267LQ)4-jOyu{p8hNRNWoRZ8usCC6~KDe)v3K|+pNzN|?&4hu{8z>Cpp<3W! zS)7?$kOL`qFz0HG3>Y%=aubWQ^(5eAoH>K zIR#XNKq3Z|GCJQ4v7qKMNU~k-8`KgLF);?0S+3i&IH$;AQmVJQd1Z}%-qC+g47fS(D*Z`j}8*bEQ3tnfaTM` z$-!AS88j3JF4PnAigPkc;?s)qbHQmB(({IilqBUq1~x!yO7c-vl;p>QZL%QuE3{Q_y*3;4Th$fHyU-EVC#-j{%Ycz{#MPp(r(77v6mW zadPuhGSf0sK@A~rJ&}|Nn#4%gg}S>SF&-=o;xd$_l|%F*_n}jZia-UuUOoe;mmUuq z69bhW$Q)2sg=z$6C2+N!nO_d=9hRr3=0SQF@E%t=s5UAs0JXOetuzn|T5p3IP@pCU zxON7&67oP?aFYb81k}m_45{BgLt5&8lY+%%7)5-Mrczq zK|us%#g`;z=74AO$_hXQ9JDr0F3Kz@iHA=7fqHfosmWyppam?TaXnC71WG}mA&%ns zl;RSG%;NZxqEhg$#2B zpinMK1&ztVR%B%6rR$k8Q zD1)<#D|12J?=sLxU;nU+0gzf$44O~| zP1-Ry>n7)eM#Dk51H>v$EzC_~fU?Sy8H!VKz#ZLu1_&cQB|ozSB$^9yCdkP-U=~!o zqzK;8LiDpBaRe%OKojg~nV@9>;1&r(L2`V4S{kVFU634K463df@`@8dt&w7ed{848 zv`i;IF}Xy~5EM#9rFkGhu&ugK`$5UR1U@YV8R%vJO(cNg1T>2T&Qu5$MX8|B2QT?4 zElP#uB~()&Y8X;-z;iyJVfXCRB9H^Xfemi@7f+!1yObQ5OF#|;^}$PE zLjx%}x@C~W0yZ0(r*%^@i&B$8Yok(fbRmub>r4R+p@T9#D9wTrY&>*Q(bdldGJpn} z^99eNFvNqJcZu47pE0K2e=V)R*>c%!i;$ES^-cl&I2{_D=f_7i!&07Qd8pd@*&->e9(+aNk&m> zaRy{T9=ICKEr>5JPBj8eMP?Sqm*#;Q7Dbt$nj{`Pugd@)7XYWj)FMzLGd?%JC^b31 z2s8)*>c|&V#wV6lm>L?z=jF$jfd+ZO(}4`}pzciycvbT*-hEFPKrBT2cxM$l?qJ@GLB-ItB%KNh;VH@W5JT9>zR9Cpzc z2wuDhN>tzxFi_kXF~q~|L5f^Zp%R~1ln$E82aP>tf($HS%s;`8z$(>3rFW?=7^=7D1ZGHnJKr6@>Ej!(%f1C_Ex@#$rW zMj2&^AXkE`4N!!n<|Y?Z#)EPS_QVHWp9BsNP`Qv4pIQX!_a*1&7Uad} zmgdCgffwk2nvmegDNo4<$2Vw%8@?PlKC>7+3z%05T73)}y~#`gt4;&;q(N4|mNr1r z0;r=3Zd!vCf!fHRaxxn{@12{Pn+BTq%K-%$sO40WpMr>*;*ym7QcxZ)PAw@0SpuC! zgw7#?&4VQis7pchHfY>BB{eNRqclCWBqs?nyH*8SS)Gznl4cCHxGWd6@B=jG3`qbb z`K38I@i`3fplS9BaQnL`wXig^C>1n#o|{<=N?y=NC`dE{_x?eF2OUC8EUSnw%>xg$ zf))!EmmE?jQ2-;0rha9F$gJMJpJQAJ@k_J za(F3G3>oDF7gL})518kREAv2UGdDFCG*TI#T9%6B9OM`QuML9O2Pw!P zD?sCJC6M9Wl>AcAT1QBq1~hsM_cUa|EMz(i)Un4XGb*49Iz9ct!#I#tC*W`g%}K|n z6z7A73L(vHkloO_%yMo#>d7$o5UKw;H3R1}psyv`o zNNQe5G1woF7GG*SWKJLCg@U|z(Byx7JY--PQln(%g9mGp%Su3fS-pQb~SxJft#4REv#WfFMxC1~vlC}zQx4a~jZwpA*) z>&p-iZbFza#Di3UOZnVlP$dChtp<%s&~QJrOo#U$(?IRR+|*o9szEJ*;voeZtfdDT z$^w=4pb2kKzDAUtpe7Au27n;sTBnb@$sM}16p$rSr7wRPMwjMlLk(4;93`wiXi=Gs0OTQEFPi_G@uC`;q-Bi zhmIS9W&%OMkXBMung<%#1cfMQBLO&tq=EV$W}vMeIhjdFnG;gULD&3%#->4C>v+i8 z60k<_B70B@hWItNpeVm2HMs=rcJL}akiC#(Ra%@1*+`L;nFwhaLs}E@NubqFdFh~K zhM=$jc?~T*z{Wvl1mKAio+=?rXd%r_aMFVmf1q&<=+p&6Q4)BJ4CGF5s{t~b3~Qo- zCV-2;s~kZMT2Sv56!V~>wj@6jv|tCRd5uylK~oQ+9TSwAo|&H)46VGOT}#*~AFNxN z3F?S}M+QJG4sa+!>ax_-Y*3>Mv^pvtlpjDzxg1oUL)XP1CAG|w{6tXi6cnTIx)s#) zN3?~&9))-UytM~ZcBQ3&;u#e4(A)s>C{hv!HSQq`^D;nD6c3x!0#($oDM4^tz>4{_ z%nER)C_S|#xg6vePzV-Og6nxuXs70aswhxl3u$#gg9^U38>9v{B?xZgfb_#=ERv>G$@CIW(mMC2C^FDL2#J@O7h?#e(*?HW=aJpxq<2wP?Hig zDw$YT0SXxSG9gea#wgw}9@5l{hjd3kgJCI|MJ1K-pan#rU_on9f~KfJ1Hd4ULE68l z4KPsK3w5a~sI>!94QuCu69hQ2Kzm|99tX)nD+ow&nwe4p>#-C=+yzn=pORV(9^cF_ zg4APBAC}~UHk*JtkDzG?aEB4n@B|e{po%jdQnEnGA8_<$WTt0;R*M#8=BC1zQh|p= z5=+3PL`rFa5ja>enmC}PUpWkgphae&#GGH8SpljGzztBa*C6YEKvS=v2~WtvnbZ_W zLQOL^0;K{_K?)uNfz?bo$i*yl1`aY`2A;SBwY8u_ozUiQN)D*gn4Asq6S$HBTV9@$ z4{LORS}))YFW^{A1SQ_`J~=z^0`^>N`;G1sMX%A&~YO zD5k;H1b9#!RP8X7f@cy^n#qk5>ST{)LsH-1#sgV)Dr_IAaIKhtgs}f7!**T_2rPsFi>2<>usny zPyhJh@=VZlENK26)Dq9lPXP@rAg|bf)k~=bpp~@6N#Md2WfTLRt@HBpz%5ebF0r$l zBX~F-G}}^|mkdg}&{_vP9|4-chio|o^Q;-** zQ=E~R2I{eanw8*nxS$cd__Un-#1caz(Edc|KnbKp015|CT!6w1DiY%B91k7Pg7x+w z4HQT!g_a?pRwZPF2egq3>_*5QJunmI+~U*{P|p=q#uS(4fl5zEbQD#B{Fe_ZtYGm{ zl2Z&_F$s$N)DqDA4W#0Thl~@$h7mv!18ymRjRN=hGxLf;+v8wOR@mM|SSXS*pg@Cm*+3;IqKbf4d3ibDwq7E1U=cDn1243|c{d)ka}C}E1I;6YLjcl8 zLX@)b1uxJN0>Up&E&@#(z!rRhVgj-y0Me8Owa{SYb`EIp44R%$#UUj+c!&fXQlMx7 z51+>)RwKe^oIrIH#MhwYk6LJh5&*dV0;ffA3k@9S;9LdOm;_qu0x|$nj)S`Euw{@) z^)|?XpsK4B)NHQ+Wpa=fXh`F*6x412jSs?RaiFCKtoDO0%LR`efSOOBH6^Lw90FRw z4$=%AJO>RcNQj`fAhbe$G&EktQ(;=xKJ|zc~I>Ge^Y$_g>F(6GsuvBhwI%r}(9#o@% z8hfcFX`swiTv7xsQ9_t zL7#@wpa+j@gI0g1q=5883#9n;)S}$Pyv$^HI~cTVAhQCr!n-^V)M*5DPl_|sp?(6j zD!_}FKs8PpsBP@&9}jI=Wafbeq#^kbQKZA87F4!Fb3J%zQaq$J3W_7phWp}FBSg*w z=Xz-K8#KmVln)kxtf_%?jv!$KUcXjcoC<1Mfzl&*JOR}8i%$ZL3?rNi>3igZyZ)fv z5wO+upy3wCm@%Z*&H)Whf#zdD4K7f$fRX^pfD6=O&|nF;A_P~hplz>+=zuR50QG3W z>sI2+i$GKOkj?{iV0 zW}v-X&?sneKD3Dj4Ggp@2NEL1sh|!ZXdXNtv@`)VK0y;+pe_J-xqDtQID>=B_<~Z9 zP*G}eF=)d!cX_@Jz;N5qyS{Iavz%>mdgM%6%C7{hunV?N^i7EMcImlyx zkZt8)x2I$lCxhyi`21q%{1qtpA){!ZBp+`GRt6d6M@-bfoD3>jFOWJ|>jl)h0>uh=YYwa>2X2v-fHqNq8u5^L1(lr; z#VEBcc$*?}>o~6x6!4H#4{o1;>uqEeIXMs&DLIgsgqEqGW_uCnGz;j66|`{=iD&2% zQc#hQ3+e-d(mbqj4-Su#;uOfrwfGQ!AOCRBLNRDR4epQl(&S>JqEt}6MC+~~B_n7n z5Y&GI%~gZP$shp$UK0#17$7+aKCA+YE3hOigM&&DP$Ldh)gbCeaCyQI?^*$Bm*&Ab zl%TF*Vh-%k3$V`I0`Tw!bif_dfP(gqiz{=J@^j)r!vvrj7}81tSpq5Ha#9mP8%DtE z$snPYQw*xG<5Nn?z^lc;y+KeN3DE;?M8Rej5d9F;`V1V{`OvvWR4M3Wa%o<22?O{% z5?HE(uYd%3E*tC=@U#vnqCssSP|GC~)PF0^OwR(%Ehm9oIs|5>ICSZF|>#U)g+La(q!0~ zBA^9l;NUFCF9xr~jE9D2d}&^OQ3|99=%A<#fl$s7&WB?oHPeJJwV9AA`=^>;oc_}%d7>P$J)*v++G@R2?6H7qr>cOYNfci2Z zpMdKtXy8EhEI>w!K+Otp&=i&AgWB2PBninh#U+V(DTzg((;Pri2F@t)&=x5u>x1T% z(?H&VEf|0-r-w}cA=;xz^O=c7C9p<5WJ?^#=G2l*P~w6&a#8YdJmdtP6mWdP$L68M zHY~J3=kLte^&|oRNSOWVBRHT9r3IMeUrKM&HEKq?KugIJ)GCsL8SAn>s=NZiLKgA+NdE-22(FV9WPs|1bP6sMLHK-%q~ zMr%wlvIKp1F);bReqAvRF664VsPO)LP{I8gVd6~yO2W+OnZg3Qi>Mg>6OhFXt+JqDU#1$EUR z+lfINb6`^`h|CU25TJ?*ng~I?1JJZLxXK1q7O2%WsIUb0OF_W_Q43m7kqs&hvq5D} zDtO@?QVvH%CZwwg%1xlAHrTogaI-w5YgVG^*zzw_v88of} z%g~8M>1ALa!=o}aHM=0c7%3qmswr^Pzy|DKvuu!p10FfhE)FQG!H3Wxs|rBfaLDRW zxP%M%BotTpF&eOz2bLHHwa>v01$Cql6D6qA$>4DhXsMZ!Sp-S|uwou*as*a$f@YqO zTUwBjF4PS^@InZ&Ed_MC3TROztjm-K8ZOOFjn6SO$V-D{YiRibEn7gN2qi_}3KHD0 zM79$a+wk~9Ol#!j!+OH-20g4QfwwqdYk|QF3lTFhMhx*Ksd?a1HYYPT2^?;a#w#p1 z5Q!Vq#(1}3Zdf);G1 z6=ddvOWXK@{BqDSm7f0bpmPbqi5yfOf_g@vVGnS{4v$yl8Wg&-xHJzmp_rNi+2{;u z>p{1egKIQU5djIn_~Z<*=Ru8l&|Yp(rw3#e$mO6>mb4V;x)abiCny{;iohe?(CiOM zps;~#=*CqfrQmW1JbnPKTR}kqYN3OUj{{XaV4oFN7K1$m9Z*lsNKFAnA-Kr{%Atr8 zmJlT!tXTuR+UQI_?>nphH`sb6ucJ0d8J_G6OV4qporW9Zv*35esyz8u;uFQ2hm2oB;MXV*CeE zftMvh&%eOZgDFleNy|wDFINFICty8zXgdO)6XSEhi|fGUEO@~uXj-=zw6qS~eN9g- zDS~W90S^a(*6pU`!1wBc>P*lP3kBeLX;9$=pFM?ELGWG(Y?mJ>>L4{SBzTd=^S}q> zfvO`EZ-Ns*8o0p>TAKh-Nzk|yebrQa0_&b2AtR+(?Xzw!b%dsc`Bo_AhifILC+8$pP8Rr0`F`=>RFI8 zz_!BOQ3PGD3^opw!w?6ULPq640R^kdi&Bdbb8lcBka^$oWCl>#QIrT;m0kv#_yujy zDbC0*DuK*SKxVhVMH;kC3LcaOrAx?Zp@~K5;L--1c|bE+@Z(p&g%PND2Cat&HQ3<; zB#`CDU}vB^9O;Z#SX&5O=EZ|otmfr|%mTFub0Dkh;lTn@gs4eC&V%<=$`GTZ@Kg)h z!Nr|-d z9#l7hcanihoJ`0DzIf2O`6_5-5D%G&DK04jZ}I@;#GGRAz+HM`0VoxNY6{3M3KUO5 zstfR<6ZppS_;|!&NubKKC>7etL0jku3OZ1|1_8l8Qhp!@%28 zV08o1BpfK`I)f&hLC3wpmUMzLFG?B*rN)f%I0V=WLi(!=;m{FPonhFCIL?D%zu>)%Mq-BCK7V_{CI8#H{ zL?NeAaHxXvcR?O#zAGLwwS` zsoPru8()R4PD4F@71Rd-`?4}K6}*rRxin^o&n(F=PmBlmnIXe}kg*9^&}V|rYsv$k zK91~Z_^1LnlY%--kR690|3cP{fyxrAogvf<|GyrgX+_~9MBQVpxH-AA0Cnq!BrJ_(K5!=HYf*ynhj9T zfND>a905J`1L6-*H3p8}c-ZbnP*(};1yD?vLXQFhmFPv_Mlhn=1uH2ao7=&81-h98 z94Lr3JUFL7U4`6L!`c)8MHgCZfksR~;ScLcfIF^W+jH`h^OLe5wP`YFC44ccsfXOl zfmh;YCXkj_Mp>d!dI4w@2~skE42B-M09lp}j_$lXP>}*&tO42n1#Zef*OfpMVK8W$ z5U5H`1)aPMF8?9Jxu9uPh<8(RK!@a~Eict)R37G?xmAFmQ7XH0uU;KzwOQngzHFgcXXV z&>;(uyFg6>NLYZD_2eKmvcY|NP-_x2cnY4!FD^}j#6k&ZoV5V5e;F(S$@}1u3kGJgMA4v>0x7EpgI+@Tr(*-9=w4ST*!bO4(eH@r{;l<0nP;XNFkvJnv`Gw z@0J10FG1#SA?lGQ5-Y$*kbzhe4$i zXz3JqM6WCtvLgVrPy^ijjW5myhZC$UfTm^CEy+rS5%S%>cBxpATx^~8(rWtYOuw1pf(0{pM801Vm8RRpw0B4L(4(4Jn3nm zL{fX{meMHy0A0%~#~1rD^|3tr(84@+>Mem~MI2q@wq;Q;SFqInuQ1B1K+I`W|; zH5VKeDa9r6kftQ)7~SI3B5*qlRM5f>(FFx*JoF?t@V040{Q;3evJFuOK;{CAl3*P> za8U}Xg}|u`vTqDhJA&(B@LV^z+yXUk5z9Icwvk>$_A~I1GQ!I zlfmOKplSnL#DT*SI#2`-3vkW=jdg%pY?;ZRxhGhe2l5^$sX+D*gU{~AzEB)gRe&p3 zP}&8jcJM$4to;fq&%rynKut@SZ(vCi)DtcO=T@-Cz^yA^Z?`MK{MHeN-7o`^DfDT*DgDgabq;1qSqv=KY<)D#>;?yG0{0VGg z65h-~ZpMM9vmx;Zb|bXRfM*{_ng&;opo$1G3J5z^5Lz0>!w)0_b$%dyGtgQg&~5-o zE(N7Ta5O^>BLTHu!EpyJUs5vTi&Kk0@dR>5X%1*RD70Y?(vt{YcMqB^gAOjG6obZI zKvfW^jsbT8Kzr4Z&enmZW5_lwlocr8ED2wU1zAUsm;;_5#TbVNr!>%VWstL=yAV(o zG=WC6a=^n(pyXEoZl{7v5O7HaE|Sxrn@M3k1Mm6@b&zCCH{PZefeuQ7J z8oQ9Lz7cp(xVR(*bmA#|1{5?Y30g-8D$ziVWl%>AT410xGO*<{@Iku}TR^R6Q2zRWw0gbZ9r-2H1P}2}JvkDo=h3wdZ9Iy{9G9bq& zK$anb(@{=JJZN1sxIhQ>9zdfvpcXhRT)>@maCU%=SV7yTptK5Vk0A|+f(I<2T}7;!E=~z{k0#AWw2ay5ni!+yy!lq5$NG_%y_zJ+wyvPRh_m z5Tun759xs+6%gRDV9@PdkTpjj--7)Iij@2!XgL509BAhbl2<|U5aHa!ih_(vP$df~ z-9R#+&JtSv1WpE^vH)5NLAJDlvNvd=Hw|v zvBM2C#|+9XAXkEhYYHkMcQS$FI2RVA;JgHFqom}3msoy!6t<^wi*j)a1;x%w!kv^;V#C zmf<{70@{3YHLtL=aRzVdKI6&deFHjc z^T20AA~$i6x2}PbS}rJygK|9b=6Z0o4r&uak0Al?1OXs3c9c;*Pa{tFaWsU@YLQWCu97rYV_KF|m& zZ;-BgVu()#&98t05qb(cD3d^<4O&Yf8Xk}=3)|)b>9vEZHAqhYd3On{1&mlk1*y3} z2^8LG14S%obr(|W0X(}0DT=|>E~vnaFU^A=e^-_YIz|he-r(ECK?M(N_y#)QgVKCW z0j)6v?K?&cUx9YE!ZHkE6a>$Z-Imas?DI z*mE5GTqmSG#o&cZu-+qRMhv{-rXarnTx+Ccf-)n>C5ScbkO~phqslD+H5ecbC-8O~ z$kYX7SO}%T2${qOx5vPV0&<}as9c65SkP1m`0yY|moz@U1T<6t4tVG(_K@%gg#&1@ zUmCc91InvqsYOZopbUkyjuh6Y2Fa(u3OSHvh;jy;F`*4)@WusDZ3{jQ3bf@CbRrRW z93I?F0&il@NrIfwfLQhj8F2uOE#)SbAgx;~NJlxh z1l?H!s@)(*8$;VYkc10KorXq8r$oWx7uv)@za|LUAk0lIE(R^`hn|FhQkj8zC5UC| zAWuSuCP5uDh#Mhm5+Pfm5qpO~B^zQ0KLv7|6};*V2HhD4%6FinnxTtlAjtsSWC2w; z@LUGk8ejq%&O>enfSakHsYcLMAfP5FD7rvXIjE;@#OK0ByTKI%sQd-5QHl@o4-EjH zSPMO=I398d4mfMT^CQ?Tkh82olg&tVCanEi3`$AR^=6Qi37WJ6|0eIsOw2~J* zkN`SlEvYySe%dOyut)L;D4!sj&(Pci@))Q90u`vR^a<(`g8Gi&lnLnrg4^kk>1CI2 zy`t1KJy63U8FUmB(gkBscVgKi7!SQM1)>7f-UXH8u+lxVI6v9aG9Gdb3plGm2XbJC z0)u89VJ3jG`ACr(!s}afeW_8(hBH!NlH#Uc<>I? zbOUWCNlb~ywp|92;*E_!E1RHmPM`u6(fWY89WoDxT0Mfo58S1O=4$XV2k`zi@Ks{a z+zM%Qffh@H?}-JEbb<#|A!#42lmm^Z!;f`N%mp7C0&Yz(KxXPuhSNdqAhfl@pb@Ni z=vrZLTLpTCG(1H@T?Lvk0EZYT8-Qz3sB<9OPQd98JZ=!51L_filL)9wfjmf1oS6<< z8w%NV3*Qs~X+J|JJwfFRwEiecEdZrxw5|KdXB;33I!M0&G!zcXl#oLcz-b@qNbtY| zq*efxE}(RV-uQsJI3+U=HXQ-!rhw`XjM#-WQNUdTkeeYRz=+{N@TIKqb9q2pOHtPB zL&s1-g(#>KRsbD~N5n0BH!MsDvUwa_o9C4jgL)t!pTa6%NT!E2zrYt}LOl*`C_v=% zKu3k9C4x?khmDs)I(4wh6|yuGy!islsW*`N8(M%vCjUX(H9?v|BU1Uv+2AvgKyzo{ zZSBP+pqm%K;R;GL@Y0nb9yH${4;ea0EWx(m1e9k%=7RRyM`(W+)K7rkh5{;n^Yh9eC;fwmtwBRtpj{W>gR&rX4`@|IVQFS^HfX#PUPHR4 zmVi2=urVq`YZjc{K_ejG@B{VW!KD~-)&{llK^;uctS7YQjV~&NERlemzzVJn!Mndf zL7rL?kGRhZ6dT}n8CnAgG%5$ZIT6&V0OiNrg7}QGM9}e$;9vnYBtaXr6G8V5fc9(^ zL5^q!72=Q~@3KVDx*AYZ22`IzybnG)40J#os6dA01f<R{WFz$aWnsz0P2 zBy1iXG>Q)n=FGed@cK{i$>j{-4Wp^><~34^MoM5v%TGbYQhr(r=nzSy+8LC!(!kTU zh+GIcOcb2eF?Jz=!v=MX0$kgHLJ+bX7BU_l59+vsW?dl@JK$6a&ZeMVCAfzJ?%hCF zvp{-*(18fhU$=KGXrKh(V)Juq9ZK zP)3{FWGDh%AApW{(*imO4Ae3JS1aHu1*tm$ZD+tUHR6_G zNX#R(;n1czz!gG4d_LsVZm-iv~bli%iheEi@}Z zuXSQz&?~OYElEsb&;#`iz;p(T1-?xoJ+D*`bOSDUgM}Vk2(%6>MK?2r0V3q+Vtuc zSx|xn*Yb&w^#^(&`=HSXb9g~XQ89xa=-OJ))+as4Ua!QW#Ju#>Vg@J|TsA@3iAhPI z?bJ{n=!7*@^1_6kGID~?eAiLlk1_p)@H2o4#{Sr|9 zCy*5**$)$rN7MfRs{a90{{=B_m{Kr}9v-P^`ZuV1gVk+Nhv-Y=0(0R6)L1yb98JH3 z5k$X)5kx;HTqT5o?*Ce-erPZ=FgQT;GdMu>mngtxzy_eZzZFe?MS?F_T}1*fnD%)N zrr-oD{$K+AX!?)1`+=p7xbuN&0Z`nCqVTlK=p4ig-Spv^zgWhreC5T5`Gf(AYU;synyP1Q80U9{2OTc z874sVGc-W-KY%HO(lGrn`XQSB2T=VFp!yA@pcVkc2GWy0);h*4Wq50`axpI_yW}Z z8(-aV1G5)u977lm{rz!*U?m#vUrcU%H} zTEPr-{RL3{=;7CuDg;)aZVRU11WZ4Su7>J|D}XXSE`sP!v&QfLHXQoH?}>m-3IJ7* zU>1ac*$d%8(k`kE5SbO`qF{!{6EMY~%)r1 Date: Mon, 18 Apr 2022 13:00:58 -0700 Subject: [PATCH 0346/1436] KVM: selftests: Use vm_create_without_vcpus() in set_boot_cpu_id Use vm_create_without_vcpus() in set_boot_cpu_id instead of open coding the equivlant now that the "without_vcpus" variant does vm_adjust_num_guest_pages(). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index b4da92ddc1c6..4c5775a8de6a 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -82,18 +82,11 @@ static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid) static struct kvm_vm *create_vm(void) { - struct kvm_vm *vm; uint64_t vcpu_pages = (DEFAULT_STACK_PGS) * 2; uint64_t extra_pg_pages = vcpu_pages / PTES_PER_MIN_PAGE * N_VCPU; uint64_t pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages; - pages = vm_adjust_num_guest_pages(VM_MODE_DEFAULT, pages); - vm = vm_create(pages); - - kvm_vm_elf_load(vm, program_invocation_name); - vm_create_irqchip(vm); - - return vm; + return vm_create_without_vcpus(VM_MODE_DEFAULT, pages); } static void add_x86_vcpu(struct kvm_vm *vm, uint32_t vcpuid, bool bsp_code) From 4acefa385c8233de756b450f87188ebadf3a3591 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 13:02:55 -0700 Subject: [PATCH 0347/1436] KVM: selftests: Use vm_create_without_vcpus() in dirty_log_test Use vm_create_without_vcpus() instead of open coding a rough equivalent. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/dirty_log_test.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 9dfc861a3cf3..13962d107948 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -674,11 +674,8 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode)); - vm = __vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); - kvm_vm_elf_load(vm, program_invocation_name); -#ifdef __x86_64__ - vm_create_irqchip(vm); -#endif + vm = vm_create_without_vcpus(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); + log_mode_create_vm_done(vm); vm_vcpu_add_default(vm, vcpuid, guest_code); return vm; From 3c16181b2652e4e99b478e2c0251aaa24a15e695 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 13:16:32 -0700 Subject: [PATCH 0348/1436] KVM: selftests: Use vm_create_without_vcpus() in hardware_disable_test Use vm_create_without_vcpus() instead of open coding a rough equivalent in hardware_disable_test. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/hardware_disable_test.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c index 81ba8645772a..76f51afa7ccc 100644 --- a/tools/testing/selftests/kvm/hardware_disable_test.c +++ b/tools/testing/selftests/kvm/hardware_disable_test.c @@ -104,9 +104,7 @@ static void run_test(uint32_t run) for (i = 0; i < VCPU_NUM; i++) CPU_SET(i, &cpu_set); - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); - kvm_vm_elf_load(vm, program_invocation_name); - vm_create_irqchip(vm); + vm = vm_create_without_vcpus(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); pr_debug("%s: [%d] start vcpus\n", __func__, run); for (i = 0; i < VCPU_NUM; ++i) { From 47b1e0ec2e1460b25674ba947723052919da7e67 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 13:16:39 -0700 Subject: [PATCH 0349/1436] KVM: selftests: Use vm_create_without_vcpus() in psci_test Use vm_create_without_vcpus() instead of open coding a rough equivalent in psci_test. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/psci_test.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index 1485d0b05b66..c9b82c0cc8d5 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -78,8 +78,7 @@ static struct kvm_vm *setup_vm(void *guest_code) struct kvm_vcpu_init init; struct kvm_vm *vm; - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); - kvm_vm_elf_load(vm, program_invocation_name); + vm = vm_create_without_vcpus(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); ucall_init(vm, NULL); vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init); From eb0adbc03aafdb3dd0740eaaeb26051fd5e35c20 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Jun 2022 10:19:01 -0700 Subject: [PATCH 0350/1436] KVM: selftests: Avoid memory allocations when adding vCPU in get-reg-list Open code adding and doing setup for a vCPU in get-reg-list in order to avoid the stack allocation that comes with aarch64_vcpu_add_default(). get-reg-list doesn't need to run the vCPU, and so doesn't need the guest to be backed with memory. This will allow future cleanup to turn what is current vm_create() into a barebones helper. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/get-reg-list.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index ecfb773ec41e..b2d1d2eaf1d3 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -418,7 +418,8 @@ static void run_test(struct vcpu_config *c) vm = vm_create(DEFAULT_GUEST_PHY_PAGES); prepare_vcpu_init(c, &init); - aarch64_vcpu_add_default(vm, 0, &init, NULL); + vm_vcpu_add(vm, 0); + aarch64_vcpu_setup(vm, 0, &init); finalize_vcpu(vm, 0, c); reg_list = vcpu_get_reg_list(vm, 0); From 95fb0460719721962997d344bf9d63812c1dab67 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 16:26:06 -0700 Subject: [PATCH 0351/1436] KVM: selftests: Rename vm_create() => vm_create_barebones(), drop param Rename vm_create() to vm_create_barebones() and drop the @phys_pages param. Pass '0' for the number of pages even though some callers pass 'DEFAULT_GUEST_PHY_PAGES', as the intent behind creating truly barebones VMs is purely to create a VM, i.e. there aren't vCPUs, there's no guest code loaded, etc..., and so there is nothing that will ever need or consume guest memory. Freeing up the name vm_create() will allow using the name for an inner helper to the other VM creators, which need a "full" VM. Opportunisticaly rewrite the function comment for addr_gpa2alias() to focus on what the _function_ does, not what its _sole caller_ does. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/get-reg-list.c | 2 +- .../selftests/kvm/aarch64/vcpu_width_config.c | 6 ++-- .../selftests/kvm/include/kvm_util_base.h | 6 +++- .../selftests/kvm/kvm_binary_stats_test.c | 2 +- .../selftests/kvm/kvm_create_max_vcpus.c | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 29 +++---------------- .../selftests/kvm/set_memory_region_test.c | 4 +-- .../kvm/x86_64/max_vcpuid_cap_test.c | 2 +- .../selftests/kvm/x86_64/set_sregs_test.c | 2 +- .../selftests/kvm/x86_64/sev_migrate_tests.c | 8 ++--- 10 files changed, 23 insertions(+), 40 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index b2d1d2eaf1d3..5476bb465b78 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -416,7 +416,7 @@ static void run_test(struct vcpu_config *c) check_supported(c); - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + vm = vm_create_barebones(); prepare_vcpu_init(c, &init); vm_vcpu_add(vm, 0); aarch64_vcpu_setup(vm, 0, &init); diff --git a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c index 4145c28a245a..1757f44dd3e2 100644 --- a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c +++ b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c @@ -24,7 +24,7 @@ static int add_init_2vcpus(struct kvm_vcpu_init *init1, struct kvm_vm *vm; int ret; - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + vm = vm_create_barebones(); vm_vcpu_add(vm, 0); ret = __vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); @@ -49,7 +49,7 @@ static int add_2vcpus_init_2vcpus(struct kvm_vcpu_init *init1, struct kvm_vm *vm; int ret; - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + vm = vm_create_barebones(); vm_vcpu_add(vm, 0); vm_vcpu_add(vm, 1); @@ -86,7 +86,7 @@ int main(void) } /* Get the preferred target type and copy that to init2 for later use */ - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + vm = vm_create_barebones(); vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init1); kvm_vm_free(vm); init2 = init1; diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index c46c03750043..c119726ba018 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -248,7 +248,6 @@ void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size); const char *vm_guest_mode_string(uint32_t i); struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t phy_pages); -struct kvm_vm *vm_create(uint64_t phy_pages); void kvm_vm_free(struct kvm_vm *vmp); void kvm_vm_restart(struct kvm_vm *vmp); void kvm_vm_release(struct kvm_vm *vmp); @@ -596,6 +595,11 @@ vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, vm_paddr_t paddr_min, uint32_t memslot); vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm); +static inline struct kvm_vm *vm_create_barebones(void) +{ + return __vm_create(VM_MODE_DEFAULT, 0); +} + /* * Create a VM with reasonable defaults * diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 0a27b0f85009..edeb08239036 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -221,7 +221,7 @@ int main(int argc, char *argv[]) vms = malloc(sizeof(vms[0]) * max_vm); TEST_ASSERT(vms, "Allocate memory for storing VM pointers"); for (i = 0; i < max_vm; ++i) { - vms[i] = vm_create(DEFAULT_GUEST_PHY_PAGES); + vms[i] = vm_create_barebones(); for (j = 0; j < max_vcpu; ++j) vm_vcpu_add(vms[i], j); } diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c index 9de5e1376c49..acc92703f563 100644 --- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c +++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c @@ -28,7 +28,7 @@ void test_vcpu_creation(int first_vcpu_id, int num_vcpus) pr_info("Testing creating %d vCPUs, with IDs %d...%d.\n", num_vcpus, first_vcpu_id, first_vcpu_id + num_vcpus - 1); - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + vm = vm_create_barebones(); for (i = first_vcpu_id; i < first_vcpu_id + num_vcpus; i++) /* This asserts that the vCPU was created. */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 8c0310094d73..50e50ed5f636 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -258,26 +258,6 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t phy_pages) return vm; } -/* - * VM Create - * - * Input Args: - * phy_pages - Physical memory pages - * - * Output Args: None - * - * Return: - * Pointer to opaque structure that describes the created VM. - * - * Creates a VM with the default physical/virtual address widths and page size. - * When phy_pages is non-zero, a memory region of phy_pages physical pages - * is created and mapped starting at guest physical address 0. - */ -struct kvm_vm *vm_create(uint64_t phy_pages) -{ - return __vm_create(VM_MODE_DEFAULT, phy_pages); -} - struct kvm_vm *vm_create_without_vcpus(enum vm_guest_mode mode, uint64_t pages) { struct kvm_vm *vm; @@ -1421,11 +1401,10 @@ vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva) * (without failing the test) if the guest memory is not shared (so * no alias exists). * - * When vm_create() and related functions are called with a shared memory - * src_type, we also create a writable, shared alias mapping of the - * underlying guest memory. This allows the host to manipulate guest memory - * without mapping that memory in the guest's address space. And, for - * userfaultfd-based demand paging, we can do so without triggering userfaults. + * Create a writable, shared virtual=>physical alias for the specific GPA. + * The primary use case is to allow the host selftest to manipulate guest + * memory without mapping said memory in the guest's address space. And, for + * userfaultfd-based demand paging, to do so without triggering userfaults. */ void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa) { diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index e66deb8ba7e0..c33402ba7587 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -314,7 +314,7 @@ static void test_zero_memory_regions(void) pr_info("Testing KVM_RUN with zero added memory regions\n"); - vm = vm_create(0); + vm = vm_create_barebones(); vm_vcpu_add(vm, VCPU_ID); vm_ioctl(vm, KVM_SET_NR_MMU_PAGES, (void *)64ul); @@ -353,7 +353,7 @@ static void test_add_max_memory_regions(void) "KVM_CAP_NR_MEMSLOTS should be greater than 0"); pr_info("Allowed number of memory slots: %i\n", max_mem_slots); - vm = vm_create(0); + vm = vm_create_barebones(); /* Check it can be added memory slots up to the maximum allowed */ pr_info("Adding slots 0..%i, each memory region with %dK size\n", diff --git a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c index 7211fd8d5d24..3cc4b86832fe 100644 --- a/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c +++ b/tools/testing/selftests/kvm/x86_64/max_vcpuid_cap_test.c @@ -16,7 +16,7 @@ int main(int argc, char *argv[]) struct kvm_vm *vm; int ret; - vm = vm_create(0); + vm = vm_create_barebones(); /* Get KVM_CAP_MAX_VCPU_ID cap supported in KVM */ ret = vm_check_cap(vm, KVM_CAP_MAX_VCPU_ID); diff --git a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c index 4dc7fd925023..f5e65db9f451 100644 --- a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c +++ b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c @@ -95,7 +95,7 @@ int main(int argc, char *argv[]) * use it to verify all supported CR4 bits can be set prior to defining * the vCPU model, i.e. without doing KVM_SET_CPUID2. */ - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + vm = vm_create_barebones(); vm_vcpu_add(vm, VCPU_ID); vcpu_sregs_get(vm, VCPU_ID, &sregs); diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index e814748bf7ba..245fd0755390 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -53,7 +53,7 @@ static struct kvm_vm *sev_vm_create(bool es) struct kvm_sev_launch_start start = { 0 }; int i; - vm = vm_create(0); + vm = vm_create_barebones(); sev_ioctl(vm->fd, es ? KVM_SEV_ES_INIT : KVM_SEV_INIT, NULL); for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i) vm_vcpu_add(vm, i); @@ -70,7 +70,7 @@ static struct kvm_vm *aux_vm_create(bool with_vcpus) struct kvm_vm *vm; int i; - vm = vm_create(0); + vm = vm_create_barebones(); if (!with_vcpus) return vm; @@ -168,7 +168,7 @@ static void test_sev_migrate_parameters(void) *sev_es_vm_no_vmsa; int ret; - vm_no_vcpu = vm_create(0); + vm_no_vcpu = vm_create_barebones(); vm_no_sev = aux_vm_create(true); ret = __sev_migrate_from(vm_no_vcpu, vm_no_sev); TEST_ASSERT(ret == -1 && errno == EINVAL, @@ -180,7 +180,7 @@ static void test_sev_migrate_parameters(void) sev_vm = sev_vm_create(/* es= */ false); sev_es_vm = sev_vm_create(/* es= */ true); - sev_es_vm_no_vmsa = vm_create(0); + sev_es_vm_no_vmsa = vm_create_barebones(); sev_ioctl(sev_es_vm_no_vmsa->fd, KVM_SEV_ES_INIT, NULL); vm_vcpu_add(sev_es_vm_no_vmsa, 1); From cfe122db3ea6908d44f51c239fb1f1608e71522b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 19 Apr 2022 14:16:34 -0700 Subject: [PATCH 0352/1436] KVM: selftests: Rename vm_create_without_vcpus() => vm_create() Rename vm_create_without_vcpus() to vm_create() so that it's not misconstrued as helper that creates a VM that can never have vCPUs, as opposed to a helper that "just" creates a VM without vCPUs added at time zero. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/psci_test.c | 2 +- tools/testing/selftests/kvm/dirty_log_test.c | 2 +- tools/testing/selftests/kvm/hardware_disable_test.c | 2 +- tools/testing/selftests/kvm/include/kvm_util_base.h | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 4 ++-- tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c | 2 +- tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index c9b82c0cc8d5..ffa0cdc0ab3d 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -78,7 +78,7 @@ static struct kvm_vm *setup_vm(void *guest_code) struct kvm_vcpu_init init; struct kvm_vm *vm; - vm = vm_create_without_vcpus(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); ucall_init(vm, NULL); vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init); diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 13962d107948..b921d0b45647 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -674,7 +674,7 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode)); - vm = vm_create_without_vcpus(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); + vm = vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); log_mode_create_vm_done(vm); vm_vcpu_add_default(vm, vcpuid, guest_code); diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c index 76f51afa7ccc..7e4df30dd1e8 100644 --- a/tools/testing/selftests/kvm/hardware_disable_test.c +++ b/tools/testing/selftests/kvm/hardware_disable_test.c @@ -104,7 +104,7 @@ static void run_test(uint32_t run) for (i = 0; i < VCPU_NUM; i++) CPU_SET(i, &cpu_set); - vm = vm_create_without_vcpus(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); pr_debug("%s: [%d] start vcpus\n", __func__, run); for (i = 0; i < VCPU_NUM; ++i) { diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index c119726ba018..b09ef551d61b 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -630,7 +630,7 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, uint32_t vcpuids[]); /* Create a default VM without any vcpus. */ -struct kvm_vm *vm_create_without_vcpus(enum vm_guest_mode mode, uint64_t pages); +struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t pages); /* * Create a VM with a single vCPU with reasonable defaults and @extra_mem_pages diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 50e50ed5f636..d538811cf93d 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -258,7 +258,7 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t phy_pages) return vm; } -struct kvm_vm *vm_create_without_vcpus(enum vm_guest_mode mode, uint64_t pages) +struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t pages) { struct kvm_vm *vm; @@ -323,7 +323,7 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, "nr_vcpus = %d too large for host, max-vcpus = %d", nr_vcpus, kvm_check_cap(KVM_CAP_MAX_VCPUS)); - vm = vm_create_without_vcpus(mode, pages); + vm = vm_create(mode, pages); for (i = 0; i < nr_vcpus; ++i) { uint32_t vcpuid = vcpuids ? vcpuids[i] : i; diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 9ec6ba2ad89b..9146d62439fc 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -365,7 +365,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) if (!(r & KVM_PMU_CAP_DISABLE)) return; - vm = vm_create_without_vcpus(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); vm_enable_cap(vm, KVM_CAP_PMU_CAPABILITY, KVM_PMU_CAP_DISABLE); diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index 4c5775a8de6a..6bc13cf17220 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -86,7 +86,7 @@ static struct kvm_vm *create_vm(void) uint64_t extra_pg_pages = vcpu_pages / PTES_PER_MIN_PAGE * N_VCPU; uint64_t pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages; - return vm_create_without_vcpus(VM_MODE_DEFAULT, pages); + return vm_create(VM_MODE_DEFAULT, pages); } static void add_x86_vcpu(struct kvm_vm *vm, uint32_t vcpuid, bool bsp_code) From 3f44e7fdca4eaeed3728d0b898ace5258f9ed474 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 19 Apr 2022 14:21:38 -0700 Subject: [PATCH 0353/1436] KVM: selftests: Make vm_create() a wrapper that specifies VM_MODE_DEFAULT Add ____vm_create() to be the innermost helper, and turn vm_create() into a wrapper the specifies VM_MODE_DEFAULT. Most of the vm_create() callers just want the default mode, or more accurately, don't care about the mode. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/psci_test.c | 2 +- tools/testing/selftests/kvm/dirty_log_test.c | 2 +- .../selftests/kvm/hardware_disable_test.c | 2 +- .../selftests/kvm/include/kvm_util_base.h | 18 +++++++++++++----- tools/testing/selftests/kvm/lib/kvm_util.c | 16 ++++++++-------- .../kvm/x86_64/pmu_event_filter_test.c | 2 +- .../selftests/kvm/x86_64/set_boot_cpu_id.c | 2 +- 7 files changed, 26 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index ffa0cdc0ab3d..fa4e6c3343d7 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -78,7 +78,7 @@ static struct kvm_vm *setup_vm(void *guest_code) struct kvm_vcpu_init init; struct kvm_vm *vm; - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); ucall_init(vm, NULL); vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init); diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index b921d0b45647..cf426a8ae816 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -674,7 +674,7 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode)); - vm = vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); + vm = __vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); log_mode_create_vm_done(vm); vm_vcpu_add_default(vm, vcpuid, guest_code); diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c index 7e4df30dd1e8..29f6ca51408f 100644 --- a/tools/testing/selftests/kvm/hardware_disable_test.c +++ b/tools/testing/selftests/kvm/hardware_disable_test.c @@ -104,7 +104,7 @@ static void run_test(uint32_t run) for (i = 0; i < VCPU_NUM; i++) CPU_SET(i, &cpu_set); - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); pr_debug("%s: [%d] start vcpus\n", __func__, run); for (i = 0; i < VCPU_NUM; ++i) { diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index b09ef551d61b..6418b1c04bc0 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -247,7 +247,6 @@ static inline void vm_enable_cap(struct kvm_vm *vm, uint32_t cap, uint64_t arg0) void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size); const char *vm_guest_mode_string(uint32_t i); -struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t phy_pages); void kvm_vm_free(struct kvm_vm *vmp); void kvm_vm_restart(struct kvm_vm *vmp); void kvm_vm_release(struct kvm_vm *vmp); @@ -595,9 +594,21 @@ vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, vm_paddr_t paddr_min, uint32_t memslot); vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm); +/* + * ____vm_create() does KVM_CREATE_VM and little else. __vm_create() also + * loads the test binary into guest memory and creates an IRQ chip (x86 only). + */ +struct kvm_vm *____vm_create(enum vm_guest_mode mode, uint64_t nr_pages); +struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t nr_pages); + static inline struct kvm_vm *vm_create_barebones(void) { - return __vm_create(VM_MODE_DEFAULT, 0); + return ____vm_create(VM_MODE_DEFAULT, 0); +} + +static inline struct kvm_vm *vm_create(uint64_t nr_pages) +{ + return __vm_create(VM_MODE_DEFAULT, nr_pages); } /* @@ -629,9 +640,6 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, uint32_t num_percpu_pages, void *guest_code, uint32_t vcpuids[]); -/* Create a default VM without any vcpus. */ -struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t pages); - /* * Create a VM with a single vCPU with reasonable defaults and @extra_mem_pages * additional pages of guest memory. Returns the VM and vCPU (via out param). diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index d538811cf93d..ea85e0e6688b 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -149,12 +149,12 @@ const struct vm_guest_mode_params vm_guest_mode_params[] = { _Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_params) == NUM_VM_MODES, "Missing new mode params?"); -struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t phy_pages) +struct kvm_vm *____vm_create(enum vm_guest_mode mode, uint64_t nr_pages) { struct kvm_vm *vm; pr_debug("%s: mode='%s' pages='%ld'\n", __func__, - vm_guest_mode_string(mode), phy_pages); + vm_guest_mode_string(mode), nr_pages); vm = calloc(1, sizeof(*vm)); TEST_ASSERT(vm != NULL, "Insufficient Memory"); @@ -251,20 +251,20 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t phy_pages) /* Allocate and setup memory for guest. */ vm->vpages_mapped = sparsebit_alloc(); - if (phy_pages != 0) + if (nr_pages != 0) vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, - 0, 0, phy_pages, 0); + 0, 0, nr_pages, 0); return vm; } -struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t pages) +struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t nr_pages) { struct kvm_vm *vm; - pages = vm_adjust_num_guest_pages(mode, pages); + nr_pages = vm_adjust_num_guest_pages(mode, nr_pages); - vm = __vm_create(mode, pages); + vm = ____vm_create(mode, nr_pages); kvm_vm_elf_load(vm, program_invocation_name); @@ -323,7 +323,7 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, "nr_vcpus = %d too large for host, max-vcpus = %d", nr_vcpus, kvm_check_cap(KVM_CAP_MAX_VCPUS)); - vm = vm_create(mode, pages); + vm = __vm_create(mode, pages); for (i = 0; i < nr_vcpus; ++i) { uint32_t vcpuid = vcpuids ? vcpuids[i] : i; diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 9146d62439fc..cdb9ce907c18 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -365,7 +365,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) if (!(r & KVM_PMU_CAP_DISABLE)) return; - vm = vm_create(VM_MODE_DEFAULT, DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); vm_enable_cap(vm, KVM_CAP_PMU_CAPABILITY, KVM_PMU_CAP_DISABLE); diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index 6bc13cf17220..9ba3cd4e7f20 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -86,7 +86,7 @@ static struct kvm_vm *create_vm(void) uint64_t extra_pg_pages = vcpu_pages / PTES_PER_MIN_PAGE * N_VCPU; uint64_t pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages; - return vm_create(VM_MODE_DEFAULT, pages); + return vm_create(pages); } static void add_x86_vcpu(struct kvm_vm *vm, uint32_t vcpuid, bool bsp_code) From 70ca149be61d9b09cc31c62e9fbe6faea4a79811 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 10:08:40 -0700 Subject: [PATCH 0354/1436] KVM: selftests: Rename xAPIC state test's vcpu struct Rename xapic_state_test's kvm_vcpu struct to xapic_vcpu to avoid a collision when the common 'struct vcpu' is renamed to 'struct kvm_vcpu' in a future patch. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/x86_64/xapic_state_test.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c index 0792334ba243..9d8393b6ec75 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c @@ -11,7 +11,7 @@ #include "processor.h" #include "test_util.h" -struct kvm_vcpu { +struct xapic_vcpu { uint32_t id; bool is_x2apic; }; @@ -47,7 +47,7 @@ static void x2apic_guest_code(void) } while (1); } -static void ____test_icr(struct kvm_vm *vm, struct kvm_vcpu *vcpu, uint64_t val) +static void ____test_icr(struct kvm_vm *vm, struct xapic_vcpu *vcpu, uint64_t val) { struct kvm_lapic_state xapic; struct ucall uc; @@ -75,13 +75,13 @@ static void ____test_icr(struct kvm_vm *vm, struct kvm_vcpu *vcpu, uint64_t val) ASSERT_EQ(icr, val & ~APIC_ICR_BUSY); } -static void __test_icr(struct kvm_vm *vm, struct kvm_vcpu *vcpu, uint64_t val) +static void __test_icr(struct kvm_vm *vm, struct xapic_vcpu *vcpu, uint64_t val) { ____test_icr(vm, vcpu, val | APIC_ICR_BUSY); ____test_icr(vm, vcpu, val & ~(u64)APIC_ICR_BUSY); } -static void test_icr(struct kvm_vm *vm, struct kvm_vcpu *vcpu) +static void test_icr(struct kvm_vm *vm, struct xapic_vcpu *vcpu) { uint64_t icr, i, j; @@ -116,7 +116,7 @@ static void test_icr(struct kvm_vm *vm, struct kvm_vcpu *vcpu) int main(int argc, char *argv[]) { - struct kvm_vcpu vcpu = { + struct xapic_vcpu vcpu = { .id = 0, .is_x2apic = true, }; From 1079c3d4e452a12f71f9ed076a37e5689f365153 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 13:26:01 -0800 Subject: [PATCH 0355/1436] KVM: selftests: Rename vcpu.state => vcpu.run Rename the "state" field of 'struct vcpu' to "run". KVM calls it "run", the struct name is "kvm_run", etc... Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 24 +++++++------------ .../selftests/kvm/lib/s390x/processor.c | 2 +- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 6418b1c04bc0..b83c3327d0e4 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -48,7 +48,7 @@ struct vcpu { uint32_t id; int fd; struct kvm_vm *vm; - struct kvm_run *state; + struct kvm_run *run; struct kvm_dirty_gfn *dirty_gfns; uint32_t fetch_index; uint32_t dirty_gfns_count; diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index ea85e0e6688b..74ab8f723288 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -514,7 +514,7 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct vcpu *vcpu) vcpu->dirty_gfns = NULL; } - ret = munmap(vcpu->state, vcpu_mmap_sz()); + ret = munmap(vcpu->run, vcpu_mmap_sz()); TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); ret = close(vcpu->fd); @@ -1081,13 +1081,7 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) struct vcpu *vcpu; /* Confirm a vcpu with the specified id doesn't already exist. */ - vcpu = vcpu_find(vm, vcpuid); - if (vcpu != NULL) - TEST_FAIL("vcpu with the specified id " - "already exists,\n" - " requested vcpuid: %u\n" - " existing vcpuid: %u state: %p", - vcpuid, vcpu->id, vcpu->state); + TEST_ASSERT(!vcpu_find(vm, vcpuid), "vCPU%d already exists\n", vcpuid); /* Allocate and initialize new vcpu structure. */ vcpu = calloc(1, sizeof(*vcpu)); @@ -1098,12 +1092,12 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) vcpu->fd = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)(unsigned long)vcpuid); TEST_ASSERT(vcpu->fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, vcpu->fd)); - TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->state), "vcpu mmap size " + TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->run), "vcpu mmap size " "smaller than expected, vcpu_mmap_sz: %i expected_min: %zi", - vcpu_mmap_sz(), sizeof(*vcpu->state)); - vcpu->state = (struct kvm_run *) mmap(NULL, vcpu_mmap_sz(), + vcpu_mmap_sz(), sizeof(*vcpu->run)); + vcpu->run = (struct kvm_run *) mmap(NULL, vcpu_mmap_sz(), PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, 0); - TEST_ASSERT(vcpu->state != MAP_FAILED, + TEST_ASSERT(vcpu->run != MAP_FAILED, __KVM_SYSCALL_ERROR("mmap()", (int)(unsigned long)MAP_FAILED)); /* Add to linked-list of VCPUs. */ @@ -1460,7 +1454,7 @@ struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) { struct vcpu *vcpu = vcpu_get(vm, vcpuid); - return vcpu->state; + return vcpu->run; } /* @@ -1502,9 +1496,9 @@ void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid) struct vcpu *vcpu = vcpu_get(vm, vcpuid); int ret; - vcpu->state->immediate_exit = 1; + vcpu->run->immediate_exit = 1; ret = __vcpu_run(vm, vcpuid); - vcpu->state->immediate_exit = 0; + vcpu->run->immediate_exit = 0; TEST_ASSERT(ret == -1 && errno == EINTR, "KVM_RUN IOCTL didn't exit immediately, rc: %i, errno: %i", diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index 53c413932f64..df9d9650d916 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -210,7 +210,7 @@ void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) struct vcpu *vcpu = vcpu_get(vm, vcpuid); fprintf(stream, "%*spstate: psw: 0x%.16llx:0x%.16llx\n", - indent, "", vcpu->state->psw_mask, vcpu->state->psw_addr); + indent, "", vcpu->run->psw_mask, vcpu->run->psw_addr); } void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid) From 0cc64b08096c71ba139e25759597c5df80ae422a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 15:24:21 -0800 Subject: [PATCH 0356/1436] KVM: selftests: Rename 'struct vcpu' to 'struct kvm_vcpu' Rename 'struct vcpu' to 'struct kvm_vcpu' to align with 'struct kvm_vm' in the selftest, and to give readers a hint that the struct is specific to KVM. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 11 +++--- tools/testing/selftests/kvm/lib/kvm_util.c | 36 +++++++++---------- .../selftests/kvm/lib/s390x/processor.c | 2 +- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index b83c3327d0e4..d2c7fb391fc7 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -16,6 +16,7 @@ #include #include "linux/rbtree.h" + #include #include "sparsebit.h" @@ -43,7 +44,7 @@ struct userspace_mem_region { struct hlist_node slot_node; }; -struct vcpu { +struct kvm_vcpu { struct list_head list; uint32_t id; int fd; @@ -92,7 +93,7 @@ struct kvm_vm { continue; \ else -struct vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid); +struct kvm_vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid); /* * Virtual Translation Tables Dump @@ -644,17 +645,17 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, * Create a VM with a single vCPU with reasonable defaults and @extra_mem_pages * additional pages of guest memory. Returns the VM and vCPU (via out param). */ -struct kvm_vm *__vm_create_with_one_vcpu(struct vcpu **vcpu, +struct kvm_vm *__vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, uint64_t extra_mem_pages, void *guest_code); -static inline struct kvm_vm *vm_create_with_one_vcpu(struct vcpu **vcpu, +static inline struct kvm_vm *vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, void *guest_code) { return __vm_create_with_one_vcpu(vcpu, 0, guest_code); } -struct vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm); +struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm); /* * Adds a vCPU with reasonable defaults (e.g. a stack) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 74ab8f723288..bd1066f789df 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -349,7 +349,7 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, (uint32_t []){ vcpuid }); } -struct kvm_vm *__vm_create_with_one_vcpu(struct vcpu **vcpu, +struct kvm_vm *__vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, uint64_t extra_mem_pages, void *guest_code) { @@ -393,7 +393,7 @@ void kvm_vm_restart(struct kvm_vm *vmp) } } -struct vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm) +struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm) { kvm_vm_restart(vm); @@ -472,23 +472,23 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, return ®ion->region; } -static struct vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpuid) +static struct kvm_vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpu_id) { - struct vcpu *vcpu; + struct kvm_vcpu *vcpu; list_for_each_entry(vcpu, &vm->vcpus, list) { - if (vcpu->id == vcpuid) + if (vcpu->id == vcpu_id) return vcpu; } return NULL; } -struct vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid) +struct kvm_vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpu_id) { - struct vcpu *vcpu = vcpu_find(vm, vcpuid); + struct kvm_vcpu *vcpu = vcpu_find(vm, vcpu_id); - TEST_ASSERT(vcpu, "vCPU %d does not exist", vcpuid); + TEST_ASSERT(vcpu, "vCPU %d does not exist", vcpu_id); return vcpu; } @@ -504,7 +504,7 @@ struct vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid) * * Removes a vCPU from a VM and frees its resources. */ -static void vm_vcpu_rm(struct kvm_vm *vm, struct vcpu *vcpu) +static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu) { int ret; @@ -526,7 +526,7 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct vcpu *vcpu) void kvm_vm_release(struct kvm_vm *vmp) { - struct vcpu *vcpu, *tmp; + struct kvm_vcpu *vcpu, *tmp; int ret; list_for_each_entry_safe(vcpu, tmp, &vmp->vcpus, list) @@ -1078,7 +1078,7 @@ static int vcpu_mmap_sz(void) */ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) { - struct vcpu *vcpu; + struct kvm_vcpu *vcpu; /* Confirm a vcpu with the specified id doesn't already exist. */ TEST_ASSERT(!vcpu_find(vm, vcpuid), "vCPU%d already exists\n", vcpuid); @@ -1452,7 +1452,7 @@ void vm_create_irqchip(struct kvm_vm *vm) */ struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) { - struct vcpu *vcpu = vcpu_get(vm, vcpuid); + struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); return vcpu->run; } @@ -1493,7 +1493,7 @@ int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid) { - struct vcpu *vcpu = vcpu_get(vm, vcpuid); + struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); int ret; vcpu->run->immediate_exit = 1; @@ -1537,7 +1537,7 @@ struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid) int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, void *arg) { - struct vcpu *vcpu = vcpu_get(vm, vcpuid); + struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); return ioctl(vcpu->fd, cmd, arg); } @@ -1552,7 +1552,7 @@ void _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid) { - struct vcpu *vcpu = vcpu_get(vm, vcpuid); + struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); uint32_t size = vm->dirty_ring_size; TEST_ASSERT(size > 0, "Should enable dirty ring first"); @@ -1684,9 +1684,7 @@ void vcpu_device_attr_set(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, uint64_t attr) { - struct vcpu *vcpu = vcpu_get(vm, vcpuid); - - return __kvm_has_device_attr(vcpu->fd, group, attr); + return __kvm_has_device_attr(vcpu_get(vm, vcpuid)->fd, group, attr); } /* @@ -1779,7 +1777,7 @@ void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) { int ctr; struct userspace_mem_region *region; - struct vcpu *vcpu; + struct kvm_vcpu *vcpu; fprintf(stream, "%*smode: 0x%x\n", indent, "", vm->mode); fprintf(stream, "%*sfd: %i\n", indent, "", vm->fd); diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index df9d9650d916..aec15ca9d887 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -207,7 +207,7 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) { - struct vcpu *vcpu = vcpu_get(vm, vcpuid); + struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); fprintf(stream, "%*spstate: psw: 0x%.16llx:0x%.16llx\n", indent, "", vcpu->run->psw_mask, vcpu->run->psw_addr); From e3763d3aebea261ac3eef24e94dc85be91209d0b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:16:45 -0800 Subject: [PATCH 0357/1436] KVM: selftests: Return the created vCPU from vm_vcpu_add() Return the created vCPU from vm_vcpu_add() so that callers don't need to manually retrieve the vCPU that was just added. Opportunistically drop the "heavy" function comment, it adds a lot of lines of "code" but not much value, e.g. it's pretty obvious that @vm is a virtual machine... Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 27 +++++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index d2c7fb391fc7..fbc54e920383 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -324,7 +324,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa); void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot); -void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid); +struct kvm_vcpu *vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid); vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min); vm_vaddr_t vm_vaddr_alloc_pages(struct kvm_vm *vm, int nr_pages); vm_vaddr_t vm_vaddr_alloc_page(struct kvm_vm *vm); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index bd1066f789df..f8274ca5fe5b 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -397,8 +397,7 @@ struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm) { kvm_vm_restart(vm); - vm_vcpu_add(vm, 0); - return vcpu_get(vm, 0); + return vm_vcpu_add(vm, 0); } /* @@ -1063,33 +1062,23 @@ static int vcpu_mmap_sz(void) } /* - * VM VCPU Add - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * - * Output Args: None - * - * Return: None - * - * Adds a virtual CPU to the VM specified by vm with the ID given by vcpuid. - * No additional VCPU setup is done. + * Adds a virtual CPU to the VM specified by vm with the ID given by vcpu_id. + * No additional vCPU setup is done. Returns the vCPU. */ -void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) +struct kvm_vcpu *vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) { struct kvm_vcpu *vcpu; /* Confirm a vcpu with the specified id doesn't already exist. */ - TEST_ASSERT(!vcpu_find(vm, vcpuid), "vCPU%d already exists\n", vcpuid); + TEST_ASSERT(!vcpu_find(vm, vcpu_id), "vCPU%d already exists\n", vcpu_id); /* Allocate and initialize new vcpu structure. */ vcpu = calloc(1, sizeof(*vcpu)); TEST_ASSERT(vcpu != NULL, "Insufficient Memory"); vcpu->vm = vm; - vcpu->id = vcpuid; - vcpu->fd = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)(unsigned long)vcpuid); + vcpu->id = vcpu_id; + vcpu->fd = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)(unsigned long)vcpu_id); TEST_ASSERT(vcpu->fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, vcpu->fd)); TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->run), "vcpu mmap size " @@ -1102,6 +1091,8 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) /* Add to linked-list of VCPUs. */ list_add(&vcpu->list, &vm->vcpus); + + return vcpu; } /* From e82e630ba965ad8a1278cf8bbe9759975a5a5109 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 13:34:31 -0800 Subject: [PATCH 0358/1436] KVM: selftests: Convert memslot_perf_test away from VCPU_ID Convert memslot_perf_test to use __vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. This is the first of many, many steps towards eliminating VCPU_ID from all KVM selftests, and towards eventually purging the VM+vcpu_id mess. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/memslot_perf_test.c | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c index 1727f75e0c2c..009eb19b28af 100644 --- a/tools/testing/selftests/kvm/memslot_perf_test.c +++ b/tools/testing/selftests/kvm/memslot_perf_test.c @@ -25,8 +25,6 @@ #include #include -#define VCPU_ID 0 - #define MEM_SIZE ((512U << 20) + 4096) #define MEM_SIZE_PAGES (MEM_SIZE / 4096) #define MEM_GPA 0x10000000UL @@ -90,6 +88,7 @@ static_assert(MEM_TEST_MOVE_SIZE <= MEM_TEST_SIZE, struct vm_data { struct kvm_vm *vm; + struct kvm_vcpu *vcpu; pthread_t vcpu_thread; uint32_t nslots; uint64_t npages; @@ -127,29 +126,29 @@ static bool verbose; pr_info(__VA_ARGS__); \ } while (0) -static void check_mmio_access(struct vm_data *vm, struct kvm_run *run) +static void check_mmio_access(struct vm_data *data, struct kvm_run *run) { - TEST_ASSERT(vm->mmio_ok, "Unexpected mmio exit"); + TEST_ASSERT(data->mmio_ok, "Unexpected mmio exit"); TEST_ASSERT(run->mmio.is_write, "Unexpected mmio read"); TEST_ASSERT(run->mmio.len == 8, "Unexpected exit mmio size = %u", run->mmio.len); - TEST_ASSERT(run->mmio.phys_addr >= vm->mmio_gpa_min && - run->mmio.phys_addr <= vm->mmio_gpa_max, + TEST_ASSERT(run->mmio.phys_addr >= data->mmio_gpa_min && + run->mmio.phys_addr <= data->mmio_gpa_max, "Unexpected exit mmio address = 0x%llx", run->mmio.phys_addr); } -static void *vcpu_worker(void *data) +static void *vcpu_worker(void *__data) { - struct vm_data *vm = data; - struct kvm_run *run; + struct vm_data *data = __data; + struct kvm_vcpu *vcpu = data->vcpu; + struct kvm_run *run = vcpu->run; struct ucall uc; - run = vcpu_state(vm->vm, VCPU_ID); while (1) { - vcpu_run(vm->vm, VCPU_ID); + vcpu_run(data->vm, vcpu->id); - switch (get_ucall(vm->vm, VCPU_ID, &uc)) { + switch (get_ucall(data->vm, vcpu->id, &uc)) { case UCALL_SYNC: TEST_ASSERT(uc.args[1] == 0, "Unexpected sync ucall, got %lx", @@ -158,7 +157,7 @@ static void *vcpu_worker(void *data) continue; case UCALL_NONE: if (run->exit_reason == KVM_EXIT_MMIO) - check_mmio_access(vm, run); + check_mmio_access(data, run); else goto done; break; @@ -238,6 +237,7 @@ static struct vm_data *alloc_vm(void) TEST_ASSERT(data, "malloc(vmdata) failed"); data->vm = NULL; + data->vcpu = NULL; data->hva_slots = NULL; return data; @@ -278,7 +278,7 @@ static bool prepare_vm(struct vm_data *data, int nslots, uint64_t *maxslots, data->hva_slots = malloc(sizeof(*data->hva_slots) * data->nslots); TEST_ASSERT(data->hva_slots, "malloc() fail"); - data->vm = vm_create_default(VCPU_ID, mempages, guest_code); + data->vm = __vm_create_with_one_vcpu(&data->vcpu, mempages, guest_code); ucall_init(data->vm, NULL); pr_info_v("Adding slots 1..%i, each slot with %"PRIu64" pages + %"PRIu64" extra pages last\n", From 2494a6d80fb58c303b542331d3218ecd70cccea3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 13:36:46 -0800 Subject: [PATCH 0359/1436] KVM: selftests: Convert rseq_test away from VCPU_ID Convert rseq_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/rseq_test.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/rseq_test.c b/tools/testing/selftests/kvm/rseq_test.c index 4158da0da2bb..fd754de0b74c 100644 --- a/tools/testing/selftests/kvm/rseq_test.c +++ b/tools/testing/selftests/kvm/rseq_test.c @@ -20,8 +20,6 @@ #include "processor.h" #include "test_util.h" -#define VCPU_ID 0 - static __thread volatile struct rseq __rseq = { .cpu_id = RSEQ_CPU_ID_UNINITIALIZED, }; @@ -207,6 +205,7 @@ int main(int argc, char *argv[]) { int r, i, snapshot; struct kvm_vm *vm; + struct kvm_vcpu *vcpu; u32 cpu, rseq_cpu; /* Tell stdout not to buffer its content */ @@ -228,14 +227,14 @@ int main(int argc, char *argv[]) * GUEST_SYNC, while concurrently migrating the process by setting its * CPU affinity. */ - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); ucall_init(vm, NULL); pthread_create(&migration_thread, NULL, migration_worker, 0); for (i = 0; !done; i++) { - vcpu_run(vm, VCPU_ID); - TEST_ASSERT(get_ucall(vm, VCPU_ID, NULL) == UCALL_SYNC, + vcpu_run(vm, vcpu->id); + TEST_ASSERT(get_ucall(vm, vcpu->id, NULL) == UCALL_SYNC, "Guest failed?"); /* From 58606e6025536a9ff3216df9cb2c6b7b7a1594be Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 13:49:19 -0800 Subject: [PATCH 0360/1436] KVM: selftests: Convert xss_msr_test away from VCPU_ID Convert xss_msr_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==1. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/x86_64/xss_msr_test.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c index a6abcb559e7c..a89d49ae79a6 100644 --- a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c +++ b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c @@ -12,7 +12,6 @@ #include "kvm_util.h" #include "vmx.h" -#define VCPU_ID 1 #define MSR_BITS 64 #define X86_FEATURE_XSAVES (1<<3) @@ -23,11 +22,12 @@ int main(int argc, char *argv[]) bool xss_supported = false; bool xss_in_msr_list; struct kvm_vm *vm; + struct kvm_vcpu *vcpu; uint64_t xss_val; int i, r; /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, 0); + vm = vm_create_with_one_vcpu(&vcpu, NULL); if (kvm_get_cpuid_max_basic() >= 0xd) { entry = kvm_get_supported_cpuid_index(0xd, 1); @@ -38,11 +38,12 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - xss_val = vcpu_get_msr(vm, VCPU_ID, MSR_IA32_XSS); + xss_val = vcpu_get_msr(vm, vcpu->id, MSR_IA32_XSS); TEST_ASSERT(xss_val == 0, "MSR_IA32_XSS should be initialized to zero\n"); - vcpu_set_msr(vm, VCPU_ID, MSR_IA32_XSS, xss_val); + vcpu_set_msr(vm, vcpu->id, MSR_IA32_XSS, xss_val); + /* * At present, KVM only supports a guest IA32_XSS value of 0. Verify * that trying to set the guest IA32_XSS to an unsupported value fails. @@ -51,7 +52,7 @@ int main(int argc, char *argv[]) */ xss_in_msr_list = kvm_msr_is_in_save_restore_list(MSR_IA32_XSS); for (i = 0; i < MSR_BITS; ++i) { - r = _vcpu_set_msr(vm, VCPU_ID, MSR_IA32_XSS, 1ull << i); + r = _vcpu_set_msr(vm, vcpu->id, MSR_IA32_XSS, 1ull << i); /* * Setting a list of MSRs returns the entry that "faulted", or From b1bc990406beab8690a20818e91d4ac522712bc7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 13:51:14 -0800 Subject: [PATCH 0361/1436] KVM: selftests: Convert vmx_preemption_timer_test away from VCPU_ID Convert vmx_preemption_timer_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically use vcpu_run() instead of _vcpu_run(), the test expects KVM_RUN to succeed. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/x86_64/vmx_preemption_timer_test.c | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c index f5b4ae914131..168adc5b2272 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c @@ -22,7 +22,6 @@ #include "processor.h" #include "vmx.h" -#define VCPU_ID 5 #define PREEMPTION_TIMER_VALUE 100000000ull #define PREEMPTION_TIMER_VALUE_THRESHOLD1 80000000ull @@ -159,6 +158,7 @@ int main(int argc, char *argv[]) struct kvm_regs regs1, regs2; struct kvm_vm *vm; struct kvm_run *run; + struct kvm_vcpu *vcpu; struct kvm_x86_state *state; struct ucall uc; int stage; @@ -175,22 +175,22 @@ int main(int argc, char *argv[]) } /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + run = vcpu->run; - vcpu_regs_get(vm, VCPU_ID, ®s1); + vcpu_regs_get(vm, vcpu->id, ®s1); vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); + vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); for (stage = 1;; stage++) { - _vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); @@ -232,22 +232,22 @@ int main(int argc, char *argv[]) stage, uc.args[4], uc.args[5]); } - state = vcpu_save_state(vm, VCPU_ID); + state = vcpu_save_state(vm, vcpu->id); memset(®s1, 0, sizeof(regs1)); - vcpu_regs_get(vm, VCPU_ID, ®s1); + vcpu_regs_get(vm, vcpu->id, ®s1); kvm_vm_release(vm); /* Restore state in a new VM. */ - kvm_vm_restart(vm); - vm_vcpu_add(vm, VCPU_ID); - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); - vcpu_load_state(vm, VCPU_ID, state); - run = vcpu_state(vm, VCPU_ID); + vcpu = vm_recreate_with_one_vcpu(vm); + + vcpu_set_cpuid(vm, vcpu->id, kvm_get_supported_cpuid()); + vcpu_load_state(vm, vcpu->id, state); + run = vcpu->run; kvm_x86_state_cleanup(state); memset(®s2, 0, sizeof(regs2)); - vcpu_regs_get(vm, VCPU_ID, ®s2); + vcpu_regs_get(vm, vcpu->id, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", (ulong) regs2.rdi, (ulong) regs2.rsi); From d8b5b5d1327175b0bd0d9c97434a307cded6b5dd Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 13:53:06 -0800 Subject: [PATCH 0362/1436] KVM: selftests: Convert vmx_pmu_msrs_test away from VCPU_ID Convert vmx_pmu_msrs_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c index 97b7fd4a9a3d..63129ff5d003 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c @@ -17,8 +17,6 @@ #include "kvm_util.h" #include "vmx.h" -#define VCPU_ID 0 - #define X86_FEATURE_PDCM (1<<15) #define PMU_CAP_FW_WRITES (1ULL << 13) #define PMU_CAP_LBR_FMT 0x3f @@ -61,6 +59,7 @@ int main(int argc, char *argv[]) struct kvm_cpuid_entry2 *entry_a_0; bool pdcm_supported = false; struct kvm_vm *vm; + struct kvm_vcpu *vcpu; int ret; union cpuid10_eax eax; union perf_capabilities host_cap; @@ -69,7 +68,7 @@ int main(int argc, char *argv[]) host_cap.capabilities &= (PMU_CAP_FW_WRITES | PMU_CAP_LBR_FMT); /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); cpuid = kvm_get_supported_cpuid(); if (kvm_get_cpuid_max_basic() >= 0xa) { @@ -88,27 +87,27 @@ int main(int argc, char *argv[]) } /* testcase 1, set capabilities when we have PDCM bit */ - vcpu_set_cpuid(vm, VCPU_ID, cpuid); - vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES); + vcpu_set_cpuid(vm, vcpu->id, cpuid); + vcpu_set_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES); /* check capabilities can be retrieved with KVM_GET_MSR */ - ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES); + ASSERT_EQ(vcpu_get_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES); /* check whatever we write with KVM_SET_MSR is _not_ modified */ - vcpu_run(vm, VCPU_ID); - ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES); + vcpu_run(vm, vcpu->id); + ASSERT_EQ(vcpu_get_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES); /* testcase 2, check valid LBR formats are accepted */ - vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, 0); - ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), 0); + vcpu_set_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES, 0); + ASSERT_EQ(vcpu_get_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES), 0); - vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, host_cap.lbr_format); - ASSERT_EQ(vcpu_get_msr(vm, VCPU_ID, MSR_IA32_PERF_CAPABILITIES), (u64)host_cap.lbr_format); + vcpu_set_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES, host_cap.lbr_format); + ASSERT_EQ(vcpu_get_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES), (u64)host_cap.lbr_format); /* testcase 3, check invalid LBR format is rejected */ /* Note, on Arch LBR capable platforms, LBR_FMT in perf capability msr is 0x3f, * to avoid the failure, use a true invalid format 0x30 for the test. */ - ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, 0x30); + ret = _vcpu_set_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES, 0x30); TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail."); printf("Completed perf capability tests.\n"); From 4bc87470858db1a329ad94e36f398fec97b54095 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 13:56:58 -0800 Subject: [PATCH 0363/1436] KVM: selftests: Convert vmx_set_nested_state_test away from VCPU_ID Convert vmx_set_nested_state_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/x86_64/vmx_set_nested_state_test.c | 86 +++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c index af3b60eb35ec..de38f0e68153 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c @@ -23,38 +23,37 @@ * changes this should be updated. */ #define VMCS12_REVISION 0x11e57ed0 -#define VCPU_ID 5 bool have_evmcs; -void test_nested_state(struct kvm_vm *vm, struct kvm_nested_state *state) +void test_nested_state(struct kvm_vcpu *vcpu, struct kvm_nested_state *state) { - vcpu_nested_state_set(vm, VCPU_ID, state); + vcpu_nested_state_set(vcpu->vm, vcpu->id, state); } -void test_nested_state_expect_errno(struct kvm_vm *vm, +void test_nested_state_expect_errno(struct kvm_vcpu *vcpu, struct kvm_nested_state *state, int expected_errno) { int rv; - rv = __vcpu_nested_state_set(vm, VCPU_ID, state); + rv = __vcpu_nested_state_set(vcpu->vm, vcpu->id, state); TEST_ASSERT(rv == -1 && errno == expected_errno, "Expected %s (%d) from vcpu_nested_state_set but got rv: %i errno: %s (%d)", strerror(expected_errno), expected_errno, rv, strerror(errno), errno); } -void test_nested_state_expect_einval(struct kvm_vm *vm, +void test_nested_state_expect_einval(struct kvm_vcpu *vcpu, struct kvm_nested_state *state) { - test_nested_state_expect_errno(vm, state, EINVAL); + test_nested_state_expect_errno(vcpu, state, EINVAL); } -void test_nested_state_expect_efault(struct kvm_vm *vm, +void test_nested_state_expect_efault(struct kvm_vcpu *vcpu, struct kvm_nested_state *state) { - test_nested_state_expect_errno(vm, state, EFAULT); + test_nested_state_expect_errno(vcpu, state, EFAULT); } void set_revision_id_for_vmcs12(struct kvm_nested_state *state, @@ -86,7 +85,7 @@ void set_default_vmx_state(struct kvm_nested_state *state, int size) set_revision_id_for_vmcs12(state, VMCS12_REVISION); } -void test_vmx_nested_state(struct kvm_vm *vm) +void test_vmx_nested_state(struct kvm_vcpu *vcpu) { /* Add a page for VMCS12. */ const int state_sz = sizeof(struct kvm_nested_state) + getpagesize(); @@ -96,14 +95,14 @@ void test_vmx_nested_state(struct kvm_vm *vm) /* The format must be set to 0. 0 for VMX, 1 for SVM. */ set_default_vmx_state(state, state_sz); state->format = 1; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* * We cannot virtualize anything if the guest does not have VMX * enabled. */ set_default_vmx_state(state, state_sz); - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* * We cannot virtualize anything if the guest does not have VMX @@ -112,17 +111,17 @@ void test_vmx_nested_state(struct kvm_vm *vm) */ set_default_vmx_state(state, state_sz); state->hdr.vmx.vmxon_pa = -1ull; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); state->hdr.vmx.vmcs12_pa = -1ull; state->flags = KVM_STATE_NESTED_EVMCS; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); state->flags = 0; - test_nested_state(vm, state); + test_nested_state(vcpu, state); /* Enable VMX in the guest CPUID. */ - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + vcpu_set_cpuid(vcpu->vm, vcpu->id, kvm_get_supported_cpuid()); /* * Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without @@ -133,34 +132,34 @@ void test_vmx_nested_state(struct kvm_vm *vm) set_default_vmx_state(state, state_sz); state->hdr.vmx.vmxon_pa = -1ull; state->hdr.vmx.vmcs12_pa = -1ull; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); state->flags &= KVM_STATE_NESTED_EVMCS; if (have_evmcs) { - test_nested_state_expect_einval(vm, state); - vcpu_enable_evmcs(vm, VCPU_ID); + test_nested_state_expect_einval(vcpu, state); + vcpu_enable_evmcs(vcpu->vm, vcpu->id); } - test_nested_state(vm, state); + test_nested_state(vcpu, state); /* It is invalid to have vmxon_pa == -1ull and SMM flags non-zero. */ state->hdr.vmx.smm.flags = 1; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* Invalid flags are rejected. */ set_default_vmx_state(state, state_sz); state->hdr.vmx.flags = ~0; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* It is invalid to have vmxon_pa == -1ull and vmcs_pa != -1ull. */ set_default_vmx_state(state, state_sz); state->hdr.vmx.vmxon_pa = -1ull; state->flags = 0; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* It is invalid to have vmxon_pa set to a non-page aligned address. */ set_default_vmx_state(state, state_sz); state->hdr.vmx.vmxon_pa = 1; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* * It is invalid to have KVM_STATE_NESTED_SMM_GUEST_MODE and @@ -170,7 +169,7 @@ void test_vmx_nested_state(struct kvm_vm *vm) state->flags = KVM_STATE_NESTED_GUEST_MODE | KVM_STATE_NESTED_RUN_PENDING; state->hdr.vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* * It is invalid to have any of the SMM flags set besides: @@ -180,13 +179,13 @@ void test_vmx_nested_state(struct kvm_vm *vm) set_default_vmx_state(state, state_sz); state->hdr.vmx.smm.flags = ~(KVM_STATE_NESTED_SMM_GUEST_MODE | KVM_STATE_NESTED_SMM_VMXON); - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* Outside SMM, SMM flags must be zero. */ set_default_vmx_state(state, state_sz); state->flags = 0; state->hdr.vmx.smm.flags = KVM_STATE_NESTED_SMM_GUEST_MODE; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* * Size must be large enough to fit kvm_nested_state and vmcs12 @@ -195,13 +194,13 @@ void test_vmx_nested_state(struct kvm_vm *vm) set_default_vmx_state(state, state_sz); state->size = sizeof(*state); state->flags = 0; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); set_default_vmx_state(state, state_sz); state->size = sizeof(*state); state->flags = 0; state->hdr.vmx.vmcs12_pa = -1; - test_nested_state(vm, state); + test_nested_state(vcpu, state); /* * KVM_SET_NESTED_STATE succeeds with invalid VMCS @@ -209,7 +208,7 @@ void test_vmx_nested_state(struct kvm_vm *vm) */ set_default_vmx_state(state, state_sz); state->flags = 0; - test_nested_state(vm, state); + test_nested_state(vcpu, state); /* Invalid flags are rejected, even if no VMCS loaded. */ set_default_vmx_state(state, state_sz); @@ -217,13 +216,13 @@ void test_vmx_nested_state(struct kvm_vm *vm) state->flags = 0; state->hdr.vmx.vmcs12_pa = -1; state->hdr.vmx.flags = ~0; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* vmxon_pa cannot be the same address as vmcs_pa. */ set_default_vmx_state(state, state_sz); state->hdr.vmx.vmxon_pa = 0; state->hdr.vmx.vmcs12_pa = 0; - test_nested_state_expect_einval(vm, state); + test_nested_state_expect_einval(vcpu, state); /* * Test that if we leave nesting the state reflects that when we get @@ -233,8 +232,8 @@ void test_vmx_nested_state(struct kvm_vm *vm) state->hdr.vmx.vmxon_pa = -1ull; state->hdr.vmx.vmcs12_pa = -1ull; state->flags = 0; - test_nested_state(vm, state); - vcpu_nested_state_get(vm, VCPU_ID, state); + test_nested_state(vcpu, state); + vcpu_nested_state_get(vcpu->vm, vcpu->id, state); TEST_ASSERT(state->size >= sizeof(*state) && state->size <= state_sz, "Size must be between %ld and %d. The size returned was %d.", sizeof(*state), state_sz, state->size); @@ -244,7 +243,7 @@ void test_vmx_nested_state(struct kvm_vm *vm) free(state); } -void disable_vmx(struct kvm_vm *vm) +void disable_vmx(struct kvm_vcpu *vcpu) { struct kvm_cpuid2 *cpuid = kvm_get_supported_cpuid(); int i; @@ -256,7 +255,7 @@ void disable_vmx(struct kvm_vm *vm) TEST_ASSERT(i != cpuid->nent, "CPUID function 1 not found"); cpuid->entries[i].ecx &= ~CPUID_VMX; - vcpu_set_cpuid(vm, VCPU_ID, cpuid); + vcpu_set_cpuid(vcpu->vm, vcpu->id, cpuid); cpuid->entries[i].ecx |= CPUID_VMX; } @@ -264,6 +263,7 @@ int main(int argc, char *argv[]) { struct kvm_vm *vm; struct kvm_nested_state state; + struct kvm_vcpu *vcpu; have_evmcs = kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS); @@ -278,20 +278,20 @@ int main(int argc, char *argv[]) */ nested_vmx_check_supported(); - vm = vm_create_default(VCPU_ID, 0, 0); + vm = vm_create_with_one_vcpu(&vcpu, NULL); /* * First run tests with VMX disabled to check error handling. */ - disable_vmx(vm); + disable_vmx(vcpu); /* Passing a NULL kvm_nested_state causes a EFAULT. */ - test_nested_state_expect_efault(vm, NULL); + test_nested_state_expect_efault(vcpu, NULL); /* 'size' cannot be smaller than sizeof(kvm_nested_state). */ set_default_state(&state); state.size = 0; - test_nested_state_expect_einval(vm, &state); + test_nested_state_expect_einval(vcpu, &state); /* * Setting the flags 0xf fails the flags check. The only flags that @@ -302,7 +302,7 @@ int main(int argc, char *argv[]) */ set_default_state(&state); state.flags = 0xf; - test_nested_state_expect_einval(vm, &state); + test_nested_state_expect_einval(vcpu, &state); /* * If KVM_STATE_NESTED_RUN_PENDING is set then @@ -310,9 +310,9 @@ int main(int argc, char *argv[]) */ set_default_state(&state); state.flags = KVM_STATE_NESTED_RUN_PENDING; - test_nested_state_expect_einval(vm, &state); + test_nested_state_expect_einval(vcpu, &state); - test_vmx_nested_state(vm); + test_vmx_nested_state(vcpu); kvm_vm_free(vm); return 0; From 5581ed8762fc9400047521be23844a27cf884b08 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 15:22:03 -0800 Subject: [PATCH 0364/1436] KVM: selftests: Convert vmx_tsc_adjust_test away from VCPU_ID Convert vmx_tsc_adjust_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/vmx_tsc_adjust_test.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c index 19b35c607dc6..29699d7c16c3 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c @@ -32,8 +32,6 @@ #define MSR_IA32_TSC_ADJUST 0x3b #endif -#define VCPU_ID 5 - #define TSC_ADJUST_VALUE (1ll << 32) #define TSC_OFFSET_VALUE -(1ll << 48) @@ -127,26 +125,27 @@ static void report(int64_t val) int main(int argc, char *argv[]) { vm_vaddr_t vmx_pages_gva; + struct kvm_vcpu *vcpu; nested_vmx_check_supported(); - vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, (void *) l1_guest_code); /* Allocate VMX pages and shared descriptors (vmx_pages). */ vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); + vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); for (;;) { - volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); + volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ From 5478431f984ec593684f0dbb212e2c141ec20320 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 15:28:49 -0800 Subject: [PATCH 0365/1436] KVM: selftests: Convert mmu_role_test away from VCPU_ID Convert mmu_role_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==1. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically use vcpu_run() instead of _vcpu_run() plus an open coded assert that KVM_RUN succeeded. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/mmu_role_test.c | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/mmu_role_test.c b/tools/testing/selftests/kvm/x86_64/mmu_role_test.c index bdecd532f935..829a5cf94f5c 100644 --- a/tools/testing/selftests/kvm/x86_64/mmu_role_test.c +++ b/tools/testing/selftests/kvm/x86_64/mmu_role_test.c @@ -3,8 +3,6 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 1 - #define MMIO_GPA 0x100000000ull static void guest_code(void) @@ -25,22 +23,21 @@ static void guest_pf_handler(struct ex_regs *regs) static void mmu_role_test(u32 *cpuid_reg, u32 evil_cpuid_val) { u32 good_cpuid_val = *cpuid_reg; + struct kvm_vcpu *vcpu; struct kvm_run *run; struct kvm_vm *vm; uint64_t cmd; - int r; /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + run = vcpu->run; /* Map 1gb page without a backing memlot. */ __virt_pg_map(vm, MMIO_GPA, MMIO_GPA, PG_LEVEL_1G); - r = _vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); /* Guest access to the 1gb page should trigger MMIO. */ - TEST_ASSERT(r == 0, "vcpu_run failed: %d\n", r); TEST_ASSERT(run->exit_reason == KVM_EXIT_MMIO, "Unexpected exit reason: %u (%s), expected MMIO exit (1gb page w/o memslot)\n", run->exit_reason, exit_reason_str(run->exit_reason)); @@ -57,7 +54,7 @@ static void mmu_role_test(u32 *cpuid_reg, u32 evil_cpuid_val) * returns the struct that contains the entry being modified. Eww. */ *cpuid_reg = evil_cpuid_val; - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + vcpu_set_cpuid(vm, vcpu->id, kvm_get_supported_cpuid()); /* * Add a dummy memslot to coerce KVM into bumping the MMIO generation. @@ -70,13 +67,12 @@ static void mmu_role_test(u32 *cpuid_reg, u32 evil_cpuid_val) /* Set up a #PF handler to eat the RSVD #PF and signal all done! */ vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, PF_VECTOR, guest_pf_handler); - r = _vcpu_run(vm, VCPU_ID); - TEST_ASSERT(r == 0, "vcpu_run failed: %d\n", r); + vcpu_run(vm, vcpu->id); - cmd = get_ucall(vm, VCPU_ID, NULL); + cmd = get_ucall(vm, vcpu->id, NULL); TEST_ASSERT(cmd == UCALL_DONE, "Unexpected guest exit, exit_reason=%s, ucall.cmd = %lu\n", exit_reason_str(run->exit_reason), cmd); From a2d5d774919ed48680d17b6b82458d184f6519dd Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 15:39:45 -0800 Subject: [PATCH 0366/1436] KVM: selftests: Convert pmu_event_filter_test away from VCPU_ID Convert pmu_event_filter_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Rename run_vm_to_sync() to run_vcpu_to_sync() accordingly. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/x86_64/pmu_event_filter_test.c | 75 ++++++++++--------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index cdb9ce907c18..d2c571f20521 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -49,7 +49,6 @@ union cpuid10_ebx { /* Oddly, this isn't in perf_event.h. */ #define ARCH_PERFMON_BRANCHES_RETIRED 5 -#define VCPU_ID 0 #define NUM_BRANCHES 42 /* @@ -173,17 +172,17 @@ static void amd_guest_code(void) * Run the VM to the next GUEST_SYNC(value), and return the value passed * to the sync. Any other exit from the guest is fatal. */ -static uint64_t run_vm_to_sync(struct kvm_vm *vm) +static uint64_t run_vcpu_to_sync(struct kvm_vcpu *vcpu) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, VCPU_ID); + vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - get_ucall(vm, VCPU_ID, &uc); + get_ucall(vcpu->vm, vcpu->id, &uc); TEST_ASSERT(uc.cmd == UCALL_SYNC, "Received ucall other than UCALL_SYNC: %lu", uc.cmd); return uc.args[1]; @@ -197,13 +196,13 @@ static uint64_t run_vm_to_sync(struct kvm_vm *vm) * a sanity check and then GUEST_SYNC(success). In the case of failure, * the behavior of the guest on resumption is undefined. */ -static bool sanity_check_pmu(struct kvm_vm *vm) +static bool sanity_check_pmu(struct kvm_vcpu *vcpu) { bool success; - vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); - success = run_vm_to_sync(vm); - vm_install_exception_handler(vm, GP_VECTOR, NULL); + vm_install_exception_handler(vcpu->vm, GP_VECTOR, guest_gp_handler); + success = run_vcpu_to_sync(vcpu); + vm_install_exception_handler(vcpu->vm, GP_VECTOR, NULL); return success; } @@ -264,9 +263,9 @@ static struct kvm_pmu_event_filter *remove_event(struct kvm_pmu_event_filter *f, return f; } -static void test_without_filter(struct kvm_vm *vm) +static void test_without_filter(struct kvm_vcpu *vcpu) { - uint64_t count = run_vm_to_sync(vm); + uint64_t count = run_vcpu_to_sync(vcpu); if (count != NUM_BRANCHES) pr_info("%s: Branch instructions retired = %lu (expected %u)\n", @@ -274,21 +273,21 @@ static void test_without_filter(struct kvm_vm *vm) TEST_ASSERT(count, "Allowed PMU event is not counting"); } -static uint64_t test_with_filter(struct kvm_vm *vm, +static uint64_t test_with_filter(struct kvm_vcpu *vcpu, struct kvm_pmu_event_filter *f) { - vm_ioctl(vm, KVM_SET_PMU_EVENT_FILTER, (void *)f); - return run_vm_to_sync(vm); + vm_ioctl(vcpu->vm, KVM_SET_PMU_EVENT_FILTER, (void *)f); + return run_vcpu_to_sync(vcpu); } -static void test_amd_deny_list(struct kvm_vm *vm) +static void test_amd_deny_list(struct kvm_vcpu *vcpu) { uint64_t event = EVENT(0x1C2, 0); struct kvm_pmu_event_filter *f; uint64_t count; f = create_pmu_event_filter(&event, 1, KVM_PMU_EVENT_DENY); - count = test_with_filter(vm, f); + count = test_with_filter(vcpu, f); free(f); if (count != NUM_BRANCHES) @@ -297,10 +296,10 @@ static void test_amd_deny_list(struct kvm_vm *vm) TEST_ASSERT(count, "Allowed PMU event is not counting"); } -static void test_member_deny_list(struct kvm_vm *vm) +static void test_member_deny_list(struct kvm_vcpu *vcpu) { struct kvm_pmu_event_filter *f = event_filter(KVM_PMU_EVENT_DENY); - uint64_t count = test_with_filter(vm, f); + uint64_t count = test_with_filter(vcpu, f); free(f); if (count) @@ -309,10 +308,10 @@ static void test_member_deny_list(struct kvm_vm *vm) TEST_ASSERT(!count, "Disallowed PMU Event is counting"); } -static void test_member_allow_list(struct kvm_vm *vm) +static void test_member_allow_list(struct kvm_vcpu *vcpu) { struct kvm_pmu_event_filter *f = event_filter(KVM_PMU_EVENT_ALLOW); - uint64_t count = test_with_filter(vm, f); + uint64_t count = test_with_filter(vcpu, f); free(f); if (count != NUM_BRANCHES) @@ -321,14 +320,14 @@ static void test_member_allow_list(struct kvm_vm *vm) TEST_ASSERT(count, "Allowed PMU event is not counting"); } -static void test_not_member_deny_list(struct kvm_vm *vm) +static void test_not_member_deny_list(struct kvm_vcpu *vcpu) { struct kvm_pmu_event_filter *f = event_filter(KVM_PMU_EVENT_DENY); uint64_t count; remove_event(f, INTEL_BR_RETIRED); remove_event(f, AMD_ZEN_BR_RETIRED); - count = test_with_filter(vm, f); + count = test_with_filter(vcpu, f); free(f); if (count != NUM_BRANCHES) pr_info("%s: Branch instructions retired = %lu (expected %u)\n", @@ -336,14 +335,14 @@ static void test_not_member_deny_list(struct kvm_vm *vm) TEST_ASSERT(count, "Allowed PMU event is not counting"); } -static void test_not_member_allow_list(struct kvm_vm *vm) +static void test_not_member_allow_list(struct kvm_vcpu *vcpu) { struct kvm_pmu_event_filter *f = event_filter(KVM_PMU_EVENT_ALLOW); uint64_t count; remove_event(f, INTEL_BR_RETIRED); remove_event(f, AMD_ZEN_BR_RETIRED); - count = test_with_filter(vm, f); + count = test_with_filter(vcpu, f); free(f); if (count) pr_info("%s: Branch instructions retired = %lu (expected 0)\n", @@ -358,6 +357,7 @@ static void test_not_member_allow_list(struct kvm_vm *vm) */ static void test_pmu_config_disable(void (*guest_code)(void)) { + struct kvm_vcpu *vcpu; int r; struct kvm_vm *vm; @@ -369,11 +369,13 @@ static void test_pmu_config_disable(void (*guest_code)(void)) vm_enable_cap(vm, KVM_CAP_PMU_CAPABILITY, KVM_PMU_CAP_DISABLE); - vm_vcpu_add_default(vm, VCPU_ID, guest_code); + vm_vcpu_add_default(vm, 0, guest_code); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); - TEST_ASSERT(!sanity_check_pmu(vm), + vcpu = vcpu_get(vm, 0); + vcpu_init_descriptor_tables(vm, vcpu->id); + + TEST_ASSERT(!sanity_check_pmu(vcpu), "Guest should not be able to use disabled PMU."); kvm_vm_free(vm); @@ -444,6 +446,7 @@ static bool use_amd_pmu(void) int main(int argc, char *argv[]) { void (*guest_code)(void) = NULL; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; int r; @@ -466,24 +469,24 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); - if (!sanity_check_pmu(vm)) { + if (!sanity_check_pmu(vcpu)) { print_skip("Guest PMU is not functional"); exit(KSFT_SKIP); } if (use_amd_pmu()) - test_amd_deny_list(vm); + test_amd_deny_list(vcpu); - test_without_filter(vm); - test_member_deny_list(vm); - test_member_allow_list(vm); - test_not_member_deny_list(vm); - test_not_member_allow_list(vm); + test_without_filter(vcpu); + test_member_deny_list(vcpu); + test_member_allow_list(vcpu); + test_not_member_deny_list(vcpu); + test_not_member_allow_list(vcpu); kvm_vm_free(vm); From 20092699759bd7f5861b9441eab5ea5c983c77a2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 15:51:19 -0800 Subject: [PATCH 0367/1436] KVM: selftests: Convert smm_test away from VCPU_ID Convert smm_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==1. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically use vcpu_run() instead of _vcpu_run(), the test expects KVM_RUN to succeed. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/x86_64/smm_test.c | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/smm_test.c b/tools/testing/selftests/kvm/x86_64/smm_test.c index dd2c1522ab90..36165b774a28 100644 --- a/tools/testing/selftests/kvm/x86_64/smm_test.c +++ b/tools/testing/selftests/kvm/x86_64/smm_test.c @@ -19,8 +19,6 @@ #include "vmx.h" #include "svm_util.h" -#define VCPU_ID 1 - #define SMRAM_SIZE 65536 #define SMRAM_MEMSLOT ((1 << 16) | 1) #define SMRAM_PAGES (SMRAM_SIZE / PAGE_SIZE) @@ -116,22 +114,23 @@ static void guest_code(void *arg) sync_with_host(DONE); } -void inject_smi(struct kvm_vm *vm) +void inject_smi(struct kvm_vcpu *vcpu) { struct kvm_vcpu_events events; - vcpu_events_get(vm, VCPU_ID, &events); + vcpu_events_get(vcpu->vm, vcpu->id, &events); events.smi.pending = 1; events.flags |= KVM_VCPUEVENT_VALID_SMM; - vcpu_events_set(vm, VCPU_ID, &events); + vcpu_events_set(vcpu->vm, vcpu->id, &events); } int main(int argc, char *argv[]) { vm_vaddr_t nested_gva = 0; + struct kvm_vcpu *vcpu; struct kvm_regs regs; struct kvm_vm *vm; struct kvm_run *run; @@ -139,9 +138,9 @@ int main(int argc, char *argv[]) int stage, stage_reported; /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); - run = vcpu_state(vm, VCPU_ID); + run = vcpu->run; vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, SMRAM_GPA, SMRAM_MEMSLOT, SMRAM_PAGES, 0); @@ -152,7 +151,7 @@ int main(int argc, char *argv[]) memcpy(addr_gpa2hva(vm, SMRAM_GPA) + 0x8000, smi_handler, sizeof(smi_handler)); - vcpu_set_msr(vm, VCPU_ID, MSR_IA32_SMBASE, SMRAM_GPA); + vcpu_set_msr(vm, vcpu->id, MSR_IA32_SMBASE, SMRAM_GPA); if (kvm_check_cap(KVM_CAP_NESTED_STATE)) { if (nested_svm_supported()) @@ -164,17 +163,17 @@ int main(int argc, char *argv[]) if (!nested_gva) pr_info("will skip SMM test with VMX enabled\n"); - vcpu_args_set(vm, VCPU_ID, 1, nested_gva); + vcpu_args_set(vm, vcpu->id, 1, nested_gva); for (stage = 1;; stage++) { - _vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); memset(®s, 0, sizeof(regs)); - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vm, vcpu->id, ®s); stage_reported = regs.rax & 0xff; @@ -191,7 +190,7 @@ int main(int argc, char *argv[]) * return from it. Do not perform save/restore while in SMM yet. */ if (stage == 8) { - inject_smi(vm); + inject_smi(vcpu); continue; } @@ -200,15 +199,15 @@ int main(int argc, char *argv[]) * during L2 execution. */ if (stage == 10) - inject_smi(vm); + inject_smi(vcpu); - state = vcpu_save_state(vm, VCPU_ID); + state = vcpu_save_state(vm, vcpu->id); kvm_vm_release(vm); - kvm_vm_restart(vm); - vm_vcpu_add(vm, VCPU_ID); - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); - vcpu_load_state(vm, VCPU_ID, state); - run = vcpu_state(vm, VCPU_ID); + + vcpu = vm_recreate_with_one_vcpu(vm); + vcpu_set_cpuid(vm, vcpu->id, kvm_get_supported_cpuid()); + vcpu_load_state(vm, vcpu->id, state); + run = vcpu->run; kvm_x86_state_cleanup(state); } From 90b13cdde1fa6b71b4d6f8a5f6298f9e54233e98 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 15:53:16 -0800 Subject: [PATCH 0368/1436] KVM: selftests: Convert state_test away from VCPU_ID Convert state_test to use vm_create_with_one_vcpu() and vm_recreate_with_one_vcpu(), and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically use vcpu_run() instead of _vcpu_run(), the test expects KVM_RUN to succeed. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/x86_64/state_test.c | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index 41f7faaef2ac..b7869efad22a 100644 --- a/tools/testing/selftests/kvm/x86_64/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -20,7 +20,6 @@ #include "vmx.h" #include "svm_util.h" -#define VCPU_ID 5 #define L2_GUEST_STACK_SIZE 256 void svm_l2_guest_code(void) @@ -157,6 +156,7 @@ int main(int argc, char *argv[]) vm_vaddr_t nested_gva = 0; struct kvm_regs regs1, regs2; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; struct kvm_x86_state *state; @@ -164,10 +164,10 @@ int main(int argc, char *argv[]) int stage; /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + run = vcpu->run; - vcpu_regs_get(vm, VCPU_ID, ®s1); + vcpu_regs_get(vm, vcpu->id, ®s1); if (kvm_check_cap(KVM_CAP_NESTED_STATE)) { if (nested_svm_supported()) @@ -179,16 +179,16 @@ int main(int argc, char *argv[]) if (!nested_gva) pr_info("will skip nested state checks\n"); - vcpu_args_set(vm, VCPU_ID, 1, nested_gva); + vcpu_args_set(vm, vcpu->id, 1, nested_gva); for (stage = 1;; stage++) { - _vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); @@ -206,22 +206,21 @@ int main(int argc, char *argv[]) uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx", stage, (ulong)uc.args[1]); - state = vcpu_save_state(vm, VCPU_ID); + state = vcpu_save_state(vm, vcpu->id); memset(®s1, 0, sizeof(regs1)); - vcpu_regs_get(vm, VCPU_ID, ®s1); + vcpu_regs_get(vm, vcpu->id, ®s1); kvm_vm_release(vm); /* Restore state in a new VM. */ - kvm_vm_restart(vm); - vm_vcpu_add(vm, VCPU_ID); - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); - vcpu_load_state(vm, VCPU_ID, state); - run = vcpu_state(vm, VCPU_ID); + vcpu = vm_recreate_with_one_vcpu(vm); + vcpu_set_cpuid(vm, vcpu->id, kvm_get_supported_cpuid()); + vcpu_load_state(vm, vcpu->id, state); + run = vcpu->run; kvm_x86_state_cleanup(state); memset(®s2, 0, sizeof(regs2)); - vcpu_regs_get(vm, VCPU_ID, ®s2); + vcpu_regs_get(vm, vcpu->id, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", (ulong) regs2.rdi, (ulong) regs2.rsi); From cb4d9608af03ef289b57ceb925c6d8c2066d45d7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 15:55:26 -0800 Subject: [PATCH 0369/1436] KVM: selftests: Convert svm_int_ctl_test away from VCPU_ID Convert svm_int_ctl_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Opportunistically make the "vm" variable a local function variable, there are no users outside of main(). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/svm_int_ctl_test.c | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c b/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c index 30a81038df46..8e90e463895a 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c @@ -13,10 +13,6 @@ #include "svm_util.h" #include "apic.h" -#define VCPU_ID 0 - -static struct kvm_vm *vm; - bool vintr_irq_called; bool intr_irq_called; @@ -88,31 +84,34 @@ static void l1_guest_code(struct svm_test_data *svm) int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; + struct kvm_run *run; vm_vaddr_t svm_gva; + struct kvm_vm *vm; + struct ucall uc; nested_svm_check_supported(); - vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, VINTR_IRQ_NUMBER, vintr_irq_handler); vm_install_exception_handler(vm, INTR_IRQ_NUMBER, intr_irq_handler); vcpu_alloc_svm(vm, &svm_gva); - vcpu_args_set(vm, VCPU_ID, 1, svm_gva); + vcpu_args_set(vm, vcpu->id, 1, svm_gva); - struct kvm_run *run = vcpu_state(vm, VCPU_ID); - struct ucall uc; + run = vcpu->run; - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); break; From 91520c5121561fd33eba8e381764ec64d2748eca Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 15:56:54 -0800 Subject: [PATCH 0370/1436] KVM: selftests: Convert svm_vmcall_test away from VCPU_ID Convert svm_vmcall_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/svm_vmcall_test.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c index be2ca157485b..15e389a7cd31 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c @@ -12,10 +12,6 @@ #include "processor.h" #include "svm_util.h" -#define VCPU_ID 5 - -static struct kvm_vm *vm; - static void l2_guest_code(struct svm_test_data *svm) { __asm__ __volatile__("vmcall"); @@ -39,26 +35,28 @@ static void l1_guest_code(struct svm_test_data *svm) int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; vm_vaddr_t svm_gva; + struct kvm_vm *vm; nested_svm_check_supported(); - vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vcpu_alloc_svm(vm, &svm_gva); - vcpu_args_set(vm, VCPU_ID, 1, svm_gva); + vcpu_args_set(vm, vcpu->id, 1, svm_gva); for (;;) { - volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); + volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ From 0184323acbc460893025871ccfd1db04223a7477 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:04:25 -0800 Subject: [PATCH 0371/1436] KVM: selftests: Convert sync_regs_test away from VCPU_ID Convert sync_regs_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/sync_regs_test.c | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c index fc03a150278d..c971706b49f5 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -20,8 +20,6 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 5 - #define UCALL_PIO_PORT ((uint16_t)0x1000) struct ucall uc_none = { @@ -84,6 +82,7 @@ static void compare_vcpu_events(struct kvm_vcpu_events *left, int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; struct kvm_regs regs; @@ -104,57 +103,56 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); - run = vcpu_state(vm, VCPU_ID); + run = vcpu->run; /* Request reading invalid register set from VCPU. */ run->kvm_valid_regs = INVALID_SYNC_FIELD; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vm, vcpu->id); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", rv); - vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0; + run->kvm_valid_regs = 0; run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vm, vcpu->id); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", rv); - vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0; + run->kvm_valid_regs = 0; /* Request setting invalid register set into VCPU. */ run->kvm_dirty_regs = INVALID_SYNC_FIELD; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vm, vcpu->id); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", rv); - vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0; + run->kvm_dirty_regs = 0; run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vm, vcpu->id); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", rv); - vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0; + run->kvm_dirty_regs = 0; /* Request and verify all valid register sets. */ /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */ run->kvm_valid_regs = TEST_SYNC_FIELDS; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vm, vcpu->id, ®s); compare_regs(®s, &run->s.regs.regs); - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vm, vcpu->id, &sregs); compare_sregs(&sregs, &run->s.regs.sregs); - vcpu_events_get(vm, VCPU_ID, &events); + vcpu_events_get(vm, vcpu->id, &events); compare_vcpu_events(&events, &run->s.regs.events); /* Set and verify various register values. */ @@ -164,7 +162,7 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = TEST_SYNC_FIELDS; run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, @@ -176,13 +174,13 @@ int main(int argc, char *argv[]) "apic_base sync regs value incorrect 0x%llx.", run->s.regs.sregs.apic_base); - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vm, vcpu->id, ®s); compare_regs(®s, &run->s.regs.regs); - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vm, vcpu->id, &sregs); compare_sregs(&sregs, &run->s.regs.sregs); - vcpu_events_get(vm, VCPU_ID, &events); + vcpu_events_get(vm, vcpu->id, &events); compare_vcpu_events(&events, &run->s.regs.events); /* Clear kvm_dirty_regs bits, verify new s.regs values are @@ -191,7 +189,7 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = TEST_SYNC_FIELDS; run->kvm_dirty_regs = 0; run->s.regs.regs.rbx = 0xDEADBEEF; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, @@ -208,8 +206,8 @@ int main(int argc, char *argv[]) run->kvm_dirty_regs = 0; run->s.regs.regs.rbx = 0xAAAA; regs.rbx = 0xBAC0; - vcpu_regs_set(vm, VCPU_ID, ®s); - rv = _vcpu_run(vm, VCPU_ID); + vcpu_regs_set(vm, vcpu->id, ®s); + rv = _vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, @@ -217,7 +215,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(run->s.regs.regs.rbx == 0xAAAA, "rbx sync regs value incorrect 0x%llx.", run->s.regs.regs.rbx); - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vm, vcpu->id, ®s); TEST_ASSERT(regs.rbx == 0xBAC0 + 1, "rbx guest value incorrect 0x%llx.", regs.rbx); @@ -229,7 +227,7 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = 0; run->kvm_dirty_regs = TEST_SYNC_FIELDS; run->s.regs.regs.rbx = 0xBBBB; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, @@ -237,7 +235,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(run->s.regs.regs.rbx == 0xBBBB, "rbx sync regs value incorrect 0x%llx.", run->s.regs.regs.rbx); - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vm, vcpu->id, ®s); TEST_ASSERT(regs.rbx == 0xBBBB + 1, "rbx guest value incorrect 0x%llx.", regs.rbx); From 5c6e31b3bc4b526f872cca35a86169b3aa968259 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:08:48 -0800 Subject: [PATCH 0372/1436] KVM: selftests: Convert hyperv_cpuid away from VCPU_ID Convert hyperv_cpuid to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/hyperv_cpuid.c | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c index 896e1e7c1df7..d1a22ee98cf3 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c @@ -20,8 +20,6 @@ #include "processor.h" #include "vmx.h" -#define VCPU_ID 0 - static void guest_code(void) { } @@ -115,25 +113,26 @@ static void test_hv_cpuid(struct kvm_cpuid2 *hv_cpuid_entries, } } -void test_hv_cpuid_e2big(struct kvm_vm *vm, bool system) +void test_hv_cpuid_e2big(struct kvm_vm *vm, struct kvm_vcpu *vcpu) { static struct kvm_cpuid2 cpuid = {.nent = 0}; int ret; - if (!system) - ret = __vcpu_ioctl(vm, VCPU_ID, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); + if (vcpu) + ret = __vcpu_ioctl(vm, vcpu->id, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); else ret = __kvm_ioctl(vm_get_kvm_fd(vm), KVM_GET_SUPPORTED_HV_CPUID, &cpuid); TEST_ASSERT(ret == -1 && errno == E2BIG, "%s KVM_GET_SUPPORTED_HV_CPUID didn't fail with -E2BIG when" - " it should have: %d %d", system ? "KVM" : "vCPU", ret, errno); + " it should have: %d %d", !vcpu ? "KVM" : "vCPU", ret, errno); } int main(int argc, char *argv[]) { struct kvm_vm *vm; struct kvm_cpuid2 *hv_cpuid_entries; + struct kvm_vcpu *vcpu; /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); @@ -143,12 +142,12 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); /* Test vCPU ioctl version */ - test_hv_cpuid_e2big(vm, false); + test_hv_cpuid_e2big(vm, vcpu); - hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vm, VCPU_ID); + hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vm, vcpu->id); test_hv_cpuid(hv_cpuid_entries, false); free(hv_cpuid_entries); @@ -157,8 +156,8 @@ int main(int argc, char *argv[]) print_skip("Enlightened VMCS is unsupported"); goto do_sys; } - vcpu_enable_evmcs(vm, VCPU_ID); - hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vm, VCPU_ID); + vcpu_enable_evmcs(vm, vcpu->id); + hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vm, vcpu->id); test_hv_cpuid(hv_cpuid_entries, true); free(hv_cpuid_entries); @@ -169,7 +168,7 @@ do_sys: goto out; } - test_hv_cpuid_e2big(vm, true); + test_hv_cpuid_e2big(vm, NULL); hv_cpuid_entries = kvm_get_supported_hv_cpuid(); test_hv_cpuid(hv_cpuid_entries, nested_vmx_supported()); From f323dbce3ba126f7b1dfeb7042c3b3037155aac2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:10:04 -0800 Subject: [PATCH 0373/1436] KVM: selftests: Convert kvm_pv_test away from VCPU_ID Convert kvm_pv_test to use vm_create_with_one_vcpu() and pass arounda 'struct kvm_vcpu' object instead of using a global VCPU_ID. Opportunistically use vcpu_run() instead of _vcpu_run() with an open coded assert that KVM_RUN succeeded. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/kvm_pv_test.c | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index 5eea3ac7958e..734e71739d33 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -171,24 +171,18 @@ static void handle_abort(struct ucall *uc) __FILE__, uc->args[1]); } -#define VCPU_ID 0 - -static void enter_guest(struct kvm_vm *vm) +static void enter_guest(struct kvm_vcpu *vcpu) { - struct kvm_run *run; + struct kvm_run *run = vcpu->run; struct ucall uc; - int r; - - run = vcpu_state(vm, VCPU_ID); while (true) { - r = _vcpu_run(vm, VCPU_ID); - TEST_ASSERT(!r, "vcpu_run failed: %d\n", r); + vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_PR_MSR: pr_msr(&uc); break; @@ -207,6 +201,7 @@ static void enter_guest(struct kvm_vm *vm) int main(void) { struct kvm_cpuid2 *best; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; if (!kvm_check_cap(KVM_CAP_ENFORCE_PV_FEATURE_CPUID)) { @@ -214,18 +209,18 @@ int main(void) exit(KSFT_SKIP); } - vm = vm_create_default(VCPU_ID, 0, guest_main); + vm = vm_create_with_one_vcpu(&vcpu, guest_main); - vcpu_enable_cap(vm, VCPU_ID, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 1); + vcpu_enable_cap(vm, vcpu->id, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 1); best = kvm_get_supported_cpuid(); clear_kvm_cpuid_features(best); - vcpu_set_cpuid(vm, VCPU_ID, best); + vcpu_set_cpuid(vm, vcpu->id, best); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); - enter_guest(vm); + enter_guest(vcpu); kvm_vm_free(vm); } From 1cc1a9f38da4d6ce650eed03721d470924559b0f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:11:59 -0800 Subject: [PATCH 0374/1436] KVM: selftests: Convert platform_info_test away from VCPU_ID Convert platform_info_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/platform_info_test.c | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/platform_info_test.c b/tools/testing/selftests/kvm/x86_64/platform_info_test.c index e79c04581ca8..eb5e1f972d76 100644 --- a/tools/testing/selftests/kvm/x86_64/platform_info_test.c +++ b/tools/testing/selftests/kvm/x86_64/platform_info_test.c @@ -21,7 +21,6 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 0 #define MSR_PLATFORM_INFO_MAX_TURBO_RATIO 0xff00 static void guest_code(void) @@ -35,18 +34,18 @@ static void guest_code(void) } } -static void test_msr_platform_info_enabled(struct kvm_vm *vm) +static void test_msr_platform_info_enabled(struct kvm_vcpu *vcpu) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; struct ucall uc; - vm_enable_cap(vm, KVM_CAP_MSR_PLATFORM_INFO, true); - vcpu_run(vm, VCPU_ID); + vm_enable_cap(vcpu->vm, KVM_CAP_MSR_PLATFORM_INFO, true); + vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Exit_reason other than KVM_EXIT_IO: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - get_ucall(vm, VCPU_ID, &uc); + get_ucall(vcpu->vm, vcpu->id, &uc); TEST_ASSERT(uc.cmd == UCALL_SYNC, "Received ucall other than UCALL_SYNC: %lu\n", uc.cmd); TEST_ASSERT((uc.args[1] & MSR_PLATFORM_INFO_MAX_TURBO_RATIO) == @@ -55,12 +54,12 @@ static void test_msr_platform_info_enabled(struct kvm_vm *vm) MSR_PLATFORM_INFO_MAX_TURBO_RATIO); } -static void test_msr_platform_info_disabled(struct kvm_vm *vm) +static void test_msr_platform_info_disabled(struct kvm_vcpu *vcpu) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; - vm_enable_cap(vm, KVM_CAP_MSR_PLATFORM_INFO, false); - vcpu_run(vm, VCPU_ID); + vm_enable_cap(vcpu->vm, KVM_CAP_MSR_PLATFORM_INFO, false); + vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN, "Exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s)\n", run->exit_reason, @@ -69,6 +68,7 @@ static void test_msr_platform_info_disabled(struct kvm_vm *vm) int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; int rv; uint64_t msr_platform_info; @@ -82,14 +82,14 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); - msr_platform_info = vcpu_get_msr(vm, VCPU_ID, MSR_PLATFORM_INFO); - vcpu_set_msr(vm, VCPU_ID, MSR_PLATFORM_INFO, + msr_platform_info = vcpu_get_msr(vm, vcpu->id, MSR_PLATFORM_INFO); + vcpu_set_msr(vm, vcpu->id, MSR_PLATFORM_INFO, msr_platform_info | MSR_PLATFORM_INFO_MAX_TURBO_RATIO); - test_msr_platform_info_enabled(vm); - test_msr_platform_info_disabled(vm); - vcpu_set_msr(vm, VCPU_ID, MSR_PLATFORM_INFO, msr_platform_info); + test_msr_platform_info_enabled(vcpu); + test_msr_platform_info_disabled(vcpu); + vcpu_set_msr(vm, vcpu->id, MSR_PLATFORM_INFO, msr_platform_info); kvm_vm_free(vm); From 6f96628f8290d2b634ba0dc5b83bd7201e099c52 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:23:43 -0800 Subject: [PATCH 0375/1436] KVM: selftests: Convert vmx_nested_tsc_scaling_test away from VCPU_ID Convert vmx_nested_tsc_scaling_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/x86_64/vmx_nested_tsc_scaling_test.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c index c35ada9f7f9c..c9cb29f06244 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c @@ -15,9 +15,6 @@ #include "vmx.h" #include "kselftest.h" - -#define VCPU_ID 0 - /* L2 is scaled up (from L1's perspective) by this factor */ #define L2_SCALE_FACTOR 4ULL @@ -150,6 +147,7 @@ skip_test: int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; vm_vaddr_t vmx_pages_gva; @@ -182,28 +180,28 @@ int main(int argc, char *argv[]) l0_tsc_freq = tsc_end - tsc_start; printf("real TSC frequency is around: %"PRIu64"\n", l0_tsc_freq); - vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); + vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); - tsc_khz = __vcpu_ioctl(vm, VCPU_ID, KVM_GET_TSC_KHZ, NULL); + tsc_khz = __vcpu_ioctl(vm, vcpu->id, KVM_GET_TSC_KHZ, NULL); TEST_ASSERT(tsc_khz != -1, "vcpu ioctl KVM_GET_TSC_KHZ failed"); /* scale down L1's TSC frequency */ - vcpu_ioctl(vm, VCPU_ID, KVM_SET_TSC_KHZ, + vcpu_ioctl(vm, vcpu->id, KVM_SET_TSC_KHZ, (void *) (tsc_khz / l1_scale_factor)); for (;;) { - volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); + volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *) uc.args[0]); case UCALL_SYNC: From d31e15005dde30f5e25308ee01b6f518b5cadecb Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:24:50 -0800 Subject: [PATCH 0376/1436] KVM: selftests: Convert set_sregs_test away from VCPU_ID Convert set_sregs_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/set_sregs_test.c | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c index f5e65db9f451..8a5c1f76287c 100644 --- a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c +++ b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c @@ -22,9 +22,7 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 5 - -static void test_cr4_feature_bit(struct kvm_vm *vm, struct kvm_sregs *orig, +static void test_cr4_feature_bit(struct kvm_vcpu *vcpu, struct kvm_sregs *orig, uint64_t feature_bit) { struct kvm_sregs sregs; @@ -37,11 +35,11 @@ static void test_cr4_feature_bit(struct kvm_vm *vm, struct kvm_sregs *orig, memcpy(&sregs, orig, sizeof(sregs)); sregs.cr4 |= feature_bit; - rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); + rc = _vcpu_sregs_set(vcpu->vm, vcpu->id, &sregs); TEST_ASSERT(rc, "KVM allowed unsupported CR4 bit (0x%lx)", feature_bit); /* Sanity check that KVM didn't change anything. */ - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); TEST_ASSERT(!memcmp(&sregs, orig, sizeof(sregs)), "KVM modified sregs"); } @@ -83,6 +81,7 @@ static uint64_t calc_cr4_feature_bits(struct kvm_vm *vm) int main(int argc, char *argv[]) { struct kvm_sregs sregs; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; uint64_t cr4; int rc; @@ -96,43 +95,43 @@ int main(int argc, char *argv[]) * the vCPU model, i.e. without doing KVM_SET_CPUID2. */ vm = vm_create_barebones(); - vm_vcpu_add(vm, VCPU_ID); + vcpu = vm_vcpu_add(vm, 0); - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vm, vcpu->id, &sregs); sregs.cr4 |= calc_cr4_feature_bits(vm); cr4 = sregs.cr4; - rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); + rc = _vcpu_sregs_set(vm, vcpu->id, &sregs); TEST_ASSERT(!rc, "Failed to set supported CR4 bits (0x%lx)", cr4); - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vm, vcpu->id, &sregs); TEST_ASSERT(sregs.cr4 == cr4, "sregs.CR4 (0x%llx) != CR4 (0x%lx)", sregs.cr4, cr4); /* Verify all unsupported features are rejected by KVM. */ - test_cr4_feature_bit(vm, &sregs, X86_CR4_UMIP); - test_cr4_feature_bit(vm, &sregs, X86_CR4_LA57); - test_cr4_feature_bit(vm, &sregs, X86_CR4_VMXE); - test_cr4_feature_bit(vm, &sregs, X86_CR4_SMXE); - test_cr4_feature_bit(vm, &sregs, X86_CR4_FSGSBASE); - test_cr4_feature_bit(vm, &sregs, X86_CR4_PCIDE); - test_cr4_feature_bit(vm, &sregs, X86_CR4_OSXSAVE); - test_cr4_feature_bit(vm, &sregs, X86_CR4_SMEP); - test_cr4_feature_bit(vm, &sregs, X86_CR4_SMAP); - test_cr4_feature_bit(vm, &sregs, X86_CR4_PKE); + test_cr4_feature_bit(vcpu, &sregs, X86_CR4_UMIP); + test_cr4_feature_bit(vcpu, &sregs, X86_CR4_LA57); + test_cr4_feature_bit(vcpu, &sregs, X86_CR4_VMXE); + test_cr4_feature_bit(vcpu, &sregs, X86_CR4_SMXE); + test_cr4_feature_bit(vcpu, &sregs, X86_CR4_FSGSBASE); + test_cr4_feature_bit(vcpu, &sregs, X86_CR4_PCIDE); + test_cr4_feature_bit(vcpu, &sregs, X86_CR4_OSXSAVE); + test_cr4_feature_bit(vcpu, &sregs, X86_CR4_SMEP); + test_cr4_feature_bit(vcpu, &sregs, X86_CR4_SMAP); + test_cr4_feature_bit(vcpu, &sregs, X86_CR4_PKE); kvm_vm_free(vm); /* Create a "real" VM and verify APIC_BASE can be set. */ - vm = vm_create_default(VCPU_ID, 0, NULL); + vm = vm_create_with_one_vcpu(&vcpu, NULL); - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vm, vcpu->id, &sregs); sregs.apic_base = 1 << 10; - rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); + rc = _vcpu_sregs_set(vm, vcpu->id, &sregs); TEST_ASSERT(rc, "Set IA32_APIC_BASE to %llx (invalid)", sregs.apic_base); sregs.apic_base = 1 << 11; - rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); + rc = _vcpu_sregs_set(vm, vcpu->id, &sregs); TEST_ASSERT(!rc, "Couldn't set IA32_APIC_BASE to %llx (valid)", sregs.apic_base); From ec7b769a732052e6c8f73db35fd8ee35d1368a4b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:26:03 -0800 Subject: [PATCH 0377/1436] KVM: selftests: Convert vmx_dirty_log_test away from VCPU_ID Convert vmx_dirty_log_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==1. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/vmx_dirty_log_test.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c index 68f26a8b4f42..fb8c7f7236f7 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c @@ -17,8 +17,6 @@ #include "processor.h" #include "vmx.h" -#define VCPU_ID 1 - /* The memory slot index to track dirty pages */ #define TEST_MEM_SLOT_INDEX 1 #define TEST_MEM_PAGES 3 @@ -73,6 +71,7 @@ int main(int argc, char *argv[]) unsigned long *bmap; uint64_t *host_test_mem; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; struct ucall uc; @@ -81,10 +80,10 @@ int main(int argc, char *argv[]) nested_vmx_check_supported(); /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vmx = vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); - run = vcpu_state(vm, VCPU_ID); + vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); + run = vcpu->run; /* Add an extra memory slot for testing dirty logging */ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, @@ -116,13 +115,13 @@ int main(int argc, char *argv[]) while (!done) { memset(host_test_mem, 0xaa, TEST_MEM_PAGES * 4096); - _vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); From 706aaa4fedd9b028a3238221a8aba499b74d8f93 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:26:58 -0800 Subject: [PATCH 0378/1436] KVM: selftests: Convert vmx_close_while_nested_test away from VCPU_ID Convert vmx_close_while_nested_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically make the "vm" variable local, it is unused outside of main(). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/x86_64/vmx_close_while_nested_test.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c b/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c index edac8839e717..da0363076fba 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c @@ -18,15 +18,10 @@ #include "kselftest.h" -#define VCPU_ID 5 - enum { PORT_L0_EXIT = 0x2000, }; -/* The virtual machine object. */ -static struct kvm_vm *vm; - static void l2_guest_code(void) { /* Exit to L0 */ @@ -53,20 +48,22 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) int main(int argc, char *argv[]) { vm_vaddr_t vmx_pages_gva; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; nested_vmx_check_supported(); - vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); /* Allocate VMX pages and shared descriptors (vmx_pages). */ vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); + vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); for (;;) { - volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); + volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, @@ -75,7 +72,7 @@ int main(int argc, char *argv[]) if (run->io.port == PORT_L0_EXIT) break; - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ From 21c602e671755765cde92dd5f07125c6ba8b8d03 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:27:47 -0800 Subject: [PATCH 0379/1436] KVM: selftests: Convert vmx_apic_access_test away from VCPU_ID Convert vmx_apic_access_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Opportunistically make the "vm" variable local, it is unused outside of main(). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/x86_64/vmx_apic_access_test.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c index d438c4d3228a..10f9c86029e6 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c @@ -28,11 +28,6 @@ #include "kselftest.h" -#define VCPU_ID 0 - -/* The virtual machine object. */ -static struct kvm_vm *vm; - static void l2_guest_code(void) { /* Exit to L1 */ @@ -84,9 +79,12 @@ int main(int argc, char *argv[]) struct vmx_pages *vmx; bool done = false; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + nested_vmx_check_supported(); - vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); kvm_get_cpu_address_width(&paddr_width, &vaddr_width); high_gpa = (1ul << paddr_width) - getpagesize(); @@ -97,13 +95,13 @@ int main(int argc, char *argv[]) vmx = vcpu_alloc_vmx(vm, &vmx_pages_gva); prepare_virtualize_apic_accesses(vmx, vm); - vcpu_args_set(vm, VCPU_ID, 2, vmx_pages_gva, high_gpa); + vcpu_args_set(vm, vcpu->id, 2, vmx_pages_gva, high_gpa); while (!done) { - volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); + volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); if (apic_access_addr == high_gpa) { TEST_ASSERT(run->exit_reason == KVM_EXIT_INTERNAL_ERROR, @@ -121,7 +119,7 @@ int main(int argc, char *argv[]) run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); From b4694260299ac4312a5a2d94a47957c1b6d55d00 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:38:01 -0800 Subject: [PATCH 0380/1436] KVM: selftests: Convert userspace_msr_exit_test away from VCPU_ID Convert userspace_msr_exit_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==1. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically use vcpu_run() instead of _vcpu_run() with an open coded assert that KVM_RUN succeeded. Fix minor coding style violations too. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/x86_64/userspace_msr_exit_test.c | 156 ++++++++---------- 1 file changed, 72 insertions(+), 84 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c index 23e9292580c9..a0d35e578b25 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c @@ -17,7 +17,6 @@ #define KVM_FEP_LENGTH 5 static int fep_available = 1; -#define VCPU_ID 1 #define MSR_NON_EXISTENT 0x474f4f00 static u64 deny_bits = 0; @@ -395,31 +394,22 @@ static void guest_ud_handler(struct ex_regs *regs) regs->rip += KVM_FEP_LENGTH; } -static void run_guest(struct kvm_vm *vm) +static void check_for_guest_assert(struct kvm_vcpu *vcpu) { - int rc; - - rc = _vcpu_run(vm, VCPU_ID); - TEST_ASSERT(rc == 0, "vcpu_run failed: %d\n", rc); -} - -static void check_for_guest_assert(struct kvm_vm *vm) -{ - struct kvm_run *run = vcpu_state(vm, VCPU_ID); struct ucall uc; - if (run->exit_reason == KVM_EXIT_IO && - get_ucall(vm, VCPU_ID, &uc) == UCALL_ABORT) { - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + if (vcpu->run->exit_reason == KVM_EXIT_IO && + get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_ABORT) { + TEST_FAIL("%s at %s:%ld", + (const char *)uc.args[0], __FILE__, uc.args[1]); } } -static void process_rdmsr(struct kvm_vm *vm, uint32_t msr_index) +static void process_rdmsr(struct kvm_vcpu *vcpu, uint32_t msr_index) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; - check_for_guest_assert(vm); + check_for_guest_assert(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_X86_RDMSR, "Unexpected exit reason: %u (%s),\n", @@ -450,11 +440,11 @@ static void process_rdmsr(struct kvm_vm *vm, uint32_t msr_index) } } -static void process_wrmsr(struct kvm_vm *vm, uint32_t msr_index) +static void process_wrmsr(struct kvm_vcpu *vcpu, uint32_t msr_index) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; - check_for_guest_assert(vm); + check_for_guest_assert(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_X86_WRMSR, "Unexpected exit reason: %u (%s),\n", @@ -481,43 +471,43 @@ static void process_wrmsr(struct kvm_vm *vm, uint32_t msr_index) } } -static void process_ucall_done(struct kvm_vm *vm) +static void process_ucall_done(struct kvm_vcpu *vcpu) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; struct ucall uc; - check_for_guest_assert(vm); + check_for_guest_assert(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - TEST_ASSERT(get_ucall(vm, VCPU_ID, &uc) == UCALL_DONE, + TEST_ASSERT(get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_DONE, "Unexpected ucall command: %lu, expected UCALL_DONE (%d)", uc.cmd, UCALL_DONE); } -static uint64_t process_ucall(struct kvm_vm *vm) +static uint64_t process_ucall(struct kvm_vcpu *vcpu) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; struct ucall uc = {}; - check_for_guest_assert(vm); + check_for_guest_assert(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_SYNC: break; case UCALL_ABORT: - check_for_guest_assert(vm); + check_for_guest_assert(vcpu); break; case UCALL_DONE: - process_ucall_done(vm); + process_ucall_done(vcpu); break; default: TEST_ASSERT(false, "Unexpected ucall"); @@ -526,38 +516,39 @@ static uint64_t process_ucall(struct kvm_vm *vm) return uc.cmd; } -static void run_guest_then_process_rdmsr(struct kvm_vm *vm, uint32_t msr_index) +static void run_guest_then_process_rdmsr(struct kvm_vcpu *vcpu, + uint32_t msr_index) { - run_guest(vm); - process_rdmsr(vm, msr_index); + vcpu_run(vcpu->vm, vcpu->id); + process_rdmsr(vcpu, msr_index); } -static void run_guest_then_process_wrmsr(struct kvm_vm *vm, uint32_t msr_index) +static void run_guest_then_process_wrmsr(struct kvm_vcpu *vcpu, + uint32_t msr_index) { - run_guest(vm); - process_wrmsr(vm, msr_index); + vcpu_run(vcpu->vm, vcpu->id); + process_wrmsr(vcpu, msr_index); } -static uint64_t run_guest_then_process_ucall(struct kvm_vm *vm) +static uint64_t run_guest_then_process_ucall(struct kvm_vcpu *vcpu) { - run_guest(vm); - return process_ucall(vm); + vcpu_run(vcpu->vm, vcpu->id); + return process_ucall(vcpu); } -static void run_guest_then_process_ucall_done(struct kvm_vm *vm) +static void run_guest_then_process_ucall_done(struct kvm_vcpu *vcpu) { - run_guest(vm); - process_ucall_done(vm); + vcpu_run(vcpu->vm, vcpu->id); + process_ucall_done(vcpu); } static void test_msr_filter_allow(void) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; int rc; - /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code_filter_allow); - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + vm = vm_create_with_one_vcpu(&vcpu, guest_code_filter_allow); rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available"); @@ -569,43 +560,43 @@ static void test_msr_filter_allow(void) vm_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter_allow); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); /* Process guest code userspace exits. */ - run_guest_then_process_rdmsr(vm, MSR_IA32_XSS); - run_guest_then_process_wrmsr(vm, MSR_IA32_XSS); - run_guest_then_process_wrmsr(vm, MSR_IA32_XSS); + run_guest_then_process_rdmsr(vcpu, MSR_IA32_XSS); + run_guest_then_process_wrmsr(vcpu, MSR_IA32_XSS); + run_guest_then_process_wrmsr(vcpu, MSR_IA32_XSS); - run_guest_then_process_rdmsr(vm, MSR_IA32_FLUSH_CMD); - run_guest_then_process_wrmsr(vm, MSR_IA32_FLUSH_CMD); - run_guest_then_process_wrmsr(vm, MSR_IA32_FLUSH_CMD); + run_guest_then_process_rdmsr(vcpu, MSR_IA32_FLUSH_CMD); + run_guest_then_process_wrmsr(vcpu, MSR_IA32_FLUSH_CMD); + run_guest_then_process_wrmsr(vcpu, MSR_IA32_FLUSH_CMD); - run_guest_then_process_wrmsr(vm, MSR_NON_EXISTENT); - run_guest_then_process_rdmsr(vm, MSR_NON_EXISTENT); + run_guest_then_process_wrmsr(vcpu, MSR_NON_EXISTENT); + run_guest_then_process_rdmsr(vcpu, MSR_NON_EXISTENT); vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); - run_guest(vm); + vcpu_run(vm, vcpu->id); vm_install_exception_handler(vm, UD_VECTOR, NULL); - if (process_ucall(vm) != UCALL_DONE) { + if (process_ucall(vcpu) != UCALL_DONE) { vm_install_exception_handler(vm, GP_VECTOR, guest_fep_gp_handler); /* Process emulated rdmsr and wrmsr instructions. */ - run_guest_then_process_rdmsr(vm, MSR_IA32_XSS); - run_guest_then_process_wrmsr(vm, MSR_IA32_XSS); - run_guest_then_process_wrmsr(vm, MSR_IA32_XSS); + run_guest_then_process_rdmsr(vcpu, MSR_IA32_XSS); + run_guest_then_process_wrmsr(vcpu, MSR_IA32_XSS); + run_guest_then_process_wrmsr(vcpu, MSR_IA32_XSS); - run_guest_then_process_rdmsr(vm, MSR_IA32_FLUSH_CMD); - run_guest_then_process_wrmsr(vm, MSR_IA32_FLUSH_CMD); - run_guest_then_process_wrmsr(vm, MSR_IA32_FLUSH_CMD); + run_guest_then_process_rdmsr(vcpu, MSR_IA32_FLUSH_CMD); + run_guest_then_process_wrmsr(vcpu, MSR_IA32_FLUSH_CMD); + run_guest_then_process_wrmsr(vcpu, MSR_IA32_FLUSH_CMD); - run_guest_then_process_wrmsr(vm, MSR_NON_EXISTENT); - run_guest_then_process_rdmsr(vm, MSR_NON_EXISTENT); + run_guest_then_process_wrmsr(vcpu, MSR_NON_EXISTENT); + run_guest_then_process_rdmsr(vcpu, MSR_NON_EXISTENT); /* Confirm the guest completed without issues. */ - run_guest_then_process_ucall_done(vm); + run_guest_then_process_ucall_done(vcpu); } else { printf("To run the instruction emulated tests set the module parameter 'kvm.force_emulation_prefix=1'\n"); } @@ -613,16 +604,16 @@ static void test_msr_filter_allow(void) kvm_vm_free(vm); } -static int handle_ucall(struct kvm_vm *vm) +static int handle_ucall(struct kvm_vcpu *vcpu) { struct ucall uc; - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("Guest assertion not met"); break; case UCALL_SYNC: - vm_ioctl(vm, KVM_X86_SET_MSR_FILTER, &no_filter_deny); + vm_ioctl(vcpu->vm, KVM_X86_SET_MSR_FILTER, &no_filter_deny); break; case UCALL_DONE: return 1; @@ -672,14 +663,13 @@ static void handle_wrmsr(struct kvm_run *run) static void test_msr_filter_deny(void) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; int rc; - /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code_filter_deny); - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code_filter_deny); + run = vcpu->run; rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available"); @@ -694,9 +684,7 @@ static void test_msr_filter_deny(void) vm_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter_deny); while (1) { - rc = _vcpu_run(vm, VCPU_ID); - - TEST_ASSERT(rc == 0, "vcpu_run failed: %d\n", rc); + vcpu_run(vm, vcpu->id); switch (run->exit_reason) { case KVM_EXIT_X86_RDMSR: @@ -706,7 +694,7 @@ static void test_msr_filter_deny(void) handle_wrmsr(run); break; case KVM_EXIT_IO: - if (handle_ucall(vm)) + if (handle_ucall(vcpu)) goto done; break; } @@ -722,12 +710,11 @@ done: static void test_msr_permission_bitmap(void) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; int rc; - /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code_permission_bitmap); - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + vm = vm_create_with_one_vcpu(&vcpu, guest_code_permission_bitmap); rc = kvm_check_cap(KVM_CAP_X86_USER_SPACE_MSR); TEST_ASSERT(rc, "KVM_CAP_X86_USER_SPACE_MSR is available"); @@ -737,11 +724,12 @@ static void test_msr_permission_bitmap(void) TEST_ASSERT(rc, "KVM_CAP_X86_MSR_FILTER is available"); vm_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter_fs); - run_guest_then_process_rdmsr(vm, MSR_FS_BASE); - TEST_ASSERT(run_guest_then_process_ucall(vm) == UCALL_SYNC, "Expected ucall state to be UCALL_SYNC."); + run_guest_then_process_rdmsr(vcpu, MSR_FS_BASE); + TEST_ASSERT(run_guest_then_process_ucall(vcpu) == UCALL_SYNC, + "Expected ucall state to be UCALL_SYNC."); vm_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter_gs); - run_guest_then_process_rdmsr(vm, MSR_GS_BASE); - run_guest_then_process_ucall_done(vm); + run_guest_then_process_rdmsr(vcpu, MSR_GS_BASE); + run_guest_then_process_ucall_done(vcpu); kvm_vm_free(vm); } From 709fd88491a819382c0f47e813628f2650497b4d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:44:36 -0800 Subject: [PATCH 0381/1436] KVM: selftests: Convert vmx_exception_with_invalid_guest_state away from VCPU_ID Convert vmx_exception_with_invalid_guest_state to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../vmx_exception_with_invalid_guest_state.c | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c index 27a850f3d7ce..70b30583e50d 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c @@ -10,10 +10,6 @@ #include "kselftest.h" -#define VCPU_ID 0 - -static struct kvm_vm *vm; - static void guest_ud_handler(struct ex_regs *regs) { /* Loop on the ud2 until guest state is made invalid. */ @@ -24,11 +20,11 @@ static void guest_code(void) asm volatile("ud2"); } -static void __run_vcpu_with_invalid_state(void) +static void __run_vcpu_with_invalid_state(struct kvm_vcpu *vcpu) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; - vcpu_run(vm, VCPU_ID); + vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_INTERNAL_ERROR, "Expected KVM_EXIT_INTERNAL_ERROR, got %d (%s)\n", @@ -38,15 +34,15 @@ static void __run_vcpu_with_invalid_state(void) run->emulation_failure.suberror); } -static void run_vcpu_with_invalid_state(void) +static void run_vcpu_with_invalid_state(struct kvm_vcpu *vcpu) { /* * Always run twice to verify KVM handles the case where _KVM_ queues * an exception with invalid state and then exits to userspace, i.e. * that KVM doesn't explode if userspace ignores the initial error. */ - __run_vcpu_with_invalid_state(); - __run_vcpu_with_invalid_state(); + __run_vcpu_with_invalid_state(vcpu); + __run_vcpu_with_invalid_state(vcpu); } static void set_timer(void) @@ -59,33 +55,43 @@ static void set_timer(void) ASSERT_EQ(setitimer(ITIMER_REAL, &timer, NULL), 0); } -static void set_or_clear_invalid_guest_state(bool set) +static void set_or_clear_invalid_guest_state(struct kvm_vcpu *vcpu, bool set) { static struct kvm_sregs sregs; if (!sregs.cr0) - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); sregs.tr.unusable = !!set; - vcpu_sregs_set(vm, VCPU_ID, &sregs); + vcpu_sregs_set(vcpu->vm, vcpu->id, &sregs); } -static void set_invalid_guest_state(void) +static void set_invalid_guest_state(struct kvm_vcpu *vcpu) { - set_or_clear_invalid_guest_state(true); + set_or_clear_invalid_guest_state(vcpu, true); } -static void clear_invalid_guest_state(void) +static void clear_invalid_guest_state(struct kvm_vcpu *vcpu) { - set_or_clear_invalid_guest_state(false); + set_or_clear_invalid_guest_state(vcpu, false); +} + +static struct kvm_vcpu *get_set_sigalrm_vcpu(struct kvm_vcpu *__vcpu) +{ + static struct kvm_vcpu *vcpu = NULL; + + if (__vcpu) + vcpu = __vcpu; + return vcpu; } static void sigalrm_handler(int sig) { + struct kvm_vcpu *vcpu = get_set_sigalrm_vcpu(NULL); struct kvm_vcpu_events events; TEST_ASSERT(sig == SIGALRM, "Unexpected signal = %d", sig); - vcpu_events_get(vm, VCPU_ID, &events); + vcpu_events_get(vcpu->vm, vcpu->id, &events); /* * If an exception is pending, attempt KVM_RUN with invalid guest, @@ -93,8 +99,8 @@ static void sigalrm_handler(int sig) * between KVM queueing an exception and re-entering the guest. */ if (events.exception.pending) { - set_invalid_guest_state(); - run_vcpu_with_invalid_state(); + set_invalid_guest_state(vcpu); + run_vcpu_with_invalid_state(vcpu); } else { set_timer(); } @@ -102,15 +108,19 @@ static void sigalrm_handler(int sig) int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + if (!is_intel_cpu() || vm_is_unrestricted_guest(NULL)) { print_skip("Must be run with kvm_intel.unrestricted_guest=0"); exit(KSFT_SKIP); } - vm = vm_create_default(VCPU_ID, 0, (void *)guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + get_set_sigalrm_vcpu(vcpu); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); @@ -119,8 +129,8 @@ int main(int argc, char *argv[]) * KVM_RUN should induce a TRIPLE_FAULT in L2 as KVM doesn't support * emulating invalid guest state for L2. */ - set_invalid_guest_state(); - run_vcpu_with_invalid_state(); + set_invalid_guest_state(vcpu); + run_vcpu_with_invalid_state(vcpu); /* * Verify KVM also handles the case where userspace gains control while @@ -129,11 +139,11 @@ int main(int argc, char *argv[]) * guest with invalid state when the handler interrupts KVM with an * exception pending. */ - clear_invalid_guest_state(); + clear_invalid_guest_state(vcpu); TEST_ASSERT(signal(SIGALRM, sigalrm_handler) != SIG_ERR, "Failed to register SIGALRM handler, errno = %d (%s)", errno, strerror(errno)); set_timer(); - run_vcpu_with_invalid_state(); + run_vcpu_with_invalid_state(vcpu); } From f7024348d7ea2bea0be3dd82703b15f3dac9590b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:45:15 -0800 Subject: [PATCH 0382/1436] KVM: selftests: Convert tsc_msrs_test away from VCPU_ID Convert tsc_msrs_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/tsc_msrs_test.c | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c index a426078b16a3..3b7bf660eced 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c @@ -9,14 +9,12 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 0 - #define UNITY (1ull << 30) #define HOST_ADJUST (UNITY * 64) #define GUEST_STEP (UNITY * 4) #define ROUND(x) ((x + UNITY / 2) & -UNITY) #define rounded_rdmsr(x) ROUND(rdmsr(x)) -#define rounded_host_rdmsr(x) ROUND(vcpu_get_msr(vm, 0, x)) +#define rounded_host_rdmsr(x) ROUND(vcpu_get_msr(vm, vcpu->id, x)) static void guest_code(void) { @@ -66,15 +64,13 @@ static void guest_code(void) GUEST_DONE(); } -static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid, int stage) +static void run_vcpu(struct kvm_vcpu *vcpu, int stage) { struct ucall uc; - vcpu_args_set(vm, vcpuid, 1, vcpuid); + vcpu_run(vcpu->vm, vcpu->id); - vcpu_ioctl(vm, vcpuid, KVM_RUN, NULL); - - switch (get_ucall(vm, vcpuid, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_SYNC: TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage + 1, "Stage %d: Unexpected register values vmexit, got %lx", @@ -88,29 +84,30 @@ static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid, int stage) __FILE__, uc.args[1], uc.args[2], uc.args[3]); default: TEST_ASSERT(false, "Unexpected exit: %s", - exit_reason_str(vcpu_state(vm, vcpuid)->exit_reason)); + exit_reason_str(vcpu->run->exit_reason)); } } int main(void) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; uint64_t val; - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); val = 0; ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); /* Guest: writes to MSR_IA32_TSC affect both MSRs. */ - run_vcpu(vm, VCPU_ID, 1); + run_vcpu(vcpu, 1); val = 1ull * GUEST_STEP; ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); /* Guest: writes to MSR_IA32_TSC_ADJUST affect both MSRs. */ - run_vcpu(vm, VCPU_ID, 2); + run_vcpu(vcpu, 2); val = 2ull * GUEST_STEP; ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); @@ -119,18 +116,18 @@ int main(void) * Host: writes to MSR_IA32_TSC set the host-side offset * and therefore do not change MSR_IA32_TSC_ADJUST. */ - vcpu_set_msr(vm, 0, MSR_IA32_TSC, HOST_ADJUST + val); + vcpu_set_msr(vm, vcpu->id, MSR_IA32_TSC, HOST_ADJUST + val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); - run_vcpu(vm, VCPU_ID, 3); + run_vcpu(vcpu, 3); /* Host: writes to MSR_IA32_TSC_ADJUST do not modify the TSC. */ - vcpu_set_msr(vm, 0, MSR_IA32_TSC_ADJUST, UNITY * 123456); + vcpu_set_msr(vm, vcpu->id, MSR_IA32_TSC_ADJUST, UNITY * 123456); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); - ASSERT_EQ(vcpu_get_msr(vm, 0, MSR_IA32_TSC_ADJUST), UNITY * 123456); + ASSERT_EQ(vcpu_get_msr(vm, vcpu->id, MSR_IA32_TSC_ADJUST), UNITY * 123456); /* Restore previous value. */ - vcpu_set_msr(vm, 0, MSR_IA32_TSC_ADJUST, val); + vcpu_set_msr(vm, vcpu->id, MSR_IA32_TSC_ADJUST, val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); @@ -138,7 +135,7 @@ int main(void) * Guest: writes to MSR_IA32_TSC_ADJUST do not destroy the * host-side offset and affect both MSRs. */ - run_vcpu(vm, VCPU_ID, 4); + run_vcpu(vcpu, 4); val = 3ull * GUEST_STEP; ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); @@ -147,7 +144,7 @@ int main(void) * Guest: writes to MSR_IA32_TSC affect both MSRs, so the host-side * offset is now visible in MSR_IA32_TSC_ADJUST. */ - run_vcpu(vm, VCPU_ID, 5); + run_vcpu(vcpu, 5); val = 4ull * GUEST_STEP; ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val - HOST_ADJUST); From 5e7cb71570b99eec5e4bb76ea5184ded87497e3f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:46:56 -0800 Subject: [PATCH 0383/1436] KVM: selftests: Convert kvm_clock_test away from VCPU_ID Convert kvm_clock_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Opportunistically use vcpu_run() instead of _vcpu_run() with an open coded assert that KVM_RUN succeeded. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/kvm_clock_test.c | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c index 97731454f3f3..2c1f850c4053 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c @@ -16,8 +16,6 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 0 - struct test_case { uint64_t kvmclock_base; int64_t realtime_offset; @@ -105,29 +103,27 @@ static void setup_clock(struct kvm_vm *vm, struct test_case *test_case) vm_ioctl(vm, KVM_SET_CLOCK, &data); } -static void enter_guest(struct kvm_vm *vm) +static void enter_guest(struct kvm_vcpu *vcpu) { struct kvm_clock_data start, end; - struct kvm_run *run; + struct kvm_run *run = vcpu->run; + struct kvm_vm *vm = vcpu->vm; struct ucall uc; - int i, r; - - run = vcpu_state(vm, VCPU_ID); + int i; for (i = 0; i < ARRAY_SIZE(test_cases); i++) { setup_clock(vm, &test_cases[i]); vm_ioctl(vm, KVM_GET_CLOCK, &start); - r = _vcpu_run(vm, VCPU_ID); + vcpu_run(vcpu->vm, vcpu->id); vm_ioctl(vm, KVM_GET_CLOCK, &end); - TEST_ASSERT(!r, "vcpu_run failed: %d\n", r); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_SYNC: handle_sync(&uc, &start, &end); break; @@ -178,6 +174,7 @@ out: int main(void) { + struct kvm_vcpu *vcpu; vm_vaddr_t pvti_gva; vm_paddr_t pvti_gpa; struct kvm_vm *vm; @@ -192,12 +189,12 @@ int main(void) check_clocksource(); - vm = vm_create_default(VCPU_ID, 0, guest_main); + vm = vm_create_with_one_vcpu(&vcpu, guest_main); pvti_gva = vm_vaddr_alloc(vm, getpagesize(), 0x10000); pvti_gpa = addr_gva2gpa(vm, pvti_gva); - vcpu_args_set(vm, VCPU_ID, 2, pvti_gpa, pvti_gva); + vcpu_args_set(vm, vcpu->id, 2, pvti_gpa, pvti_gva); - enter_guest(vm); + enter_guest(vcpu); kvm_vm_free(vm); } From a1918c0fbeea59ccc629d83e491e798fc657fe41 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:47:48 -0800 Subject: [PATCH 0384/1436] KVM: selftests: Convert hyperv_svm_test away from VCPU_ID Convert hyperv_svm_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==1. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically use vcpu_run() instead of _vcpu_run(), the test expects KVM_RUN to succeed. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/x86_64/hyperv_svm_test.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c index 994b33fd8724..b6a749f5c766 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c @@ -21,7 +21,6 @@ #include "svm_util.h" #include "hyperv.h" -#define VCPU_ID 1 #define L2_GUEST_STACK_SIZE 256 struct hv_enlightenments { @@ -122,6 +121,7 @@ int main(int argc, char *argv[]) { vm_vaddr_t nested_gva = 0; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; struct ucall uc; @@ -132,20 +132,20 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); - vcpu_set_hv_cpuid(vm, VCPU_ID); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + vcpu_set_hv_cpuid(vm, vcpu->id); + run = vcpu->run; vcpu_alloc_svm(vm, &nested_gva); - vcpu_args_set(vm, VCPU_ID, 1, nested_gva); + vcpu_args_set(vm, vcpu->id, 1, nested_gva); for (stage = 1;; stage++) { - _vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); From d96b959600e540337fc489564dd93fc9a5ee9fe7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:50:11 -0800 Subject: [PATCH 0385/1436] KVM: selftests: Convert hyperv_features away from VCPU_ID Convert hyperv_features to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Opportunistically use vcpu_run() instead of _vcpu_run() with an open coded assert that KVM_RUN succeeded. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/hyperv_features.c | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index 7ff6e4d70333..d0bd9d5e8a99 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -13,7 +13,6 @@ #include "processor.h" #include "hyperv.h" -#define VCPU_ID 0 #define LINUX_OS_ID ((u64)0x8100 << 48) extern unsigned char rdmsr_start; @@ -151,7 +150,7 @@ static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) GUEST_DONE(); } -static void hv_set_cpuid(struct kvm_vm *vm, struct kvm_cpuid2 *cpuid, +static void hv_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 *feat, struct kvm_cpuid_entry2 *recomm, struct kvm_cpuid_entry2 *dbg) @@ -162,15 +161,16 @@ static void hv_set_cpuid(struct kvm_vm *vm, struct kvm_cpuid2 *cpuid, "failed to set HYPERV_CPUID_ENLIGHTMENT_INFO leaf"); TEST_ASSERT(set_cpuid(cpuid, dbg), "failed to set HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES leaf"); - vcpu_set_cpuid(vm, VCPU_ID, cpuid); + vcpu_set_cpuid(vcpu->vm, vcpu->id, cpuid); } static void guest_test_msrs_access(void) { + struct kvm_vcpu *vcpu; struct kvm_run *run; struct kvm_vm *vm; struct ucall uc; - int stage = 0, r; + int stage = 0; struct kvm_cpuid_entry2 feat = { .function = HYPERV_CPUID_FEATURES }; @@ -185,24 +185,24 @@ static void guest_test_msrs_access(void) struct msr_data *msr; while (true) { - vm = vm_create_default(VCPU_ID, 0, guest_msr); + vm = vm_create_with_one_vcpu(&vcpu, guest_msr); msr_gva = vm_vaddr_alloc_page(vm); memset(addr_gva2hva(vm, msr_gva), 0x0, getpagesize()); msr = addr_gva2hva(vm, msr_gva); - vcpu_args_set(vm, VCPU_ID, 1, msr_gva); - vcpu_enable_cap(vm, VCPU_ID, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); + vcpu_args_set(vm, vcpu->id, 1, msr_gva); + vcpu_enable_cap(vm, vcpu->id, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); - vcpu_set_hv_cpuid(vm, VCPU_ID); + vcpu_set_hv_cpuid(vm, vcpu->id); best = kvm_get_supported_hv_cpuid(); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); - run = vcpu_state(vm, VCPU_ID); + run = vcpu->run; switch (stage) { case 0: @@ -333,7 +333,7 @@ static void guest_test_msrs_access(void) * Remains unavailable even with KVM_CAP_HYPERV_SYNIC2 * capability enabled and guest visible CPUID bit unset. */ - vcpu_enable_cap(vm, VCPU_ID, KVM_CAP_HYPERV_SYNIC2, 0); + vcpu_enable_cap(vm, vcpu->id, KVM_CAP_HYPERV_SYNIC2, 0); break; case 22: feat.eax |= HV_MSR_SYNIC_AVAILABLE; @@ -463,7 +463,7 @@ static void guest_test_msrs_access(void) break; } - hv_set_cpuid(vm, best, &feat, &recomm, &dbg); + hv_set_cpuid(vcpu, best, &feat, &recomm, &dbg); if (msr->idx) pr_debug("Stage %d: testing msr: 0x%x for %s\n", stage, @@ -471,13 +471,12 @@ static void guest_test_msrs_access(void) else pr_debug("Stage %d: finish\n", stage); - r = _vcpu_run(vm, VCPU_ID); - TEST_ASSERT(!r, "vcpu_run failed: %d\n", r); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_SYNC: TEST_ASSERT(uc.args[1] == 0, "Unexpected stage: %ld (0 expected)\n", @@ -498,10 +497,11 @@ static void guest_test_msrs_access(void) static void guest_test_hcalls_access(void) { + struct kvm_vcpu *vcpu; struct kvm_run *run; struct kvm_vm *vm; struct ucall uc; - int stage = 0, r; + int stage = 0; struct kvm_cpuid_entry2 feat = { .function = HYPERV_CPUID_FEATURES, .eax = HV_MSR_HYPERCALL_AVAILABLE @@ -517,10 +517,10 @@ static void guest_test_hcalls_access(void) struct kvm_cpuid2 *best; while (true) { - vm = vm_create_default(VCPU_ID, 0, guest_hcall); + vm = vm_create_with_one_vcpu(&vcpu, guest_hcall); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); /* Hypercall input/output */ @@ -531,14 +531,14 @@ static void guest_test_hcalls_access(void) hcall_params = vm_vaddr_alloc_page(vm); memset(addr_gva2hva(vm, hcall_params), 0x0, getpagesize()); - vcpu_args_set(vm, VCPU_ID, 2, addr_gva2gpa(vm, hcall_page), hcall_params); - vcpu_enable_cap(vm, VCPU_ID, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); + vcpu_args_set(vm, vcpu->id, 2, addr_gva2gpa(vm, hcall_page), hcall_params); + vcpu_enable_cap(vm, vcpu->id, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); - vcpu_set_hv_cpuid(vm, VCPU_ID); + vcpu_set_hv_cpuid(vm, vcpu->id); best = kvm_get_supported_hv_cpuid(); - run = vcpu_state(vm, VCPU_ID); + run = vcpu->run; switch (stage) { case 0: @@ -633,7 +633,7 @@ static void guest_test_hcalls_access(void) break; } - hv_set_cpuid(vm, best, &feat, &recomm, &dbg); + hv_set_cpuid(vcpu, best, &feat, &recomm, &dbg); if (hcall->control) pr_debug("Stage %d: testing hcall: 0x%lx\n", stage, @@ -641,13 +641,12 @@ static void guest_test_hcalls_access(void) else pr_debug("Stage %d: finish\n", stage); - r = _vcpu_run(vm, VCPU_ID); - TEST_ASSERT(!r, "vcpu_run failed: %d\n", r); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_SYNC: TEST_ASSERT(uc.args[1] == 0, "Unexpected stage: %ld (0 expected)\n", From a858163711751b1caba7415c473a0668de1ef2bf Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:54:04 -0800 Subject: [PATCH 0386/1436] KVM: selftests: Convert hyperv_clock away from VCPU_ID Convert hyperv_clock to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Opportunistically use vcpu_run() instead of _vcpu_run() with an open coded assert that KVM_RUN succeeded. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/hyperv_clock.c | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c index 3330fb183c68..4f8f3999de2d 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c @@ -173,23 +173,21 @@ static void guest_main(struct ms_hyperv_tsc_page *tsc_page, vm_paddr_t tsc_page_ GUEST_DONE(); } -#define VCPU_ID 0 - -static void host_check_tsc_msr_rdtsc(struct kvm_vm *vm) +static void host_check_tsc_msr_rdtsc(struct kvm_vcpu *vcpu) { u64 tsc_freq, r1, r2, t1, t2; s64 delta_ns; - tsc_freq = vcpu_get_msr(vm, VCPU_ID, HV_X64_MSR_TSC_FREQUENCY); + tsc_freq = vcpu_get_msr(vcpu->vm, vcpu->id, HV_X64_MSR_TSC_FREQUENCY); TEST_ASSERT(tsc_freq > 0, "TSC frequency must be nonzero"); /* For increased accuracy, take mean rdtsc() before and afrer ioctl */ r1 = rdtsc(); - t1 = vcpu_get_msr(vm, VCPU_ID, HV_X64_MSR_TIME_REF_COUNT); + t1 = vcpu_get_msr(vcpu->vm, vcpu->id, HV_X64_MSR_TIME_REF_COUNT); r1 = (r1 + rdtsc()) / 2; nop_loop(); r2 = rdtsc(); - t2 = vcpu_get_msr(vm, VCPU_ID, HV_X64_MSR_TIME_REF_COUNT); + t2 = vcpu_get_msr(vcpu->vm, vcpu->id, HV_X64_MSR_TIME_REF_COUNT); r2 = (r2 + rdtsc()) / 2; TEST_ASSERT(t2 > t1, "Time reference MSR is not monotonic (%ld <= %ld)", t1, t2); @@ -207,33 +205,34 @@ static void host_check_tsc_msr_rdtsc(struct kvm_vm *vm) int main(void) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; struct ucall uc; vm_vaddr_t tsc_page_gva; int stage; - vm = vm_create_default(VCPU_ID, 0, guest_main); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_main); + run = vcpu->run; - vcpu_set_hv_cpuid(vm, VCPU_ID); + vcpu_set_hv_cpuid(vm, vcpu->id); tsc_page_gva = vm_vaddr_alloc_page(vm); memset(addr_gva2hva(vm, tsc_page_gva), 0x0, getpagesize()); TEST_ASSERT((addr_gva2gpa(vm, tsc_page_gva) & (getpagesize() - 1)) == 0, "TSC page has to be page aligned\n"); - vcpu_args_set(vm, VCPU_ID, 2, tsc_page_gva, addr_gva2gpa(vm, tsc_page_gva)); + vcpu_args_set(vm, vcpu->id, 2, tsc_page_gva, addr_gva2gpa(vm, tsc_page_gva)); - host_check_tsc_msr_rdtsc(vm); + host_check_tsc_msr_rdtsc(vcpu); for (stage = 1;; stage++) { - _vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); From be0dff8610b15976151934d25f433391880f88a9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 16:57:49 -0800 Subject: [PATCH 0387/1436] KVM: selftests: Convert evmcs_test away from VCPU_ID Convert evmcs_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically use vcpu_run() instead of _vcpu_run(), the test expects KVM_RUN to succeed. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/x86_64/evmcs_test.c | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c index 78668605f673..ba39042a5d96 100644 --- a/tools/testing/selftests/kvm/x86_64/evmcs_test.c +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c @@ -18,8 +18,6 @@ #include "vmx.h" -#define VCPU_ID 5 - static int ud_count; static void guest_ud_handler(struct ex_regs *regs) @@ -159,55 +157,56 @@ void guest_code(struct vmx_pages *vmx_pages) GUEST_DONE(); } -void inject_nmi(struct kvm_vm *vm) +void inject_nmi(struct kvm_vcpu *vcpu) { struct kvm_vcpu_events events; - vcpu_events_get(vm, VCPU_ID, &events); + vcpu_events_get(vcpu->vm, vcpu->id, &events); events.nmi.pending = 1; events.flags |= KVM_VCPUEVENT_VALID_NMI_PENDING; - vcpu_events_set(vm, VCPU_ID, &events); + vcpu_events_set(vcpu->vm, vcpu->id, &events); } -static void save_restore_vm(struct kvm_vm *vm) +static struct kvm_vcpu *save_restore_vm(struct kvm_vm *vm, + struct kvm_vcpu *vcpu) { struct kvm_regs regs1, regs2; struct kvm_x86_state *state; - state = vcpu_save_state(vm, VCPU_ID); + state = vcpu_save_state(vm, vcpu->id); memset(®s1, 0, sizeof(regs1)); - vcpu_regs_get(vm, VCPU_ID, ®s1); + vcpu_regs_get(vm, vcpu->id, ®s1); kvm_vm_release(vm); /* Restore state in a new VM. */ - kvm_vm_restart(vm); - vm_vcpu_add(vm, VCPU_ID); - vcpu_set_hv_cpuid(vm, VCPU_ID); - vcpu_enable_evmcs(vm, VCPU_ID); - vcpu_load_state(vm, VCPU_ID, state); + vcpu = vm_recreate_with_one_vcpu(vm); + vcpu_set_hv_cpuid(vm, vcpu->id); + vcpu_enable_evmcs(vm, vcpu->id); + vcpu_load_state(vm, vcpu->id, state); kvm_x86_state_cleanup(state); memset(®s2, 0, sizeof(regs2)); - vcpu_regs_get(vm, VCPU_ID, ®s2); + vcpu_regs_get(vm, vcpu->id, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", (ulong) regs2.rdi, (ulong) regs2.rsi); + return vcpu; } int main(int argc, char *argv[]) { vm_vaddr_t vmx_pages_gva = 0; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; struct ucall uc; int stage; - /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); if (!nested_vmx_supported() || !kvm_check_cap(KVM_CAP_NESTED_STATE) || @@ -216,28 +215,29 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - vcpu_set_hv_cpuid(vm, VCPU_ID); - vcpu_enable_evmcs(vm, VCPU_ID); + vcpu_set_hv_cpuid(vm, vcpu->id); + vcpu_enable_evmcs(vm, vcpu->id); vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); + vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler); pr_info("Running L1 which uses EVMCS to run L2\n"); for (stage = 1;; stage++) { - run = vcpu_state(vm, VCPU_ID); - _vcpu_run(vm, VCPU_ID); + run = vcpu->run; + + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); @@ -255,12 +255,12 @@ int main(int argc, char *argv[]) uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx", stage, (ulong)uc.args[1]); - save_restore_vm(vm); + vcpu = save_restore_vm(vm, vcpu); /* Force immediate L2->L1 exit before resuming */ if (stage == 8) { pr_info("Injecting NMI into L1 before L2 had a chance to run after restore\n"); - inject_nmi(vm); + inject_nmi(vcpu); } /* @@ -270,7 +270,7 @@ int main(int argc, char *argv[]) */ if (stage == 9) { pr_info("Trying extra KVM_GET_NESTED_STATE/KVM_SET_NESTED_STATE cycle\n"); - save_restore_vm(vm); + vcpu = save_restore_vm(vm, vcpu); } } From 42975c219975f5df0d686868e8b57698b2d09561 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:02:44 -0800 Subject: [PATCH 0388/1436] KVM: selftests: Convert emulator_error_test away from VCPU_ID Convert emulator_error_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically use vcpu_run() instead of _vcpu_run() with an open coded assert that KVM_RUN succeeded. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/x86_64/emulator_error_test.c | 65 ++++++++----------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c index 9c156f9cfa15..08a95dab3a6b 100644 --- a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c +++ b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c @@ -11,7 +11,6 @@ #include "kvm_util.h" #include "vmx.h" -#define VCPU_ID 1 #define MAXPHYADDR 36 #define MEM_REGION_GVA 0x0000123456789000 @@ -27,14 +26,6 @@ static void guest_code(void) GUEST_DONE(); } -static void run_guest(struct kvm_vm *vm) -{ - int rc; - - rc = _vcpu_run(vm, VCPU_ID); - TEST_ASSERT(rc == 0, "vcpu_run failed: %d\n", rc); -} - /* * Accessors to get R/M, REG, and Mod bits described in the SDM vol 2, * figure 2-2 "Table Interpretation of ModR/M Byte (C8H)". @@ -56,9 +47,9 @@ static bool is_flds(uint8_t *insn_bytes, uint8_t insn_size) GET_RM(insn_bytes[1]) != 0x5; } -static void process_exit_on_emulation_error(struct kvm_vm *vm) +static void process_exit_on_emulation_error(struct kvm_vcpu *vcpu) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; struct kvm_regs regs; uint8_t *insn_bytes; uint8_t insn_size; @@ -92,50 +83,49 @@ static void process_exit_on_emulation_error(struct kvm_vm *vm) * contained an flds instruction that is 2-bytes in * length (ie: no prefix, no SIB, no displacement). */ - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vcpu->vm, vcpu->id, ®s); regs.rip += 2; - vcpu_regs_set(vm, VCPU_ID, ®s); + vcpu_regs_set(vcpu->vm, vcpu->id, ®s); } } } -static void do_guest_assert(struct kvm_vm *vm, struct ucall *uc) +static void do_guest_assert(struct ucall *uc) { TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], __FILE__, uc->args[1]); } -static void check_for_guest_assert(struct kvm_vm *vm) +static void check_for_guest_assert(struct kvm_vcpu *vcpu) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); struct ucall uc; - if (run->exit_reason == KVM_EXIT_IO && - get_ucall(vm, VCPU_ID, &uc) == UCALL_ABORT) { - do_guest_assert(vm, &uc); + if (vcpu->run->exit_reason == KVM_EXIT_IO && + get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_ABORT) { + do_guest_assert(&uc); } } -static void process_ucall_done(struct kvm_vm *vm) +static void process_ucall_done(struct kvm_vcpu *vcpu) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; struct ucall uc; - check_for_guest_assert(vm); + check_for_guest_assert(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - TEST_ASSERT(get_ucall(vm, VCPU_ID, &uc) == UCALL_DONE, + TEST_ASSERT(get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_DONE, "Unexpected ucall command: %lu, expected UCALL_DONE (%d)", uc.cmd, UCALL_DONE); } -static uint64_t process_ucall(struct kvm_vm *vm) +static uint64_t process_ucall(struct kvm_vcpu *vcpu) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; struct ucall uc; TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, @@ -143,14 +133,14 @@ static uint64_t process_ucall(struct kvm_vm *vm) run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_SYNC: break; case UCALL_ABORT: - do_guest_assert(vm, &uc); + do_guest_assert(&uc); break; case UCALL_DONE: - process_ucall_done(vm); + process_ucall_done(vcpu); break; default: TEST_ASSERT(false, "Unexpected ucall"); @@ -163,6 +153,7 @@ int main(int argc, char *argv[]) { struct kvm_cpuid_entry2 *entry; struct kvm_cpuid2 *cpuid; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; uint64_t gpa, pte; uint64_t *hva; @@ -171,20 +162,20 @@ int main(int argc, char *argv[]) /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - vm = vm_create_default(VCPU_ID, 0, guest_code); - if (!kvm_check_cap(KVM_CAP_SMALLER_MAXPHYADDR)) { printf("module parameter 'allow_smaller_maxphyaddr' is not set. Skipping test.\n"); return 0; } + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + cpuid = kvm_get_supported_cpuid(); entry = kvm_get_supported_cpuid_index(0x80000008, 0); entry->eax = (entry->eax & 0xffffff00) | MAXPHYADDR; set_cpuid(cpuid, entry); - vcpu_set_cpuid(vm, VCPU_ID, cpuid); + vcpu_set_cpuid(vm, vcpu->id, cpuid); rc = kvm_check_cap(KVM_CAP_EXIT_ON_EMULATION_FAILURE); TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable"); @@ -199,14 +190,14 @@ int main(int argc, char *argv[]) virt_map(vm, MEM_REGION_GVA, MEM_REGION_GPA, 1); hva = addr_gpa2hva(vm, MEM_REGION_GPA); memset(hva, 0, PAGE_SIZE); - pte = vm_get_page_table_entry(vm, VCPU_ID, MEM_REGION_GVA); - vm_set_page_table_entry(vm, VCPU_ID, MEM_REGION_GVA, pte | (1ull << 36)); + pte = vm_get_page_table_entry(vm, vcpu->id, MEM_REGION_GVA); + vm_set_page_table_entry(vm, vcpu->id, MEM_REGION_GVA, pte | (1ull << 36)); - run_guest(vm); - process_exit_on_emulation_error(vm); - run_guest(vm); + vcpu_run(vm, vcpu->id); + process_exit_on_emulation_error(vcpu); + vcpu_run(vm, vcpu->id); - TEST_ASSERT(process_ucall(vm) == UCALL_DONE, "Expected UCALL_DONE"); + TEST_ASSERT(process_ucall(vcpu) == UCALL_DONE, "Expected UCALL_DONE"); kvm_vm_free(vm); From 28039449b83e21f741937e84d4fd6485ad4fb9f8 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:06:02 -0800 Subject: [PATCH 0389/1436] KVM: selftests: Convert debug_regs away from VCPU_ID Convert debug_regs to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Opportunstically drop the CLEAR_DEBUG/APPLY_DEBUG macros as they only obfuscate the code, e.g. operating on local variables not "passed" to the macro is all kinds of confusing. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/x86_64/debug_regs.c | 53 +++++++++---------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/debug_regs.c b/tools/testing/selftests/kvm/x86_64/debug_regs.c index f726645bb9c3..182d71c6d13a 100644 --- a/tools/testing/selftests/kvm/x86_64/debug_regs.c +++ b/tools/testing/selftests/kvm/x86_64/debug_regs.c @@ -10,8 +10,6 @@ #include "processor.h" #include "apic.h" -#define VCPU_ID 0 - #define DR6_BD (1 << 13) #define DR7_GD (1 << 13) @@ -66,13 +64,11 @@ static void guest_code(void) GUEST_DONE(); } -#define CLEAR_DEBUG() memset(&debug, 0, sizeof(debug)) -#define APPLY_DEBUG() vcpu_guest_debug_set(vm, VCPU_ID, &debug) #define CAST_TO_RIP(v) ((unsigned long long)&(v)) #define SET_RIP(v) do { \ - vcpu_regs_get(vm, VCPU_ID, ®s); \ + vcpu_regs_get(vm, vcpu->id, ®s); \ regs.rip = (v); \ - vcpu_regs_set(vm, VCPU_ID, ®s); \ + vcpu_regs_set(vm, vcpu->id, ®s); \ } while (0) #define MOVE_RIP(v) SET_RIP(regs.rip + (v)); @@ -80,6 +76,7 @@ int main(void) { struct kvm_guest_debug debug; unsigned long long target_dr6, target_rip; + struct kvm_vcpu *vcpu; struct kvm_regs regs; struct kvm_run *run; struct kvm_vm *vm; @@ -101,14 +98,14 @@ int main(void) return 0; } - vm = vm_create_default(VCPU_ID, 0, guest_code); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + run = vcpu->run; /* Test software BPs - int3 */ - CLEAR_DEBUG(); + memset(&debug, 0, sizeof(debug)); debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; - APPLY_DEBUG(); - vcpu_run(vm, VCPU_ID); + vcpu_guest_debug_set(vm, vcpu->id, &debug); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_DEBUG && run->debug.arch.exception == BP_VECTOR && run->debug.arch.pc == CAST_TO_RIP(sw_bp), @@ -119,12 +116,12 @@ int main(void) /* Test instruction HW BP over DR[0-3] */ for (i = 0; i < 4; i++) { - CLEAR_DEBUG(); + memset(&debug, 0, sizeof(debug)); debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; debug.arch.debugreg[i] = CAST_TO_RIP(hw_bp); debug.arch.debugreg[7] = 0x400 | (1UL << (2*i+1)); - APPLY_DEBUG(); - vcpu_run(vm, VCPU_ID); + vcpu_guest_debug_set(vm, vcpu->id, &debug); + vcpu_run(vm, vcpu->id); target_dr6 = 0xffff0ff0 | (1UL << i); TEST_ASSERT(run->exit_reason == KVM_EXIT_DEBUG && run->debug.arch.exception == DB_VECTOR && @@ -141,13 +138,13 @@ int main(void) /* Test data access HW BP over DR[0-3] */ for (i = 0; i < 4; i++) { - CLEAR_DEBUG(); + memset(&debug, 0, sizeof(debug)); debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; debug.arch.debugreg[i] = CAST_TO_RIP(guest_value); debug.arch.debugreg[7] = 0x00000400 | (1UL << (2*i+1)) | (0x000d0000UL << (4*i)); - APPLY_DEBUG(); - vcpu_run(vm, VCPU_ID); + vcpu_guest_debug_set(vm, vcpu->id, &debug); + vcpu_run(vm, vcpu->id); target_dr6 = 0xffff0ff0 | (1UL << i); TEST_ASSERT(run->exit_reason == KVM_EXIT_DEBUG && run->debug.arch.exception == DB_VECTOR && @@ -167,15 +164,15 @@ int main(void) /* Test single step */ target_rip = CAST_TO_RIP(ss_start); target_dr6 = 0xffff4ff0ULL; - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vm, vcpu->id, ®s); for (i = 0; i < (sizeof(ss_size) / sizeof(ss_size[0])); i++) { target_rip += ss_size[i]; - CLEAR_DEBUG(); + memset(&debug, 0, sizeof(debug)); debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_BLOCKIRQ; debug.arch.debugreg[7] = 0x00000400; - APPLY_DEBUG(); - vcpu_run(vm, VCPU_ID); + vcpu_guest_debug_set(vm, vcpu->id, &debug); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_DEBUG && run->debug.arch.exception == DB_VECTOR && run->debug.arch.pc == target_rip && @@ -188,11 +185,11 @@ int main(void) } /* Finally test global disable */ - CLEAR_DEBUG(); + memset(&debug, 0, sizeof(debug)); debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; debug.arch.debugreg[7] = 0x400 | DR7_GD; - APPLY_DEBUG(); - vcpu_run(vm, VCPU_ID); + vcpu_guest_debug_set(vm, vcpu->id, &debug); + vcpu_run(vm, vcpu->id); target_dr6 = 0xffff0ff0 | DR6_BD; TEST_ASSERT(run->exit_reason == KVM_EXIT_DEBUG && run->debug.arch.exception == DB_VECTOR && @@ -205,12 +202,12 @@ int main(void) target_dr6); /* Disable all debug controls, run to the end */ - CLEAR_DEBUG(); - APPLY_DEBUG(); + memset(&debug, 0, sizeof(debug)); + vcpu_guest_debug_set(vm, vcpu->id, &debug); - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "KVM_EXIT_IO"); - cmd = get_ucall(vm, VCPU_ID, &uc); + cmd = get_ucall(vm, vcpu->id, &uc); TEST_ASSERT(cmd == UCALL_DONE, "UCALL_DONE"); kvm_vm_free(vm); From 2571bcdb136a3daf59df677585f32b89615eea47 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:09:25 -0800 Subject: [PATCH 0390/1436] KVM: selftests: Add proper helper for advancing RIP in debug_regs Replace MOVE_RIP+SET_RIP with a proper helper, vcpu_skip_insn(), that is more descriptive, doesn't subtly access local variables, and provides type safety. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/x86_64/debug_regs.c | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/debug_regs.c b/tools/testing/selftests/kvm/x86_64/debug_regs.c index 182d71c6d13a..3cc25714d703 100644 --- a/tools/testing/selftests/kvm/x86_64/debug_regs.c +++ b/tools/testing/selftests/kvm/x86_64/debug_regs.c @@ -65,19 +65,21 @@ static void guest_code(void) } #define CAST_TO_RIP(v) ((unsigned long long)&(v)) -#define SET_RIP(v) do { \ - vcpu_regs_get(vm, vcpu->id, ®s); \ - regs.rip = (v); \ - vcpu_regs_set(vm, vcpu->id, ®s); \ - } while (0) -#define MOVE_RIP(v) SET_RIP(regs.rip + (v)); + +static void vcpu_skip_insn(struct kvm_vcpu *vcpu, int insn_len) +{ + struct kvm_regs regs; + + vcpu_regs_get(vcpu->vm, vcpu->id, ®s); + regs.rip += insn_len; + vcpu_regs_set(vcpu->vm, vcpu->id, ®s); +} int main(void) { struct kvm_guest_debug debug; unsigned long long target_dr6, target_rip; struct kvm_vcpu *vcpu; - struct kvm_regs regs; struct kvm_run *run; struct kvm_vm *vm; struct ucall uc; @@ -112,7 +114,7 @@ int main(void) "INT3: exit %d exception %d rip 0x%llx (should be 0x%llx)", run->exit_reason, run->debug.arch.exception, run->debug.arch.pc, CAST_TO_RIP(sw_bp)); - MOVE_RIP(1); + vcpu_skip_insn(vcpu, 1); /* Test instruction HW BP over DR[0-3] */ for (i = 0; i < 4; i++) { @@ -134,7 +136,7 @@ int main(void) run->debug.arch.dr6, target_dr6); } /* Skip "nop" */ - MOVE_RIP(1); + vcpu_skip_insn(vcpu, 1); /* Test data access HW BP over DR[0-3] */ for (i = 0; i < 4; i++) { @@ -156,15 +158,14 @@ int main(void) run->debug.arch.pc, CAST_TO_RIP(write_data), run->debug.arch.dr6, target_dr6); /* Rollback the 4-bytes "mov" */ - MOVE_RIP(-7); + vcpu_skip_insn(vcpu, -7); } /* Skip the 4-bytes "mov" */ - MOVE_RIP(7); + vcpu_skip_insn(vcpu, 7); /* Test single step */ target_rip = CAST_TO_RIP(ss_start); target_dr6 = 0xffff4ff0ULL; - vcpu_regs_get(vm, vcpu->id, ®s); for (i = 0; i < (sizeof(ss_size) / sizeof(ss_size[0])); i++) { target_rip += ss_size[i]; memset(&debug, 0, sizeof(debug)); From 39839c1a68ce28ea38ca3f789c9981b0d7310def Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:11:25 -0800 Subject: [PATCH 0391/1436] KVM: selftests: Convert amx_test away from VCPU_ID Convert amx_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID.o Opportunistically use vcpu_run() instead of _vcpu_run(), the test expects KVM_RUN to succeed. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/x86_64/amx_test.c | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index 2f01247da0b5..7755fe8fcffb 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -25,7 +25,6 @@ # error This test is 64-bit only #endif -#define VCPU_ID 0 #define X86_FEATURE_XSAVE (1 << 26) #define X86_FEATURE_OSXSAVE (1 << 27) @@ -319,6 +318,7 @@ int main(int argc, char *argv[]) struct kvm_cpuid_entry2 *entry; struct kvm_regs regs1, regs2; bool amx_supported = false; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; struct kvm_x86_state *state; @@ -331,7 +331,7 @@ int main(int argc, char *argv[]) vm_xsave_req_perm(XSTATE_XTILE_DATA_BIT); /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); entry = kvm_get_supported_cpuid_entry(1); if (!(entry->ecx & X86_FEATURE_XSAVE)) { @@ -350,12 +350,12 @@ int main(int argc, char *argv[]) xsave_restore_size = entry->ecx; } - run = vcpu_state(vm, VCPU_ID); - vcpu_regs_get(vm, VCPU_ID, ®s1); + run = vcpu->run; + vcpu_regs_get(vm, vcpu->id, ®s1); /* Register #NM handler */ vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, NM_VECTOR, guest_nm_handler); /* amx cfg for guest_code */ @@ -369,16 +369,16 @@ int main(int argc, char *argv[]) /* xsave data for guest_code */ xsavedata = vm_vaddr_alloc_pages(vm, 3); memset(addr_gva2hva(vm, xsavedata), 0, 3 * getpagesize()); - vcpu_args_set(vm, VCPU_ID, 3, amx_cfg, tiledata, xsavedata); + vcpu_args_set(vm, vcpu->id, 3, amx_cfg, tiledata, xsavedata); for (stage = 1; ; stage++) { - _vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); @@ -403,7 +403,7 @@ int main(int argc, char *argv[]) * size subtract 8K amx size. */ amx_offset = xsave_restore_size - NUM_TILES*TILE_SIZE; - state = vcpu_save_state(vm, VCPU_ID); + state = vcpu_save_state(vm, vcpu->id); void *amx_start = (void *)state->xsave + amx_offset; void *tiles_data = (void *)addr_gva2hva(vm, tiledata); /* Only check TMM0 register, 1 tile */ @@ -424,22 +424,21 @@ int main(int argc, char *argv[]) TEST_FAIL("Unknown ucall %lu", uc.cmd); } - state = vcpu_save_state(vm, VCPU_ID); + state = vcpu_save_state(vm, vcpu->id); memset(®s1, 0, sizeof(regs1)); - vcpu_regs_get(vm, VCPU_ID, ®s1); + vcpu_regs_get(vm, vcpu->id, ®s1); kvm_vm_release(vm); /* Restore state in a new VM. */ - kvm_vm_restart(vm); - vm_vcpu_add(vm, VCPU_ID); - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); - vcpu_load_state(vm, VCPU_ID, state); - run = vcpu_state(vm, VCPU_ID); + vcpu = vm_recreate_with_one_vcpu(vm); + vcpu_set_cpuid(vm, vcpu->id, kvm_get_supported_cpuid()); + vcpu_load_state(vm, vcpu->id, state); + run = vcpu->run; kvm_x86_state_cleanup(state); memset(®s2, 0, sizeof(regs2)); - vcpu_regs_get(vm, VCPU_ID, ®s2); + vcpu_regs_get(vm, vcpu->id, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", (ulong) regs2.rdi, (ulong) regs2.rsi); From 50630b80eb8f8779f301e12c1328e200b004df61 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:12:37 -0800 Subject: [PATCH 0392/1436] KVM: selftests: Convert cr4_cpuid_sync_test away from VCPU_ID Convert cr4_cpuid_sync_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==1. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically use vcpu_run() instead of _vcpu_run() with an open coded assert that KVM_RUN succeeded. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/cr4_cpuid_sync_test.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c index 6f6fd189dda3..d5615cd0b81b 100644 --- a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c +++ b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c @@ -21,7 +21,6 @@ #define X86_FEATURE_XSAVE (1<<26) #define X86_FEATURE_OSXSAVE (1<<27) -#define VCPU_ID 1 static inline bool cr4_cpuid_is_sync(void) { @@ -63,12 +62,12 @@ static void guest_code(void) int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; struct kvm_run *run; struct kvm_vm *vm; struct kvm_sregs sregs; struct kvm_cpuid_entry2 *entry; struct ucall uc; - int rc; entry = kvm_get_supported_cpuid_entry(1); if (!(entry->ecx & X86_FEATURE_XSAVE)) { @@ -79,25 +78,23 @@ int main(int argc, char *argv[]) /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + run = vcpu->run; while (1) { - rc = _vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - TEST_ASSERT(rc == 0, "vcpu_run failed: %d\n", rc); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_SYNC: /* emulate hypervisor clearing CR4.OSXSAVE */ - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vm, vcpu->id, &sregs); sregs.cr4 &= ~X86_CR4_OSXSAVE; - vcpu_sregs_set(vm, VCPU_ID, &sregs); + vcpu_sregs_set(vm, vcpu->id, &sregs); break; case UCALL_ABORT: TEST_FAIL("Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit."); From 87f1b5b3c0cda3feed7de624285966dcf3a1c7ae Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:13:53 -0800 Subject: [PATCH 0393/1436] KVM: selftests: Convert cpuid_test away from VCPU_ID Convert cpuid_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Opportunistically use vcpu_run() instead of _vcpu_run(), the test expects KVM_RUN to succeed. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/x86_64/cpuid_test.c | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index 16d2465c5634..76cdd0d10757 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -12,8 +12,6 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 0 - /* CPUIDs known to differ */ struct { u32 function; @@ -118,13 +116,13 @@ static void compare_cpuids(struct kvm_cpuid2 *cpuid1, struct kvm_cpuid2 *cpuid2) check_cpuid(cpuid1, &cpuid2->entries[i]); } -static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid, int stage) +static void run_vcpu(struct kvm_vcpu *vcpu, int stage) { struct ucall uc; - _vcpu_run(vm, vcpuid); + vcpu_run(vcpu->vm, vcpu->id); - switch (get_ucall(vm, vcpuid, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_SYNC: TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage + 1, @@ -138,7 +136,7 @@ static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid, int stage) __FILE__, uc.args[1], uc.args[2], uc.args[3]); default: TEST_ASSERT(false, "Unexpected exit: %s", - exit_reason_str(vcpu_state(vm, vcpuid)->exit_reason)); + exit_reason_str(vcpu->run->exit_reason)); } } @@ -154,21 +152,21 @@ struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm, vm_vaddr_t *p_gva, struct return guest_cpuids; } -static void set_cpuid_after_run(struct kvm_vm *vm, struct kvm_cpuid2 *cpuid) +static void set_cpuid_after_run(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) { struct kvm_cpuid_entry2 *ent; int rc; u32 eax, ebx, x; /* Setting unmodified CPUID is allowed */ - rc = __vcpu_set_cpuid(vm, VCPU_ID, cpuid); + rc = __vcpu_set_cpuid(vcpu->vm, vcpu->id, cpuid); TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc); /* Changing CPU features is forbidden */ ent = get_cpuid(cpuid, 0x7, 0); ebx = ent->ebx; ent->ebx--; - rc = __vcpu_set_cpuid(vm, VCPU_ID, cpuid); + rc = __vcpu_set_cpuid(vcpu->vm, vcpu->id, cpuid); TEST_ASSERT(rc, "Changing CPU features should fail"); ent->ebx = ebx; @@ -177,7 +175,7 @@ static void set_cpuid_after_run(struct kvm_vm *vm, struct kvm_cpuid2 *cpuid) eax = ent->eax; x = eax & 0xff; ent->eax = (eax & ~0xffu) | (x - 1); - rc = __vcpu_set_cpuid(vm, VCPU_ID, cpuid); + rc = __vcpu_set_cpuid(vcpu->vm, vcpu->id, cpuid); TEST_ASSERT(rc, "Changing MAXPHYADDR should fail"); ent->eax = eax; } @@ -185,25 +183,26 @@ static void set_cpuid_after_run(struct kvm_vm *vm, struct kvm_cpuid2 *cpuid) int main(void) { struct kvm_cpuid2 *supp_cpuid, *cpuid2; + struct kvm_vcpu *vcpu; vm_vaddr_t cpuid_gva; struct kvm_vm *vm; int stage; - vm = vm_create_default(VCPU_ID, 0, guest_main); + vm = vm_create_with_one_vcpu(&vcpu, guest_main); supp_cpuid = kvm_get_supported_cpuid(); - cpuid2 = vcpu_get_cpuid(vm, VCPU_ID); + cpuid2 = vcpu_get_cpuid(vm, vcpu->id); compare_cpuids(supp_cpuid, cpuid2); vcpu_alloc_cpuid(vm, &cpuid_gva, cpuid2); - vcpu_args_set(vm, VCPU_ID, 1, cpuid_gva); + vcpu_args_set(vm, vcpu->id, 1, cpuid_gva); for (stage = 0; stage < 3; stage++) - run_vcpu(vm, VCPU_ID, stage); + run_vcpu(vcpu, stage); - set_cpuid_after_run(vm, cpuid2); + set_cpuid_after_run(vcpu, cpuid2); kvm_vm_free(vm); } From ada1bf4d653168ee209d7825ed3f19a8fe418d07 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:15:15 -0800 Subject: [PATCH 0394/1436] KVM: selftests: Convert userspace_io_test away from VCPU_ID Convert userspace_io_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==1. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically use vcpu_run() instead of _vcpu_run() with an open coded assert that KVM_RUN succeeded. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/userspace_io_test.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c index e4bef2e05686..0ba774ed6476 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c @@ -10,8 +10,6 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 1 - static void guest_ins_port80(uint8_t *buffer, unsigned int count) { unsigned long end; @@ -52,31 +50,29 @@ static void guest_code(void) int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; struct kvm_regs regs; struct kvm_run *run; struct kvm_vm *vm; struct ucall uc; - int rc; /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + run = vcpu->run; memset(®s, 0, sizeof(regs)); while (1) { - rc = _vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - TEST_ASSERT(rc == 0, "vcpu_run failed: %d\n", rc); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - if (get_ucall(vm, VCPU_ID, &uc)) + if (get_ucall(vm, vcpu->id, &uc)) break; TEST_ASSERT(run->io.port == 0x80, @@ -89,13 +85,13 @@ int main(int argc, char *argv[]) * scope from a testing perspective as it's not ABI in any way, * i.e. it really is abusing internal KVM knowledge. */ - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vm, vcpu->id, ®s); if (regs.rcx == 2) regs.rcx = 1; if (regs.rcx == 3) regs.rcx = 8192; memset((void *)run + run->io.data_offset, 0xaa, 4096); - vcpu_regs_set(vm, VCPU_ID, ®s); + vcpu_regs_set(vm, vcpu->id, ®s); } switch (uc.cmd) { From 35b6cb825abdd15a6b2f3da22ffcfb076ecb75db Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:30:35 -0800 Subject: [PATCH 0395/1436] KVM: selftests: Convert vmx_invalid_nested_guest_state away from VCPU_ID Convert vmx_invalid_nested_guest_state to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../x86_64/vmx_invalid_nested_guest_state.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c index 489fbed4ca6f..ba534be498f9 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c @@ -9,7 +9,6 @@ #include "kselftest.h" -#define VCPU_ID 0 #define ARBITRARY_IO_PORT 0x2000 static struct kvm_vm *vm; @@ -55,20 +54,21 @@ int main(int argc, char *argv[]) { vm_vaddr_t vmx_pages_gva; struct kvm_sregs sregs; + struct kvm_vcpu *vcpu; struct kvm_run *run; struct ucall uc; nested_vmx_check_supported(); - vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); /* Allocate VMX pages and shared descriptors (vmx_pages). */ vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); + vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - run = vcpu_state(vm, VCPU_ID); + run = vcpu->run; /* * The first exit to L0 userspace should be an I/O access from L2. @@ -88,13 +88,13 @@ int main(int argc, char *argv[]) * emulating invalid guest state for L2. */ memset(&sregs, 0, sizeof(sregs)); - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vm, vcpu->id, &sregs); sregs.tr.unusable = 1; - vcpu_sregs_set(vm, VCPU_ID, &sregs); + vcpu_sregs_set(vm, vcpu->id, &sregs); - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_DONE: break; case UCALL_ABORT: From 92897016697754a2709e42d56117824b0401c7dd Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:33:28 -0800 Subject: [PATCH 0396/1436] KVM: selftests: Convert xen_vmcall_test away from VCPU_ID Convert xen_vmcall_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Opportunistically make the "vm" variable local, it is unused outside of main(). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/xen_vmcall_test.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c index b30fe9de1d4f..1411ead620fe 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c @@ -11,13 +11,9 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 5 - #define HCALL_REGION_GPA 0xc0000000ULL #define HCALL_REGION_SLOT 10 -static struct kvm_vm *vm; - #define INPUTVALUE 17 #define ARGVALUE(x) (0xdeadbeef5a5a0000UL + x) #define RETVALUE 0xcafef00dfbfbffffUL @@ -84,14 +80,17 @@ static void guest_code(void) int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + if (!(kvm_check_cap(KVM_CAP_XEN_HVM) & KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL) ) { print_skip("KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL not available"); exit(KSFT_SKIP); } - vm = vm_create_default(VCPU_ID, 0, (void *) guest_code); - vcpu_set_hv_cpuid(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + vcpu_set_hv_cpuid(vm, vcpu->id); struct kvm_xen_hvm_config hvmc = { .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL, @@ -105,10 +104,10 @@ int main(int argc, char *argv[]) virt_map(vm, HCALL_REGION_GPA, HCALL_REGION_GPA, 2); for (;;) { - volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); + volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); if (run->exit_reason == KVM_EXIT_XEN) { ASSERT_EQ(run->xen.type, KVM_EXIT_XEN_HCALL); @@ -130,7 +129,7 @@ int main(int argc, char *argv[]) run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ From 0037727b3989c3fe1929c89a9a1dfe289ad86f58 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:34:32 -0800 Subject: [PATCH 0397/1436] KVM: selftests: Convert xen_shinfo_test away from VCPU_ID Convert xen_shinfo_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/xen_shinfo_test.c | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c index 7a51bb648fbb..5c0abaf0eb60 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c @@ -18,8 +18,6 @@ #include -#define VCPU_ID 5 - #define SHINFO_REGION_GVA 0xc0000000ULL #define SHINFO_REGION_GPA 0xc0000000ULL #define SHINFO_REGION_SLOT 10 @@ -42,8 +40,6 @@ #define EVTCHN_TEST2 66 #define EVTCHN_TIMER 13 -static struct kvm_vm *vm; - #define XEN_HYPERCALL_MSR 0x40000000 #define MIN_STEAL_TIME 50000 @@ -344,19 +340,22 @@ static int cmp_timespec(struct timespec *a, struct timespec *b) else return 0; } -struct vcpu_info *vinfo; + +static struct vcpu_info *vinfo; +static struct kvm_vcpu *vcpu; static void handle_alrm(int sig) { if (vinfo) printf("evtchn_upcall_pending 0x%x\n", vinfo->evtchn_upcall_pending); - vcpu_dump(stdout, vm, VCPU_ID, 0); + vcpu_dump(stdout, vcpu->vm, vcpu->id, 0); TEST_FAIL("IRQ delivery timed out"); } int main(int argc, char *argv[]) { struct timespec min_ts, max_ts, vm_ts; + struct kvm_vm *vm; bool verbose; verbose = argc > 1 && (!strncmp(argv[1], "-v", 3) || @@ -374,8 +373,7 @@ int main(int argc, char *argv[]) clock_gettime(CLOCK_REALTIME, &min_ts); - vm = vm_create_default(VCPU_ID, 0, (void *) guest_code); - vcpu_set_cpuid(vm, VCPU_ID, kvm_get_supported_cpuid()); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); /* Map a region for the shared_info page */ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, @@ -425,13 +423,13 @@ int main(int argc, char *argv[]) .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, .u.gpa = VCPU_INFO_ADDR, }; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &vi); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &vi); struct kvm_xen_vcpu_attr pvclock = { .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO, .u.gpa = PVTIME_ADDR, }; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &pvclock); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &pvclock); struct kvm_xen_hvm_attr vec = { .type = KVM_XEN_ATTR_TYPE_UPCALL_VECTOR, @@ -440,7 +438,7 @@ int main(int argc, char *argv[]) vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &vec); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, EVTCHN_VECTOR, evtchn_handler); if (do_runstate_tests) { @@ -448,7 +446,7 @@ int main(int argc, char *argv[]) .type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, .u.gpa = RUNSTATE_ADDR, }; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &st); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &st); } int irq_fd[2] = { -1, -1 }; @@ -468,13 +466,13 @@ int main(int argc, char *argv[]) irq_routes.entries[0].gsi = 32; irq_routes.entries[0].type = KVM_IRQ_ROUTING_XEN_EVTCHN; irq_routes.entries[0].u.xen_evtchn.port = EVTCHN_TEST1; - irq_routes.entries[0].u.xen_evtchn.vcpu = VCPU_ID; + irq_routes.entries[0].u.xen_evtchn.vcpu = vcpu->id; irq_routes.entries[0].u.xen_evtchn.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL; irq_routes.entries[1].gsi = 33; irq_routes.entries[1].type = KVM_IRQ_ROUTING_XEN_EVTCHN; irq_routes.entries[1].u.xen_evtchn.port = EVTCHN_TEST2; - irq_routes.entries[1].u.xen_evtchn.vcpu = VCPU_ID; + irq_routes.entries[1].u.xen_evtchn.vcpu = vcpu->id; irq_routes.entries[1].u.xen_evtchn.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL; vm_ioctl(vm, KVM_SET_GSI_ROUTING, &irq_routes); @@ -508,14 +506,14 @@ int main(int argc, char *argv[]) .u.evtchn.type = EVTCHNSTAT_interdomain, .u.evtchn.flags = 0, .u.evtchn.deliver.port.port = EVTCHN_TEST1, - .u.evtchn.deliver.port.vcpu = VCPU_ID + 1, + .u.evtchn.deliver.port.vcpu = vcpu->id + 1, .u.evtchn.deliver.port.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL, }; vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &inj); /* Test migration to a different vCPU */ inj.u.evtchn.flags = KVM_XEN_EVTCHN_UPDATE; - inj.u.evtchn.deliver.port.vcpu = VCPU_ID; + inj.u.evtchn.deliver.port.vcpu = vcpu->id; vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &inj); inj.u.evtchn.send_port = 197; @@ -524,7 +522,7 @@ int main(int argc, char *argv[]) inj.u.evtchn.flags = 0; vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &inj); - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &tmr); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &tmr); } vinfo = addr_gpa2hva(vm, VCPU_INFO_VADDR); vinfo->evtchn_upcall_pending = 0; @@ -535,17 +533,17 @@ int main(int argc, char *argv[]) bool evtchn_irq_expected = false; for (;;) { - volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); + volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ @@ -574,7 +572,7 @@ int main(int argc, char *argv[]) printf("Testing runstate %s\n", runstate_names[uc.args[1]]); rst.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT; rst.u.runstate.state = uc.args[1]; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &rst); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &rst); break; case 4: @@ -589,7 +587,7 @@ int main(int argc, char *argv[]) 0x6b6b - rs->time[RUNSTATE_offline]; rst.u.runstate.time_runnable = -rst.u.runstate.time_blocked - rst.u.runstate.time_offline; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &rst); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &rst); break; case 5: @@ -601,7 +599,7 @@ int main(int argc, char *argv[]) rst.u.runstate.state_entry_time = 0x6b6b + 0x5a; rst.u.runstate.time_blocked = 0x6b6b; rst.u.runstate.time_offline = 0x5a; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &rst); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &rst); break; case 6: @@ -660,7 +658,7 @@ int main(int argc, char *argv[]) struct kvm_irq_routing_xen_evtchn e; e.port = EVTCHN_TEST2; - e.vcpu = VCPU_ID; + e.vcpu = vcpu->id; e.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL; vm_ioctl(vm, KVM_XEN_HVM_EVTCHN_SEND, &e); @@ -702,7 +700,7 @@ int main(int argc, char *argv[]) case 14: memset(&tmr, 0, sizeof(tmr)); tmr.type = KVM_XEN_VCPU_ATTR_TYPE_TIMER; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_GET_ATTR, &tmr); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_GET_ATTR, &tmr); TEST_ASSERT(tmr.u.timer.port == EVTCHN_TIMER, "Timer port not returned"); TEST_ASSERT(tmr.u.timer.priority == KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL, @@ -722,7 +720,7 @@ int main(int argc, char *argv[]) printf("Testing restored oneshot timer\n"); tmr.u.timer.expires_ns = rs->state_entry_time + 100000000, - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &tmr); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &tmr); evtchn_irq_expected = true; alarm(1); break; @@ -749,7 +747,7 @@ int main(int argc, char *argv[]) printf("Testing SCHEDOP_poll wake on masked event\n"); tmr.u.timer.expires_ns = rs->state_entry_time + 100000000, - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &tmr); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &tmr); alarm(1); break; @@ -760,11 +758,11 @@ int main(int argc, char *argv[]) evtchn_irq_expected = true; tmr.u.timer.expires_ns = rs->state_entry_time + 100000000; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &tmr); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &tmr); /* Read it back and check the pending time is reported correctly */ tmr.u.timer.expires_ns = 0; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_GET_ATTR, &tmr); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_GET_ATTR, &tmr); TEST_ASSERT(tmr.u.timer.expires_ns == rs->state_entry_time + 100000000, "Timer not reported pending"); alarm(1); @@ -774,7 +772,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(!evtchn_irq_expected, "Expected event channel IRQ but it didn't happen"); /* Read timer and check it is no longer pending */ - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_GET_ATTR, &tmr); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_GET_ATTR, &tmr); TEST_ASSERT(!tmr.u.timer.expires_ns, "Timer still reported pending"); shinfo->evtchn_pending[0] = 0; @@ -783,7 +781,7 @@ int main(int argc, char *argv[]) evtchn_irq_expected = true; tmr.u.timer.expires_ns = rs->state_entry_time - 100000000ULL; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &tmr); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &tmr); alarm(1); break; @@ -853,7 +851,7 @@ int main(int argc, char *argv[]) struct kvm_xen_vcpu_attr rst = { .type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA, }; - vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_GET_ATTR, &rst); + vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_GET_ATTR, &rst); if (verbose) { printf("Runstate: %s(%d), entry %" PRIu64 " ns\n", From c09aee348495af4cc15f823ff7256b77728d53c7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:40:19 -0800 Subject: [PATCH 0398/1436] KVM: selftests: Convert dirty_log_test away from VCPU_ID Convert dirty_log_test to pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. The test still hardcodes usage of vcpu_id==0, but only for a few lines. That wart will be removed in the not-too-distant future. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/dirty_log_test.c | 59 ++++++++++---------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index cf426a8ae816..23e0c727e375 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -23,8 +23,6 @@ #include "guest_modes.h" #include "processor.h" -#define VCPU_ID 1 - /* The memory slot index to track dirty pages */ #define TEST_MEM_SLOT_INDEX 1 @@ -226,17 +224,17 @@ static void clear_log_create_vm_done(struct kvm_vm *vm) vm_enable_cap(vm, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, manual_caps); } -static void dirty_log_collect_dirty_pages(struct kvm_vm *vm, int slot, +static void dirty_log_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, void *bitmap, uint32_t num_pages) { - kvm_vm_get_dirty_log(vm, slot, bitmap); + kvm_vm_get_dirty_log(vcpu->vm, slot, bitmap); } -static void clear_log_collect_dirty_pages(struct kvm_vm *vm, int slot, +static void clear_log_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, void *bitmap, uint32_t num_pages) { - kvm_vm_get_dirty_log(vm, slot, bitmap); - kvm_vm_clear_dirty_log(vm, slot, bitmap, 0, num_pages); + kvm_vm_get_dirty_log(vcpu->vm, slot, bitmap); + kvm_vm_clear_dirty_log(vcpu->vm, slot, bitmap, 0, num_pages); } /* Should only be called after a GUEST_SYNC */ @@ -250,14 +248,14 @@ static void vcpu_handle_sync_stop(void) } } -static void default_after_vcpu_run(struct kvm_vm *vm, int ret, int err) +static void default_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; TEST_ASSERT(ret == 0 || (ret == -1 && err == EINTR), "vcpu run failed: errno=%d", err); - TEST_ASSERT(get_ucall(vm, VCPU_ID, NULL) == UCALL_SYNC, + TEST_ASSERT(get_ucall(vcpu->vm, vcpu->id, NULL) == UCALL_SYNC, "Invalid guest sync status: exit_reason=%s\n", exit_reason_str(run->exit_reason)); @@ -328,7 +326,7 @@ static void dirty_ring_continue_vcpu(void) sem_post(&sem_vcpu_cont); } -static void dirty_ring_collect_dirty_pages(struct kvm_vm *vm, int slot, +static void dirty_ring_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, void *bitmap, uint32_t num_pages) { /* We only have one vcpu */ @@ -348,10 +346,10 @@ static void dirty_ring_collect_dirty_pages(struct kvm_vm *vm, int slot, } /* Only have one vcpu */ - count = dirty_ring_collect_one(vcpu_map_dirty_ring(vm, VCPU_ID), + count = dirty_ring_collect_one(vcpu_map_dirty_ring(vcpu->vm, vcpu->id), slot, bitmap, num_pages, &fetch_index); - cleared = kvm_vm_reset_dirty_ring(vm); + cleared = kvm_vm_reset_dirty_ring(vcpu->vm); /* Cleared pages should be the same as collected */ TEST_ASSERT(cleared == count, "Reset dirty pages (%u) mismatch " @@ -366,12 +364,12 @@ static void dirty_ring_collect_dirty_pages(struct kvm_vm *vm, int slot, pr_info("Iteration %ld collected %u pages\n", iteration, count); } -static void dirty_ring_after_vcpu_run(struct kvm_vm *vm, int ret, int err) +static void dirty_ring_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) { - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; /* A ucall-sync or ring-full event is allowed */ - if (get_ucall(vm, VCPU_ID, NULL) == UCALL_SYNC) { + if (get_ucall(vcpu->vm, vcpu->id, NULL) == UCALL_SYNC) { /* We should allow this to continue */ ; } else if (run->exit_reason == KVM_EXIT_DIRTY_RING_FULL || @@ -405,10 +403,10 @@ struct log_mode { /* Hook when the vm creation is done (before vcpu creation) */ void (*create_vm_done)(struct kvm_vm *vm); /* Hook to collect the dirty pages into the bitmap provided */ - void (*collect_dirty_pages) (struct kvm_vm *vm, int slot, + void (*collect_dirty_pages) (struct kvm_vcpu *vcpu, int slot, void *bitmap, uint32_t num_pages); /* Hook to call when after each vcpu run */ - void (*after_vcpu_run)(struct kvm_vm *vm, int ret, int err); + void (*after_vcpu_run)(struct kvm_vcpu *vcpu, int ret, int err); void (*before_vcpu_join) (void); } log_modes[LOG_MODE_NUM] = { { @@ -470,22 +468,22 @@ static void log_mode_create_vm_done(struct kvm_vm *vm) mode->create_vm_done(vm); } -static void log_mode_collect_dirty_pages(struct kvm_vm *vm, int slot, +static void log_mode_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, void *bitmap, uint32_t num_pages) { struct log_mode *mode = &log_modes[host_log_mode]; TEST_ASSERT(mode->collect_dirty_pages != NULL, "collect_dirty_pages() is required for any log mode!"); - mode->collect_dirty_pages(vm, slot, bitmap, num_pages); + mode->collect_dirty_pages(vcpu, slot, bitmap, num_pages); } -static void log_mode_after_vcpu_run(struct kvm_vm *vm, int ret, int err) +static void log_mode_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) { struct log_mode *mode = &log_modes[host_log_mode]; if (mode->after_vcpu_run) - mode->after_vcpu_run(vm, ret, err); + mode->after_vcpu_run(vcpu, ret, err); } static void log_mode_before_vcpu_join(void) @@ -507,7 +505,8 @@ static void generate_random_array(uint64_t *guest_array, uint64_t size) static void *vcpu_worker(void *data) { int ret; - struct kvm_vm *vm = data; + struct kvm_vcpu *vcpu = data; + struct kvm_vm *vm = vcpu->vm; uint64_t *guest_array; uint64_t pages_count = 0; struct kvm_signal_mask *sigmask = alloca(offsetof(struct kvm_signal_mask, sigset) @@ -522,7 +521,7 @@ static void *vcpu_worker(void *data) sigmask->len = 8; pthread_sigmask(0, NULL, sigset); sigdelset(sigset, SIG_IPI); - vcpu_ioctl(vm, VCPU_ID, KVM_SET_SIGNAL_MASK, sigmask); + vcpu_ioctl(vm, vcpu->id, KVM_SET_SIGNAL_MASK, sigmask); sigemptyset(sigset); sigaddset(sigset, SIG_IPI); @@ -534,13 +533,13 @@ static void *vcpu_worker(void *data) generate_random_array(guest_array, TEST_PAGES_PER_LOOP); pages_count += TEST_PAGES_PER_LOOP; /* Let the guest dirty the random pages */ - ret = __vcpu_run(vm, VCPU_ID); + ret = __vcpu_run(vm, vcpu->id); if (ret == -1 && errno == EINTR) { int sig = -1; sigwait(sigset, &sig); assert(sig == SIG_IPI); } - log_mode_after_vcpu_run(vm, ret, errno); + log_mode_after_vcpu_run(vcpu, ret, errno); } pr_info("Dirtied %"PRIu64" pages\n", pages_count); @@ -693,6 +692,7 @@ struct test_params { static void run_test(enum vm_guest_mode mode, void *arg) { struct test_params *p = arg; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; unsigned long *bmap; @@ -710,9 +710,10 @@ static void run_test(enum vm_guest_mode mode, void *arg) * (e.g., 64K page size guest will need even less memory for * page tables). */ - vm = create_vm(mode, VCPU_ID, + vm = create_vm(mode, 0, 2ul << (DIRTY_MEM_BITS - PAGE_SHIFT_4K), guest_code); + vcpu = vcpu_get(vm, 0); guest_page_size = vm_get_page_size(vm); /* @@ -773,12 +774,12 @@ static void run_test(enum vm_guest_mode mode, void *arg) host_clear_count = 0; host_track_next_count = 0; - pthread_create(&vcpu_thread, NULL, vcpu_worker, vm); + pthread_create(&vcpu_thread, NULL, vcpu_worker, vcpu); while (iteration < p->iterations) { /* Give the vcpu thread some time to dirty some pages */ usleep(p->interval * 1000); - log_mode_collect_dirty_pages(vm, TEST_MEM_SLOT_INDEX, + log_mode_collect_dirty_pages(vcpu, TEST_MEM_SLOT_INDEX, bmap, host_num_pages); /* From d7828144d4651efc063d0889c9498176da2aed8c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 15 Feb 2022 17:44:50 -0800 Subject: [PATCH 0399/1436] KVM: selftests: Convert set_memory_region_test away from VCPU_ID Convert set_memory_region_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/set_memory_region_test.c | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index c33402ba7587..1274bbb0e30b 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -17,8 +17,6 @@ #include #include -#define VCPU_ID 0 - /* * s390x needs at least 1MB alignment, and the x86_64 MOVE/DELETE tests need a * 2MB sized and aligned region so that the initial region corresponds to @@ -54,8 +52,8 @@ static inline uint64_t guest_spin_on_val(uint64_t spin_val) static void *vcpu_worker(void *data) { - struct kvm_vm *vm = data; - struct kvm_run *run; + struct kvm_vcpu *vcpu = data; + struct kvm_run *run = vcpu->run; struct ucall uc; uint64_t cmd; @@ -64,13 +62,11 @@ static void *vcpu_worker(void *data) * which will occur if the guest attempts to access a memslot after it * has been deleted or while it is being moved . */ - run = vcpu_state(vm, VCPU_ID); - while (1) { - vcpu_run(vm, VCPU_ID); + vcpu_run(vcpu->vm, vcpu->id); if (run->exit_reason == KVM_EXIT_IO) { - cmd = get_ucall(vm, VCPU_ID, &uc); + cmd = get_ucall(vcpu->vm, vcpu->id, &uc); if (cmd != UCALL_SYNC) break; @@ -113,13 +109,14 @@ static void wait_for_vcpu(void) usleep(100000); } -static struct kvm_vm *spawn_vm(pthread_t *vcpu_thread, void *guest_code) +static struct kvm_vm *spawn_vm(struct kvm_vcpu **vcpu, pthread_t *vcpu_thread, + void *guest_code) { struct kvm_vm *vm; uint64_t *hva; uint64_t gpa; - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(vcpu, guest_code); vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS_THP, MEM_REGION_GPA, MEM_REGION_SLOT, @@ -138,7 +135,7 @@ static struct kvm_vm *spawn_vm(pthread_t *vcpu_thread, void *guest_code) hva = addr_gpa2hva(vm, MEM_REGION_GPA); memset(hva, 0, 2 * 4096); - pthread_create(vcpu_thread, NULL, vcpu_worker, vm); + pthread_create(vcpu_thread, NULL, vcpu_worker, *vcpu); /* Ensure the guest thread is spun up. */ wait_for_vcpu(); @@ -180,10 +177,11 @@ static void guest_code_move_memory_region(void) static void test_move_memory_region(void) { pthread_t vcpu_thread; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; uint64_t *hva; - vm = spawn_vm(&vcpu_thread, guest_code_move_memory_region); + vm = spawn_vm(&vcpu, &vcpu_thread, guest_code_move_memory_region); hva = addr_gpa2hva(vm, MEM_REGION_GPA); @@ -258,11 +256,12 @@ static void guest_code_delete_memory_region(void) static void test_delete_memory_region(void) { pthread_t vcpu_thread; + struct kvm_vcpu *vcpu; struct kvm_regs regs; struct kvm_run *run; struct kvm_vm *vm; - vm = spawn_vm(&vcpu_thread, guest_code_delete_memory_region); + vm = spawn_vm(&vcpu, &vcpu_thread, guest_code_delete_memory_region); /* Delete the memory region, the guest should not die. */ vm_mem_region_delete(vm, MEM_REGION_SLOT); @@ -286,13 +285,13 @@ static void test_delete_memory_region(void) pthread_join(vcpu_thread, NULL); - run = vcpu_state(vm, VCPU_ID); + run = vcpu->run; TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN || run->exit_reason == KVM_EXIT_INTERNAL_ERROR, "Unexpected exit reason = %d", run->exit_reason); - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vm, vcpu->id, ®s); /* * On AMD, after KVM_EXIT_SHUTDOWN the VMCB has been reinitialized already, @@ -309,18 +308,19 @@ static void test_delete_memory_region(void) static void test_zero_memory_regions(void) { + struct kvm_vcpu *vcpu; struct kvm_run *run; struct kvm_vm *vm; pr_info("Testing KVM_RUN with zero added memory regions\n"); vm = vm_create_barebones(); - vm_vcpu_add(vm, VCPU_ID); + vcpu = vm_vcpu_add(vm, 0); vm_ioctl(vm, KVM_SET_NR_MMU_PAGES, (void *)64ul); - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - run = vcpu_state(vm, VCPU_ID); + run = vcpu->run; TEST_ASSERT(run->exit_reason == KVM_EXIT_INTERNAL_ERROR, "Unexpected exit_reason = %u\n", run->exit_reason); From 10f0b222ea7e0ab90e7c72a255ce8e4f284b12e3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 11:28:15 -0700 Subject: [PATCH 0400/1436] KVM: selftests: Convert system_counter_offset_test away from VCPU_ID Convert system_counter_offset_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/system_counter_offset_test.c | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c b/tools/testing/selftests/kvm/system_counter_offset_test.c index 5dd9d28efb97..0690ce0ae4fa 100644 --- a/tools/testing/selftests/kvm/system_counter_offset_test.c +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c @@ -14,8 +14,6 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 0 - #ifdef __x86_64__ struct test_case { @@ -28,18 +26,19 @@ static struct test_case test_cases[] = { { -180 * NSEC_PER_SEC }, }; -static void check_preconditions(struct kvm_vm *vm) +static void check_preconditions(struct kvm_vcpu *vcpu) { - if (!__vcpu_has_device_attr(vm, VCPU_ID, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET)) + if (!__vcpu_has_device_attr(vcpu->vm, vcpu->id, KVM_VCPU_TSC_CTRL, + KVM_VCPU_TSC_OFFSET)) return; print_skip("KVM_VCPU_TSC_OFFSET not supported; skipping test"); exit(KSFT_SKIP); } -static void setup_system_counter(struct kvm_vm *vm, struct test_case *test) +static void setup_system_counter(struct kvm_vcpu *vcpu, struct test_case *test) { - vcpu_device_attr_set(vm, VCPU_ID, KVM_VCPU_TSC_CTRL, + vcpu_device_attr_set(vcpu->vm, vcpu->id, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET, &test->tsc_offset); } @@ -91,7 +90,7 @@ static void handle_abort(struct ucall *uc) __FILE__, uc->args[1]); } -static void enter_guest(struct kvm_vm *vm) +static void enter_guest(struct kvm_vcpu *vcpu) { uint64_t start, end; struct ucall uc; @@ -100,12 +99,12 @@ static void enter_guest(struct kvm_vm *vm) for (i = 0; i < ARRAY_SIZE(test_cases); i++) { struct test_case *test = &test_cases[i]; - setup_system_counter(vm, test); + setup_system_counter(vcpu, test); start = host_read_guest_system_counter(test); - vcpu_run(vm, VCPU_ID); + vcpu_run(vcpu->vm, vcpu->id); end = host_read_guest_system_counter(test); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_SYNC: handle_sync(&uc, start, end); break; @@ -114,19 +113,20 @@ static void enter_guest(struct kvm_vm *vm) return; default: TEST_ASSERT(0, "unhandled ucall %ld\n", - get_ucall(vm, VCPU_ID, &uc)); + get_ucall(vcpu->vm, vcpu->id, &uc)); } } } int main(void) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; - vm = vm_create_default(VCPU_ID, 0, guest_main); - check_preconditions(vm); + vm = vm_create_with_one_vcpu(&vcpu, guest_main); + check_preconditions(vcpu); ucall_init(vm, NULL); - enter_guest(vm); + enter_guest(vcpu); kvm_vm_free(vm); } From ee7f7d9e988e137f20a34b8c02dd28dd5312e3f1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 11:28:21 -0700 Subject: [PATCH 0401/1436] KVM: selftests: Track kvm_vcpu object in tsc_scaling_sync Track the added 'struct kvm_vcpu' object in tsc_scaling_sync instead of relying purely on the VM + vcpu_id combination. Ideally, the test wouldn't need to manually manage vCPUs, but the need to invoke a per-VM ioctl before creating vCPUs is not handled by the selftests framework, at least not yet... Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/tsc_scaling_sync.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c index f0083d8cfe98..b7cd5c47fc53 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c @@ -46,38 +46,41 @@ static void guest_code(void) static void *run_vcpu(void *_cpu_nr) { - unsigned long cpu = (unsigned long)_cpu_nr; + unsigned long vcpu_id = (unsigned long)_cpu_nr; unsigned long failures = 0; static bool first_cpu_done; + struct kvm_vcpu *vcpu; /* The kernel is fine, but vm_vcpu_add_default() needs locking */ pthread_spin_lock(&create_lock); - vm_vcpu_add_default(vm, cpu, guest_code); + vm_vcpu_add_default(vm, vcpu_id, guest_code); + vcpu = vcpu_get(vm, vcpu_id); if (!first_cpu_done) { first_cpu_done = true; - vcpu_set_msr(vm, cpu, MSR_IA32_TSC, TEST_TSC_OFFSET); + vcpu_set_msr(vm, vcpu->id, MSR_IA32_TSC, TEST_TSC_OFFSET); } pthread_spin_unlock(&create_lock); for (;;) { - volatile struct kvm_run *run = vcpu_state(vm, cpu); + volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, cpu); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, cpu, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_DONE: goto out; case UCALL_SYNC: - printf("Guest %ld sync %lx %lx %ld\n", cpu, uc.args[2], uc.args[3], uc.args[2] - uc.args[3]); + printf("Guest %d sync %lx %lx %ld\n", vcpu->id, + uc.args[2], uc.args[3], uc.args[2] - uc.args[3]); failures++; break; From 20a7eb990ae8eeb33e072e97dfb05042603b0d81 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 12:11:54 -0700 Subject: [PATCH 0402/1436] KVM: selftests: Convert xapic_state_test away from hardcoded vCPU ID Convert xapic_state_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of the raw vCPU ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/xapic_state_test.c | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c index 9d8393b6ec75..56301ee1adee 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c @@ -12,7 +12,7 @@ #include "test_util.h" struct xapic_vcpu { - uint32_t id; + struct kvm_vcpu *vcpu; bool is_x2apic; }; @@ -47,8 +47,9 @@ static void x2apic_guest_code(void) } while (1); } -static void ____test_icr(struct kvm_vm *vm, struct xapic_vcpu *vcpu, uint64_t val) +static void ____test_icr(struct kvm_vm *vm, struct xapic_vcpu *x, uint64_t val) { + struct kvm_vcpu *vcpu = x->vcpu; struct kvm_lapic_state xapic; struct ucall uc; uint64_t icr; @@ -70,28 +71,29 @@ static void ____test_icr(struct kvm_vm *vm, struct xapic_vcpu *vcpu, uint64_t va vcpu_ioctl(vm, vcpu->id, KVM_GET_LAPIC, &xapic); icr = (u64)(*((u32 *)&xapic.regs[APIC_ICR])) | (u64)(*((u32 *)&xapic.regs[APIC_ICR2])) << 32; - if (!vcpu->is_x2apic) + if (!x->is_x2apic) val &= (-1u | (0xffull << (32 + 24))); ASSERT_EQ(icr, val & ~APIC_ICR_BUSY); } -static void __test_icr(struct kvm_vm *vm, struct xapic_vcpu *vcpu, uint64_t val) +static void __test_icr(struct kvm_vm *vm, struct xapic_vcpu *x, uint64_t val) { - ____test_icr(vm, vcpu, val | APIC_ICR_BUSY); - ____test_icr(vm, vcpu, val & ~(u64)APIC_ICR_BUSY); + ____test_icr(vm, x, val | APIC_ICR_BUSY); + ____test_icr(vm, x, val & ~(u64)APIC_ICR_BUSY); } -static void test_icr(struct kvm_vm *vm, struct xapic_vcpu *vcpu) +static void test_icr(struct kvm_vm *vm, struct xapic_vcpu *x) { + struct kvm_vcpu *vcpu = x->vcpu; uint64_t icr, i, j; icr = APIC_DEST_SELF | APIC_INT_ASSERT | APIC_DM_FIXED; for (i = 0; i <= 0xff; i++) - __test_icr(vm, vcpu, icr | i); + __test_icr(vm, x, icr | i); icr = APIC_INT_ASSERT | APIC_DM_FIXED; for (i = 0; i <= 0xff; i++) - __test_icr(vm, vcpu, icr | i); + __test_icr(vm, x, icr | i); /* * Send all flavors of IPIs to non-existent vCPUs. TODO: use number of @@ -100,32 +102,32 @@ static void test_icr(struct kvm_vm *vm, struct xapic_vcpu *vcpu) icr = APIC_INT_ASSERT | 0xff; for (i = vcpu->id + 1; i < 0xff; i++) { for (j = 0; j < 8; j++) - __test_icr(vm, vcpu, i << (32 + 24) | APIC_INT_ASSERT | (j << 8)); + __test_icr(vm, x, i << (32 + 24) | APIC_INT_ASSERT | (j << 8)); } /* And again with a shorthand destination for all types of IPIs. */ icr = APIC_DEST_ALLBUT | APIC_INT_ASSERT; for (i = 0; i < 8; i++) - __test_icr(vm, vcpu, icr | (i << 8)); + __test_icr(vm, x, icr | (i << 8)); /* And a few garbage value, just make sure it's an IRQ (blocked). */ - __test_icr(vm, vcpu, 0xa5a5a5a5a5a5a5a5 & ~APIC_DM_FIXED_MASK); - __test_icr(vm, vcpu, 0x5a5a5a5a5a5a5a5a & ~APIC_DM_FIXED_MASK); - __test_icr(vm, vcpu, -1ull & ~APIC_DM_FIXED_MASK); + __test_icr(vm, x, 0xa5a5a5a5a5a5a5a5 & ~APIC_DM_FIXED_MASK); + __test_icr(vm, x, 0x5a5a5a5a5a5a5a5a & ~APIC_DM_FIXED_MASK); + __test_icr(vm, x, -1ull & ~APIC_DM_FIXED_MASK); } int main(int argc, char *argv[]) { - struct xapic_vcpu vcpu = { - .id = 0, + struct xapic_vcpu x = { + .vcpu = NULL, .is_x2apic = true, }; struct kvm_cpuid2 *cpuid; struct kvm_vm *vm; int i; - vm = vm_create_default(vcpu.id, 0, x2apic_guest_code); - test_icr(vm, &vcpu); + vm = vm_create_with_one_vcpu(&x.vcpu, x2apic_guest_code); + test_icr(vm, &x); kvm_vm_free(vm); /* @@ -133,18 +135,18 @@ int main(int argc, char *argv[]) * the guest in order to test AVIC. KVM disallows changing CPUID after * KVM_RUN and AVIC is disabled if _any_ vCPU is allowed to use x2APIC. */ - vm = vm_create_default(vcpu.id, 0, xapic_guest_code); - vcpu.is_x2apic = false; + vm = vm_create_with_one_vcpu(&x.vcpu, xapic_guest_code); + x.is_x2apic = false; - cpuid = vcpu_get_cpuid(vm, vcpu.id); + cpuid = vcpu_get_cpuid(vm, x.vcpu->id); for (i = 0; i < cpuid->nent; i++) { if (cpuid->entries[i].function == 1) break; } cpuid->entries[i].ecx &= ~BIT(21); - vcpu_set_cpuid(vm, vcpu.id, cpuid); + vcpu_set_cpuid(vm, x.vcpu->id, cpuid); virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); - test_icr(vm, &vcpu); + test_icr(vm, &x); kvm_vm_free(vm); } From e5d86c7a032362b0051aaa75d8a1ee2291d16b42 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 08:35:01 -0800 Subject: [PATCH 0403/1436] KVM: selftests: Convert debug-exceptions away from VCPU_ID Convert debug-exceptions to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/debug-exceptions.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c index 63b2178210c4..b69db0942169 100644 --- a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c +++ b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c @@ -3,8 +3,6 @@ #include #include -#define VCPU_ID 0 - #define MDSCR_KDE (1 << 13) #define MDSCR_MDE (1 << 15) #define MDSCR_SS (1 << 0) @@ -240,27 +238,28 @@ static void guest_svc_handler(struct ex_regs *regs) svc_addr = regs->pc; } -static int debug_version(struct kvm_vm *vm) +static int debug_version(struct kvm_vcpu *vcpu) { uint64_t id_aa64dfr0; - get_reg(vm, VCPU_ID, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), &id_aa64dfr0); + get_reg(vcpu->vm, vcpu->id, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), &id_aa64dfr0); return id_aa64dfr0 & 0xf; } int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct ucall uc; int stage; - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); ucall_init(vm, NULL); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); - if (debug_version(vm) < 6) { + if (debug_version(vcpu) < 6) { print_skip("Armv8 debug architecture not supported."); kvm_vm_free(vm); exit(KSFT_SKIP); @@ -278,9 +277,9 @@ int main(int argc, char *argv[]) ESR_EC_SVC64, guest_svc_handler); for (stage = 0; stage < 11; stage++) { - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_SYNC: TEST_ASSERT(uc.args[1] == stage, "Stage %d: Unexpected sync ucall, got %lx", From afcda3dcb3787d100d6e9e3ee97ebf0ff3e67dbb Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 11:50:15 -0700 Subject: [PATCH 0404/1436] KVM: selftests: Convert fix_hypercall_test away from VCPU_ID Convert fix_hypercall_test to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of using a global VCPU_ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/fix_hypercall_test.c | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c index 81f9f5b1f655..108c3f75361d 100644 --- a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c @@ -14,8 +14,6 @@ #include "kvm_util.h" #include "processor.h" -#define VCPU_ID 0 - static bool ud_expected; static void guest_ud_handler(struct ex_regs *regs) @@ -94,22 +92,20 @@ static void guest_main(void) GUEST_DONE(); } -static void setup_ud_vector(struct kvm_vm *vm) +static void setup_ud_vector(struct kvm_vcpu *vcpu) { - vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); - vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); + vm_init_descriptor_tables(vcpu->vm); + vcpu_init_descriptor_tables(vcpu->vm, vcpu->id); + vm_install_exception_handler(vcpu->vm, UD_VECTOR, guest_ud_handler); } -static void enter_guest(struct kvm_vm *vm) +static void enter_guest(struct kvm_vcpu *vcpu) { - struct kvm_run *run; + struct kvm_run *run = vcpu->run; struct ucall uc; - run = vcpu_state(vm, VCPU_ID); - - vcpu_run(vm, VCPU_ID); - switch (get_ucall(vm, VCPU_ID, &uc)) { + vcpu_run(vcpu->vm, vcpu->id); + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_SYNC: pr_info("%s: %016lx\n", (const char *)uc.args[2], uc.args[3]); break; @@ -125,25 +121,27 @@ static void enter_guest(struct kvm_vm *vm) static void test_fix_hypercall(void) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; - vm = vm_create_default(VCPU_ID, 0, guest_main); - setup_ud_vector(vm); + vm = vm_create_with_one_vcpu(&vcpu, guest_main); + setup_ud_vector(vcpu); ud_expected = false; sync_global_to_guest(vm, ud_expected); virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); - enter_guest(vm); + enter_guest(vcpu); } static void test_fix_hypercall_disabled(void) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; - vm = vm_create_default(VCPU_ID, 0, guest_main); - setup_ud_vector(vm); + vm = vm_create_with_one_vcpu(&vcpu, guest_main); + setup_ud_vector(vcpu); vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, KVM_X86_QUIRK_FIX_HYPERCALL_INSN); @@ -153,7 +151,7 @@ static void test_fix_hypercall_disabled(void) virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); - enter_guest(vm); + enter_guest(vcpu); } int main(void) From fd04edc3560c1be3321c50da1bb504ebc002e676 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 08:41:38 -0800 Subject: [PATCH 0405/1436] KVM: selftests: Convert vgic_irq away from VCPU_ID Convert vgic_irq to use vm_create_with_one_vcpu() and pass around a 'struct kvm_vcpu' object instead of passing around a vCPU ID (which is always the global VCPU_ID...). Opportunstically align the indentation for multiple functions' parameters. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/vgic_irq.c | 30 ++++++++++--------- .../selftests/kvm/include/aarch64/vgic.h | 6 ++-- .../testing/selftests/kvm/lib/aarch64/vgic.c | 10 +++---- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_irq.c b/tools/testing/selftests/kvm/aarch64/vgic_irq.c index 87e41895b385..111170201e9b 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_irq.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_irq.c @@ -22,7 +22,6 @@ #define GICD_BASE_GPA 0x08000000ULL #define GICR_BASE_GPA 0x080A0000ULL -#define VCPU_ID 0 /* * Stores the user specified args; it's passed to the guest and to every test @@ -589,7 +588,8 @@ static void kvm_set_gsi_routing_irqchip_check(struct kvm_vm *vm, } static void kvm_irq_write_ispendr_check(int gic_fd, uint32_t intid, - uint32_t vcpu, bool expect_failure) + struct kvm_vcpu *vcpu, + bool expect_failure) { /* * Ignore this when expecting failure as invalid intids will lead to @@ -659,15 +659,16 @@ static void kvm_routing_and_irqfd_check(struct kvm_vm *vm, (tmp) < (uint64_t)(first) + (uint64_t)(num); \ (tmp)++, (i)++) -static void run_guest_cmd(struct kvm_vm *vm, int gic_fd, - struct kvm_inject_args *inject_args, - struct test_args *test_args) +static void run_guest_cmd(struct kvm_vcpu *vcpu, int gic_fd, + struct kvm_inject_args *inject_args, + struct test_args *test_args) { kvm_inject_cmd cmd = inject_args->cmd; uint32_t intid = inject_args->first_intid; uint32_t num = inject_args->num; int level = inject_args->level; bool expect_failure = inject_args->expect_failure; + struct kvm_vm *vm = vcpu->vm; uint64_t tmp; uint32_t i; @@ -705,12 +706,12 @@ static void run_guest_cmd(struct kvm_vm *vm, int gic_fd, break; case KVM_WRITE_ISPENDR: for (i = intid; i < intid + num; i++) - kvm_irq_write_ispendr_check(gic_fd, i, - VCPU_ID, expect_failure); + kvm_irq_write_ispendr_check(gic_fd, i, vcpu, + expect_failure); break; case KVM_WRITE_ISACTIVER: for (i = intid; i < intid + num; i++) - kvm_irq_write_isactiver(gic_fd, i, VCPU_ID); + kvm_irq_write_isactiver(gic_fd, i, vcpu); break; default: break; @@ -739,6 +740,7 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) { struct ucall uc; int gic_fd; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_inject_args inject_args; vm_vaddr_t args_gva; @@ -753,16 +755,16 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) print_args(&args); - vm = vm_create_default(VCPU_ID, 0, guest_code); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); ucall_init(vm, NULL); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); /* Setup the guest args page (so it gets the args). */ args_gva = vm_vaddr_alloc_page(vm); memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args)); - vcpu_args_set(vm, 0, 1, args_gva); + vcpu_args_set(vm, vcpu->id, 1, args_gva); gic_fd = vgic_v3_setup(vm, 1, nr_irqs, GICD_BASE_GPA, GICR_BASE_GPA); @@ -775,12 +777,12 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) guest_irq_handlers[args.eoi_split][args.level_sensitive]); while (1) { - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_SYNC: kvm_inject_get_call(vm, &uc, &inject_args); - run_guest_cmd(vm, gic_fd, &inject_args, &args); + run_guest_cmd(vcpu, gic_fd, &inject_args, &args); break; case UCALL_ABORT: TEST_FAIL("%s at %s:%ld\n\tvalues: %#lx, %#lx", diff --git a/tools/testing/selftests/kvm/include/aarch64/vgic.h b/tools/testing/selftests/kvm/include/aarch64/vgic.h index 4442081221a0..0ac6f05c63f9 100644 --- a/tools/testing/selftests/kvm/include/aarch64/vgic.h +++ b/tools/testing/selftests/kvm/include/aarch64/vgic.h @@ -8,6 +8,8 @@ #include +#include "kvm_util.h" + #define REDIST_REGION_ATTR_ADDR(count, base, flags, index) \ (((uint64_t)(count) << 52) | \ ((uint64_t)((base) >> 16) << 16) | \ @@ -26,8 +28,8 @@ void kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level); int _kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level); /* The vcpu arg only applies to private interrupts. */ -void kvm_irq_write_ispendr(int gic_fd, uint32_t intid, uint32_t vcpu); -void kvm_irq_write_isactiver(int gic_fd, uint32_t intid, uint32_t vcpu); +void kvm_irq_write_ispendr(int gic_fd, uint32_t intid, struct kvm_vcpu *vcpu); +void kvm_irq_write_isactiver(int gic_fd, uint32_t intid, struct kvm_vcpu *vcpu); #define KVM_IRQCHIP_NUM_PINS (1020 - 32) diff --git a/tools/testing/selftests/kvm/lib/aarch64/vgic.c b/tools/testing/selftests/kvm/lib/aarch64/vgic.c index cfe3067efbf0..b5f28d21a947 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/vgic.c +++ b/tools/testing/selftests/kvm/lib/aarch64/vgic.c @@ -127,8 +127,8 @@ void kvm_arm_irq_line(struct kvm_vm *vm, uint32_t intid, int level) TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_IRQ_LINE, ret)); } -static void vgic_poke_irq(int gic_fd, uint32_t intid, - uint32_t vcpu, uint64_t reg_off) +static void vgic_poke_irq(int gic_fd, uint32_t intid, struct kvm_vcpu *vcpu, + uint64_t reg_off) { uint64_t reg = intid / 32; uint64_t index = intid % 32; @@ -141,7 +141,7 @@ static void vgic_poke_irq(int gic_fd, uint32_t intid, if (intid_is_private) { /* TODO: only vcpu 0 implemented for now. */ - assert(vcpu == 0); + assert(vcpu->id == 0); attr += SZ_64K; } @@ -159,12 +159,12 @@ static void vgic_poke_irq(int gic_fd, uint32_t intid, kvm_device_attr_set(gic_fd, group, attr, &val); } -void kvm_irq_write_ispendr(int gic_fd, uint32_t intid, uint32_t vcpu) +void kvm_irq_write_ispendr(int gic_fd, uint32_t intid, struct kvm_vcpu *vcpu) { vgic_poke_irq(gic_fd, intid, vcpu, GICD_ISPENDR); } -void kvm_irq_write_isactiver(int gic_fd, uint32_t intid, uint32_t vcpu) +void kvm_irq_write_isactiver(int gic_fd, uint32_t intid, struct kvm_vcpu *vcpu) { vgic_poke_irq(gic_fd, intid, vcpu, GICD_ISACTIVER); } From 033899489062e69d06e1ef7c0795ad9ac9bd47c1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 09:02:27 -0800 Subject: [PATCH 0406/1436] KVM: selftests: Make arm64's guest_get_vcpuid() declaration arm64-only Move the declaration of guest_get_vcpuid() to include/aarch64/processor.h, it is implemented and used only by arm64. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/include/aarch64/processor.h | 2 ++ tools/testing/selftests/kvm/include/kvm_util_base.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index 59ece9d4e0d1..4d2d474b6874 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -207,4 +207,6 @@ void smccc_hvc(uint32_t function_id, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, struct arm_smccc_res *res); +uint32_t guest_get_vcpuid(void); + #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index fbc54e920383..d94b6083d678 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -707,6 +707,4 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid); -uint32_t guest_get_vcpuid(void); - #endif /* SELFTEST_KVM_UTIL_BASE_H */ From b8592448370b1235119a0a135e99277430c76d53 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 09:08:00 -0800 Subject: [PATCH 0407/1436] KVM: selftests: Move vm_is_unrestricted_guest() to x86-64 An "unrestricted guest" is an VMX-only concept, move the relevant helper to x86-64 code. Assume most readers can correctly convert underscores to spaces and oppurtunistically trim the function comment. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 2 -- .../selftests/kvm/include/x86_64/processor.h | 1 + tools/testing/selftests/kvm/lib/kvm_util.c | 33 ------------------- .../selftests/kvm/lib/x86_64/processor.c | 21 ++++++++++++ 4 files changed, 22 insertions(+), 35 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index d94b6083d678..5426de96e169 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -667,8 +667,6 @@ struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm); */ void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); -bool vm_is_unrestricted_guest(struct kvm_vm *vm); - unsigned int vm_get_page_size(struct kvm_vm *vm); unsigned int vm_get_page_shift(struct kvm_vm *vm); unsigned long vm_compute_max_gfn(struct kvm_vm *vm); diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 0bb9ba955d18..a19a52c50608 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -526,6 +526,7 @@ static inline void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t kvm_get_cpuid_max_basic(void); uint32_t kvm_get_cpuid_max_extended(void); void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits); +bool vm_is_unrestricted_guest(struct kvm_vm *vm); struct ex_regs { uint64_t rax, rcx, rdx, rbx; diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index f8274ca5fe5b..752731cf4292 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1948,39 +1948,6 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva) return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); } -/* - * Is Unrestricted Guest - * - * Input Args: - * vm - Virtual Machine - * - * Output Args: None - * - * Return: True if the unrestricted guest is set to 'Y', otherwise return false. - * - * Check if the unrestricted guest flag is enabled. - */ -bool vm_is_unrestricted_guest(struct kvm_vm *vm) -{ - char val = 'N'; - size_t count; - FILE *f; - - if (vm == NULL) { - /* Ensure that the KVM vendor-specific module is loaded. */ - close(open_kvm_dev_path_or_exit()); - } - - f = fopen("/sys/module/kvm_intel/parameters/unrestricted_guest", "r"); - if (f) { - count = fread(&val, sizeof(char), 1, f); - TEST_ASSERT(count == 1, "Unable to read from param file."); - fclose(f); - } - - return val == 'Y'; -} - unsigned int vm_get_page_size(struct kvm_vm *vm) { return vm->page_size; diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 47bc84d1aeb0..d25a6a9cdfee 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1357,3 +1357,24 @@ unsigned long vm_compute_max_gfn(struct kvm_vm *vm) done: return min(max_gfn, ht_gfn - 1); } + +/* Returns true if kvm_intel was loaded with unrestricted_guest=1. */ +bool vm_is_unrestricted_guest(struct kvm_vm *vm) +{ + char val = 'N'; + size_t count; + FILE *f; + + /* Ensure that a KVM vendor-specific module is loaded. */ + if (vm == NULL) + close(open_kvm_dev_path_or_exit()); + + f = fopen("/sys/module/kvm_intel/parameters/unrestricted_guest", "r"); + if (f) { + count = fread(&val, sizeof(char), 1, f); + TEST_ASSERT(count == 1, "Unable to read from param file."); + fclose(f); + } + + return val == 'Y'; +} From 9931be3fc62edad381de074ad0db576eefed7fee Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 09:30:39 -0800 Subject: [PATCH 0408/1436] KVM: selftests: Add "arch" to common utils that have arch implementations Add "arch" into the name of utility functions that are declared in common code, but (surprise!) have arch-specific implementations. Shuffle code around so that all such helpers' declarations are bundled together. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 200 ++++++++++-------- .../selftests/kvm/lib/aarch64/processor.c | 12 +- .../selftests/kvm/lib/riscv/processor.c | 12 +- .../selftests/kvm/lib/s390x/processor.c | 12 +- .../selftests/kvm/lib/x86_64/processor.c | 12 +- 5 files changed, 141 insertions(+), 107 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 5426de96e169..c7abe48d07cb 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -95,23 +95,6 @@ struct kvm_vm { struct kvm_vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid); -/* - * Virtual Translation Tables Dump - * - * Input Args: - * stream - Output FILE stream - * vm - Virtual Machine - * indent - Left margin indent amount - * - * Output Args: None - * - * Return: None - * - * Dumps to the FILE stream given by @stream, the contents of all the - * virtual translation tables for the VM given by @vm. - */ -void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); - struct userspace_mem_region * memslot2region(struct kvm_vm *vm, uint32_t memslot); @@ -291,25 +274,6 @@ static inline int vm_get_stats_fd(struct kvm_vm *vm) return fd; } -/* - * VM VCPU Dump - * - * Input Args: - * stream - Output FILE stream - * vm - Virtual Machine - * vcpuid - VCPU ID - * indent - Left margin indent amount - * - * Output Args: None - * - * Return: None - * - * Dumps the current state of the VCPU specified by @vcpuid, within the VM - * given by @vm, to the FILE stream given by @stream. - */ -void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, - uint8_t indent); - void vm_create_irqchip(struct kvm_vm *vm); void vm_set_user_memory_region(struct kvm_vm *vm, uint32_t slot, uint32_t flags, @@ -336,23 +300,6 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva); vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva); void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa); -/* - * Address Guest Virtual to Guest Physical - * - * Input Args: - * vm - Virtual Machine - * gva - VM virtual address - * - * Output Args: None - * - * Return: - * Equivalent VM physical address - * - * Returns the VM physical address of the translated VM virtual - * address given by @gva. - */ -vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva); - struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid); void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); @@ -569,26 +516,6 @@ void kvm_gsi_routing_write(struct kvm_vm *vm, struct kvm_irq_routing *routing); const char *exit_reason_str(unsigned int exit_reason); -void virt_pgd_alloc(struct kvm_vm *vm); - -/* - * VM Virtual Page Map - * - * Input Args: - * vm - Virtual Machine - * vaddr - VM Virtual Address - * paddr - VM Physical Address - * memslot - Memory region slot for new virtual translation tables - * - * Output Args: None - * - * Return: None - * - * Within @vm, creates a virtual translation for the page starting - * at @vaddr to the page starting at @paddr. - */ -void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr); - vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, uint32_t memslot); vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, @@ -657,16 +584,6 @@ static inline struct kvm_vm *vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm); -/* - * Adds a vCPU with reasonable defaults (e.g. a stack) - * - * Input Args: - * vm - Virtual Machine - * vcpuid - The id of the VCPU to add to the VM. - * guest_code - The vCPU's entry point - */ -void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); - unsigned int vm_get_page_size(struct kvm_vm *vm); unsigned int vm_get_page_shift(struct kvm_vm *vm); unsigned long vm_compute_max_gfn(struct kvm_vm *vm); @@ -705,4 +622,121 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid); +/* + * VM VCPU Dump + * + * Input Args: + * stream - Output FILE stream + * vm - Virtual Machine + * vcpuid - VCPU ID + * indent - Left margin indent amount + * + * Output Args: None + * + * Return: None + * + * Dumps the current state of the VCPU specified by @vcpuid, within the VM + * given by @vm, to the FILE stream given by @stream. + */ + +void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, + uint8_t indent); + +static inline void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, + uint8_t indent) +{ + vcpu_arch_dump(stream, vm, vcpuid, indent); +} + +/* + * Adds a vCPU with reasonable defaults (e.g. a stack) + * + * Input Args: + * vm - Virtual Machine + * vcpuid - The id of the VCPU to add to the VM. + * guest_code - The vCPU's entry point + */ +void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); + +static inline void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, + void *guest_code) +{ + vm_arch_vcpu_add(vm, vcpuid, guest_code); +} + +void virt_arch_pgd_alloc(struct kvm_vm *vm); + +static inline void virt_pgd_alloc(struct kvm_vm *vm) +{ + virt_arch_pgd_alloc(vm); +} + +/* + * VM Virtual Page Map + * + * Input Args: + * vm - Virtual Machine + * vaddr - VM Virtual Address + * paddr - VM Physical Address + * memslot - Memory region slot for new virtual translation tables + * + * Output Args: None + * + * Return: None + * + * Within @vm, creates a virtual translation for the page starting + * at @vaddr to the page starting at @paddr. + */ +void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr); + +static inline void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) +{ + virt_arch_pg_map(vm, vaddr, paddr); +} + + +/* + * Address Guest Virtual to Guest Physical + * + * Input Args: + * vm - Virtual Machine + * gva - VM virtual address + * + * Output Args: None + * + * Return: + * Equivalent VM physical address + * + * Returns the VM physical address of the translated VM virtual + * address given by @gva. + */ +vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva); + +static inline vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) +{ + return addr_arch_gva2gpa(vm, gva); +} + +/* + * Virtual Translation Tables Dump + * + * Input Args: + * stream - Output FILE stream + * vm - Virtual Machine + * indent - Left margin indent amount + * + * Output Args: None + * + * Return: None + * + * Dumps to the FILE stream given by @stream, the contents of all the + * virtual translation tables for the VM given by @vm. + */ +void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); + +static inline void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) +{ + virt_arch_dump(stream, vm, indent); +} + #endif /* SELFTEST_KVM_UTIL_BASE_H */ diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 2e73853f485e..d14579176e52 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -74,7 +74,7 @@ static uint64_t __maybe_unused ptrs_per_pte(struct kvm_vm *vm) return 1 << (vm->page_shift - 3); } -void virt_pgd_alloc(struct kvm_vm *vm) +void virt_arch_pgd_alloc(struct kvm_vm *vm) { if (!vm->pgd_created) { vm_paddr_t paddr = vm_phy_pages_alloc(vm, @@ -131,14 +131,14 @@ static void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, *ptep |= (attr_idx << 2) | (1 << 10) /* Access Flag */; } -void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) +void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) { uint64_t attr_idx = 4; /* NORMAL (See DEFAULT_MAIR_EL1) */ _virt_pg_map(vm, vaddr, paddr, attr_idx); } -vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) +vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) { uint64_t *ptep; @@ -195,7 +195,7 @@ static void pte_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent, uint64_t p #endif } -void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) +void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) { int level = 4 - (vm->pgtable_levels - 1); uint64_t pgd, *ptep; @@ -303,7 +303,7 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TPIDR_EL1), vcpuid); } -void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) +void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) { uint64_t pstate, pc; @@ -330,7 +330,7 @@ void aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, set_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); } -void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) +void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) { aarch64_vcpu_add_default(vm, vcpuid, NULL, guest_code); } diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index 5ee8250dd74c..d70d5a4c5ad6 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -53,7 +53,7 @@ static uint64_t pte_index(struct kvm_vm *vm, vm_vaddr_t gva, int level) return (gva & pte_index_mask[level]) >> pte_index_shift[level]; } -void virt_pgd_alloc(struct kvm_vm *vm) +void virt_arch_pgd_alloc(struct kvm_vm *vm) { if (!vm->pgd_created) { vm_paddr_t paddr = vm_phy_pages_alloc(vm, @@ -64,7 +64,7 @@ void virt_pgd_alloc(struct kvm_vm *vm) } } -void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) +void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) { uint64_t *ptep, next_ppn; int level = vm->pgtable_levels - 1; @@ -108,7 +108,7 @@ void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) PGTBL_PTE_PERM_MASK | PGTBL_PTE_VALID_MASK; } -vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) +vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) { uint64_t *ptep; int level = vm->pgtable_levels - 1; @@ -159,7 +159,7 @@ static void pte_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent, #endif } -void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) +void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) { int level = vm->pgtable_levels - 1; uint64_t pgd, *ptep; @@ -201,7 +201,7 @@ void riscv_vcpu_mmu_setup(struct kvm_vm *vm, int vcpuid) set_reg(vm, vcpuid, RISCV_CSR_REG(satp), satp); } -void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) +void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) { struct kvm_riscv_core core; @@ -274,7 +274,7 @@ static void __aligned(16) guest_unexp_trap(void) 0, 0, 0, 0, 0, 0); } -void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) +void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) { int r; size_t stack_size = vm->page_size == 4096 ? diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index aec15ca9d887..c2fe56a3fb74 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -10,7 +10,7 @@ #define PAGES_PER_REGION 4 -void virt_pgd_alloc(struct kvm_vm *vm) +void virt_arch_pgd_alloc(struct kvm_vm *vm) { vm_paddr_t paddr; @@ -46,7 +46,7 @@ static uint64_t virt_alloc_region(struct kvm_vm *vm, int ri) | ((ri < 4 ? (PAGES_PER_REGION - 1) : 0) & REGION_ENTRY_LENGTH); } -void virt_pg_map(struct kvm_vm *vm, uint64_t gva, uint64_t gpa) +void virt_arch_pg_map(struct kvm_vm *vm, uint64_t gva, uint64_t gpa) { int ri, idx; uint64_t *entry; @@ -85,7 +85,7 @@ void virt_pg_map(struct kvm_vm *vm, uint64_t gva, uint64_t gpa) entry[idx] = gpa; } -vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) +vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) { int ri, idx; uint64_t *entry; @@ -146,7 +146,7 @@ static void virt_dump_region(FILE *stream, struct kvm_vm *vm, uint8_t indent, } } -void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) +void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) { if (!vm->pgd_created) return; @@ -154,7 +154,7 @@ void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) virt_dump_region(stream, vm, indent, vm->pgd); } -void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) +void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) { size_t stack_size = DEFAULT_STACK_PGS * getpagesize(); uint64_t stack_vaddr; @@ -205,7 +205,7 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) va_end(ap); } -void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) +void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) { struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index d25a6a9cdfee..1bc406b6317d 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -109,7 +109,7 @@ static void sregs_dump(FILE *stream, struct kvm_sregs *sregs, uint8_t indent) } } -void virt_pgd_alloc(struct kvm_vm *vm) +void virt_arch_pgd_alloc(struct kvm_vm *vm) { TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, "Attempt to use " "unknown or unsupported guest mode, mode: 0x%x", vm->mode); @@ -207,7 +207,7 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level) *pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK); } -void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) +void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) { __virt_pg_map(vm, vaddr, paddr, PG_LEVEL_4K); } @@ -302,7 +302,7 @@ void vm_set_page_table_entry(struct kvm_vm *vm, int vcpuid, uint64_t vaddr, *(uint64_t *)new_pte = pte; } -void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) +void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) { uint64_t *pml4e, *pml4e_start; uint64_t *pdpe, *pdpe_start; @@ -483,7 +483,7 @@ static void kvm_seg_set_kernel_data_64bit(struct kvm_vm *vm, uint16_t selector, kvm_seg_fill_gdt_64bit(vm, segp); } -vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) +vm_paddr_t addr_arch_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) { uint16_t index[4]; uint64_t *pml4e, *pdpe, *pde; @@ -632,7 +632,7 @@ void vm_xsave_req_perm(int bit) bitmask); } -void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) +void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) { struct kvm_mp_state mp_state; struct kvm_regs regs; @@ -873,7 +873,7 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) va_end(ap); } -void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) +void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) { struct kvm_regs regs; struct kvm_sregs sregs; From 1422efd6bb75e4ae038432449bf9229d6be8e0b4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 09:37:11 -0800 Subject: [PATCH 0409/1436] KVM: selftests: Return created vcpu from vm_vcpu_add_default() Return the created 'struct kvm_vcpu' object from vm_vcpu_add_default(), which cleans up a few tests and will eventually allow removing vcpu_get() entirely. Opportunistically rename @vcpuid to @vcpu_id to follow preferred kernel style. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/aarch64/processor.h | 5 +++-- .../selftests/kvm/include/kvm_util_base.h | 10 ++++++---- .../selftests/kvm/lib/aarch64/processor.c | 20 +++++++++++-------- .../selftests/kvm/lib/riscv/processor.c | 20 +++++++++++-------- .../selftests/kvm/lib/s390x/processor.c | 18 ++++++++++------- .../selftests/kvm/lib/x86_64/processor.c | 20 +++++++++++-------- .../kvm/x86_64/pmu_event_filter_test.c | 4 +--- .../selftests/kvm/x86_64/tsc_scaling_sync.c | 3 +-- 8 files changed, 58 insertions(+), 42 deletions(-) diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index 4d2d474b6874..9dad391b4fec 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -64,8 +64,9 @@ static inline void set_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint } void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init *init); -void aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_vcpu_init *init, void *guest_code); +struct kvm_vcpu *aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpu_id, + struct kvm_vcpu_init *init, + void *guest_code); struct ex_regs { u64 regs[31]; diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index c7abe48d07cb..622b09ec23dd 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -656,12 +656,14 @@ static inline void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, * vcpuid - The id of the VCPU to add to the VM. * guest_code - The vCPU's entry point */ -void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, + void *guest_code); -static inline void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, - void *guest_code) +static inline struct kvm_vcpu *vm_vcpu_add_default(struct kvm_vm *vm, + uint32_t vcpu_id, + void *guest_code) { - vm_arch_vcpu_add(vm, vcpuid, guest_code); + return vm_arch_vcpu_add(vm, vcpu_id, guest_code); } void virt_arch_pgd_alloc(struct kvm_vm *vm); diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index d14579176e52..2b169b4ec29e 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -314,25 +314,29 @@ void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t in indent, "", pstate, pc); } -void aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_vcpu_init *init, void *guest_code) +struct kvm_vcpu *aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpu_id, + struct kvm_vcpu_init *init, + void *guest_code) { size_t stack_size = vm->page_size == 4096 ? DEFAULT_STACK_PGS * vm->page_size : vm->page_size; uint64_t stack_vaddr = vm_vaddr_alloc(vm, stack_size, DEFAULT_ARM64_GUEST_STACK_VADDR_MIN); + struct kvm_vcpu *vcpu = vm_vcpu_add(vm, vcpu_id); - vm_vcpu_add(vm, vcpuid); - aarch64_vcpu_setup(vm, vcpuid, init); + aarch64_vcpu_setup(vm, vcpu_id, init); - set_reg(vm, vcpuid, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); - set_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); + set_reg(vm, vcpu_id, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); + set_reg(vm, vcpu_id, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); + + return vcpu; } -void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, + void *guest_code) { - aarch64_vcpu_add_default(vm, vcpuid, NULL, guest_code); + return aarch64_vcpu_add_default(vm, vcpu_id, NULL, guest_code); } void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index d70d5a4c5ad6..5946101144eb 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -274,7 +274,8 @@ static void __aligned(16) guest_unexp_trap(void) 0, 0, 0, 0, 0, 0); } -void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, + void *guest_code) { int r; size_t stack_size = vm->page_size == 4096 ? @@ -284,9 +285,10 @@ void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) DEFAULT_RISCV_GUEST_STACK_VADDR_MIN); unsigned long current_gp = 0; struct kvm_mp_state mps; + struct kvm_vcpu *vcpu; - vm_vcpu_add(vm, vcpuid); - riscv_vcpu_mmu_setup(vm, vcpuid); + vcpu = vm_vcpu_add(vm, vcpu_id); + riscv_vcpu_mmu_setup(vm, vcpu_id); /* * With SBI HSM support in KVM RISC-V, all secondary VCPUs are @@ -294,23 +296,25 @@ void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) * are powered-on using KVM_SET_MP_STATE ioctl(). */ mps.mp_state = KVM_MP_STATE_RUNNABLE; - r = __vcpu_ioctl(vm, vcpuid, KVM_SET_MP_STATE, &mps); + r = __vcpu_ioctl(vm, vcpu_id, KVM_SET_MP_STATE, &mps); TEST_ASSERT(!r, "IOCTL KVM_SET_MP_STATE failed (error %d)", r); /* Setup global pointer of guest to be same as the host */ asm volatile ( "add %0, gp, zero" : "=r" (current_gp) : : "memory"); - set_reg(vm, vcpuid, RISCV_CORE_REG(regs.gp), current_gp); + set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.gp), current_gp); /* Setup stack pointer and program counter of guest */ - set_reg(vm, vcpuid, RISCV_CORE_REG(regs.sp), + set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.sp), stack_vaddr + stack_size); - set_reg(vm, vcpuid, RISCV_CORE_REG(regs.pc), + set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.pc), (unsigned long)guest_code); /* Setup default exception vector of guest */ - set_reg(vm, vcpuid, RISCV_CSR_REG(stvec), + set_reg(vm, vcpu_id, RISCV_CSR_REG(stvec), (unsigned long)guest_unexp_trap); + + return vcpu; } void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index c2fe56a3fb74..cf759844b226 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -154,12 +154,14 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) virt_dump_region(stream, vm, indent, vm->pgd); } -void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, + void *guest_code) { size_t stack_size = DEFAULT_STACK_PGS * getpagesize(); uint64_t stack_vaddr; struct kvm_regs regs; struct kvm_sregs sregs; + struct kvm_vcpu *vcpu; struct kvm_run *run; TEST_ASSERT(vm->page_size == 4096, "Unsupported page size: 0x%x", @@ -168,21 +170,23 @@ void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) stack_vaddr = vm_vaddr_alloc(vm, stack_size, DEFAULT_GUEST_STACK_VADDR_MIN); - vm_vcpu_add(vm, vcpuid); + vcpu = vm_vcpu_add(vm, vcpu_id); /* Setup guest registers */ - vcpu_regs_get(vm, vcpuid, ®s); + vcpu_regs_get(vm, vcpu_id, ®s); regs.gprs[15] = stack_vaddr + (DEFAULT_STACK_PGS * getpagesize()) - 160; - vcpu_regs_set(vm, vcpuid, ®s); + vcpu_regs_set(vm, vcpu_id, ®s); - vcpu_sregs_get(vm, vcpuid, &sregs); + vcpu_sregs_get(vm, vcpu_id, &sregs); sregs.crs[0] |= 0x00040000; /* Enable floating point regs */ sregs.crs[1] = vm->pgd | 0xf; /* Primary region table */ - vcpu_sregs_set(vm, vcpuid, &sregs); + vcpu_sregs_set(vm, vcpu_id, &sregs); - run = vcpu_state(vm, vcpuid); + run = vcpu_state(vm, vcpu_id); run->psw_mask = 0x0400000180000000ULL; /* DAT enabled + 64 bit mode */ run->psw_addr = (uintptr_t)guest_code; + + return vcpu; } void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 1bc406b6317d..bafa8ec54569 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -632,29 +632,33 @@ void vm_xsave_req_perm(int bit) bitmask); } -void vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) +struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, + void *guest_code) { struct kvm_mp_state mp_state; struct kvm_regs regs; vm_vaddr_t stack_vaddr; + struct kvm_vcpu *vcpu; + stack_vaddr = vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(), DEFAULT_GUEST_STACK_VADDR_MIN); - /* Create VCPU */ - vm_vcpu_add(vm, vcpuid); - vcpu_set_cpuid(vm, vcpuid, kvm_get_supported_cpuid()); - vcpu_setup(vm, vcpuid); + vcpu = vm_vcpu_add(vm, vcpu_id); + vcpu_set_cpuid(vm, vcpu_id, kvm_get_supported_cpuid()); + vcpu_setup(vm, vcpu_id); /* Setup guest general purpose registers */ - vcpu_regs_get(vm, vcpuid, ®s); + vcpu_regs_get(vm, vcpu_id, ®s); regs.rflags = regs.rflags | 0x2; regs.rsp = stack_vaddr + (DEFAULT_STACK_PGS * getpagesize()); regs.rip = (unsigned long) guest_code; - vcpu_regs_set(vm, vcpuid, ®s); + vcpu_regs_set(vm, vcpu_id, ®s); /* Setup the MP state */ mp_state.mp_state = 0; - vcpu_mp_state_set(vm, vcpuid, &mp_state); + vcpu_mp_state_set(vm, vcpu_id, &mp_state); + + return vcpu; } /* diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index d2c571f20521..2faa43336131 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -369,10 +369,8 @@ static void test_pmu_config_disable(void (*guest_code)(void)) vm_enable_cap(vm, KVM_CAP_PMU_CAPABILITY, KVM_PMU_CAP_DISABLE); - vm_vcpu_add_default(vm, 0, guest_code); + vcpu = vm_vcpu_add_default(vm, 0, guest_code); vm_init_descriptor_tables(vm); - - vcpu = vcpu_get(vm, 0); vcpu_init_descriptor_tables(vm, vcpu->id); TEST_ASSERT(!sanity_check_pmu(vcpu), diff --git a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c index b7cd5c47fc53..ea70ca2e63c3 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c @@ -54,8 +54,7 @@ static void *run_vcpu(void *_cpu_nr) /* The kernel is fine, but vm_vcpu_add_default() needs locking */ pthread_spin_lock(&create_lock); - vm_vcpu_add_default(vm, vcpu_id, guest_code); - vcpu = vcpu_get(vm, vcpu_id); + vcpu = vm_vcpu_add_default(vm, vcpu_id, guest_code); if (!first_cpu_done) { first_cpu_done = true; From f742d94ff4e5147e08b3bb7826f009eda7545124 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 09:56:24 -0800 Subject: [PATCH 0410/1436] KVM: selftests: Rename vm_vcpu_add* helpers to better show relationships Rename vm_vcpu_add() to __vm_vcpu_add(), and vm_vcpu_add_default() to vm_vcpu_add() to show the relationship between the newly minted vm_vcpu_add() and __vm_vcpu_add(). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/get-reg-list.c | 2 +- tools/testing/selftests/kvm/aarch64/psci_test.c | 4 ++-- .../testing/selftests/kvm/aarch64/vcpu_width_config.c | 8 ++++---- tools/testing/selftests/kvm/aarch64/vgic_init.c | 10 +++++----- tools/testing/selftests/kvm/dirty_log_test.c | 2 +- tools/testing/selftests/kvm/hardware_disable_test.c | 2 +- .../testing/selftests/kvm/include/aarch64/processor.h | 5 ++--- tools/testing/selftests/kvm/include/kvm_util_base.h | 7 +++---- tools/testing/selftests/kvm/kvm_binary_stats_test.c | 2 +- tools/testing/selftests/kvm/kvm_create_max_vcpus.c | 2 +- tools/testing/selftests/kvm/lib/aarch64/processor.c | 9 ++++----- tools/testing/selftests/kvm/lib/kvm_util.c | 6 +++--- tools/testing/selftests/kvm/lib/riscv/processor.c | 2 +- tools/testing/selftests/kvm/lib/s390x/processor.c | 2 +- tools/testing/selftests/kvm/lib/x86_64/processor.c | 2 +- tools/testing/selftests/kvm/set_memory_region_test.c | 2 +- tools/testing/selftests/kvm/steal_time.c | 2 +- .../selftests/kvm/x86_64/pmu_event_filter_test.c | 2 +- tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c | 4 ++-- tools/testing/selftests/kvm/x86_64/set_sregs_test.c | 2 +- tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c | 8 ++++---- tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c | 4 ++-- tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c | 2 +- 23 files changed, 44 insertions(+), 47 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index 5476bb465b78..fbb0c714211d 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -418,7 +418,7 @@ static void run_test(struct vcpu_config *c) vm = vm_create_barebones(); prepare_vcpu_init(c, &init); - vm_vcpu_add(vm, 0); + __vm_vcpu_add(vm, 0); aarch64_vcpu_setup(vm, 0, &init); finalize_vcpu(vm, 0, c); diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index fa4e6c3343d7..347cb5c130e2 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -84,8 +84,8 @@ static struct kvm_vm *setup_vm(void *guest_code) vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init); init.features[0] |= (1 << KVM_ARM_VCPU_PSCI_0_2); - aarch64_vcpu_add_default(vm, VCPU_ID_SOURCE, &init, guest_code); - aarch64_vcpu_add_default(vm, VCPU_ID_TARGET, &init, guest_code); + aarch64_vcpu_add(vm, VCPU_ID_SOURCE, &init, guest_code); + aarch64_vcpu_add(vm, VCPU_ID_TARGET, &init, guest_code); return vm; } diff --git a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c index 1757f44dd3e2..1dd856a58f5d 100644 --- a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c +++ b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c @@ -26,12 +26,12 @@ static int add_init_2vcpus(struct kvm_vcpu_init *init1, vm = vm_create_barebones(); - vm_vcpu_add(vm, 0); + __vm_vcpu_add(vm, 0); ret = __vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); if (ret) goto free_exit; - vm_vcpu_add(vm, 1); + __vm_vcpu_add(vm, 1); ret = __vcpu_ioctl(vm, 1, KVM_ARM_VCPU_INIT, init2); free_exit: @@ -51,8 +51,8 @@ static int add_2vcpus_init_2vcpus(struct kvm_vcpu_init *init1, vm = vm_create_barebones(); - vm_vcpu_add(vm, 0); - vm_vcpu_add(vm, 1); + __vm_vcpu_add(vm, 0); + __vm_vcpu_add(vm, 1); ret = __vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); if (ret) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index c5866c3f4516..451f65b199ad 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -331,7 +331,7 @@ static void test_vgic_then_vcpus(uint32_t gic_dev_type) /* Add the rest of the VCPUs */ for (i = 1; i < NR_VCPUS; ++i) - vm_vcpu_add_default(v.vm, i, guest_code); + vm_vcpu_add(v.vm, i, guest_code); ret = run_vcpu(v.vm, 3); TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run"); @@ -418,17 +418,17 @@ static void test_v3_typer_accesses(void) v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); - vm_vcpu_add_default(v.vm, 3, guest_code); + vm_vcpu_add(v.vm, 3, guest_code); v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EINVAL, "attempting to read GICR_TYPER of non created vcpu"); - vm_vcpu_add_default(v.vm, 1, guest_code); + vm_vcpu_add(v.vm, 1, guest_code); v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EBUSY, "read GICR_TYPER before GIC initialized"); - vm_vcpu_add_default(v.vm, 2, guest_code); + vm_vcpu_add(v.vm, 2, guest_code); kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); @@ -559,7 +559,7 @@ static void test_v3_redist_ipa_range_check_at_vcpu_run(void) /* Add the rest of the VCPUs */ for (i = 1; i < NR_VCPUS; ++i) - vm_vcpu_add_default(v.vm, i, guest_code); + vm_vcpu_add(v.vm, i, guest_code); kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 23e0c727e375..1a5c01c65044 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -676,7 +676,7 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, vm = __vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); log_mode_create_vm_done(vm); - vm_vcpu_add_default(vm, vcpuid, guest_code); + vm_vcpu_add(vm, vcpuid, guest_code); return vm; } diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c index 29f6ca51408f..be2763ecb6e7 100644 --- a/tools/testing/selftests/kvm/hardware_disable_test.c +++ b/tools/testing/selftests/kvm/hardware_disable_test.c @@ -108,7 +108,7 @@ static void run_test(uint32_t run) pr_debug("%s: [%d] start vcpus\n", __func__, run); for (i = 0; i < VCPU_NUM; ++i) { - vm_vcpu_add_default(vm, i, guest_code); + vm_vcpu_add(vm, i, guest_code); payloads[i].vm = vm; payloads[i].index = i; diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index 9dad391b4fec..f774609f7848 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -64,9 +64,8 @@ static inline void set_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint } void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init *init); -struct kvm_vcpu *aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpu_id, - struct kvm_vcpu_init *init, - void *guest_code); +struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, + struct kvm_vcpu_init *init, void *guest_code); struct ex_regs { u64 regs[31]; diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 622b09ec23dd..2c7a8a91ebe2 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -288,7 +288,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa); void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot); -struct kvm_vcpu *vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid); +struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid); vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min); vm_vaddr_t vm_vaddr_alloc_pages(struct kvm_vm *vm, int nr_pages); vm_vaddr_t vm_vaddr_alloc_page(struct kvm_vm *vm); @@ -659,9 +659,8 @@ static inline void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, void *guest_code); -static inline struct kvm_vcpu *vm_vcpu_add_default(struct kvm_vm *vm, - uint32_t vcpu_id, - void *guest_code) +static inline struct kvm_vcpu *vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, + void *guest_code) { return vm_arch_vcpu_add(vm, vcpu_id, guest_code); } diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index edeb08239036..407e9ea8e6f3 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -223,7 +223,7 @@ int main(int argc, char *argv[]) for (i = 0; i < max_vm; ++i) { vms[i] = vm_create_barebones(); for (j = 0; j < max_vcpu; ++j) - vm_vcpu_add(vms[i], j); + __vm_vcpu_add(vms[i], j); } /* Check stats read for every VM and VCPU */ diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c index acc92703f563..3ae0237e96b2 100644 --- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c +++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c @@ -32,7 +32,7 @@ void test_vcpu_creation(int first_vcpu_id, int num_vcpus) for (i = first_vcpu_id; i < first_vcpu_id + num_vcpus; i++) /* This asserts that the vCPU was created. */ - vm_vcpu_add(vm, i); + __vm_vcpu_add(vm, i); kvm_vm_free(vm); } diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 2b169b4ec29e..5b95fa2cce18 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -314,16 +314,15 @@ void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t in indent, "", pstate, pc); } -struct kvm_vcpu *aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpu_id, - struct kvm_vcpu_init *init, - void *guest_code) +struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, + struct kvm_vcpu_init *init, void *guest_code) { size_t stack_size = vm->page_size == 4096 ? DEFAULT_STACK_PGS * vm->page_size : vm->page_size; uint64_t stack_vaddr = vm_vaddr_alloc(vm, stack_size, DEFAULT_ARM64_GUEST_STACK_VADDR_MIN); - struct kvm_vcpu *vcpu = vm_vcpu_add(vm, vcpu_id); + struct kvm_vcpu *vcpu = __vm_vcpu_add(vm, vcpu_id); aarch64_vcpu_setup(vm, vcpu_id, init); @@ -336,7 +335,7 @@ struct kvm_vcpu *aarch64_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpu_id, struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, void *guest_code) { - return aarch64_vcpu_add_default(vm, vcpu_id, NULL, guest_code); + return aarch64_vcpu_add(vm, vcpu_id, NULL, guest_code); } void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 752731cf4292..c2a99f26e9ba 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -328,7 +328,7 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, for (i = 0; i < nr_vcpus; ++i) { uint32_t vcpuid = vcpuids ? vcpuids[i] : i; - vm_vcpu_add_default(vm, vcpuid, guest_code); + vm_vcpu_add(vm, vcpuid, guest_code); } return vm; @@ -397,7 +397,7 @@ struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm) { kvm_vm_restart(vm); - return vm_vcpu_add(vm, 0); + return __vm_vcpu_add(vm, 0); } /* @@ -1065,7 +1065,7 @@ static int vcpu_mmap_sz(void) * Adds a virtual CPU to the VM specified by vm with the ID given by vcpu_id. * No additional vCPU setup is done. Returns the vCPU. */ -struct kvm_vcpu *vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) +struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) { struct kvm_vcpu *vcpu; diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index 5946101144eb..ba5761843c76 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -287,7 +287,7 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, struct kvm_mp_state mps; struct kvm_vcpu *vcpu; - vcpu = vm_vcpu_add(vm, vcpu_id); + vcpu = __vm_vcpu_add(vm, vcpu_id); riscv_vcpu_mmu_setup(vm, vcpu_id); /* diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index cf759844b226..f8170e97eeb7 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -170,7 +170,7 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, stack_vaddr = vm_vaddr_alloc(vm, stack_size, DEFAULT_GUEST_STACK_VADDR_MIN); - vcpu = vm_vcpu_add(vm, vcpu_id); + vcpu = __vm_vcpu_add(vm, vcpu_id); /* Setup guest registers */ vcpu_regs_get(vm, vcpu_id, ®s); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index bafa8ec54569..f89d67101bf1 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -643,7 +643,7 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, stack_vaddr = vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(), DEFAULT_GUEST_STACK_VADDR_MIN); - vcpu = vm_vcpu_add(vm, vcpu_id); + vcpu = __vm_vcpu_add(vm, vcpu_id); vcpu_set_cpuid(vm, vcpu_id, kvm_get_supported_cpuid()); vcpu_setup(vm, vcpu_id); diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index 1274bbb0e30b..d832fc12984e 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -315,7 +315,7 @@ static void test_zero_memory_regions(void) pr_info("Testing KVM_RUN with zero added memory regions\n"); vm = vm_create_barebones(); - vcpu = vm_vcpu_add(vm, 0); + vcpu = __vm_vcpu_add(vm, 0); vm_ioctl(vm, KVM_SET_NR_MMU_PAGES, (void *)64ul); vcpu_run(vm, vcpu->id); diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index 75303fe8359d..fd3533582509 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -275,7 +275,7 @@ int main(int ac, char **av) /* Add the rest of the VCPUs */ for (i = 1; i < NR_VCPUS; ++i) - vm_vcpu_add_default(vm, i, guest_code); + vm_vcpu_add(vm, i, guest_code); steal_time_init(vm); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 2faa43336131..ffa9e267188c 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -369,7 +369,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) vm_enable_cap(vm, KVM_CAP_PMU_CAPABILITY, KVM_PMU_CAP_DISABLE); - vcpu = vm_vcpu_add_default(vm, 0, guest_code); + vcpu = vm_vcpu_add(vm, 0, guest_code); vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vm, vcpu->id); diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index 9ba3cd4e7f20..e63709894030 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -92,9 +92,9 @@ static struct kvm_vm *create_vm(void) static void add_x86_vcpu(struct kvm_vm *vm, uint32_t vcpuid, bool bsp_code) { if (bsp_code) - vm_vcpu_add_default(vm, vcpuid, guest_bsp_vcpu); + vm_vcpu_add(vm, vcpuid, guest_bsp_vcpu); else - vm_vcpu_add_default(vm, vcpuid, guest_not_bsp_vcpu); + vm_vcpu_add(vm, vcpuid, guest_not_bsp_vcpu); } static void run_vm_bsp(uint32_t bsp_vcpu) diff --git a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c index 8a5c1f76287c..2e67df3a95ba 100644 --- a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c +++ b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c @@ -95,7 +95,7 @@ int main(int argc, char *argv[]) * the vCPU model, i.e. without doing KVM_SET_CPUID2. */ vm = vm_create_barebones(); - vcpu = vm_vcpu_add(vm, 0); + vcpu = __vm_vcpu_add(vm, 0); vcpu_sregs_get(vm, vcpu->id, &sregs); diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index 245fd0755390..ec418b823273 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -56,7 +56,7 @@ static struct kvm_vm *sev_vm_create(bool es) vm = vm_create_barebones(); sev_ioctl(vm->fd, es ? KVM_SEV_ES_INIT : KVM_SEV_INIT, NULL); for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i) - vm_vcpu_add(vm, i); + __vm_vcpu_add(vm, i); if (es) start.policy |= SEV_POLICY_ES; sev_ioctl(vm->fd, KVM_SEV_LAUNCH_START, &start); @@ -75,7 +75,7 @@ static struct kvm_vm *aux_vm_create(bool with_vcpus) return vm; for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i) - vm_vcpu_add(vm, i); + __vm_vcpu_add(vm, i); return vm; } @@ -182,7 +182,7 @@ static void test_sev_migrate_parameters(void) sev_es_vm = sev_vm_create(/* es= */ true); sev_es_vm_no_vmsa = vm_create_barebones(); sev_ioctl(sev_es_vm_no_vmsa->fd, KVM_SEV_ES_INIT, NULL); - vm_vcpu_add(sev_es_vm_no_vmsa, 1); + __vm_vcpu_add(sev_es_vm_no_vmsa, 1); ret = __sev_migrate_from(sev_vm, sev_es_vm); TEST_ASSERT( @@ -278,7 +278,7 @@ static void test_sev_mirror(bool es) /* Check that we can complete creation of the mirror VM. */ for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i) - vm_vcpu_add(dst_vm, i); + __vm_vcpu_add(dst_vm, i); if (es) sev_ioctl(dst_vm->fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL); diff --git a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c index ea70ca2e63c3..2411215e7ae8 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c @@ -51,10 +51,10 @@ static void *run_vcpu(void *_cpu_nr) static bool first_cpu_done; struct kvm_vcpu *vcpu; - /* The kernel is fine, but vm_vcpu_add_default() needs locking */ + /* The kernel is fine, but vm_vcpu_add() needs locking */ pthread_spin_lock(&create_lock); - vcpu = vm_vcpu_add_default(vm, vcpu_id, guest_code); + vcpu = vm_vcpu_add(vm, vcpu_id, guest_code); if (!first_cpu_done) { first_cpu_done = true; diff --git a/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c b/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c index afbbc40df884..8b366652be31 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c @@ -425,7 +425,7 @@ int main(int argc, char *argv[]) virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); - vm_vcpu_add_default(vm, SENDER_VCPU_ID, sender_guest_code); + vm_vcpu_add(vm, SENDER_VCPU_ID, sender_guest_code); test_data_page_vaddr = vm_vaddr_alloc_page(vm); data = From 682b11a012b85c18310a6798fe2509c55bf6563e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 11:07:09 -0800 Subject: [PATCH 0411/1436] KVM: selftests: Convert set_boot_cpu_id away from global VCPU_IDs Rework set_boot_cpu_id to pass around 'struct kvm_vcpu' objects instead of relying on global VCPU_IDs. The test is still ugly, but that's unavoidable since the point of the test is to verify that KVM correctly assigns VCPU_ID==0 to be the BSP by default. This is literally one of two KVM selftests that legitimately needs to care about the exact vCPU IDs of the vCPUs it creates. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/set_boot_cpu_id.c | 92 ++++++++----------- 1 file changed, 39 insertions(+), 53 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index e63709894030..b11f12888fad 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -16,10 +16,6 @@ #include "processor.h" #include "apic.h" -#define N_VCPU 2 -#define VCPU_ID0 0 -#define VCPU_ID1 1 - static void guest_bsp_vcpu(void *arg) { GUEST_SYNC(1); @@ -38,31 +34,30 @@ static void guest_not_bsp_vcpu(void *arg) GUEST_DONE(); } -static void test_set_boot_busy(struct kvm_vm *vm) +static void test_set_bsp_busy(struct kvm_vcpu *vcpu, const char *msg) { - int res; + int r = __vm_ioctl(vcpu->vm, KVM_SET_BOOT_CPU_ID, + (void *)(unsigned long)vcpu->id); - res = __vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID0); - TEST_ASSERT(res == -1 && errno == EBUSY, - "KVM_SET_BOOT_CPU_ID set while running vm"); + TEST_ASSERT(r == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set %s", msg); } -static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid) +static void run_vcpu(struct kvm_vcpu *vcpu) { struct ucall uc; int stage; for (stage = 0; stage < 2; stage++) { - vcpu_run(vm, vcpuid); + vcpu_run(vcpu->vm, vcpu->id); - switch (get_ucall(vm, vcpuid, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_SYNC: TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage + 1, "Stage %d: Unexpected register values vmexit, got %lx", stage + 1, (ulong)uc.args[1]); - test_set_boot_busy(vm); + test_set_bsp_busy(vcpu, "while running vm"); break; case UCALL_DONE: TEST_ASSERT(stage == 1, @@ -75,65 +70,56 @@ static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid) uc.args[1], uc.args[2], uc.args[3]); default: TEST_ASSERT(false, "Unexpected exit: %s", - exit_reason_str(vcpu_state(vm, vcpuid)->exit_reason)); + exit_reason_str(vcpu->run->exit_reason)); } } } -static struct kvm_vm *create_vm(void) +static struct kvm_vm *create_vm(uint32_t nr_vcpus, uint32_t bsp_vcpu_id, + struct kvm_vcpu *vcpus[]) { - uint64_t vcpu_pages = (DEFAULT_STACK_PGS) * 2; - uint64_t extra_pg_pages = vcpu_pages / PTES_PER_MIN_PAGE * N_VCPU; + uint64_t vcpu_pages = (DEFAULT_STACK_PGS) * nr_vcpus; + uint64_t extra_pg_pages = vcpu_pages / PTES_PER_MIN_PAGE * nr_vcpus; uint64_t pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages; - - return vm_create(pages); -} - -static void add_x86_vcpu(struct kvm_vm *vm, uint32_t vcpuid, bool bsp_code) -{ - if (bsp_code) - vm_vcpu_add(vm, vcpuid, guest_bsp_vcpu); - else - vm_vcpu_add(vm, vcpuid, guest_not_bsp_vcpu); -} - -static void run_vm_bsp(uint32_t bsp_vcpu) -{ struct kvm_vm *vm; - bool is_bsp_vcpu1 = bsp_vcpu == VCPU_ID1; + uint32_t i; - vm = create_vm(); + vm = vm_create(pages); - if (is_bsp_vcpu1) - vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1); + vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *)(unsigned long)bsp_vcpu_id); - add_x86_vcpu(vm, VCPU_ID0, !is_bsp_vcpu1); - add_x86_vcpu(vm, VCPU_ID1, is_bsp_vcpu1); + for (i = 0; i < nr_vcpus; i++) + vcpus[i] = vm_vcpu_add(vm, i, i == bsp_vcpu_id ? guest_bsp_vcpu : + guest_not_bsp_vcpu); + return vm; +} - run_vcpu(vm, VCPU_ID0); - run_vcpu(vm, VCPU_ID1); +static void run_vm_bsp(uint32_t bsp_vcpu_id) +{ + struct kvm_vcpu *vcpus[2]; + struct kvm_vm *vm; + + vm = create_vm(ARRAY_SIZE(vcpus), bsp_vcpu_id, vcpus); + + run_vcpu(vcpus[0]); + run_vcpu(vcpus[1]); kvm_vm_free(vm); } static void check_set_bsp_busy(void) { + struct kvm_vcpu *vcpus[2]; struct kvm_vm *vm; - int res; - vm = create_vm(); + vm = create_vm(ARRAY_SIZE(vcpus), 0, vcpus); - add_x86_vcpu(vm, VCPU_ID0, true); - add_x86_vcpu(vm, VCPU_ID1, false); + test_set_bsp_busy(vcpus[1], "after adding vcpu"); - res = __vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1); - TEST_ASSERT(res == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set after adding vcpu"); + run_vcpu(vcpus[0]); + run_vcpu(vcpus[1]); - run_vcpu(vm, VCPU_ID0); - run_vcpu(vm, VCPU_ID1); - - res = __vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *) VCPU_ID1); - TEST_ASSERT(res == -1 && errno == EBUSY, "KVM_SET_BOOT_CPU_ID set to a terminated vcpu"); + test_set_bsp_busy(vcpus[1], "to a terminated vcpu"); kvm_vm_free(vm); } @@ -145,9 +131,9 @@ int main(int argc, char *argv[]) return 0; } - run_vm_bsp(VCPU_ID0); - run_vm_bsp(VCPU_ID1); - run_vm_bsp(VCPU_ID0); + run_vm_bsp(0); + run_vm_bsp(1); + run_vm_bsp(0); check_set_bsp_busy(); } From b093da659f3d0ff291fcd6373090ba17cf183253 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 11:11:50 -0800 Subject: [PATCH 0412/1436] KVM: selftests: Convert psci_test away from VCPU_ID Pass around 'struct kvm_vcpu' objects in psci_test instead of relying on global VCPU_IDs. Ideally, the test wouldn't have to manually create vCPUs and thus care about vCPU IDs, but it's not the end of the world and avoiding that behavior isn't guaranteed to be a net positive (an attempt at macro shenanigans did not go very well). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/psci_test.c | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index 347cb5c130e2..d9695a939cc9 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -17,9 +17,6 @@ #include "processor.h" #include "test_util.h" -#define VCPU_ID_SOURCE 0 -#define VCPU_ID_TARGET 1 - #define CPU_ON_ENTRY_ADDR 0xfeedf00dul #define CPU_ON_CONTEXT_ID 0xdeadc0deul @@ -64,16 +61,17 @@ static uint64_t psci_features(uint32_t func_id) return res.a0; } -static void vcpu_power_off(struct kvm_vm *vm, uint32_t vcpuid) +static void vcpu_power_off(struct kvm_vcpu *vcpu) { struct kvm_mp_state mp_state = { .mp_state = KVM_MP_STATE_STOPPED, }; - vcpu_mp_state_set(vm, vcpuid, &mp_state); + vcpu_mp_state_set(vcpu->vm, vcpu->id, &mp_state); } -static struct kvm_vm *setup_vm(void *guest_code) +static struct kvm_vm *setup_vm(void *guest_code, struct kvm_vcpu **source, + struct kvm_vcpu **target) { struct kvm_vcpu_init init; struct kvm_vm *vm; @@ -84,28 +82,28 @@ static struct kvm_vm *setup_vm(void *guest_code) vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init); init.features[0] |= (1 << KVM_ARM_VCPU_PSCI_0_2); - aarch64_vcpu_add(vm, VCPU_ID_SOURCE, &init, guest_code); - aarch64_vcpu_add(vm, VCPU_ID_TARGET, &init, guest_code); + *source = aarch64_vcpu_add(vm, 0, &init, guest_code); + *target = aarch64_vcpu_add(vm, 1, &init, guest_code); return vm; } -static void enter_guest(struct kvm_vm *vm, uint32_t vcpuid) +static void enter_guest(struct kvm_vcpu *vcpu) { struct ucall uc; - vcpu_run(vm, vcpuid); - if (get_ucall(vm, vcpuid, &uc) == UCALL_ABORT) + vcpu_run(vcpu->vm, vcpu->id); + if (get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_ABORT) TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); } -static void assert_vcpu_reset(struct kvm_vm *vm, uint32_t vcpuid) +static void assert_vcpu_reset(struct kvm_vcpu *vcpu) { uint64_t obs_pc, obs_x0; - get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), &obs_pc); - get_reg(vm, vcpuid, ARM64_CORE_REG(regs.regs[0]), &obs_x0); + get_reg(vcpu->vm, vcpu->id, ARM64_CORE_REG(regs.pc), &obs_pc); + get_reg(vcpu->vm, vcpu->id, ARM64_CORE_REG(regs.regs[0]), &obs_x0); TEST_ASSERT(obs_pc == CPU_ON_ENTRY_ADDR, "unexpected target cpu pc: %lx (expected: %lx)", @@ -133,25 +131,26 @@ static void guest_test_cpu_on(uint64_t target_cpu) static void host_test_cpu_on(void) { + struct kvm_vcpu *source, *target; uint64_t target_mpidr; struct kvm_vm *vm; struct ucall uc; - vm = setup_vm(guest_test_cpu_on); + vm = setup_vm(guest_test_cpu_on, &source, &target); /* * make sure the target is already off when executing the test. */ - vcpu_power_off(vm, VCPU_ID_TARGET); + vcpu_power_off(target); - get_reg(vm, VCPU_ID_TARGET, KVM_ARM64_SYS_REG(SYS_MPIDR_EL1), &target_mpidr); - vcpu_args_set(vm, VCPU_ID_SOURCE, 1, target_mpidr & MPIDR_HWID_BITMASK); - enter_guest(vm, VCPU_ID_SOURCE); + get_reg(vm, target->id, KVM_ARM64_SYS_REG(SYS_MPIDR_EL1), &target_mpidr); + vcpu_args_set(vm, source->id, 1, target_mpidr & MPIDR_HWID_BITMASK); + enter_guest(source); - if (get_ucall(vm, VCPU_ID_SOURCE, &uc) != UCALL_DONE) + if (get_ucall(vm, source->id, &uc) != UCALL_DONE) TEST_FAIL("Unhandled ucall: %lu", uc.cmd); - assert_vcpu_reset(vm, VCPU_ID_TARGET); + assert_vcpu_reset(target); kvm_vm_free(vm); } @@ -169,16 +168,17 @@ static void guest_test_system_suspend(void) static void host_test_system_suspend(void) { + struct kvm_vcpu *source, *target; struct kvm_run *run; struct kvm_vm *vm; - vm = setup_vm(guest_test_system_suspend); + vm = setup_vm(guest_test_system_suspend, &source, &target); vm_enable_cap(vm, KVM_CAP_ARM_SYSTEM_SUSPEND, 0); - vcpu_power_off(vm, VCPU_ID_TARGET); - run = vcpu_state(vm, VCPU_ID_SOURCE); + vcpu_power_off(target); + run = source->run; - enter_guest(vm, VCPU_ID_SOURCE); + enter_guest(source); TEST_ASSERT(run->exit_reason == KVM_EXIT_SYSTEM_EVENT, "Unhandled exit reason: %u (%s)", From 0750388ca7110d332547f3669715442eac6a1254 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 11:15:08 -0800 Subject: [PATCH 0413/1436] KVM: selftests: Convert hardware_disable_test to pass around vCPU objects Pass around 'struct kvm_vcpu' objects in hardware_disable_test instead of the VM+vcpu_id (called "index" by the test). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/hardware_disable_test.c | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c index be2763ecb6e7..59bb43345a3e 100644 --- a/tools/testing/selftests/kvm/hardware_disable_test.c +++ b/tools/testing/selftests/kvm/hardware_disable_test.c @@ -27,12 +27,6 @@ sem_t *sem; -/* Arguments for the pthreads */ -struct payload { - struct kvm_vm *vm; - uint32_t index; -}; - static void guest_code(void) { for (;;) @@ -42,14 +36,14 @@ static void guest_code(void) static void *run_vcpu(void *arg) { - struct payload *payload = (struct payload *)arg; - struct kvm_run *state = vcpu_state(payload->vm, payload->index); + struct kvm_vcpu *vcpu = arg; + struct kvm_run *run = vcpu->run; - vcpu_run(payload->vm, payload->index); + vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(false, "%s: exited with reason %d: %s\n", - __func__, state->exit_reason, - exit_reason_str(state->exit_reason)); + __func__, run->exit_reason, + exit_reason_str(run->exit_reason)); pthread_exit(NULL); } @@ -92,11 +86,11 @@ static inline void check_join(pthread_t thread, void **retval) static void run_test(uint32_t run) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; cpu_set_t cpu_set; pthread_t threads[VCPU_NUM]; pthread_t throw_away; - struct payload payloads[VCPU_NUM]; void *b; uint32_t i, j; @@ -108,12 +102,9 @@ static void run_test(uint32_t run) pr_debug("%s: [%d] start vcpus\n", __func__, run); for (i = 0; i < VCPU_NUM; ++i) { - vm_vcpu_add(vm, i, guest_code); - payloads[i].vm = vm; - payloads[i].index = i; + vcpu = vm_vcpu_add(vm, i, guest_code); - check_create_thread(&threads[i], NULL, run_vcpu, - (void *)&payloads[i]); + check_create_thread(&threads[i], NULL, run_vcpu, vcpu); check_set_affinity(threads[i], &cpu_set); for (j = 0; j < SLEEPING_THREAD_NUM; ++j) { From 0ffc70eab775b52432a76f26aada24c5b78ef0eb Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 11:19:18 -0800 Subject: [PATCH 0414/1436] KVM: selftests: Add VM creation helper that "returns" vCPUs Add a VM creator that "returns" the created vCPUs by filling the provided array. This will allow converting multi-vCPU tests away from hardcoded vCPU IDs. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 17 +++++++++++++---- .../testing/selftests/kvm/kvm_page_table_test.c | 4 ++-- tools/testing/selftests/kvm/lib/kvm_util.c | 17 ++++++++++------- .../testing/selftests/kvm/lib/perf_test_util.c | 5 +++-- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 2c7a8a91ebe2..c0b2158a53d5 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -563,10 +563,19 @@ struct kvm_vm *vm_create_default_with_vcpus(uint32_t nr_vcpus, uint64_t extra_me uint32_t vcpuids[]); /* Like vm_create_default_with_vcpus, but accepts mode and slot0 memory as a parameter */ -struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, - uint64_t slot0_mem_pages, uint64_t extra_mem_pages, - uint32_t num_percpu_pages, void *guest_code, - uint32_t vcpuids[]); +struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, + uint64_t slot0_mem_pages, uint64_t extra_mem_pages, + uint32_t num_percpu_pages, void *guest_code, + uint32_t vcpuids[], struct kvm_vcpu *vcpus[]); + +static inline struct kvm_vm *vm_create_with_vcpus(uint32_t nr_vcpus, + void *guest_code, + struct kvm_vcpu *vcpus[]) +{ + return __vm_create_with_vcpus(VM_MODE_DEFAULT, nr_vcpus, + DEFAULT_GUEST_PHY_PAGES, 0, 0, + guest_code, NULL, vcpus); +} /* * Create a VM with a single vCPU with reasonable defaults and @extra_mem_pages diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c index 2c4a7563a4f8..e91bc7f1400d 100644 --- a/tools/testing/selftests/kvm/kvm_page_table_test.c +++ b/tools/testing/selftests/kvm/kvm_page_table_test.c @@ -268,8 +268,8 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg) /* Create a VM with enough guest pages */ guest_num_pages = test_mem_size / guest_page_size; - vm = vm_create_with_vcpus(mode, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, - guest_num_pages, 0, guest_code, NULL); + vm = __vm_create_with_vcpus(mode, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, + guest_num_pages, 0, guest_code, NULL, NULL); /* Align down GPA of the testing memslot */ if (!p->phys_offset) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index c2a99f26e9ba..3015d490a8f6 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -296,12 +296,13 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t nr_pages) * extra_mem_pages is only used to calculate the maximum page table size, * no real memory allocation for non-slot0 memory in this function. */ -struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, - uint64_t slot0_mem_pages, uint64_t extra_mem_pages, - uint32_t num_percpu_pages, void *guest_code, - uint32_t vcpuids[]) +struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, + uint64_t slot0_mem_pages, uint64_t extra_mem_pages, + uint32_t num_percpu_pages, void *guest_code, + uint32_t vcpuids[], struct kvm_vcpu *vcpus[]) { uint64_t vcpu_pages, extra_pg_pages, pages; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; int i; @@ -328,7 +329,9 @@ struct kvm_vm *vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, for (i = 0; i < nr_vcpus; ++i) { uint32_t vcpuid = vcpuids ? vcpuids[i] : i; - vm_vcpu_add(vm, vcpuid, guest_code); + vcpu = vm_vcpu_add(vm, vcpuid, guest_code); + if (vcpus) + vcpus[i] = vcpu; } return vm; @@ -338,8 +341,8 @@ struct kvm_vm *vm_create_default_with_vcpus(uint32_t nr_vcpus, uint64_t extra_me uint32_t num_percpu_pages, void *guest_code, uint32_t vcpuids[]) { - return vm_create_with_vcpus(VM_MODE_DEFAULT, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, - extra_mem_pages, num_percpu_pages, guest_code, vcpuids); + return __vm_create_with_vcpus(VM_MODE_DEFAULT, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, + extra_mem_pages, num_percpu_pages, guest_code, vcpuids, NULL); } struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, diff --git a/tools/testing/selftests/kvm/lib/perf_test_util.c b/tools/testing/selftests/kvm/lib/perf_test_util.c index f989ff91f022..d3ff05f00653 100644 --- a/tools/testing/selftests/kvm/lib/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/perf_test_util.c @@ -147,8 +147,9 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, * The memory is also added to memslot 0, but that's a benign side * effect as KVM allows aliasing HVAs in meslots. */ - vm = vm_create_with_vcpus(mode, vcpus, slot0_pages, guest_num_pages, 0, - perf_test_guest_code, NULL); + vm = __vm_create_with_vcpus(mode, vcpus, DEFAULT_GUEST_PHY_PAGES, + slot0_pages + guest_num_pages, 0, + perf_test_guest_code, NULL, NULL); pta->vm = vm; From 9980160482213a9334e864774f789336960568a3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 11:24:01 -0800 Subject: [PATCH 0415/1436] KVM: selftests: Convert steal_time away from VCPU_ID Convert steal_time to use vm_create_with_vcpus() and pass around a 'struct kvm_vcpu' object instead of requiring that the index into the array of vCPUs for a given vCPU is also the ID of the vCPU. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/steal_time.c | 145 ++++++++++++----------- 1 file changed, 73 insertions(+), 72 deletions(-) diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index fd3533582509..7a6645464925 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -58,36 +58,34 @@ static void guest_code(int cpu) GUEST_DONE(); } -static void steal_time_init(struct kvm_vm *vm) +static bool is_steal_time_supported(struct kvm_vcpu *vcpu) { - int i; + struct kvm_cpuid_entry2 *cpuid = kvm_get_supported_cpuid_entry(KVM_CPUID_FEATURES); - if (!(kvm_get_supported_cpuid_entry(KVM_CPUID_FEATURES)->eax & - KVM_FEATURE_STEAL_TIME)) { - print_skip("steal-time not supported"); - exit(KSFT_SKIP); - } - - for (i = 0; i < NR_VCPUS; ++i) { - int ret; - - /* ST_GPA_BASE is identity mapped */ - st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE); - sync_global_to_guest(vm, st_gva[i]); - - ret = _vcpu_set_msr(vm, i, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_STEAL_RESERVED_MASK); - TEST_ASSERT(ret == 0, "Bad GPA didn't fail"); - - vcpu_set_msr(vm, i, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_MSR_ENABLED); - } + return cpuid && (cpuid->eax & KVM_FEATURE_STEAL_TIME); } -static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpuid) +static void steal_time_init(struct kvm_vcpu *vcpu, uint32_t i) { - struct kvm_steal_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpuid]); + int ret; + + /* ST_GPA_BASE is identity mapped */ + st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE); + sync_global_to_guest(vcpu->vm, st_gva[i]); + + ret = _vcpu_set_msr(vcpu->vm, vcpu->id, MSR_KVM_STEAL_TIME, + (ulong)st_gva[i] | KVM_STEAL_RESERVED_MASK); + TEST_ASSERT(ret == 0, "Bad GPA didn't fail"); + + vcpu_set_msr(vcpu->vm, vcpu->id, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_MSR_ENABLED); +} + +static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx) +{ + struct kvm_steal_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); int i; - pr_info("VCPU%d:\n", vcpuid); + pr_info("VCPU%d:\n", vcpu_idx); pr_info(" steal: %lld\n", st->steal); pr_info(" version: %d\n", st->version); pr_info(" flags: %d\n", st->flags); @@ -158,49 +156,50 @@ static void guest_code(int cpu) GUEST_DONE(); } -static void steal_time_init(struct kvm_vm *vm) +static bool is_steal_time_supported(struct kvm_vcpu *vcpu) { struct kvm_device_attr dev = { .group = KVM_ARM_VCPU_PVTIME_CTRL, .attr = KVM_ARM_VCPU_PVTIME_IPA, }; - int i, ret; - ret = __vcpu_ioctl(vm, 0, KVM_HAS_DEVICE_ATTR, &dev); - if (ret != 0 && errno == ENXIO) { - print_skip("steal-time not supported"); - exit(KSFT_SKIP); - } - - for (i = 0; i < NR_VCPUS; ++i) { - uint64_t st_ipa; - - vcpu_ioctl(vm, i, KVM_HAS_DEVICE_ATTR, &dev); - - dev.addr = (uint64_t)&st_ipa; - - /* ST_GPA_BASE is identity mapped */ - st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE); - sync_global_to_guest(vm, st_gva[i]); - - st_ipa = (ulong)st_gva[i] | 1; - ret = __vcpu_ioctl(vm, i, KVM_SET_DEVICE_ATTR, &dev); - TEST_ASSERT(ret == -1 && errno == EINVAL, "Bad IPA didn't report EINVAL"); - - st_ipa = (ulong)st_gva[i]; - vcpu_ioctl(vm, i, KVM_SET_DEVICE_ATTR, &dev); - - ret = __vcpu_ioctl(vm, i, KVM_SET_DEVICE_ATTR, &dev); - TEST_ASSERT(ret == -1 && errno == EEXIST, "Set IPA twice without EEXIST"); - - } + return !__vcpu_ioctl(vcpu->vm, vcpu->id, KVM_HAS_DEVICE_ATTR, &dev); } -static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpuid) +static void steal_time_init(struct kvm_vcpu *vcpu, uint32_t i) { - struct st_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpuid]); + struct kvm_vm *vm = vcpu->vm; + uint64_t st_ipa; + int ret; - pr_info("VCPU%d:\n", vcpuid); + struct kvm_device_attr dev = { + .group = KVM_ARM_VCPU_PVTIME_CTRL, + .attr = KVM_ARM_VCPU_PVTIME_IPA, + .addr = (uint64_t)&st_ipa, + }; + + vcpu_ioctl(vm, vcpu->id, KVM_HAS_DEVICE_ATTR, &dev); + + /* ST_GPA_BASE is identity mapped */ + st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE); + sync_global_to_guest(vm, st_gva[i]); + + st_ipa = (ulong)st_gva[i] | 1; + ret = __vcpu_ioctl(vm, vcpu->id, KVM_SET_DEVICE_ATTR, &dev); + TEST_ASSERT(ret == -1 && errno == EINVAL, "Bad IPA didn't report EINVAL"); + + st_ipa = (ulong)st_gva[i]; + vcpu_ioctl(vm, vcpu->id, KVM_SET_DEVICE_ATTR, &dev); + + ret = __vcpu_ioctl(vm, vcpu->id, KVM_SET_DEVICE_ATTR, &dev); + TEST_ASSERT(ret == -1 && errno == EEXIST, "Set IPA twice without EEXIST"); +} + +static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx) +{ + struct st_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]); + + pr_info("VCPU%d:\n", vcpu_idx); pr_info(" rev: %d\n", st->rev); pr_info(" attr: %d\n", st->attr); pr_info(" st_time: %ld\n", st->st_time); @@ -224,15 +223,13 @@ static void *do_steal_time(void *arg) return NULL; } -static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid) +static void run_vcpu(struct kvm_vcpu *vcpu) { struct ucall uc; - vcpu_args_set(vm, vcpuid, 1, vcpuid); + vcpu_run(vcpu->vm, vcpu->id); - vcpu_ioctl(vm, vcpuid, KVM_RUN, NULL); - - switch (get_ucall(vm, vcpuid, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_SYNC: case UCALL_DONE: break; @@ -241,12 +238,13 @@ static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid) __FILE__, uc.args[1]); default: TEST_ASSERT(false, "Unexpected exit: %s", - exit_reason_str(vcpu_state(vm, vcpuid)->exit_reason)); + exit_reason_str(vcpu->run->exit_reason)); } } int main(int ac, char **av) { + struct kvm_vcpu *vcpus[NR_VCPUS]; struct kvm_vm *vm; pthread_attr_t attr; pthread_t thread; @@ -266,26 +264,29 @@ int main(int ac, char **av) pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset); - /* Create a one VCPU guest and an identity mapped memslot for the steal time structure */ - vm = vm_create_default(0, 0, guest_code); + /* Create a VM and an identity mapped memslot for the steal time structure */ + vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus); gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE * NR_VCPUS); vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0); virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, gpages); ucall_init(vm, NULL); - /* Add the rest of the VCPUs */ - for (i = 1; i < NR_VCPUS; ++i) - vm_vcpu_add(vm, i, guest_code); - - steal_time_init(vm); + if (!is_steal_time_supported(vcpus[0])) { + print_skip("steal-time not supported"); + exit(KSFT_SKIP); + } /* Run test on each VCPU */ for (i = 0; i < NR_VCPUS; ++i) { + steal_time_init(vcpus[i], i); + + vcpu_args_set(vm, vcpus[i]->id, 1, i); + /* First VCPU run initializes steal-time */ - run_vcpu(vm, i); + run_vcpu(vcpus[i]); /* Second VCPU run, expect guest stolen time to be <= run_delay */ - run_vcpu(vm, i); + run_vcpu(vcpus[i]); sync_global_from_guest(vm, guest_stolen_time[i]); stolen_time = guest_stolen_time[i]; run_delay = get_run_delay(); @@ -306,7 +307,7 @@ int main(int ac, char **av) MIN_RUN_DELAY_NS, run_delay); /* Run VCPU again to confirm stolen time is consistent with run_delay */ - run_vcpu(vm, i); + run_vcpu(vcpus[i]); sync_global_from_guest(vm, guest_stolen_time[i]); stolen_time = guest_stolen_time[i] - stolen_time; TEST_ASSERT(stolen_time >= run_delay, From 7a5e4ae3db643e4b14453c5f67e4670a83284644 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 11:40:33 -0800 Subject: [PATCH 0416/1436] KVM: selftests: Convert arch_timer away from VCPU_ID Convert arch_timer to use vm_create_with_vcpus() and pass around a 'struct kvm_vcpu' object instead of requiring that the index into the array of vCPUs for a given vCPU is also the ID of the vCPU Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/arch_timer.c | 62 ++++++++----------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index f04ca07c7f14..a873d9adc558 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -76,13 +76,8 @@ struct test_vcpu_shared_data { uint64_t xcnt; }; -struct test_vcpu { - uint32_t vcpuid; - pthread_t pt_vcpu_run; - struct kvm_vm *vm; -}; - -static struct test_vcpu test_vcpu[KVM_MAX_VCPUS]; +static struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; +static pthread_t pt_vcpu_run[KVM_MAX_VCPUS]; static struct test_vcpu_shared_data vcpu_shared_data[KVM_MAX_VCPUS]; static int vtimer_irq, ptimer_irq; @@ -217,20 +212,20 @@ static void guest_code(void) static void *test_vcpu_run(void *arg) { + unsigned int vcpu_idx = (unsigned long)arg; struct ucall uc; - struct test_vcpu *vcpu = arg; + struct kvm_vcpu *vcpu = vcpus[vcpu_idx]; struct kvm_vm *vm = vcpu->vm; - uint32_t vcpuid = vcpu->vcpuid; - struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[vcpuid]; + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[vcpu_idx]; - vcpu_run(vm, vcpuid); + vcpu_run(vm, vcpu->id); /* Currently, any exit from guest is an indication of completion */ pthread_mutex_lock(&vcpu_done_map_lock); - set_bit(vcpuid, vcpu_done_map); + set_bit(vcpu_idx, vcpu_done_map); pthread_mutex_unlock(&vcpu_done_map_lock); - switch (get_ucall(vm, vcpuid, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_SYNC: case UCALL_DONE: break; @@ -238,7 +233,7 @@ static void *test_vcpu_run(void *arg) sync_global_from_guest(vm, *shared_data); TEST_FAIL("%s at %s:%ld\n\tvalues: %lu, %lu; %lu, vcpu: %u; stage: %u; iter: %u", (const char *)uc.args[0], __FILE__, uc.args[1], - uc.args[2], uc.args[3], uc.args[4], vcpuid, + uc.args[2], uc.args[3], uc.args[4], vcpu_idx, shared_data->guest_stage, shared_data->nr_iter); break; default: @@ -265,7 +260,7 @@ static uint32_t test_get_pcpu(void) return pcpu; } -static int test_migrate_vcpu(struct test_vcpu *vcpu) +static int test_migrate_vcpu(unsigned int vcpu_idx) { int ret; cpu_set_t cpuset; @@ -274,15 +269,15 @@ static int test_migrate_vcpu(struct test_vcpu *vcpu) CPU_ZERO(&cpuset); CPU_SET(new_pcpu, &cpuset); - pr_debug("Migrating vCPU: %u to pCPU: %u\n", vcpu->vcpuid, new_pcpu); + pr_debug("Migrating vCPU: %u to pCPU: %u\n", vcpu_idx, new_pcpu); - ret = pthread_setaffinity_np(vcpu->pt_vcpu_run, - sizeof(cpuset), &cpuset); + ret = pthread_setaffinity_np(pt_vcpu_run[vcpu_idx], + sizeof(cpuset), &cpuset); /* Allow the error where the vCPU thread is already finished */ TEST_ASSERT(ret == 0 || ret == ESRCH, - "Failed to migrate the vCPU:%u to pCPU: %u; ret: %d\n", - vcpu->vcpuid, new_pcpu, ret); + "Failed to migrate the vCPU:%u to pCPU: %u; ret: %d\n", + vcpu_idx, new_pcpu, ret); return ret; } @@ -305,7 +300,7 @@ static void *test_vcpu_migration(void *arg) continue; } - test_migrate_vcpu(&test_vcpu[i]); + test_migrate_vcpu(i); } } while (test_args.nr_vcpus != n_done); @@ -314,16 +309,17 @@ static void *test_vcpu_migration(void *arg) static void test_run(struct kvm_vm *vm) { - int i, ret; pthread_t pt_vcpu_migration; + unsigned int i; + int ret; pthread_mutex_init(&vcpu_done_map_lock, NULL); vcpu_done_map = bitmap_zalloc(test_args.nr_vcpus); TEST_ASSERT(vcpu_done_map, "Failed to allocate vcpu done bitmap\n"); - for (i = 0; i < test_args.nr_vcpus; i++) { - ret = pthread_create(&test_vcpu[i].pt_vcpu_run, NULL, - test_vcpu_run, &test_vcpu[i]); + for (i = 0; i < (unsigned long)test_args.nr_vcpus; i++) { + ret = pthread_create(&pt_vcpu_run[i], NULL, test_vcpu_run, + (void *)(unsigned long)i); TEST_ASSERT(!ret, "Failed to create vCPU-%d pthread\n", i); } @@ -338,7 +334,7 @@ static void test_run(struct kvm_vm *vm) for (i = 0; i < test_args.nr_vcpus; i++) - pthread_join(test_vcpu[i].pt_vcpu_run, NULL); + pthread_join(pt_vcpu_run[i], NULL); if (test_args.migration_freq_ms) pthread_join(pt_vcpu_migration, NULL); @@ -349,9 +345,9 @@ static void test_run(struct kvm_vm *vm) static void test_init_timer_irq(struct kvm_vm *vm) { /* Timer initid should be same for all the vCPUs, so query only vCPU-0 */ - vcpu_device_attr_get(vm, 0, KVM_ARM_VCPU_TIMER_CTRL, + vcpu_device_attr_get(vm, vcpus[0]->id, KVM_ARM_VCPU_TIMER_CTRL, KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq); - vcpu_device_attr_get(vm, 0, KVM_ARM_VCPU_TIMER_CTRL, + vcpu_device_attr_get(vm, vcpus[0]->id, KVM_ARM_VCPU_TIMER_CTRL, KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq); sync_global_to_guest(vm, ptimer_irq); @@ -368,17 +364,13 @@ static struct kvm_vm *test_vm_create(void) unsigned int i; int nr_vcpus = test_args.nr_vcpus; - vm = vm_create_default_with_vcpus(nr_vcpus, 0, 0, guest_code, NULL); + vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus); vm_init_descriptor_tables(vm); vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT, guest_irq_handler); - for (i = 0; i < nr_vcpus; i++) { - vcpu_init_descriptor_tables(vm, i); - - test_vcpu[i].vcpuid = i; - test_vcpu[i].vm = vm; - } + for (i = 0; i < nr_vcpus; i++) + vcpu_init_descriptor_tables(vm, vcpus[i]->id); ucall_init(vm, NULL); test_init_timer_irq(vm); From 08ce0888c1f440f6a19133de124feb7280171754 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 1 Jun 2022 13:41:09 -0700 Subject: [PATCH 0417/1436] KVM: selftests: Convert svm_nested_soft_inject_test away from VCPU_ID Convert svm_nested_soft_inject_test to use vm_create_with_one_vcpu() and pull the vCPU's ID from 'struct kvm_vcpu'. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/x86_64/svm_nested_soft_inject_test.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c index f834b9a1a7fa..a337ab2ec101 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -18,7 +18,6 @@ #include "svm_util.h" #include "test_util.h" -#define VCPU_ID 0 #define INT_NR 0x20 #define X86_FEATURE_NRIPS BIT(3) @@ -135,6 +134,7 @@ static void l1_guest_code(struct svm_test_data *svm, uint64_t is_nmi, uint64_t i static void run_test(bool is_nmi) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; vm_vaddr_t svm_gva; vm_vaddr_t idt_alt_vm; @@ -142,10 +142,10 @@ static void run_test(bool is_nmi) pr_info("Running %s test\n", is_nmi ? "NMI" : "soft int"); - vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, VCPU_ID); + vcpu_init_descriptor_tables(vm, vcpu->id); vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler); vm_install_exception_handler(vm, BP_VECTOR, guest_bp_handler); @@ -163,23 +163,23 @@ static void run_test(bool is_nmi) } else { idt_alt_vm = 0; } - vcpu_args_set(vm, VCPU_ID, 3, svm_gva, (uint64_t)is_nmi, (uint64_t)idt_alt_vm); + vcpu_args_set(vm, vcpu->id, 3, svm_gva, (uint64_t)is_nmi, (uint64_t)idt_alt_vm); memset(&debug, 0, sizeof(debug)); - vcpu_guest_debug_set(vm, VCPU_ID, &debug); + vcpu_guest_debug_set(vm, vcpu->id, &debug); - struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct kvm_run *run = vcpu->run; struct ucall uc; alarm(2); - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); alarm(0); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld, vals = 0x%lx 0x%lx 0x%lx", (const char *)uc.args[0], __FILE__, uc.args[1], uc.args[2], uc.args[3], uc.args[4]); From f3443bed2989a27a4d5c69c01e80d873139b4178 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 1 Jun 2022 13:43:40 -0700 Subject: [PATCH 0418/1436] KVM: selftests: Convert triple_fault_event_test away from VCPU_ID Convert triple_fault_event_test to use vm_create_with_one_vcpu() and pull the vCPU's ID from 'struct kvm_vcpu'. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../kvm/x86_64/triple_fault_event_test.c | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c index 68e0f1c5ec5a..2b0f19ddbc8b 100644 --- a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c +++ b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c @@ -9,7 +9,6 @@ #include "kselftest.h" -#define VCPU_ID 0 #define ARBITRARY_IO_PORT 0x2000 /* The virtual machine object. */ @@ -41,6 +40,7 @@ void l1_guest_code(struct vmx_pages *vmx) int main(void) { + struct kvm_vcpu *vcpu; struct kvm_run *run; struct kvm_vcpu_events events; vm_vaddr_t vmx_pages_gva; @@ -56,13 +56,13 @@ int main(void) exit(KSFT_SKIP); } - vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vm_enable_cap(vm, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 1); - run = vcpu_state(vm, VCPU_ID); + run = vcpu->run; vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, VCPU_ID, 1, vmx_pages_gva); - vcpu_run(vm, VCPU_ID); + vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); + vcpu_run(vm, vcpu->id); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Expected KVM_EXIT_IO, got: %u (%s)\n", @@ -70,21 +70,21 @@ int main(void) TEST_ASSERT(run->io.port == ARBITRARY_IO_PORT, "Expected IN from port %d from L2, got port %d", ARBITRARY_IO_PORT, run->io.port); - vcpu_events_get(vm, VCPU_ID, &events); + vcpu_events_get(vm, vcpu->id, &events); events.flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT; events.triple_fault.pending = true; - vcpu_events_set(vm, VCPU_ID, &events); + vcpu_events_set(vm, vcpu->id, &events); run->immediate_exit = true; - vcpu_run_complete_io(vm, VCPU_ID); + vcpu_run_complete_io(vm, vcpu->id); - vcpu_events_get(vm, VCPU_ID, &events); + vcpu_events_get(vm, vcpu->id, &events); TEST_ASSERT(events.flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT, "Triple fault event invalid"); TEST_ASSERT(events.triple_fault.pending, "No triple fault pending"); - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - switch (get_ucall(vm, VCPU_ID, &uc)) { + switch (get_ucall(vm, vcpu->id, &uc)) { case UCALL_DONE: break; case UCALL_ABORT: From 45f568084a7a86960d55cf70fd9bf06fbb29e792 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 11:57:41 -0800 Subject: [PATCH 0419/1436] KVM: selftests: Convert vgic_init away from vm_create_default_with_vcpus() Use a combination of vm_create(), vm_create_with_vcpus(), and vm_vcpu_add() to convert vgic_init from vm_create_default_with_vcpus(), and away from referncing vCPUs by ID. Thus continues the march toward total annihilation of "default" helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/vgic_init.c | 82 ++++++++++++------- 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 451f65b199ad..40504f05641d 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -66,19 +66,21 @@ static void guest_code(void) } /* we don't want to assert on run execution, hence that helper */ -static int run_vcpu(struct kvm_vm *vm, uint32_t vcpuid) +static int run_vcpu(struct kvm_vcpu *vcpu) { - ucall_init(vm, NULL); + ucall_init(vcpu->vm, NULL); - return __vcpu_run(vm, vcpuid) ? -errno : 0; + return __vcpu_run(vcpu->vm, vcpu->id) ? -errno : 0; } -static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type, uint32_t nr_vcpus) +static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type, + uint32_t nr_vcpus, + struct kvm_vcpu *vcpus[]) { struct vm_gic v; v.gic_dev_type = gic_dev_type; - v.vm = vm_create_default_with_vcpus(nr_vcpus, 0, 0, guest_code, NULL); + v.vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus); v.gic_fd = kvm_create_device(v.vm, gic_dev_type); return v; @@ -322,18 +324,19 @@ static void subtest_v3_redist_regions(struct vm_gic *v) */ static void test_vgic_then_vcpus(uint32_t gic_dev_type) { + struct kvm_vcpu *vcpus[NR_VCPUS]; struct vm_gic v; int ret, i; - v = vm_gic_create_with_vcpus(gic_dev_type, 1); + v = vm_gic_create_with_vcpus(gic_dev_type, 1, vcpus); subtest_dist_rdist(&v); /* Add the rest of the VCPUs */ for (i = 1; i < NR_VCPUS; ++i) - vm_vcpu_add(v.vm, i, guest_code); + vcpus[i] = vm_vcpu_add(v.vm, i, guest_code); - ret = run_vcpu(v.vm, 3); + ret = run_vcpu(vcpus[3]); TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run"); vm_gic_destroy(&v); @@ -342,14 +345,15 @@ static void test_vgic_then_vcpus(uint32_t gic_dev_type) /* All the VCPUs are created before the VGIC KVM device gets initialized */ static void test_vcpus_then_vgic(uint32_t gic_dev_type) { + struct kvm_vcpu *vcpus[NR_VCPUS]; struct vm_gic v; int ret; - v = vm_gic_create_with_vcpus(gic_dev_type, NR_VCPUS); + v = vm_gic_create_with_vcpus(gic_dev_type, NR_VCPUS, vcpus); subtest_dist_rdist(&v); - ret = run_vcpu(v.vm, 3); + ret = run_vcpu(vcpus[3]); TEST_ASSERT(ret == -EINVAL, "dist/rdist overlap detected on 1st vcpu run"); vm_gic_destroy(&v); @@ -357,37 +361,38 @@ static void test_vcpus_then_vgic(uint32_t gic_dev_type) static void test_v3_new_redist_regions(void) { + struct kvm_vcpu *vcpus[NR_VCPUS]; void *dummy = NULL; struct vm_gic v; uint64_t addr; int ret; - v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS); + v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus); subtest_v3_redist_regions(&v); kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); - ret = run_vcpu(v.vm, 3); + ret = run_vcpu(vcpus[3]); TEST_ASSERT(ret == -ENXIO, "running without sufficient number of rdists"); vm_gic_destroy(&v); /* step2 */ - v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS); + v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus); subtest_v3_redist_regions(&v); addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2); kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr); - ret = run_vcpu(v.vm, 3); + ret = run_vcpu(vcpus[3]); TEST_ASSERT(ret == -EBUSY, "running without vgic explicit init"); vm_gic_destroy(&v); /* step 3 */ - v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS); + v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus); subtest_v3_redist_regions(&v); ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, @@ -402,7 +407,7 @@ static void test_v3_new_redist_regions(void) kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); - ret = run_vcpu(v.vm, 3); + ret = run_vcpu(vcpus[3]); TEST_ASSERT(!ret, "vcpu run"); vm_gic_destroy(&v); @@ -414,21 +419,22 @@ static void test_v3_typer_accesses(void) uint64_t addr; int ret, i; - v.vm = vm_create_default(0, 0, guest_code); + v.vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + (void)vm_vcpu_add(v.vm, 0, guest_code); v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); - vm_vcpu_add(v.vm, 3, guest_code); + (void)vm_vcpu_add(v.vm, 3, guest_code); v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EINVAL, "attempting to read GICR_TYPER of non created vcpu"); - vm_vcpu_add(v.vm, 1, guest_code); + (void)vm_vcpu_add(v.vm, 1, guest_code); v3_redist_reg_get_errno(v.gic_fd, 1, GICR_TYPER, EBUSY, "read GICR_TYPER before GIC initialized"); - vm_vcpu_add(v.vm, 2, guest_code); + (void)vm_vcpu_add(v.vm, 2, guest_code); kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); @@ -467,6 +473,21 @@ static void test_v3_typer_accesses(void) vm_gic_destroy(&v); } +static struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus, + uint32_t vcpuids[]) +{ + struct vm_gic v; + int i; + + v.vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + for (i = 0; i < nr_vcpus; i++) + vm_vcpu_add(v.vm, vcpuids[i], guest_code); + + v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); + + return v; +} + /** * Test GICR_TYPER last bit with new redist regions * rdist regions #1 and #2 are contiguous @@ -483,9 +504,7 @@ static void test_v3_last_bit_redist_regions(void) struct vm_gic v; uint64_t addr; - v.vm = vm_create_default_with_vcpus(6, 0, 0, guest_code, vcpuids); - - v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); + v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids); kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); @@ -519,9 +538,7 @@ static void test_v3_last_bit_single_rdist(void) struct vm_gic v; uint64_t addr; - v.vm = vm_create_default_with_vcpus(6, 0, 0, guest_code, vcpuids); - - v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); + v = vm_gic_v3_create_with_vcpuids(ARRAY_SIZE(vcpuids), vcpuids); kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); @@ -542,11 +559,12 @@ static void test_v3_last_bit_single_rdist(void) /* Uses the legacy REDIST region API. */ static void test_v3_redist_ipa_range_check_at_vcpu_run(void) { + struct kvm_vcpu *vcpus[NR_VCPUS]; struct vm_gic v; int ret, i; uint64_t addr; - v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1); + v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1, vcpus); /* Set space for 3 redists, we have 1 vcpu, so this succeeds. */ addr = max_phys_size - (3 * 2 * 0x10000); @@ -559,13 +577,13 @@ static void test_v3_redist_ipa_range_check_at_vcpu_run(void) /* Add the rest of the VCPUs */ for (i = 1; i < NR_VCPUS; ++i) - vm_vcpu_add(v.vm, i, guest_code); + vcpus[i] = vm_vcpu_add(v.vm, i, guest_code); kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, KVM_DEV_ARM_VGIC_CTRL_INIT, NULL); /* Attempt to run a vcpu without enough redist space. */ - ret = run_vcpu(v.vm, 2); + ret = run_vcpu(vcpus[2]); TEST_ASSERT(ret && errno == EINVAL, "redist base+size above PA range detected on 1st vcpu run"); @@ -574,11 +592,12 @@ static void test_v3_redist_ipa_range_check_at_vcpu_run(void) static void test_v3_its_region(void) { + struct kvm_vcpu *vcpus[NR_VCPUS]; struct vm_gic v; uint64_t addr; int its_fd, ret; - v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS); + v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus); its_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_ITS); addr = 0x401000; @@ -618,11 +637,12 @@ static void test_v3_its_region(void) */ int test_kvm_device(uint32_t gic_dev_type) { + struct kvm_vcpu *vcpus[NR_VCPUS]; struct vm_gic v; uint32_t other; int ret; - v.vm = vm_create_default_with_vcpus(NR_VCPUS, 0, 0, guest_code, NULL); + v.vm = vm_create_with_vcpus(NR_VCPUS, guest_code, vcpus); /* try to create a non existing KVM device */ ret = __kvm_test_create_device(v.vm, 0); From bfff0f60db89f425920580900ba242df3bd3c652 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 1 Jun 2022 17:16:11 -0700 Subject: [PATCH 0420/1436] KVM: selftests: Consolidate KVM_{G,S}ET_ONE_REG helpers Rework vcpu_{g,s}et_reg() to provide the APIs that tests actually want to use, and drop the three "one-off" implementations that cropped up due to the poor API. Ignore the handful of direct KVM_{G,S}ET_ONE_REG calls that don't fit the APIs for one reason or another. No functional change intended. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/debug-exceptions.c | 2 +- .../selftests/kvm/aarch64/get-reg-list.c | 2 +- .../selftests/kvm/aarch64/hypercalls.c | 32 ++----- .../testing/selftests/kvm/aarch64/psci_test.c | 6 +- .../selftests/kvm/include/aarch64/processor.h | 18 +--- .../selftests/kvm/include/kvm_util_base.h | 30 +++++-- .../selftests/kvm/include/riscv/processor.h | 20 ----- .../selftests/kvm/lib/aarch64/processor.c | 28 +++---- .../selftests/kvm/lib/riscv/processor.c | 84 +++++++++---------- tools/testing/selftests/kvm/s390x/resets.c | 5 +- 10 files changed, 94 insertions(+), 133 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c index b69db0942169..2fe13e117dba 100644 --- a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c +++ b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c @@ -242,7 +242,7 @@ static int debug_version(struct kvm_vcpu *vcpu) { uint64_t id_aa64dfr0; - get_reg(vcpu->vm, vcpu->id, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), &id_aa64dfr0); + vcpu_get_reg(vcpu->vm, vcpu->id, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), &id_aa64dfr0); return id_aa64dfr0 & 0xf; } diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index fbb0c714211d..22f5e4124304 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -458,7 +458,7 @@ static void run_test(struct vcpu_config *c) bool reject_reg = false; int ret; - ret = __vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, ®); + ret = __vcpu_get_reg(vm, 0, reg_list->reg[i], &addr); if (ret) { printf("%s: Failed to get ", config_name(c)); print_reg(c, reg.id); diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c index 1eb9738453b4..b1f99e786d05 100644 --- a/tools/testing/selftests/kvm/aarch64/hypercalls.c +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c @@ -141,26 +141,6 @@ static void guest_code(void) GUEST_DONE(); } -static int set_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t val) -{ - struct kvm_one_reg reg = { - .id = id, - .addr = (uint64_t)&val, - }; - - return __vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, ®); -} - -static void get_fw_reg(struct kvm_vm *vm, uint64_t id, uint64_t *addr) -{ - struct kvm_one_reg reg = { - .id = id, - .addr = (uint64_t)addr, - }; - - vcpu_ioctl(vm, 0, KVM_GET_ONE_REG, ®); -} - struct st_time { uint32_t rev; uint32_t attr; @@ -196,18 +176,18 @@ static void test_fw_regs_before_vm_start(struct kvm_vm *vm) const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i]; /* First 'read' should be an upper limit of the features supported */ - get_fw_reg(vm, reg_info->reg, &val); + vcpu_get_reg(vm, 0, reg_info->reg, &val); TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n", reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val); /* Test a 'write' by disabling all the features of the register map */ - ret = set_fw_reg(vm, reg_info->reg, 0); + ret = __vcpu_set_reg(vm, 0, reg_info->reg, 0); TEST_ASSERT(ret == 0, "Failed to clear all the features of reg: 0x%lx; ret: %d\n", reg_info->reg, errno); - get_fw_reg(vm, reg_info->reg, &val); + vcpu_get_reg(vm, 0, reg_info->reg, &val); TEST_ASSERT(val == 0, "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg); @@ -216,7 +196,7 @@ static void test_fw_regs_before_vm_start(struct kvm_vm *vm) * Avoid this check if all the bits are occupied. */ if (reg_info->max_feat_bit < 63) { - ret = set_fw_reg(vm, reg_info->reg, BIT(reg_info->max_feat_bit + 1)); + ret = __vcpu_set_reg(vm, 0, reg_info->reg, BIT(reg_info->max_feat_bit + 1)); TEST_ASSERT(ret != 0 && errno == EINVAL, "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n", errno, reg_info->reg); @@ -237,7 +217,7 @@ static void test_fw_regs_after_vm_start(struct kvm_vm *vm) * Before starting the VM, the test clears all the bits. * Check if that's still the case. */ - get_fw_reg(vm, reg_info->reg, &val); + vcpu_get_reg(vm, 0, reg_info->reg, &val); TEST_ASSERT(val == 0, "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg); @@ -247,7 +227,7 @@ static void test_fw_regs_after_vm_start(struct kvm_vm *vm) * the registers and should return EBUSY. Set the registers and check for * the expected errno. */ - ret = set_fw_reg(vm, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit)); + ret = __vcpu_set_reg(vm, 0, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit)); TEST_ASSERT(ret != 0 && errno == EBUSY, "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n", errno, reg_info->reg); diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index d9695a939cc9..f4f73934351f 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -102,8 +102,8 @@ static void assert_vcpu_reset(struct kvm_vcpu *vcpu) { uint64_t obs_pc, obs_x0; - get_reg(vcpu->vm, vcpu->id, ARM64_CORE_REG(regs.pc), &obs_pc); - get_reg(vcpu->vm, vcpu->id, ARM64_CORE_REG(regs.regs[0]), &obs_x0); + vcpu_get_reg(vcpu->vm, vcpu->id, ARM64_CORE_REG(regs.pc), &obs_pc); + vcpu_get_reg(vcpu->vm, vcpu->id, ARM64_CORE_REG(regs.regs[0]), &obs_x0); TEST_ASSERT(obs_pc == CPU_ON_ENTRY_ADDR, "unexpected target cpu pc: %lx (expected: %lx)", @@ -143,7 +143,7 @@ static void host_test_cpu_on(void) */ vcpu_power_off(target); - get_reg(vm, target->id, KVM_ARM64_SYS_REG(SYS_MPIDR_EL1), &target_mpidr); + vcpu_get_reg(vm, target->id, KVM_ARM64_SYS_REG(SYS_MPIDR_EL1), &target_mpidr); vcpu_args_set(vm, source->id, 1, target_mpidr & MPIDR_HWID_BITMASK); enter_guest(source); diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index f774609f7848..ba3e9066d990 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -19,7 +19,7 @@ /* * KVM_ARM64_SYS_REG(sys_reg_id): Helper macro to convert * SYS_* register definitions in asm/sysreg.h to use in KVM - * calls such as get_reg() and set_reg(). + * calls such as vcpu_get_reg() and vcpu_set_reg(). */ #define KVM_ARM64_SYS_REG(sys_reg_id) \ ARM64_SYS_REG(sys_reg_Op0(sys_reg_id), \ @@ -47,22 +47,6 @@ #define MPIDR_HWID_BITMASK (0xff00fffffful) -static inline void get_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint64_t *addr) -{ - struct kvm_one_reg reg; - reg.id = id; - reg.addr = (uint64_t)addr; - vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, ®); -} - -static inline void set_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, uint64_t val) -{ - struct kvm_one_reg reg; - reg.id = id; - reg.addr = (uint64_t)&val; - vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, ®); -} - void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init *init); struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, struct kvm_vcpu_init *init, void *guest_code); diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index c0b2158a53d5..9c29b6797ce8 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -374,16 +374,36 @@ static inline void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, { vcpu_ioctl(vm, vcpuid, KVM_SET_FPU, fpu); } -static inline void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_one_reg *reg) + +static inline int __vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, + uint64_t reg_id, void *addr) { - vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, reg); + struct kvm_one_reg reg = { .id = reg_id, .addr = (uint64_t)addr }; + + return __vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, ®); +} +static inline int __vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, + uint64_t reg_id, uint64_t val) +{ + struct kvm_one_reg reg = { .id = reg_id, .addr = (uint64_t)&val }; + + return __vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, ®); +} +static inline void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, + uint64_t reg_id, void *addr) +{ + struct kvm_one_reg reg = { .id = reg_id, .addr = (uint64_t)addr }; + + vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, ®); } static inline void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_one_reg *reg) + uint64_t reg_id, uint64_t val) { - vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, reg); + struct kvm_one_reg reg = { .id = reg_id, .addr = (uint64_t)&val }; + + vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, ®); } + #ifdef __KVM_HAVE_VCPU_EVENTS static inline void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_events *events) diff --git a/tools/testing/selftests/kvm/include/riscv/processor.h b/tools/testing/selftests/kvm/include/riscv/processor.h index 4fcfd1c0389d..d00d213c3805 100644 --- a/tools/testing/selftests/kvm/include/riscv/processor.h +++ b/tools/testing/selftests/kvm/include/riscv/processor.h @@ -38,26 +38,6 @@ static inline uint64_t __kvm_reg_id(uint64_t type, uint64_t idx, KVM_REG_RISCV_TIMER_REG(name), \ KVM_REG_SIZE_U64) -static inline void get_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, - unsigned long *addr) -{ - struct kvm_one_reg reg; - - reg.id = id; - reg.addr = (unsigned long)addr; - vcpu_get_reg(vm, vcpuid, ®); -} - -static inline void set_reg(struct kvm_vm *vm, uint32_t vcpuid, uint64_t id, - unsigned long val) -{ - struct kvm_one_reg reg; - - reg.id = id; - reg.addr = (unsigned long)&val; - vcpu_set_reg(vm, vcpuid, ®); -} - /* L3 index Bit[47:39] */ #define PGTBL_L3_INDEX_MASK 0x0000FF8000000000ULL #define PGTBL_L3_INDEX_SHIFT 39 diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 5b95fa2cce18..d158d5aa26e6 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -232,10 +232,10 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init * Enable FP/ASIMD to avoid trapping when accessing Q0-Q15 * registers, which the variable argument list macros do. */ - set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_CPACR_EL1), 3 << 20); + vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_CPACR_EL1), 3 << 20); - get_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), &sctlr_el1); - get_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TCR_EL1), &tcr_el1); + vcpu_get_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), &sctlr_el1); + vcpu_get_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TCR_EL1), &tcr_el1); /* Configure base granule size */ switch (vm->mode) { @@ -296,19 +296,19 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12); tcr_el1 |= (64 - vm->va_bits) /* T0SZ */; - set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1); - set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1); - set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_MAIR_EL1), DEFAULT_MAIR_EL1); - set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TTBR0_EL1), vm->pgd); - set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TPIDR_EL1), vcpuid); + vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1); + vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1); + vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_MAIR_EL1), DEFAULT_MAIR_EL1); + vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TTBR0_EL1), vm->pgd); + vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TPIDR_EL1), vcpuid); } void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) { uint64_t pstate, pc; - get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pstate), &pstate); - get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), &pc); + vcpu_get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pstate), &pstate); + vcpu_get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), &pc); fprintf(stream, "%*spstate: 0x%.16lx pc: 0x%.16lx\n", indent, "", pstate, pc); @@ -326,8 +326,8 @@ struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, aarch64_vcpu_setup(vm, vcpu_id, init); - set_reg(vm, vcpu_id, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); - set_reg(vm, vcpu_id, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); + vcpu_set_reg(vm, vcpu_id, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); + vcpu_set_reg(vm, vcpu_id, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); return vcpu; } @@ -349,7 +349,7 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) va_start(ap, num); for (i = 0; i < num; i++) { - set_reg(vm, vcpuid, ARM64_CORE_REG(regs.regs[i]), + vcpu_set_reg(vm, vcpuid, ARM64_CORE_REG(regs.regs[i]), va_arg(ap, uint64_t)); } @@ -389,7 +389,7 @@ void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid) { extern char vectors; - set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_VBAR_EL1), (uint64_t)&vectors); + vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_VBAR_EL1), (uint64_t)&vectors); } void route_exception(struct ex_regs *regs, int vector) diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index ba5761843c76..edbdc7bef05b 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -198,46 +198,46 @@ void riscv_vcpu_mmu_setup(struct kvm_vm *vm, int vcpuid) satp = (vm->pgd >> PGTBL_PAGE_SIZE_SHIFT) & SATP_PPN; satp |= SATP_MODE_48; - set_reg(vm, vcpuid, RISCV_CSR_REG(satp), satp); + vcpu_set_reg(vm, vcpuid, RISCV_CSR_REG(satp), satp); } void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) { struct kvm_riscv_core core; - get_reg(vm, vcpuid, RISCV_CORE_REG(mode), &core.mode); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.pc), &core.regs.pc); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.ra), &core.regs.ra); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.sp), &core.regs.sp); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.gp), &core.regs.gp); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.tp), &core.regs.tp); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t0), &core.regs.t0); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t1), &core.regs.t1); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t2), &core.regs.t2); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s0), &core.regs.s0); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s1), &core.regs.s1); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a0), &core.regs.a0); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a1), &core.regs.a1); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a2), &core.regs.a2); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a3), &core.regs.a3); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a4), &core.regs.a4); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a5), &core.regs.a5); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a6), &core.regs.a6); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a7), &core.regs.a7); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s2), &core.regs.s2); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s3), &core.regs.s3); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s4), &core.regs.s4); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s5), &core.regs.s5); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s6), &core.regs.s6); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s7), &core.regs.s7); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s8), &core.regs.s8); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s9), &core.regs.s9); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s10), &core.regs.s10); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s11), &core.regs.s11); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t3), &core.regs.t3); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t4), &core.regs.t4); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t5), &core.regs.t5); - get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t6), &core.regs.t6); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(mode), &core.mode); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.pc), &core.regs.pc); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.ra), &core.regs.ra); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.sp), &core.regs.sp); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.gp), &core.regs.gp); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.tp), &core.regs.tp); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t0), &core.regs.t0); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t1), &core.regs.t1); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t2), &core.regs.t2); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s0), &core.regs.s0); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s1), &core.regs.s1); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a0), &core.regs.a0); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a1), &core.regs.a1); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a2), &core.regs.a2); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a3), &core.regs.a3); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a4), &core.regs.a4); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a5), &core.regs.a5); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a6), &core.regs.a6); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a7), &core.regs.a7); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s2), &core.regs.s2); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s3), &core.regs.s3); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s4), &core.regs.s4); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s5), &core.regs.s5); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s6), &core.regs.s6); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s7), &core.regs.s7); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s8), &core.regs.s8); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s9), &core.regs.s9); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s10), &core.regs.s10); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s11), &core.regs.s11); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t3), &core.regs.t3); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t4), &core.regs.t4); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t5), &core.regs.t5); + vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t6), &core.regs.t6); fprintf(stream, " MODE: 0x%lx\n", core.mode); @@ -302,17 +302,17 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, /* Setup global pointer of guest to be same as the host */ asm volatile ( "add %0, gp, zero" : "=r" (current_gp) : : "memory"); - set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.gp), current_gp); + vcpu_set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.gp), current_gp); /* Setup stack pointer and program counter of guest */ - set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.sp), - stack_vaddr + stack_size); - set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.pc), - (unsigned long)guest_code); + vcpu_set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.sp), + stack_vaddr + stack_size); + vcpu_set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.pc), + (unsigned long)guest_code); /* Setup default exception vector of guest */ - set_reg(vm, vcpu_id, RISCV_CSR_REG(stvec), - (unsigned long)guest_unexp_trap); + vcpu_set_reg(vm, vcpu_id, RISCV_CSR_REG(stvec), + (unsigned long)guest_unexp_trap); return vcpu; } @@ -355,7 +355,7 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) id = RISCV_CORE_REG(regs.a7); break; } - set_reg(vm, vcpuid, id, va_arg(ap, uint64_t)); + vcpu_set_reg(vm, vcpuid, id, va_arg(ap, uint64_t)); } va_end(ap); diff --git a/tools/testing/selftests/kvm/s390x/resets.c b/tools/testing/selftests/kvm/s390x/resets.c index 298bff3fd52e..85d290454776 100644 --- a/tools/testing/selftests/kvm/s390x/resets.c +++ b/tools/testing/selftests/kvm/s390x/resets.c @@ -61,12 +61,9 @@ static void guest_code_initial(void) static void test_one_reg(uint64_t id, uint64_t value) { - struct kvm_one_reg reg; uint64_t eval_reg; - reg.addr = (uintptr_t)&eval_reg; - reg.id = id; - vcpu_get_reg(vm, VCPU_ID, ®); + vcpu_get_reg(vm, VCPU_ID, id, &eval_reg); TEST_ASSERT(eval_reg == value, "value == 0x%lx", value); } From f05427faedff746e08b2098195c15d8691bc5fbe Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 1 Jun 2022 17:27:51 -0700 Subject: [PATCH 0421/1436] KVM: selftests: Sync stage before VM is freed in hypercalls test Sync the next stage using the VM before said VM is potentially freed by the TEST_STAGE_HVC_IFACE_FEAT_DISABLED stage. Opportunistically take a double pointer in anticipation of also having to set the new vCPU pointer once the test stops hardcoding '0' everywhere. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/hypercalls.c | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c index b1f99e786d05..44ca840e8219 100644 --- a/tools/testing/selftests/kvm/aarch64/hypercalls.c +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c @@ -246,32 +246,31 @@ static struct kvm_vm *test_vm_create(void) return vm; } -static struct kvm_vm *test_guest_stage(struct kvm_vm *vm) +static void test_guest_stage(struct kvm_vm **vm) { - struct kvm_vm *ret_vm = vm; + int prev_stage = stage; - pr_debug("Stage: %d\n", stage); + pr_debug("Stage: %d\n", prev_stage); - switch (stage) { + /* Sync the stage early, the VM might be freed below. */ + stage++; + sync_global_to_guest(*vm, stage); + + switch (prev_stage) { case TEST_STAGE_REG_IFACE: - test_fw_regs_after_vm_start(vm); + test_fw_regs_after_vm_start(*vm); break; case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: /* Start a new VM so that all the features are now enabled by default */ - kvm_vm_free(vm); - ret_vm = test_vm_create(); + kvm_vm_free(*vm); + *vm = test_vm_create(); break; case TEST_STAGE_HVC_IFACE_FEAT_ENABLED: case TEST_STAGE_HVC_IFACE_FALSE_INFO: break; default: - TEST_FAIL("Unknown test stage: %d\n", stage); + TEST_FAIL("Unknown test stage: %d\n", prev_stage); } - - stage++; - sync_global_to_guest(vm, stage); - - return ret_vm; } static void test_run(void) @@ -289,7 +288,7 @@ static void test_run(void) switch (get_ucall(vm, 0, &uc)) { case UCALL_SYNC: - vm = test_guest_stage(vm); + test_guest_stage(&vm); break; case UCALL_DONE: guest_done = true; From 8a093ea0d104998c4755743cdc5df7349356ae81 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 1 Jun 2022 17:32:52 -0700 Subject: [PATCH 0422/1436] KVM: selftests: Convert hypercalls test away from vm_create_default() Use a combination of vm_create(), vm_create_with_vcpus(), and vm_vcpu_add() to convert vgic_init from vm_create_default_with_vcpus(), and away from referncing vCPUs by ID. Thus continues the march toward total annihilation of "default" helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/hypercalls.c | 51 +++++++++---------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c index 44ca840e8219..fefa39dc9bc8 100644 --- a/tools/testing/selftests/kvm/aarch64/hypercalls.c +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c @@ -150,23 +150,19 @@ struct st_time { #define STEAL_TIME_SIZE ((sizeof(struct st_time) + 63) & ~63) #define ST_GPA_BASE (1 << 30) -static void steal_time_init(struct kvm_vm *vm) +static void steal_time_init(struct kvm_vcpu *vcpu) { uint64_t st_ipa = (ulong)ST_GPA_BASE; unsigned int gpages; - struct kvm_device_attr dev = { - .group = KVM_ARM_VCPU_PVTIME_CTRL, - .attr = KVM_ARM_VCPU_PVTIME_IPA, - .addr = (uint64_t)&st_ipa, - }; gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE); - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0); + vm_userspace_mem_region_add(vcpu->vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0); - vcpu_ioctl(vm, 0, KVM_SET_DEVICE_ATTR, &dev); + vcpu_device_attr_set(vcpu->vm, vcpu->id, KVM_ARM_VCPU_PVTIME_CTRL, + KVM_ARM_VCPU_PVTIME_IPA, &st_ipa); } -static void test_fw_regs_before_vm_start(struct kvm_vm *vm) +static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu) { uint64_t val; unsigned int i; @@ -176,18 +172,18 @@ static void test_fw_regs_before_vm_start(struct kvm_vm *vm) const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i]; /* First 'read' should be an upper limit of the features supported */ - vcpu_get_reg(vm, 0, reg_info->reg, &val); + vcpu_get_reg(vcpu->vm, vcpu->id, reg_info->reg, &val); TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n", reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val); /* Test a 'write' by disabling all the features of the register map */ - ret = __vcpu_set_reg(vm, 0, reg_info->reg, 0); + ret = __vcpu_set_reg(vcpu->vm, vcpu->id, reg_info->reg, 0); TEST_ASSERT(ret == 0, "Failed to clear all the features of reg: 0x%lx; ret: %d\n", reg_info->reg, errno); - vcpu_get_reg(vm, 0, reg_info->reg, &val); + vcpu_get_reg(vcpu->vm, vcpu->id, reg_info->reg, &val); TEST_ASSERT(val == 0, "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg); @@ -196,7 +192,7 @@ static void test_fw_regs_before_vm_start(struct kvm_vm *vm) * Avoid this check if all the bits are occupied. */ if (reg_info->max_feat_bit < 63) { - ret = __vcpu_set_reg(vm, 0, reg_info->reg, BIT(reg_info->max_feat_bit + 1)); + ret = __vcpu_set_reg(vcpu->vm, vcpu->id, reg_info->reg, BIT(reg_info->max_feat_bit + 1)); TEST_ASSERT(ret != 0 && errno == EINVAL, "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n", errno, reg_info->reg); @@ -204,7 +200,7 @@ static void test_fw_regs_before_vm_start(struct kvm_vm *vm) } } -static void test_fw_regs_after_vm_start(struct kvm_vm *vm) +static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu) { uint64_t val; unsigned int i; @@ -217,7 +213,7 @@ static void test_fw_regs_after_vm_start(struct kvm_vm *vm) * Before starting the VM, the test clears all the bits. * Check if that's still the case. */ - vcpu_get_reg(vm, 0, reg_info->reg, &val); + vcpu_get_reg(vcpu->vm, vcpu->id, reg_info->reg, &val); TEST_ASSERT(val == 0, "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg); @@ -227,26 +223,26 @@ static void test_fw_regs_after_vm_start(struct kvm_vm *vm) * the registers and should return EBUSY. Set the registers and check for * the expected errno. */ - ret = __vcpu_set_reg(vm, 0, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit)); + ret = __vcpu_set_reg(vcpu->vm, vcpu->id, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit)); TEST_ASSERT(ret != 0 && errno == EBUSY, "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n", errno, reg_info->reg); } } -static struct kvm_vm *test_vm_create(void) +static struct kvm_vm *test_vm_create(struct kvm_vcpu **vcpu) { struct kvm_vm *vm; - vm = vm_create_default(0, 0, guest_code); + vm = vm_create_with_one_vcpu(vcpu, guest_code); ucall_init(vm, NULL); - steal_time_init(vm); + steal_time_init(*vcpu); return vm; } -static void test_guest_stage(struct kvm_vm **vm) +static void test_guest_stage(struct kvm_vm **vm, struct kvm_vcpu **vcpu) { int prev_stage = stage; @@ -258,12 +254,12 @@ static void test_guest_stage(struct kvm_vm **vm) switch (prev_stage) { case TEST_STAGE_REG_IFACE: - test_fw_regs_after_vm_start(*vm); + test_fw_regs_after_vm_start(*vcpu); break; case TEST_STAGE_HVC_IFACE_FEAT_DISABLED: /* Start a new VM so that all the features are now enabled by default */ kvm_vm_free(*vm); - *vm = test_vm_create(); + *vm = test_vm_create(vcpu); break; case TEST_STAGE_HVC_IFACE_FEAT_ENABLED: case TEST_STAGE_HVC_IFACE_FALSE_INFO: @@ -275,20 +271,21 @@ static void test_guest_stage(struct kvm_vm **vm) static void test_run(void) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct ucall uc; bool guest_done = false; - vm = test_vm_create(); + vm = test_vm_create(&vcpu); - test_fw_regs_before_vm_start(vm); + test_fw_regs_before_vm_start(vcpu); while (!guest_done) { - vcpu_run(vm, 0); + vcpu_run(vcpu->vm, vcpu->id); - switch (get_ucall(vm, 0, &uc)) { + switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { case UCALL_SYNC: - test_guest_stage(&vm); + test_guest_stage(&vm, &vcpu); break; case UCALL_DONE: guest_done = true; From ebca1b8056dae8593bb350178d2ea454b3e123ad Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 12:10:40 -0800 Subject: [PATCH 0423/1436] KVM: selftests: Convert xapic_ipi_test away from *_VCPU_ID Convert vm_create_with_one_vcpu to use vm_create_with_vcpus() and pass around 'struct kvm_vcpu' objects instead of passing around vCPU IDs. Don't bother with macros for the HALTER versus SENDER indices, the vast majority of references don't differentiate between the vCPU roles, and the code that does either has a comment or an explicit reference to the role, e.g. to halter_guest_code() or sender_guest_code(). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/xapic_ipi_test.c | 48 ++++++++----------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c b/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c index 8b366652be31..4484ee563b18 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c @@ -39,9 +39,6 @@ /* Default delay between migrate_pages calls (microseconds) */ #define DEFAULT_DELAY_USECS 500000 -#define HALTER_VCPU_ID 0 -#define SENDER_VCPU_ID 1 - /* * Vector for IPI from sender vCPU to halting vCPU. * Value is arbitrary and was chosen for the alternating bit pattern. Any @@ -79,8 +76,7 @@ struct test_data_page { struct thread_params { struct test_data_page *data; - struct kvm_vm *vm; - uint32_t vcpu_id; + struct kvm_vcpu *vcpu; uint64_t *pipis_rcvd; /* host address of ipis_rcvd global */ }; @@ -198,6 +194,7 @@ static void sender_guest_code(struct test_data_page *data) static void *vcpu_thread(void *arg) { struct thread_params *params = (struct thread_params *)arg; + struct kvm_vcpu *vcpu = params->vcpu; struct ucall uc; int old; int r; @@ -206,17 +203,17 @@ static void *vcpu_thread(void *arg) r = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old); TEST_ASSERT(r == 0, "pthread_setcanceltype failed on vcpu_id=%u with errno=%d", - params->vcpu_id, r); + vcpu->id, r); - fprintf(stderr, "vCPU thread running vCPU %u\n", params->vcpu_id); - vcpu_run(params->vm, params->vcpu_id); - exit_reason = vcpu_state(params->vm, params->vcpu_id)->exit_reason; + fprintf(stderr, "vCPU thread running vCPU %u\n", vcpu->id); + vcpu_run(vcpu->vm, vcpu->id); + exit_reason = vcpu->run->exit_reason; TEST_ASSERT(exit_reason == KVM_EXIT_IO, "vCPU %u exited with unexpected exit reason %u-%s, expected KVM_EXIT_IO", - params->vcpu_id, exit_reason, exit_reason_str(exit_reason)); + vcpu->id, exit_reason, exit_reason_str(exit_reason)); - if (get_ucall(params->vm, params->vcpu_id, &uc) == UCALL_ABORT) { + if (get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_ABORT) { TEST_ASSERT(false, "vCPU %u exited with error: %s.\n" "Sending vCPU sent %lu IPIs to halting vCPU\n" @@ -224,7 +221,7 @@ static void *vcpu_thread(void *arg) "Halter TPR=%#x PPR=%#x LVR=%#x\n" "Migrations attempted: %lu\n" "Migrations completed: %lu\n", - params->vcpu_id, (const char *)uc.args[0], + vcpu->id, (const char *)uc.args[0], params->data->ipis_sent, params->data->hlt_count, params->data->wake_count, *params->pipis_rcvd, params->data->halter_tpr, @@ -236,7 +233,7 @@ static void *vcpu_thread(void *arg) return NULL; } -static void cancel_join_vcpu_thread(pthread_t thread, uint32_t vcpu_id) +static void cancel_join_vcpu_thread(pthread_t thread, struct kvm_vcpu *vcpu) { void *retval; int r; @@ -244,12 +241,12 @@ static void cancel_join_vcpu_thread(pthread_t thread, uint32_t vcpu_id) r = pthread_cancel(thread); TEST_ASSERT(r == 0, "pthread_cancel on vcpu_id=%d failed with errno=%d", - vcpu_id, r); + vcpu->id, r); r = pthread_join(thread, &retval); TEST_ASSERT(r == 0, "pthread_join on vcpu_id=%d failed with errno=%d", - vcpu_id, r); + vcpu->id, r); TEST_ASSERT(retval == PTHREAD_CANCELED, "expected retval=%p, got %p", PTHREAD_CANCELED, retval); @@ -415,34 +412,30 @@ int main(int argc, char *argv[]) if (delay_usecs <= 0) delay_usecs = DEFAULT_DELAY_USECS; - vm = vm_create_default(HALTER_VCPU_ID, 0, halter_guest_code); - params[0].vm = vm; - params[1].vm = vm; + vm = vm_create_with_one_vcpu(¶ms[0].vcpu, halter_guest_code); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, HALTER_VCPU_ID); + vcpu_init_descriptor_tables(vm, params[0].vcpu->id); vm_install_exception_handler(vm, IPI_VECTOR, guest_ipi_handler); virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); - vm_vcpu_add(vm, SENDER_VCPU_ID, sender_guest_code); + params[1].vcpu = vm_vcpu_add(vm, 1, sender_guest_code); test_data_page_vaddr = vm_vaddr_alloc_page(vm); - data = - (struct test_data_page *)addr_gva2hva(vm, test_data_page_vaddr); + data = addr_gva2hva(vm, test_data_page_vaddr); memset(data, 0, sizeof(*data)); params[0].data = data; params[1].data = data; - vcpu_args_set(vm, HALTER_VCPU_ID, 1, test_data_page_vaddr); - vcpu_args_set(vm, SENDER_VCPU_ID, 1, test_data_page_vaddr); + vcpu_args_set(vm, params[0].vcpu->id, 1, test_data_page_vaddr); + vcpu_args_set(vm, params[1].vcpu->id, 1, test_data_page_vaddr); pipis_rcvd = (uint64_t *)addr_gva2hva(vm, (uint64_t)&ipis_rcvd); params[0].pipis_rcvd = pipis_rcvd; params[1].pipis_rcvd = pipis_rcvd; /* Start halter vCPU thread and wait for it to execute first HLT. */ - params[0].vcpu_id = HALTER_VCPU_ID; r = pthread_create(&threads[0], NULL, vcpu_thread, ¶ms[0]); TEST_ASSERT(r == 0, "pthread_create halter failed errno=%d", errno); @@ -462,7 +455,6 @@ int main(int argc, char *argv[]) "Halter vCPU thread reported its APIC ID: %u after %d seconds.\n", data->halter_apic_id, wait_secs); - params[1].vcpu_id = SENDER_VCPU_ID; r = pthread_create(&threads[1], NULL, vcpu_thread, ¶ms[1]); TEST_ASSERT(r == 0, "pthread_create sender failed errno=%d", errno); @@ -478,8 +470,8 @@ int main(int argc, char *argv[]) /* * Cancel threads and wait for them to stop. */ - cancel_join_vcpu_thread(threads[0], HALTER_VCPU_ID); - cancel_join_vcpu_thread(threads[1], SENDER_VCPU_ID); + cancel_join_vcpu_thread(threads[0], params[0].vcpu); + cancel_join_vcpu_thread(threads[1], params[1].vcpu); fprintf(stderr, "Test successful after running for %d seconds.\n" From e5b77cdef9e3023b8156d81e005c3b7f27a1eaa5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 12:20:41 -0800 Subject: [PATCH 0424/1436] KVM: selftests: Convert sync_regs_test away from VCPU_ID Convert sync_regs_test to use vm_create_with_vcpus() and pass around a 'struct kvm_vcpu' object instead of passing around vCPU IDs. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==5. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/s390x/sync_regs_test.c | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/tools/testing/selftests/kvm/s390x/sync_regs_test.c b/tools/testing/selftests/kvm/s390x/sync_regs_test.c index 9510739e226d..7c4143141ca7 100644 --- a/tools/testing/selftests/kvm/s390x/sync_regs_test.c +++ b/tools/testing/selftests/kvm/s390x/sync_regs_test.c @@ -23,8 +23,6 @@ #include "diag318_test_handler.h" #include "kselftest.h" -#define VCPU_ID 5 - static void guest_code(void) { /* @@ -75,55 +73,58 @@ static void compare_sregs(struct kvm_sregs *left, struct kvm_sync_regs *right) #define TEST_SYNC_FIELDS (KVM_SYNC_GPRS|KVM_SYNC_ACRS|KVM_SYNC_CRS|KVM_SYNC_DIAG318) #define INVALID_SYNC_FIELD 0x80000000 -void test_read_invalid(struct kvm_vm *vm, struct kvm_run *run) +void test_read_invalid(struct kvm_vcpu *vcpu) { + struct kvm_run *run = vcpu->run; int rv; /* Request reading invalid register set from VCPU. */ run->kvm_valid_regs = INVALID_SYNC_FIELD; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", rv); - vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0; + run->kvm_valid_regs = 0; run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", rv); - vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0; + run->kvm_valid_regs = 0; } -void test_set_invalid(struct kvm_vm *vm, struct kvm_run *run) +void test_set_invalid(struct kvm_vcpu *vcpu) { + struct kvm_run *run = vcpu->run; int rv; /* Request setting invalid register set into VCPU. */ run->kvm_dirty_regs = INVALID_SYNC_FIELD; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", rv); - vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0; + run->kvm_dirty_regs = 0; run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", rv); - vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0; + run->kvm_dirty_regs = 0; } -void test_req_and_verify_all_valid_regs(struct kvm_vm *vm, struct kvm_run *run) +void test_req_and_verify_all_valid_regs(struct kvm_vcpu *vcpu) { + struct kvm_run *run = vcpu->run; struct kvm_sregs sregs; struct kvm_regs regs; int rv; /* Request and verify all valid register sets. */ run->kvm_valid_regs = TEST_SYNC_FIELDS; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, "Unexpected exit reason: %u (%s)\n", @@ -136,15 +137,16 @@ void test_req_and_verify_all_valid_regs(struct kvm_vm *vm, struct kvm_run *run) run->s390_sieic.icptcode, run->s390_sieic.ipa, run->s390_sieic.ipb); - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vcpu->vm, vcpu->id, ®s); compare_regs(®s, &run->s.regs); - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); compare_sregs(&sregs, &run->s.regs); } -void test_set_and_verify_various_reg_values(struct kvm_vm *vm, struct kvm_run *run) +void test_set_and_verify_various_reg_values(struct kvm_vcpu *vcpu) { + struct kvm_run *run = vcpu->run; struct kvm_sregs sregs; struct kvm_regs regs; int rv; @@ -161,7 +163,7 @@ void test_set_and_verify_various_reg_values(struct kvm_vm *vm, struct kvm_run *r run->kvm_dirty_regs |= KVM_SYNC_DIAG318; } - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, "Unexpected exit reason: %u (%s)\n", @@ -177,15 +179,16 @@ void test_set_and_verify_various_reg_values(struct kvm_vm *vm, struct kvm_run *r "diag318 sync regs value incorrect 0x%llx.", run->s.regs.diag318); - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vcpu->vm, vcpu->id, ®s); compare_regs(®s, &run->s.regs); - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); compare_sregs(&sregs, &run->s.regs); } -void test_clear_kvm_dirty_regs_bits(struct kvm_vm *vm, struct kvm_run *run) +void test_clear_kvm_dirty_regs_bits(struct kvm_vcpu *vcpu) { + struct kvm_run *run = vcpu->run; int rv; /* Clear kvm_dirty_regs bits, verify new s.regs values are @@ -195,7 +198,7 @@ void test_clear_kvm_dirty_regs_bits(struct kvm_vm *vm, struct kvm_run *run) run->kvm_dirty_regs = 0; run->s.regs.gprs[11] = 0xDEADBEEF; run->s.regs.diag318 = 0x4B1D; - rv = _vcpu_run(vm, VCPU_ID); + rv = _vcpu_run(vcpu->vm, vcpu->id); TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, "Unexpected exit reason: %u (%s)\n", @@ -211,7 +214,7 @@ void test_clear_kvm_dirty_regs_bits(struct kvm_vm *vm, struct kvm_run *run) struct testdef { const char *name; - void (*test)(struct kvm_vm *vm, struct kvm_run *run); + void (*test)(struct kvm_vcpu *vcpu); } testlist[] = { { "read invalid", test_read_invalid }, { "set invalid", test_set_invalid }, @@ -222,8 +225,8 @@ struct testdef { int main(int argc, char *argv[]) { - static struct kvm_run *run; - static struct kvm_vm *vm; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; int idx; /* Tell stdout not to buffer its content */ @@ -237,12 +240,10 @@ int main(int argc, char *argv[]) ksft_set_plan(ARRAY_SIZE(testlist)); /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code); - - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) { - testlist[idx].test(vm, run); + testlist[idx].test(vcpu); ksft_test_result_pass("%s\n", testlist[idx].name); } From 371dfb2e90d942fb651c324505bc4929447b081b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 12:38:26 -0800 Subject: [PATCH 0425/1436] KVM: selftests: Convert s390's "resets" test away from VCPU_ID Pass around a 'struct kvm_vcpu' object in the "resets" test instead of referencing the vCPU by the global VCPU_ID. Rename the #define for the vCPU's ID to ARBITRARY_NON_ZERO_VCPU_ID to make it more obvious that (a) the value matters but (b) is otherwise arbitrary. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/s390x/resets.c | 137 ++++++++++++--------- 1 file changed, 77 insertions(+), 60 deletions(-) diff --git a/tools/testing/selftests/kvm/s390x/resets.c b/tools/testing/selftests/kvm/s390x/resets.c index 85d290454776..b2375d81571c 100644 --- a/tools/testing/selftests/kvm/s390x/resets.c +++ b/tools/testing/selftests/kvm/s390x/resets.c @@ -14,14 +14,12 @@ #include "kvm_util.h" #include "kselftest.h" -#define VCPU_ID 3 #define LOCAL_IRQS 32 -struct kvm_s390_irq buf[VCPU_ID + LOCAL_IRQS]; +#define ARBITRARY_NON_ZERO_VCPU_ID 3 + +struct kvm_s390_irq buf[ARBITRARY_NON_ZERO_VCPU_ID + LOCAL_IRQS]; -struct kvm_vm *vm; -struct kvm_run *run; -struct kvm_sync_regs *sync_regs; static uint8_t regs_null[512]; static void guest_code_initial(void) @@ -59,22 +57,22 @@ static void guest_code_initial(void) ); } -static void test_one_reg(uint64_t id, uint64_t value) +static void test_one_reg(struct kvm_vcpu *vcpu, uint64_t id, uint64_t value) { uint64_t eval_reg; - vcpu_get_reg(vm, VCPU_ID, id, &eval_reg); + vcpu_get_reg(vcpu->vm, vcpu->id, id, &eval_reg); TEST_ASSERT(eval_reg == value, "value == 0x%lx", value); } -static void assert_noirq(void) +static void assert_noirq(struct kvm_vcpu *vcpu) { struct kvm_s390_irq_state irq_state; int irqs; irq_state.len = sizeof(buf); irq_state.buf = (unsigned long)buf; - irqs = __vcpu_ioctl(vm, VCPU_ID, KVM_S390_GET_IRQ_STATE, &irq_state); + irqs = __vcpu_ioctl(vcpu->vm, vcpu->id, KVM_S390_GET_IRQ_STATE, &irq_state); /* * irqs contains the number of retrieved interrupts. Any interrupt * (notably, the emergency call interrupt we have injected) should @@ -84,19 +82,20 @@ static void assert_noirq(void) TEST_ASSERT(!irqs, "IRQ pending"); } -static void assert_clear(void) +static void assert_clear(struct kvm_vcpu *vcpu) { + struct kvm_sync_regs *sync_regs = &vcpu->run->s.regs; struct kvm_sregs sregs; struct kvm_regs regs; struct kvm_fpu fpu; - vcpu_regs_get(vm, VCPU_ID, ®s); + vcpu_regs_get(vcpu->vm, vcpu->id, ®s); TEST_ASSERT(!memcmp(®s.gprs, regs_null, sizeof(regs.gprs)), "grs == 0"); - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); TEST_ASSERT(!memcmp(&sregs.acrs, regs_null, sizeof(sregs.acrs)), "acrs == 0"); - vcpu_fpu_get(vm, VCPU_ID, &fpu); + vcpu_fpu_get(vcpu->vm, vcpu->id, &fpu); TEST_ASSERT(!memcmp(&fpu.fprs, regs_null, sizeof(fpu.fprs)), "fprs == 0"); /* sync regs */ @@ -110,8 +109,10 @@ static void assert_clear(void) "vrs0-15 == 0 (sync_regs)"); } -static void assert_initial_noclear(void) +static void assert_initial_noclear(struct kvm_vcpu *vcpu) { + struct kvm_sync_regs *sync_regs = &vcpu->run->s.regs; + TEST_ASSERT(sync_regs->gprs[0] == 0xffff000000000000UL, "gpr0 == 0xffff000000000000 (sync_regs)"); TEST_ASSERT(sync_regs->gprs[1] == 0x0000555500000000UL, @@ -125,13 +126,14 @@ static void assert_initial_noclear(void) TEST_ASSERT(sync_regs->acrs[9] == 1, "ar9 == 1 (sync_regs)"); } -static void assert_initial(void) +static void assert_initial(struct kvm_vcpu *vcpu) { + struct kvm_sync_regs *sync_regs = &vcpu->run->s.regs; struct kvm_sregs sregs; struct kvm_fpu fpu; /* KVM_GET_SREGS */ - vcpu_sregs_get(vm, VCPU_ID, &sregs); + vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); TEST_ASSERT(sregs.crs[0] == 0xE0UL, "cr0 == 0xE0 (KVM_GET_SREGS)"); TEST_ASSERT(sregs.crs[14] == 0xC2000000UL, "cr14 == 0xC2000000 (KVM_GET_SREGS)"); @@ -154,36 +156,38 @@ static void assert_initial(void) TEST_ASSERT(sync_regs->gbea == 1, "gbea == 1 (sync_regs)"); /* kvm_run */ - TEST_ASSERT(run->psw_addr == 0, "psw_addr == 0 (kvm_run)"); - TEST_ASSERT(run->psw_mask == 0, "psw_mask == 0 (kvm_run)"); + TEST_ASSERT(vcpu->run->psw_addr == 0, "psw_addr == 0 (kvm_run)"); + TEST_ASSERT(vcpu->run->psw_mask == 0, "psw_mask == 0 (kvm_run)"); - vcpu_fpu_get(vm, VCPU_ID, &fpu); + vcpu_fpu_get(vcpu->vm, vcpu->id, &fpu); TEST_ASSERT(!fpu.fpc, "fpc == 0"); - test_one_reg(KVM_REG_S390_GBEA, 1); - test_one_reg(KVM_REG_S390_PP, 0); - test_one_reg(KVM_REG_S390_TODPR, 0); - test_one_reg(KVM_REG_S390_CPU_TIMER, 0); - test_one_reg(KVM_REG_S390_CLOCK_COMP, 0); + test_one_reg(vcpu, KVM_REG_S390_GBEA, 1); + test_one_reg(vcpu, KVM_REG_S390_PP, 0); + test_one_reg(vcpu, KVM_REG_S390_TODPR, 0); + test_one_reg(vcpu, KVM_REG_S390_CPU_TIMER, 0); + test_one_reg(vcpu, KVM_REG_S390_CLOCK_COMP, 0); } -static void assert_normal_noclear(void) +static void assert_normal_noclear(struct kvm_vcpu *vcpu) { + struct kvm_sync_regs *sync_regs = &vcpu->run->s.regs; + TEST_ASSERT(sync_regs->crs[2] == 0x10, "cr2 == 10 (sync_regs)"); TEST_ASSERT(sync_regs->crs[8] == 1, "cr10 == 1 (sync_regs)"); TEST_ASSERT(sync_regs->crs[10] == 1, "cr10 == 1 (sync_regs)"); TEST_ASSERT(sync_regs->crs[11] == -1, "cr11 == -1 (sync_regs)"); } -static void assert_normal(void) +static void assert_normal(struct kvm_vcpu *vcpu) { - test_one_reg(KVM_REG_S390_PFTOKEN, KVM_S390_PFAULT_TOKEN_INVALID); - TEST_ASSERT(sync_regs->pft == KVM_S390_PFAULT_TOKEN_INVALID, + test_one_reg(vcpu, KVM_REG_S390_PFTOKEN, KVM_S390_PFAULT_TOKEN_INVALID); + TEST_ASSERT(vcpu->run->s.regs.pft == KVM_S390_PFAULT_TOKEN_INVALID, "pft == 0xff..... (sync_regs)"); - assert_noirq(); + assert_noirq(vcpu); } -static void inject_irq(int cpu_id) +static void inject_irq(struct kvm_vcpu *vcpu) { struct kvm_s390_irq_state irq_state; struct kvm_s390_irq *irq = &buf[0]; @@ -193,73 +197,86 @@ static void inject_irq(int cpu_id) irq_state.len = sizeof(struct kvm_s390_irq); irq_state.buf = (unsigned long)buf; irq->type = KVM_S390_INT_EMERGENCY; - irq->u.emerg.code = cpu_id; - irqs = __vcpu_ioctl(vm, cpu_id, KVM_S390_SET_IRQ_STATE, &irq_state); + irq->u.emerg.code = vcpu->id; + irqs = __vcpu_ioctl(vcpu->vm, vcpu->id, KVM_S390_SET_IRQ_STATE, &irq_state); TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d\n", errno); } +static struct kvm_vm *create_vm(struct kvm_vcpu **vcpu) +{ + struct kvm_vm *vm; + + vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + + *vcpu = vm_vcpu_add(vm, ARBITRARY_NON_ZERO_VCPU_ID, guest_code_initial); + + return vm; +} + static void test_normal(void) { + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + ksft_print_msg("Testing normal reset\n"); - /* Create VM */ - vm = vm_create_default(VCPU_ID, 0, guest_code_initial); - run = vcpu_state(vm, VCPU_ID); - sync_regs = &run->s.regs; + vm = create_vm(&vcpu); - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - inject_irq(VCPU_ID); + inject_irq(vcpu); - vcpu_ioctl(vm, VCPU_ID, KVM_S390_NORMAL_RESET, 0); + vcpu_ioctl(vm, vcpu->id, KVM_S390_NORMAL_RESET, 0); /* must clears */ - assert_normal(); + assert_normal(vcpu); /* must not clears */ - assert_normal_noclear(); - assert_initial_noclear(); + assert_normal_noclear(vcpu); + assert_initial_noclear(vcpu); kvm_vm_free(vm); } static void test_initial(void) { + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + ksft_print_msg("Testing initial reset\n"); - vm = vm_create_default(VCPU_ID, 0, guest_code_initial); - run = vcpu_state(vm, VCPU_ID); - sync_regs = &run->s.regs; + vm = create_vm(&vcpu); - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - inject_irq(VCPU_ID); + inject_irq(vcpu); - vcpu_ioctl(vm, VCPU_ID, KVM_S390_INITIAL_RESET, 0); + vcpu_ioctl(vm, vcpu->id, KVM_S390_INITIAL_RESET, 0); /* must clears */ - assert_normal(); - assert_initial(); + assert_normal(vcpu); + assert_initial(vcpu); /* must not clears */ - assert_initial_noclear(); + assert_initial_noclear(vcpu); kvm_vm_free(vm); } static void test_clear(void) { + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + ksft_print_msg("Testing clear reset\n"); - vm = vm_create_default(VCPU_ID, 0, guest_code_initial); - run = vcpu_state(vm, VCPU_ID); - sync_regs = &run->s.regs; + vm = create_vm(&vcpu); - vcpu_run(vm, VCPU_ID); + vcpu_run(vm, vcpu->id); - inject_irq(VCPU_ID); + inject_irq(vcpu); - vcpu_ioctl(vm, VCPU_ID, KVM_S390_CLEAR_RESET, 0); + vcpu_ioctl(vm, vcpu->id, KVM_S390_CLEAR_RESET, 0); /* must clears */ - assert_normal(); - assert_initial(); - assert_clear(); + assert_normal(vcpu); + assert_initial(vcpu); + assert_clear(vcpu); kvm_vm_free(vm); } From 5241904f2eb6289dd1e7f7c80f612016afcb00cd Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 12:39:34 -0800 Subject: [PATCH 0426/1436] KVM: selftests: Convert memop away from VCPU_ID Pass around a 'struct kvm_vcpu' object instead of a vCPU ID in s390's memop test. Pass NULL for the vCPU instead of a magic '-1' ID to indicate that an ioctl/test should be done at VM scope. Rename "struct test_vcpu vcpu" to "struct test_info info" in order to avoid naming collisions (this is the bulk of the diff :-( ). Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/s390x/memop.c | 82 ++++++++++++----------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c index 230d4b6301e6..703bf137d6ac 100644 --- a/tools/testing/selftests/kvm/s390x/memop.c +++ b/tools/testing/selftests/kvm/s390x/memop.c @@ -99,21 +99,18 @@ static struct kvm_s390_mem_op ksmo_from_desc(struct mop_desc desc) return ksmo; } -/* vcpu dummy id signifying that vm instead of vcpu ioctl is to occur */ -const uint32_t VM_VCPU_ID = (uint32_t)-1; - -struct test_vcpu { +struct test_info { struct kvm_vm *vm; - uint32_t id; + struct kvm_vcpu *vcpu; }; #define PRINT_MEMOP false -static void print_memop(uint32_t vcpu_id, const struct kvm_s390_mem_op *ksmo) +static void print_memop(struct kvm_vcpu *vcpu, const struct kvm_s390_mem_op *ksmo) { if (!PRINT_MEMOP) return; - if (vcpu_id == VM_VCPU_ID) + if (!vcpu) printf("vm memop("); else printf("vcpu memop("); @@ -148,25 +145,29 @@ static void print_memop(uint32_t vcpu_id, const struct kvm_s390_mem_op *ksmo) puts(")"); } -static void memop_ioctl(struct test_vcpu vcpu, struct kvm_s390_mem_op *ksmo) +static void memop_ioctl(struct test_info info, struct kvm_s390_mem_op *ksmo) { - if (vcpu.id == VM_VCPU_ID) - vm_ioctl(vcpu.vm, KVM_S390_MEM_OP, ksmo); + struct kvm_vcpu *vcpu = info.vcpu; + + if (!vcpu) + vm_ioctl(info.vm, KVM_S390_MEM_OP, ksmo); else - vcpu_ioctl(vcpu.vm, vcpu.id, KVM_S390_MEM_OP, ksmo); + vcpu_ioctl(vcpu->vm, vcpu->id, KVM_S390_MEM_OP, ksmo); } -static int err_memop_ioctl(struct test_vcpu vcpu, struct kvm_s390_mem_op *ksmo) +static int err_memop_ioctl(struct test_info info, struct kvm_s390_mem_op *ksmo) { - if (vcpu.id == VM_VCPU_ID) - return __vm_ioctl(vcpu.vm, KVM_S390_MEM_OP, ksmo); + struct kvm_vcpu *vcpu = info.vcpu; + + if (!vcpu) + return __vm_ioctl(info.vm, KVM_S390_MEM_OP, ksmo); else - return __vcpu_ioctl(vcpu.vm, vcpu.id, KVM_S390_MEM_OP, ksmo); + return __vcpu_ioctl(vcpu->vm, vcpu->id, KVM_S390_MEM_OP, ksmo); } -#define MEMOP(err, vcpu_p, mop_target_p, access_mode_p, buf_p, size_p, ...) \ +#define MEMOP(err, info_p, mop_target_p, access_mode_p, buf_p, size_p, ...) \ ({ \ - struct test_vcpu __vcpu = (vcpu_p); \ + struct test_info __info = (info_p); \ struct mop_desc __desc = { \ .target = (mop_target_p), \ .mode = (access_mode_p), \ @@ -178,13 +179,13 @@ static int err_memop_ioctl(struct test_vcpu vcpu, struct kvm_s390_mem_op *ksmo) \ if (__desc._gaddr_v) { \ if (__desc.target == ABSOLUTE) \ - __desc.gaddr = addr_gva2gpa(__vcpu.vm, __desc.gaddr_v); \ + __desc.gaddr = addr_gva2gpa(__info.vm, __desc.gaddr_v); \ else \ __desc.gaddr = __desc.gaddr_v; \ } \ __ksmo = ksmo_from_desc(__desc); \ - print_memop(__vcpu.id, &__ksmo); \ - err##memop_ioctl(__vcpu, &__ksmo); \ + print_memop(__info.vcpu, &__ksmo); \ + err##memop_ioctl(__info, &__ksmo); \ }) #define MOP(...) MEMOP(, __VA_ARGS__) @@ -201,7 +202,6 @@ static int err_memop_ioctl(struct test_vcpu vcpu, struct kvm_s390_mem_op *ksmo) #define CHECK_N_DO(f, ...) ({ f(__VA_ARGS__, CHECK_ONLY); f(__VA_ARGS__); }) -#define VCPU_ID 1 #define PAGE_SHIFT 12 #define PAGE_SIZE (1ULL << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE - 1)) @@ -213,21 +213,22 @@ static uint8_t mem2[65536]; struct test_default { struct kvm_vm *kvm_vm; - struct test_vcpu vm; - struct test_vcpu vcpu; + struct test_info vm; + struct test_info vcpu; struct kvm_run *run; int size; }; static struct test_default test_default_init(void *guest_code) { + struct kvm_vcpu *vcpu; struct test_default t; t.size = min((size_t)kvm_check_cap(KVM_CAP_S390_MEM_OP), sizeof(mem1)); - t.kvm_vm = vm_create_default(VCPU_ID, 0, guest_code); - t.vm = (struct test_vcpu) { t.kvm_vm, VM_VCPU_ID }; - t.vcpu = (struct test_vcpu) { t.kvm_vm, VCPU_ID }; - t.run = vcpu_state(t.kvm_vm, VCPU_ID); + t.kvm_vm = vm_create_with_one_vcpu(&vcpu, guest_code); + t.vm = (struct test_info) { t.kvm_vm, NULL }; + t.vcpu = (struct test_info) { t.kvm_vm, vcpu }; + t.run = vcpu->run; return t; } @@ -242,14 +243,15 @@ enum stage { STAGE_COPIED, }; -#define HOST_SYNC(vcpu_p, stage) \ +#define HOST_SYNC(info_p, stage) \ ({ \ - struct test_vcpu __vcpu = (vcpu_p); \ + struct test_info __info = (info_p); \ + struct kvm_vcpu *__vcpu = __info.vcpu; \ struct ucall uc; \ int __stage = (stage); \ \ - vcpu_run(__vcpu.vm, __vcpu.id); \ - get_ucall(__vcpu.vm, __vcpu.id, &uc); \ + vcpu_run(__vcpu->vm, __vcpu->id); \ + get_ucall(__vcpu->vm, __vcpu->id, &uc); \ ASSERT_EQ(uc.cmd, UCALL_SYNC); \ ASSERT_EQ(uc.args[1], __stage); \ }) \ @@ -268,7 +270,7 @@ static void prepare_mem12(void) #define DEFAULT_WRITE_READ(copy_cpu, mop_cpu, mop_target_p, size, ...) \ ({ \ - struct test_vcpu __copy_cpu = (copy_cpu), __mop_cpu = (mop_cpu); \ + struct test_info __copy_cpu = (copy_cpu), __mop_cpu = (mop_cpu); \ enum mop_target __target = (mop_target_p); \ uint32_t __size = (size); \ \ @@ -283,7 +285,7 @@ static void prepare_mem12(void) #define DEFAULT_READ(copy_cpu, mop_cpu, mop_target_p, size, ...) \ ({ \ - struct test_vcpu __copy_cpu = (copy_cpu), __mop_cpu = (mop_cpu); \ + struct test_info __copy_cpu = (copy_cpu), __mop_cpu = (mop_cpu); \ enum mop_target __target = (mop_target_p); \ uint32_t __size = (size); \ \ @@ -624,34 +626,34 @@ static void guest_idle(void) GUEST_SYNC(STAGE_IDLED); } -static void _test_errors_common(struct test_vcpu vcpu, enum mop_target target, int size) +static void _test_errors_common(struct test_info info, enum mop_target target, int size) { int rv; /* Bad size: */ - rv = ERR_MOP(vcpu, target, WRITE, mem1, -1, GADDR_V(mem1)); + rv = ERR_MOP(info, target, WRITE, mem1, -1, GADDR_V(mem1)); TEST_ASSERT(rv == -1 && errno == E2BIG, "ioctl allows insane sizes"); /* Zero size: */ - rv = ERR_MOP(vcpu, target, WRITE, mem1, 0, GADDR_V(mem1)); + rv = ERR_MOP(info, target, WRITE, mem1, 0, GADDR_V(mem1)); TEST_ASSERT(rv == -1 && (errno == EINVAL || errno == ENOMEM), "ioctl allows 0 as size"); /* Bad flags: */ - rv = ERR_MOP(vcpu, target, WRITE, mem1, size, GADDR_V(mem1), SET_FLAGS(-1)); + rv = ERR_MOP(info, target, WRITE, mem1, size, GADDR_V(mem1), SET_FLAGS(-1)); TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows all flags"); /* Bad guest address: */ - rv = ERR_MOP(vcpu, target, WRITE, mem1, size, GADDR((void *)~0xfffUL), CHECK_ONLY); + rv = ERR_MOP(info, target, WRITE, mem1, size, GADDR((void *)~0xfffUL), CHECK_ONLY); TEST_ASSERT(rv > 0, "ioctl does not report bad guest memory access"); /* Bad host address: */ - rv = ERR_MOP(vcpu, target, WRITE, 0, size, GADDR_V(mem1)); + rv = ERR_MOP(info, target, WRITE, 0, size, GADDR_V(mem1)); TEST_ASSERT(rv == -1 && errno == EFAULT, "ioctl does not report bad host memory address"); /* Bad key: */ - rv = ERR_MOP(vcpu, target, WRITE, mem1, size, GADDR_V(mem1), KEY(17)); + rv = ERR_MOP(info, target, WRITE, mem1, size, GADDR_V(mem1), KEY(17)); TEST_ASSERT(rv == -1 && errno == EINVAL, "ioctl allows invalid key"); } From 7cdcdfe50d8d68b7b9ba2e1b0345ff47fdda390f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 12:40:18 -0800 Subject: [PATCH 0427/1436] KVM: selftests: Convert s390x/diag318_test_handler away from VCPU_ID Convert diag318_test_handler to use vm_create_with_vcpus() and pass around a 'struct kvm_vcpu' object instead of passing around vCPU IDs. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==6. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/lib/s390x/diag318_test_handler.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c b/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c index 86b9e611ad87..21c31fe10c1a 100644 --- a/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c +++ b/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c @@ -8,8 +8,6 @@ #include "test_util.h" #include "kvm_util.h" -#define VCPU_ID 6 - #define ICPT_INSTRUCTION 0x04 #define IPA0_DIAG 0x8300 @@ -27,14 +25,15 @@ static void guest_code(void) */ static uint64_t diag318_handler(void) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; uint64_t reg; uint64_t diag318_info; - vm = vm_create_default(VCPU_ID, 0, guest_code); - vcpu_run(vm, VCPU_ID); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + vcpu_run(vm, vcpu->id); + run = vcpu->run; TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, "DIAGNOSE 0x0318 instruction was not intercepted"); From 6a9d37efa2cf3e2ba551c660fe52496742cbfbc4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 21 Apr 2022 08:34:06 -0700 Subject: [PATCH 0428/1436] KVM: selftests: Convert tprot away from VCPU_ID Convert tprot to use vm_create_with_vcpus() and pass around a 'struct kvm_vcpu' object instead of passing around vCPU IDs. Note, this is a "functional" change in the sense that the test now creates a vCPU with vcpu_id==0 instead of vcpu_id==1. The non-zero VCPU_ID was 100% arbitrary and added little to no validation coverage. If testing non-zero vCPU IDs is desirable for generic tests, that can be done in the future by tweaking the VM creation helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/s390x/tprot.c | 31 +++++++++++------------ 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/tools/testing/selftests/kvm/s390x/tprot.c b/tools/testing/selftests/kvm/s390x/tprot.c index 14d74a9e7b3d..a82a8d1dc6c8 100644 --- a/tools/testing/selftests/kvm/s390x/tprot.c +++ b/tools/testing/selftests/kvm/s390x/tprot.c @@ -15,8 +15,6 @@ #define CR0_FETCH_PROTECTION_OVERRIDE (1UL << (63 - 38)) #define CR0_STORAGE_PROTECTION_OVERRIDE (1UL << (63 - 39)) -#define VCPU_ID 1 - static __aligned(PAGE_SIZE) uint8_t pages[2][PAGE_SIZE]; static uint8_t *const page_store_prot = pages[0]; static uint8_t *const page_fetch_prot = pages[1]; @@ -183,14 +181,14 @@ static void guest_code(void) GUEST_SYNC(perform_next_stage(&i, mapped_0)); } -#define HOST_SYNC_NO_TAP(vmp, stage) \ +#define HOST_SYNC_NO_TAP(vcpup, stage) \ ({ \ - struct kvm_vm *__vm = (vmp); \ + struct kvm_vcpu *__vcpu = (vcpup); \ struct ucall uc; \ int __stage = (stage); \ \ - vcpu_run(__vm, VCPU_ID); \ - get_ucall(__vm, VCPU_ID, &uc); \ + vcpu_run(__vcpu->vm, __vcpu->id); \ + get_ucall(__vcpu->vm, __vcpu->id, &uc); \ if (uc.cmd == UCALL_ABORT) { \ TEST_FAIL("line %lu: %s, hints: %lu, %lu", uc.args[1], \ (const char *)uc.args[0], uc.args[2], uc.args[3]); \ @@ -199,14 +197,15 @@ static void guest_code(void) ASSERT_EQ(uc.args[1], __stage); \ }) -#define HOST_SYNC(vmp, stage) \ +#define HOST_SYNC(vcpu, stage) \ ({ \ - HOST_SYNC_NO_TAP(vmp, stage); \ + HOST_SYNC_NO_TAP(vcpu, stage); \ ksft_test_result_pass("" #stage "\n"); \ }) int main(int argc, char *argv[]) { + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; vm_vaddr_t guest_0_page; @@ -214,31 +213,31 @@ int main(int argc, char *argv[]) ksft_print_header(); ksft_set_plan(STAGE_END); - vm = vm_create_default(VCPU_ID, 0, guest_code); - run = vcpu_state(vm, VCPU_ID); + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + run = vcpu->run; - HOST_SYNC(vm, STAGE_INIT_SIMPLE); + HOST_SYNC(vcpu, STAGE_INIT_SIMPLE); mprotect(addr_gva2hva(vm, (vm_vaddr_t)pages), PAGE_SIZE * 2, PROT_READ); - HOST_SYNC(vm, TEST_SIMPLE); + HOST_SYNC(vcpu, TEST_SIMPLE); guest_0_page = vm_vaddr_alloc(vm, PAGE_SIZE, 0); if (guest_0_page != 0) { /* Use NO_TAP so we don't get a PASS print */ - HOST_SYNC_NO_TAP(vm, STAGE_INIT_FETCH_PROT_OVERRIDE); + HOST_SYNC_NO_TAP(vcpu, STAGE_INIT_FETCH_PROT_OVERRIDE); ksft_test_result_skip("STAGE_INIT_FETCH_PROT_OVERRIDE - " "Did not allocate page at 0\n"); } else { - HOST_SYNC(vm, STAGE_INIT_FETCH_PROT_OVERRIDE); + HOST_SYNC(vcpu, STAGE_INIT_FETCH_PROT_OVERRIDE); } if (guest_0_page == 0) mprotect(addr_gva2hva(vm, (vm_vaddr_t)0), PAGE_SIZE, PROT_READ); run->s.regs.crs[0] |= CR0_FETCH_PROTECTION_OVERRIDE; run->kvm_dirty_regs = KVM_SYNC_CRS; - HOST_SYNC(vm, TEST_FETCH_PROT_OVERRIDE); + HOST_SYNC(vcpu, TEST_FETCH_PROT_OVERRIDE); run->s.regs.crs[0] |= CR0_STORAGE_PROTECTION_OVERRIDE; run->kvm_dirty_regs = KVM_SYNC_CRS; - HOST_SYNC(vm, TEST_STORAGE_PROT_OVERRIDE); + HOST_SYNC(vcpu, TEST_STORAGE_PROT_OVERRIDE); kvm_vm_free(vm); From 46647c65e1e618cc75961ef4d887f90ba7e18431 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 18 Apr 2022 17:35:33 -0700 Subject: [PATCH 0429/1436] KVM: selftests: Use vm_create() in tsc_scaling_sync Use vm_create() instead of vm_create_default_with_vcpus() in tsc_scaling_sync. The existing call doesn't create any vCPUs, and the guest_code() entry point is set when vm_vcpu_add_default() is invoked. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c index 2411215e7ae8..728b252597cc 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - vm = vm_create_default_with_vcpus(0, DEFAULT_STACK_PGS * NR_TEST_VCPUS, 0, guest_code, NULL); + vm = vm_create(DEFAULT_GUEST_PHY_PAGES + DEFAULT_STACK_PGS * NR_TEST_VCPUS); vm_ioctl(vm, KVM_SET_TSC_KHZ, (void *) TEST_TSC_KHZ); pthread_spin_init(&create_lock, PTHREAD_PROCESS_PRIVATE); From 3468fd7d883110e481dfb8c8c7b802dc252ab186 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 19 Apr 2022 11:35:28 -0700 Subject: [PATCH 0430/1436] KVM: selftests: Use vm_create_with_vcpus() in max_guest_memory_test Use vm_create_with_vcpus() in max_guest_memory_test and reference vCPUs by their 'struct kvm_vcpu' object instead of their ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/max_guest_memory_test.c | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/max_guest_memory_test.c b/tools/testing/selftests/kvm/max_guest_memory_test.c index 15f046e19cb2..d59918d5cbe2 100644 --- a/tools/testing/selftests/kvm/max_guest_memory_test.c +++ b/tools/testing/selftests/kvm/max_guest_memory_test.c @@ -28,8 +28,7 @@ static void guest_code(uint64_t start_gpa, uint64_t end_gpa, uint64_t stride) } struct vcpu_info { - struct kvm_vm *vm; - uint32_t id; + struct kvm_vcpu *vcpu; uint64_t start_gpa; uint64_t end_gpa; }; @@ -60,12 +59,13 @@ static void run_vcpu(struct kvm_vm *vm, uint32_t vcpu_id) static void *vcpu_worker(void *data) { - struct vcpu_info *vcpu = data; + struct vcpu_info *info = data; + struct kvm_vcpu *vcpu = info->vcpu; struct kvm_vm *vm = vcpu->vm; struct kvm_sregs sregs; struct kvm_regs regs; - vcpu_args_set(vm, vcpu->id, 3, vcpu->start_gpa, vcpu->end_gpa, + vcpu_args_set(vm, vcpu->id, 3, info->start_gpa, info->end_gpa, vm_get_page_size(vm)); /* Snapshot regs before the first run. */ @@ -89,8 +89,8 @@ static void *vcpu_worker(void *data) return NULL; } -static pthread_t *spawn_workers(struct kvm_vm *vm, uint64_t start_gpa, - uint64_t end_gpa) +static pthread_t *spawn_workers(struct kvm_vm *vm, struct kvm_vcpu **vcpus, + uint64_t start_gpa, uint64_t end_gpa) { struct vcpu_info *info; uint64_t gpa, nr_bytes; @@ -108,8 +108,7 @@ static pthread_t *spawn_workers(struct kvm_vm *vm, uint64_t start_gpa, TEST_ASSERT(nr_bytes, "C'mon, no way you have %d CPUs", nr_vcpus); for (i = 0, gpa = start_gpa; i < nr_vcpus; i++, gpa += nr_bytes) { - info[i].vm = vm; - info[i].id = i; + info[i].vcpu = vcpus[i]; info[i].start_gpa = gpa; info[i].end_gpa = gpa + nr_bytes; pthread_create(&threads[i], NULL, vcpu_worker, &info[i]); @@ -172,6 +171,7 @@ int main(int argc, char *argv[]) uint64_t max_gpa, gpa, slot_size, max_mem, i; int max_slots, slot, opt, fd; bool hugepages = false; + struct kvm_vcpu **vcpus; pthread_t *threads; struct kvm_vm *vm; void *mem; @@ -215,7 +215,10 @@ int main(int argc, char *argv[]) } } - vm = vm_create_default_with_vcpus(nr_vcpus, 0, 0, guest_code, NULL); + vcpus = malloc(nr_vcpus * sizeof(*vcpus)); + TEST_ASSERT(vcpus, "Failed to allocate vCPU array"); + + vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus); max_gpa = vm_get_max_gfn(vm) << vm_get_page_shift(vm); TEST_ASSERT(max_gpa > (4 * slot_size), "MAXPHYADDR <4gb "); @@ -252,7 +255,10 @@ int main(int argc, char *argv[]) } atomic_set(&rendezvous, nr_vcpus + 1); - threads = spawn_workers(vm, start_gpa, gpa); + threads = spawn_workers(vm, vcpus, start_gpa, gpa); + + free(vcpus); + vcpus = NULL; pr_info("Running with %lugb of guest memory and %u vCPUs\n", (gpa - start_gpa) / size_1gb, nr_vcpus); From 82ba83cbb76aa6480729f98d3fdeeb162a5cea30 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 12:45:22 -0800 Subject: [PATCH 0431/1436] KVM: selftests: Drop vm_create_default* helpers Drop all vm_create_default*() helpers, the "default" naming turned out to terrible as wasn't extensible (hard to have multiple defaults), was a lie (half the settings were default, half weren't), and failed to capture relationships between helpers, e.g. compared with the kernel's standard underscores pattern. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 23 ------------------- tools/testing/selftests/kvm/lib/kvm_util.c | 23 +++++-------------- 2 files changed, 6 insertions(+), 40 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 9c29b6797ce8..90521c5716b1 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -559,29 +559,6 @@ static inline struct kvm_vm *vm_create(uint64_t nr_pages) return __vm_create(VM_MODE_DEFAULT, nr_pages); } -/* - * Create a VM with reasonable defaults - * - * Input Args: - * vcpuid - The id of the single VCPU to add to the VM. - * extra_mem_pages - The number of extra pages to add (this will - * decide how much extra space we will need to - * setup the page tables using memslot 0) - * guest_code - The vCPU's entry point - * - * Output Args: None - * - * Return: - * Pointer to opaque structure that describes the created VM. - */ -struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, - void *guest_code); - -/* Same as vm_create_default, but can be used for more than one vcpu */ -struct kvm_vm *vm_create_default_with_vcpus(uint32_t nr_vcpus, uint64_t extra_mem_pages, - uint32_t num_percpu_pages, void *guest_code, - uint32_t vcpuids[]); - /* Like vm_create_default_with_vcpus, but accepts mode and slot0 memory as a parameter */ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, uint64_t slot0_mem_pages, uint64_t extra_mem_pages, diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 3015d490a8f6..137ffa1bc1f2 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -337,28 +337,17 @@ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus return vm; } -struct kvm_vm *vm_create_default_with_vcpus(uint32_t nr_vcpus, uint64_t extra_mem_pages, - uint32_t num_percpu_pages, void *guest_code, - uint32_t vcpuids[]) -{ - return __vm_create_with_vcpus(VM_MODE_DEFAULT, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, - extra_mem_pages, num_percpu_pages, guest_code, vcpuids, NULL); -} - -struct kvm_vm *vm_create_default(uint32_t vcpuid, uint64_t extra_mem_pages, - void *guest_code) -{ - return vm_create_default_with_vcpus(1, extra_mem_pages, 0, guest_code, - (uint32_t []){ vcpuid }); -} - struct kvm_vm *__vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, uint64_t extra_mem_pages, void *guest_code) { - struct kvm_vm *vm = vm_create_default(0, extra_mem_pages, guest_code); + struct kvm_vcpu *vcpus[1]; + struct kvm_vm *vm; - *vcpu = vcpu_get(vm, 0); + vm = __vm_create_with_vcpus(VM_MODE_DEFAULT, 1, DEFAULT_GUEST_PHY_PAGES, + extra_mem_pages, 0, guest_code, NULL, vcpus); + + *vcpu = vcpus[0]; return vm; } From 5114c3e2f1b90ca5417c42d3eb17fcf5ac4dc724 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 12:49:13 -0800 Subject: [PATCH 0432/1436] KVM: selftests: Drop @vcpuids param from VM creators Drop the @vcpuids parameter from VM creators now that there are no users. Allowing tests to specify IDs was a gigantic mistake as it resulted in tests with arbitrary and ultimately meaningless IDs that differed only because the author used test X intead of test Y as the source for copy+paste (the de facto standard way to create a KVM selftest). Except for literally two tests, x86's set_boot_cpu_id and s390's resets, tests do not and should not care about the vCPU ID. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/include/kvm_util_base.h | 4 ++-- tools/testing/selftests/kvm/kvm_page_table_test.c | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 8 +++----- tools/testing/selftests/kvm/lib/perf_test_util.c | 2 +- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 90521c5716b1..f409bae336d5 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -563,7 +563,7 @@ static inline struct kvm_vm *vm_create(uint64_t nr_pages) struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, uint64_t slot0_mem_pages, uint64_t extra_mem_pages, uint32_t num_percpu_pages, void *guest_code, - uint32_t vcpuids[], struct kvm_vcpu *vcpus[]); + struct kvm_vcpu *vcpus[]); static inline struct kvm_vm *vm_create_with_vcpus(uint32_t nr_vcpus, void *guest_code, @@ -571,7 +571,7 @@ static inline struct kvm_vm *vm_create_with_vcpus(uint32_t nr_vcpus, { return __vm_create_with_vcpus(VM_MODE_DEFAULT, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, 0, 0, - guest_code, NULL, vcpus); + guest_code, vcpus); } /* diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c index e91bc7f1400d..76031be195fa 100644 --- a/tools/testing/selftests/kvm/kvm_page_table_test.c +++ b/tools/testing/selftests/kvm/kvm_page_table_test.c @@ -269,7 +269,7 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg) /* Create a VM with enough guest pages */ guest_num_pages = test_mem_size / guest_page_size; vm = __vm_create_with_vcpus(mode, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, - guest_num_pages, 0, guest_code, NULL, NULL); + guest_num_pages, 0, guest_code, NULL); /* Align down GPA of the testing memslot */ if (!p->phys_offset) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 137ffa1bc1f2..c338713d8245 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -299,7 +299,7 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t nr_pages) struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, uint64_t slot0_mem_pages, uint64_t extra_mem_pages, uint32_t num_percpu_pages, void *guest_code, - uint32_t vcpuids[], struct kvm_vcpu *vcpus[]) + struct kvm_vcpu *vcpus[]) { uint64_t vcpu_pages, extra_pg_pages, pages; struct kvm_vcpu *vcpu; @@ -327,9 +327,7 @@ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus vm = __vm_create(mode, pages); for (i = 0; i < nr_vcpus; ++i) { - uint32_t vcpuid = vcpuids ? vcpuids[i] : i; - - vcpu = vm_vcpu_add(vm, vcpuid, guest_code); + vcpu = vm_vcpu_add(vm, i, guest_code); if (vcpus) vcpus[i] = vcpu; } @@ -345,7 +343,7 @@ struct kvm_vm *__vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, struct kvm_vm *vm; vm = __vm_create_with_vcpus(VM_MODE_DEFAULT, 1, DEFAULT_GUEST_PHY_PAGES, - extra_mem_pages, 0, guest_code, NULL, vcpus); + extra_mem_pages, 0, guest_code, vcpus); *vcpu = vcpus[0]; return vm; diff --git a/tools/testing/selftests/kvm/lib/perf_test_util.c b/tools/testing/selftests/kvm/lib/perf_test_util.c index d3ff05f00653..05f65c9292eb 100644 --- a/tools/testing/selftests/kvm/lib/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/perf_test_util.c @@ -149,7 +149,7 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, */ vm = __vm_create_with_vcpus(mode, vcpus, DEFAULT_GUEST_PHY_PAGES, slot0_pages + guest_num_pages, 0, - perf_test_guest_code, NULL, NULL); + perf_test_guest_code, NULL); pta->vm = vm; From 0f678e732099f1cd9b42461708374e14cc63847f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 13:06:18 -0800 Subject: [PATCH 0433/1436] KVM: selftests: Convert kvm_page_table_test away from reliance on vcpu_id Reference vCPUs by their 'struct kvm_vcpu' object in kvm_page_table_test instead of by their ID. This moves selftests one step closer towards taking a 'struct kvm_vcpu *' instead of VM+vcpu_id for vCPU helpers. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/kvm_page_table_test.c | 62 +++++++------------ 1 file changed, 21 insertions(+), 41 deletions(-) diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c index 76031be195fa..b577b5999c95 100644 --- a/tools/testing/selftests/kvm/kvm_page_table_test.c +++ b/tools/testing/selftests/kvm/kvm_page_table_test.c @@ -46,11 +46,6 @@ static const char * const test_stage_string[] = { "KVM_ADJUST_MAPPINGS", }; -struct vcpu_args { - int vcpu_id; - bool vcpu_write; -}; - struct test_args { struct kvm_vm *vm; uint64_t guest_test_virt_mem; @@ -60,7 +55,7 @@ struct test_args { uint64_t large_num_pages; uint64_t host_pages_per_lpage; enum vm_mem_backing_src_type src_type; - struct vcpu_args vcpu_args[KVM_MAX_VCPUS]; + struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; }; /* @@ -92,17 +87,13 @@ static uint64_t guest_test_phys_mem; */ static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM; -static void guest_code(int vcpu_id) +static void guest_code(bool do_write) { struct test_args *p = &test_args; - struct vcpu_args *vcpu_args = &p->vcpu_args[vcpu_id]; enum test_stage *current_stage = &guest_test_stage; uint64_t addr; int i, j; - /* Make sure vCPU args data structure is not corrupt */ - GUEST_ASSERT(vcpu_args->vcpu_id == vcpu_id); - while (true) { addr = p->guest_test_virt_mem; @@ -123,7 +114,7 @@ static void guest_code(int vcpu_id) */ case KVM_CREATE_MAPPINGS: for (i = 0; i < p->large_num_pages; i++) { - if (vcpu_args->vcpu_write) + if (do_write) *(uint64_t *)addr = 0x0123456789ABCDEF; else READ_ONCE(*(uint64_t *)addr); @@ -193,17 +184,15 @@ static void guest_code(int vcpu_id) static void *vcpu_worker(void *data) { - int ret; - struct vcpu_args *vcpu_args = data; struct kvm_vm *vm = test_args.vm; - int vcpu_id = vcpu_args->vcpu_id; - struct kvm_run *run; + struct kvm_vcpu *vcpu = data; + bool do_write = !(vcpu->id % 2); struct timespec start; struct timespec ts_diff; enum test_stage stage; + int ret; - vcpu_args_set(vm, vcpu_id, 1, vcpu_id); - run = vcpu_state(vm, vcpu_id); + vcpu_args_set(vm, vcpu->id, 1, do_write); while (!READ_ONCE(host_quit)) { ret = sem_wait(&test_stage_updated); @@ -213,15 +202,15 @@ static void *vcpu_worker(void *data) return NULL; clock_gettime(CLOCK_MONOTONIC_RAW, &start); - ret = _vcpu_run(vm, vcpu_id); + ret = _vcpu_run(vm, vcpu->id); ts_diff = timespec_elapsed(start); TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); - TEST_ASSERT(get_ucall(vm, vcpu_id, NULL) == UCALL_SYNC, + TEST_ASSERT(get_ucall(vm, vcpu->id, NULL) == UCALL_SYNC, "Invalid guest sync status: exit_reason=%s\n", - exit_reason_str(run->exit_reason)); + exit_reason_str(vcpu->run->exit_reason)); - pr_debug("Got sync event from vCPU %d\n", vcpu_id); + pr_debug("Got sync event from vCPU %d\n", vcpu->id); stage = READ_ONCE(*current_stage); /* @@ -230,7 +219,7 @@ static void *vcpu_worker(void *data) */ pr_debug("vCPU %d has completed stage %s\n" "execution time is: %ld.%.9lds\n\n", - vcpu_id, test_stage_string[stage], + vcpu->id, test_stage_string[stage], ts_diff.tv_sec, ts_diff.tv_nsec); ret = sem_post(&test_stage_completed); @@ -250,7 +239,6 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg) { int ret; struct test_params *p = arg; - struct vcpu_args *vcpu_args; enum vm_mem_backing_src_type src_type = p->src_type; uint64_t large_page_size = get_backing_src_pagesz(src_type); uint64_t guest_page_size = vm_guest_mode_params[mode].page_size; @@ -260,7 +248,6 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg) uint64_t alignment; void *host_test_mem; struct kvm_vm *vm; - int vcpu_id; /* Align up the test memory size */ alignment = max(large_page_size, guest_page_size); @@ -269,7 +256,8 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg) /* Create a VM with enough guest pages */ guest_num_pages = test_mem_size / guest_page_size; vm = __vm_create_with_vcpus(mode, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, - guest_num_pages, 0, guest_code, NULL); + guest_num_pages, 0, guest_code, + test_args.vcpus); /* Align down GPA of the testing memslot */ if (!p->phys_offset) @@ -292,12 +280,6 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg) test_args.host_pages_per_lpage = large_page_size / host_page_size; test_args.src_type = src_type; - for (vcpu_id = 0; vcpu_id < KVM_MAX_VCPUS; vcpu_id++) { - vcpu_args = &test_args.vcpu_args[vcpu_id]; - vcpu_args->vcpu_id = vcpu_id; - vcpu_args->vcpu_write = !(vcpu_id % 2); - } - /* Add an extra memory slot with specified backing src type */ vm_userspace_mem_region_add(vm, src_type, guest_test_phys_mem, TEST_MEM_SLOT_INDEX, guest_num_pages, 0); @@ -363,12 +345,11 @@ static void vcpus_complete_new_stage(enum test_stage stage) static void run_test(enum vm_guest_mode mode, void *arg) { - int ret; pthread_t *vcpu_threads; struct kvm_vm *vm; - int vcpu_id; struct timespec start; struct timespec ts_diff; + int ret, i; /* Create VM with vCPUs and make some pre-initialization */ vm = pre_init_before_test(mode, arg); @@ -379,10 +360,9 @@ static void run_test(enum vm_guest_mode mode, void *arg) host_quit = false; *current_stage = KVM_BEFORE_MAPPINGS; - for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) { - pthread_create(&vcpu_threads[vcpu_id], NULL, vcpu_worker, - &test_args.vcpu_args[vcpu_id]); - } + for (i = 0; i < nr_vcpus; i++) + pthread_create(&vcpu_threads[i], NULL, vcpu_worker, + test_args.vcpus[i]); vcpus_complete_new_stage(*current_stage); pr_info("Started all vCPUs successfully\n"); @@ -424,13 +404,13 @@ static void run_test(enum vm_guest_mode mode, void *arg) /* Tell the vcpu thread to quit */ host_quit = true; - for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) { + for (i = 0; i < nr_vcpus; i++) { ret = sem_post(&test_stage_updated); TEST_ASSERT(ret == 0, "Error in sem_post"); } - for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) - pthread_join(vcpu_threads[vcpu_id], NULL); + for (i = 0; i < nr_vcpus; i++) + pthread_join(vcpu_threads[i], NULL); ret = sem_destroy(&test_stage_updated); TEST_ASSERT(ret == 0, "Error in sem_destroy"); From e813129a3dea6588e57ebfebae75cef6946a89d1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 16:16:32 -0800 Subject: [PATCH 0434/1436] KVM: selftests: Convert kvm_binary_stats_test away from vCPU IDs Track vCPUs by their 'struct kvm_vcpu' object in kvm_binary_stats_test, not by their ID. The per-vCPU helpers will soon take a vCPU instead of a VM+vcpu_id pair. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/kvm_binary_stats_test.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 407e9ea8e6f3..dfc3cf531ced 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -172,9 +172,9 @@ static void vm_stats_test(struct kvm_vm *vm) TEST_ASSERT(fcntl(stats_fd, F_GETFD) == -1, "Stats fd not freed"); } -static void vcpu_stats_test(struct kvm_vm *vm, int vcpu_id) +static void vcpu_stats_test(struct kvm_vcpu *vcpu) { - int stats_fd = vcpu_get_stats_fd(vm, vcpu_id); + int stats_fd = vcpu_get_stats_fd(vcpu->vm, vcpu->id); stats_test(stats_fd); close(stats_fd); @@ -195,6 +195,7 @@ static void vcpu_stats_test(struct kvm_vm *vm, int vcpu_id) int main(int argc, char *argv[]) { int i, j; + struct kvm_vcpu **vcpus; struct kvm_vm **vms; int max_vm = DEFAULT_NUM_VM; int max_vcpu = DEFAULT_NUM_VCPU; @@ -220,17 +221,21 @@ int main(int argc, char *argv[]) /* Create VMs and VCPUs */ vms = malloc(sizeof(vms[0]) * max_vm); TEST_ASSERT(vms, "Allocate memory for storing VM pointers"); + + vcpus = malloc(sizeof(struct kvm_vcpu *) * max_vm * max_vcpu); + TEST_ASSERT(vcpus, "Allocate memory for storing vCPU pointers"); + for (i = 0; i < max_vm; ++i) { vms[i] = vm_create_barebones(); for (j = 0; j < max_vcpu; ++j) - __vm_vcpu_add(vms[i], j); + vcpus[j * max_vcpu + i] = __vm_vcpu_add(vms[i], j); } /* Check stats read for every VM and VCPU */ for (i = 0; i < max_vm; ++i) { vm_stats_test(vms[i]); for (j = 0; j < max_vcpu; ++j) - vcpu_stats_test(vms[i], j); + vcpu_stats_test(vcpus[j * max_vcpu + i]); } for (i = 0; i < max_vm; ++i) From 3cc3eeb165a0afa91365fcf7fa284cd766d2f0bf Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 17 Feb 2022 17:01:58 -0800 Subject: [PATCH 0435/1436] KVM: selftests: Convert get-reg-list away from its "VCPU_ID" Track the vCPU's 'struct kvm_vcpu' object in get-reg-list instead of hardcoding '0' everywhere. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/get-reg-list.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index 22f5e4124304..f0aec117faae 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -411,6 +411,7 @@ static void run_test(struct vcpu_config *c) struct kvm_vcpu_init init = { .target = -1, }; int new_regs = 0, missing_regs = 0, i, n; int failed_get = 0, failed_set = 0, failed_reject = 0; + struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct reg_sublist *s; @@ -418,11 +419,11 @@ static void run_test(struct vcpu_config *c) vm = vm_create_barebones(); prepare_vcpu_init(c, &init); - __vm_vcpu_add(vm, 0); - aarch64_vcpu_setup(vm, 0, &init); - finalize_vcpu(vm, 0, c); + vcpu = __vm_vcpu_add(vm, 0); + aarch64_vcpu_setup(vm, vcpu->id, &init); + finalize_vcpu(vm, vcpu->id, c); - reg_list = vcpu_get_reg_list(vm, 0); + reg_list = vcpu_get_reg_list(vm, vcpu->id); if (fixup_core_regs) core_reg_fixup(); @@ -458,7 +459,7 @@ static void run_test(struct vcpu_config *c) bool reject_reg = false; int ret; - ret = __vcpu_get_reg(vm, 0, reg_list->reg[i], &addr); + ret = __vcpu_get_reg(vm, vcpu->id, reg_list->reg[i], &addr); if (ret) { printf("%s: Failed to get ", config_name(c)); print_reg(c, reg.id); @@ -470,7 +471,7 @@ static void run_test(struct vcpu_config *c) for_each_sublist(c, s) { if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) { reject_reg = true; - ret = __vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, ®); + ret = __vcpu_ioctl(vm, vcpu->id, KVM_SET_ONE_REG, ®); if (ret != -1 || errno != EPERM) { printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno); print_reg(c, reg.id); @@ -482,7 +483,7 @@ static void run_test(struct vcpu_config *c) } if (!reject_reg) { - ret = __vcpu_ioctl(vm, 0, KVM_SET_ONE_REG, ®); + ret = __vcpu_ioctl(vm, vcpu->id, KVM_SET_ONE_REG, ®); if (ret) { printf("%s: Failed to set ", config_name(c)); print_reg(c, reg.id); From 376851f8953a28be237b0a99adef91f422fa8f19 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 20 Apr 2022 12:15:50 -0700 Subject: [PATCH 0436/1436] KVM: selftests: Stop hardcoding vCPU IDs in vcpu_width_config In preparation for taking a vCPU pointer in vCPU-scoped functions, grab the vCPU(s) created by __vm_vcpu_add() and use the ID from the vCPU object instead of hardcoding the ID in ioctl() invocations. Rename init1/init2 => init0/init1 to avoid having odd/confusing code where vcpu0 consumes init1 and vcpu1 consumes init2. Note, this change could easily be done when the functions are converted in the future, and/or the vcpu{0,1} vs. init{1,2} discrepancy could be ignored, but then there would be no opportunity to poke fun at the 1-based counting scheme. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/vcpu_width_config.c | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c index 1dd856a58f5d..e4e66632f05c 100644 --- a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c +++ b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c @@ -15,24 +15,25 @@ /* - * Add a vCPU, run KVM_ARM_VCPU_INIT with @init1, and then - * add another vCPU, and run KVM_ARM_VCPU_INIT with @init2. + * Add a vCPU, run KVM_ARM_VCPU_INIT with @init0, and then + * add another vCPU, and run KVM_ARM_VCPU_INIT with @init1. */ -static int add_init_2vcpus(struct kvm_vcpu_init *init1, - struct kvm_vcpu_init *init2) +static int add_init_2vcpus(struct kvm_vcpu_init *init0, + struct kvm_vcpu_init *init1) { + struct kvm_vcpu *vcpu0, *vcpu1; struct kvm_vm *vm; int ret; vm = vm_create_barebones(); - __vm_vcpu_add(vm, 0); - ret = __vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); + vcpu0 = __vm_vcpu_add(vm, 0); + ret = __vcpu_ioctl(vm, vcpu0->id, KVM_ARM_VCPU_INIT, init0); if (ret) goto free_exit; - __vm_vcpu_add(vm, 1); - ret = __vcpu_ioctl(vm, 1, KVM_ARM_VCPU_INIT, init2); + vcpu1 = __vm_vcpu_add(vm, 1); + ret = __vcpu_ioctl(vm, vcpu1->id, KVM_ARM_VCPU_INIT, init1); free_exit: kvm_vm_free(vm); @@ -40,25 +41,26 @@ free_exit: } /* - * Add two vCPUs, then run KVM_ARM_VCPU_INIT for one vCPU with @init1, - * and run KVM_ARM_VCPU_INIT for another vCPU with @init2. + * Add two vCPUs, then run KVM_ARM_VCPU_INIT for one vCPU with @init0, + * and run KVM_ARM_VCPU_INIT for another vCPU with @init1. */ -static int add_2vcpus_init_2vcpus(struct kvm_vcpu_init *init1, - struct kvm_vcpu_init *init2) +static int add_2vcpus_init_2vcpus(struct kvm_vcpu_init *init0, + struct kvm_vcpu_init *init1) { + struct kvm_vcpu *vcpu0, *vcpu1; struct kvm_vm *vm; int ret; vm = vm_create_barebones(); - __vm_vcpu_add(vm, 0); - __vm_vcpu_add(vm, 1); + vcpu0 = __vm_vcpu_add(vm, 0); + vcpu1 = __vm_vcpu_add(vm, 1); - ret = __vcpu_ioctl(vm, 0, KVM_ARM_VCPU_INIT, init1); + ret = __vcpu_ioctl(vm, vcpu0->id, KVM_ARM_VCPU_INIT, init0); if (ret) goto free_exit; - ret = __vcpu_ioctl(vm, 1, KVM_ARM_VCPU_INIT, init2); + ret = __vcpu_ioctl(vm, vcpu1->id, KVM_ARM_VCPU_INIT, init1); free_exit: kvm_vm_free(vm); @@ -76,7 +78,7 @@ free_exit: */ int main(void) { - struct kvm_vcpu_init init1, init2; + struct kvm_vcpu_init init0, init1; struct kvm_vm *vm; int ret; @@ -85,36 +87,36 @@ int main(void) exit(KSFT_SKIP); } - /* Get the preferred target type and copy that to init2 for later use */ + /* Get the preferred target type and copy that to init1 for later use */ vm = vm_create_barebones(); - vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init1); + vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init0); kvm_vm_free(vm); - init2 = init1; + init1 = init0; /* Test with 64bit vCPUs */ - ret = add_init_2vcpus(&init1, &init1); + ret = add_init_2vcpus(&init0, &init0); TEST_ASSERT(ret == 0, "Configuring 64bit EL1 vCPUs failed unexpectedly"); - ret = add_2vcpus_init_2vcpus(&init1, &init1); + ret = add_2vcpus_init_2vcpus(&init0, &init0); TEST_ASSERT(ret == 0, "Configuring 64bit EL1 vCPUs failed unexpectedly"); /* Test with 32bit vCPUs */ - init1.features[0] = (1 << KVM_ARM_VCPU_EL1_32BIT); - ret = add_init_2vcpus(&init1, &init1); + init0.features[0] = (1 << KVM_ARM_VCPU_EL1_32BIT); + ret = add_init_2vcpus(&init0, &init0); TEST_ASSERT(ret == 0, "Configuring 32bit EL1 vCPUs failed unexpectedly"); - ret = add_2vcpus_init_2vcpus(&init1, &init1); + ret = add_2vcpus_init_2vcpus(&init0, &init0); TEST_ASSERT(ret == 0, "Configuring 32bit EL1 vCPUs failed unexpectedly"); /* Test with mixed-width vCPUs */ - init1.features[0] = 0; - init2.features[0] = (1 << KVM_ARM_VCPU_EL1_32BIT); - ret = add_init_2vcpus(&init1, &init2); + init0.features[0] = 0; + init1.features[0] = (1 << KVM_ARM_VCPU_EL1_32BIT); + ret = add_init_2vcpus(&init0, &init1); TEST_ASSERT(ret != 0, "Configuring mixed-width vCPUs worked unexpectedly"); - ret = add_2vcpus_init_2vcpus(&init1, &init2); + ret = add_2vcpus_init_2vcpus(&init0, &init1); TEST_ASSERT(ret != 0, "Configuring mixed-width vCPUs worked unexpectedly"); From df84cef531ca481cbc1dbce84eb13efc6623e4e1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 13:38:12 -0800 Subject: [PATCH 0437/1436] KVM: selftests: Stop conflating vCPU index and ID in perf tests Track vCPUs by their 'struct kvm_vcpu' object, and stop assuming that a vCPU's ID is the same as its index when referencing a vCPU's metadata. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/access_tracking_perf_test.c | 81 ++++++++--------- .../selftests/kvm/demand_paging_test.c | 36 ++++---- .../selftests/kvm/dirty_log_perf_test.c | 39 ++++---- .../selftests/kvm/include/perf_test_util.h | 7 +- .../selftests/kvm/lib/perf_test_util.c | 88 ++++++++++--------- .../selftests/kvm/lib/x86_64/perf_test_util.c | 8 +- .../kvm/memslot_modification_stress_test.c | 10 +-- 7 files changed, 138 insertions(+), 131 deletions(-) diff --git a/tools/testing/selftests/kvm/access_tracking_perf_test.c b/tools/testing/selftests/kvm/access_tracking_perf_test.c index d8909032317a..86a90222f913 100644 --- a/tools/testing/selftests/kvm/access_tracking_perf_test.c +++ b/tools/testing/selftests/kvm/access_tracking_perf_test.c @@ -74,7 +74,7 @@ struct test_params { uint64_t vcpu_memory_bytes; /* The number of vCPUs to create in the VM. */ - int vcpus; + int nr_vcpus; }; static uint64_t pread_uint64(int fd, const char *filename, uint64_t index) @@ -127,10 +127,12 @@ static void mark_page_idle(int page_idle_fd, uint64_t pfn) "Set page_idle bits for PFN 0x%" PRIx64, pfn); } -static void mark_vcpu_memory_idle(struct kvm_vm *vm, int vcpu_id) +static void mark_vcpu_memory_idle(struct kvm_vm *vm, + struct perf_test_vcpu_args *vcpu_args) { - uint64_t base_gva = perf_test_args.vcpu_args[vcpu_id].gva; - uint64_t pages = perf_test_args.vcpu_args[vcpu_id].pages; + int vcpu_idx = vcpu_args->vcpu_idx; + uint64_t base_gva = vcpu_args->gva; + uint64_t pages = vcpu_args->pages; uint64_t page; uint64_t still_idle = 0; uint64_t no_pfn = 0; @@ -138,7 +140,7 @@ static void mark_vcpu_memory_idle(struct kvm_vm *vm, int vcpu_id) int pagemap_fd; /* If vCPUs are using an overlapping region, let vCPU 0 mark it idle. */ - if (overlap_memory_access && vcpu_id) + if (overlap_memory_access && vcpu_idx) return; page_idle_fd = open("/sys/kernel/mm/page_idle/bitmap", O_RDWR); @@ -170,7 +172,7 @@ static void mark_vcpu_memory_idle(struct kvm_vm *vm, int vcpu_id) */ TEST_ASSERT(no_pfn < pages / 100, "vCPU %d: No PFN for %" PRIu64 " out of %" PRIu64 " pages.", - vcpu_id, no_pfn, pages); + vcpu_idx, no_pfn, pages); /* * Test that at least 90% of memory has been marked idle (the rest might @@ -183,17 +185,16 @@ static void mark_vcpu_memory_idle(struct kvm_vm *vm, int vcpu_id) TEST_ASSERT(still_idle < pages / 10, "vCPU%d: Too many pages still idle (%"PRIu64 " out of %" PRIu64 ").\n", - vcpu_id, still_idle, pages); + vcpu_idx, still_idle, pages); close(page_idle_fd); close(pagemap_fd); } -static void assert_ucall(struct kvm_vm *vm, uint32_t vcpu_id, - uint64_t expected_ucall) +static void assert_ucall(struct kvm_vcpu *vcpu, uint64_t expected_ucall) { struct ucall uc; - uint64_t actual_ucall = get_ucall(vm, vcpu_id, &uc); + uint64_t actual_ucall = get_ucall(vcpu->vm, vcpu->id, &uc); TEST_ASSERT(expected_ucall == actual_ucall, "Guest exited unexpectedly (expected ucall %" PRIu64 @@ -217,28 +218,29 @@ static bool spin_wait_for_next_iteration(int *current_iteration) static void vcpu_thread_main(struct perf_test_vcpu_args *vcpu_args) { + struct kvm_vcpu *vcpu = vcpu_args->vcpu; struct kvm_vm *vm = perf_test_args.vm; - int vcpu_id = vcpu_args->vcpu_id; + int vcpu_idx = vcpu_args->vcpu_idx; int current_iteration = 0; while (spin_wait_for_next_iteration(¤t_iteration)) { switch (READ_ONCE(iteration_work)) { case ITERATION_ACCESS_MEMORY: - vcpu_run(vm, vcpu_id); - assert_ucall(vm, vcpu_id, UCALL_SYNC); + vcpu_run(vm, vcpu->id); + assert_ucall(vcpu, UCALL_SYNC); break; case ITERATION_MARK_IDLE: - mark_vcpu_memory_idle(vm, vcpu_id); + mark_vcpu_memory_idle(vm, vcpu_args); break; }; - vcpu_last_completed_iteration[vcpu_id] = current_iteration; + vcpu_last_completed_iteration[vcpu_idx] = current_iteration; } } -static void spin_wait_for_vcpu(int vcpu_id, int target_iteration) +static void spin_wait_for_vcpu(int vcpu_idx, int target_iteration) { - while (READ_ONCE(vcpu_last_completed_iteration[vcpu_id]) != + while (READ_ONCE(vcpu_last_completed_iteration[vcpu_idx]) != target_iteration) { continue; } @@ -250,12 +252,11 @@ enum access_type { ACCESS_WRITE, }; -static void run_iteration(struct kvm_vm *vm, int vcpus, const char *description) +static void run_iteration(struct kvm_vm *vm, int nr_vcpus, const char *description) { struct timespec ts_start; struct timespec ts_elapsed; - int next_iteration; - int vcpu_id; + int next_iteration, i; /* Kick off the vCPUs by incrementing iteration. */ next_iteration = ++iteration; @@ -263,23 +264,23 @@ static void run_iteration(struct kvm_vm *vm, int vcpus, const char *description) clock_gettime(CLOCK_MONOTONIC, &ts_start); /* Wait for all vCPUs to finish the iteration. */ - for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) - spin_wait_for_vcpu(vcpu_id, next_iteration); + for (i = 0; i < nr_vcpus; i++) + spin_wait_for_vcpu(i, next_iteration); ts_elapsed = timespec_elapsed(ts_start); pr_info("%-30s: %ld.%09lds\n", description, ts_elapsed.tv_sec, ts_elapsed.tv_nsec); } -static void access_memory(struct kvm_vm *vm, int vcpus, enum access_type access, - const char *description) +static void access_memory(struct kvm_vm *vm, int nr_vcpus, + enum access_type access, const char *description) { perf_test_set_wr_fract(vm, (access == ACCESS_READ) ? INT_MAX : 1); iteration_work = ITERATION_ACCESS_MEMORY; - run_iteration(vm, vcpus, description); + run_iteration(vm, nr_vcpus, description); } -static void mark_memory_idle(struct kvm_vm *vm, int vcpus) +static void mark_memory_idle(struct kvm_vm *vm, int nr_vcpus) { /* * Even though this parallelizes the work across vCPUs, this is still a @@ -289,37 +290,37 @@ static void mark_memory_idle(struct kvm_vm *vm, int vcpus) */ pr_debug("Marking VM memory idle (slow)...\n"); iteration_work = ITERATION_MARK_IDLE; - run_iteration(vm, vcpus, "Mark memory idle"); + run_iteration(vm, nr_vcpus, "Mark memory idle"); } static void run_test(enum vm_guest_mode mode, void *arg) { struct test_params *params = arg; struct kvm_vm *vm; - int vcpus = params->vcpus; + int nr_vcpus = params->nr_vcpus; - vm = perf_test_create_vm(mode, vcpus, params->vcpu_memory_bytes, 1, + vm = perf_test_create_vm(mode, nr_vcpus, params->vcpu_memory_bytes, 1, params->backing_src, !overlap_memory_access); - perf_test_start_vcpu_threads(vcpus, vcpu_thread_main); + perf_test_start_vcpu_threads(nr_vcpus, vcpu_thread_main); pr_info("\n"); - access_memory(vm, vcpus, ACCESS_WRITE, "Populating memory"); + access_memory(vm, nr_vcpus, ACCESS_WRITE, "Populating memory"); /* As a control, read and write to the populated memory first. */ - access_memory(vm, vcpus, ACCESS_WRITE, "Writing to populated memory"); - access_memory(vm, vcpus, ACCESS_READ, "Reading from populated memory"); + access_memory(vm, nr_vcpus, ACCESS_WRITE, "Writing to populated memory"); + access_memory(vm, nr_vcpus, ACCESS_READ, "Reading from populated memory"); /* Repeat on memory that has been marked as idle. */ - mark_memory_idle(vm, vcpus); - access_memory(vm, vcpus, ACCESS_WRITE, "Writing to idle memory"); - mark_memory_idle(vm, vcpus); - access_memory(vm, vcpus, ACCESS_READ, "Reading from idle memory"); + mark_memory_idle(vm, nr_vcpus); + access_memory(vm, nr_vcpus, ACCESS_WRITE, "Writing to idle memory"); + mark_memory_idle(vm, nr_vcpus); + access_memory(vm, nr_vcpus, ACCESS_READ, "Reading from idle memory"); /* Set done to signal the vCPU threads to exit */ done = true; - perf_test_join_vcpu_threads(vcpus); + perf_test_join_vcpu_threads(nr_vcpus); perf_test_destroy_vm(vm); } @@ -347,7 +348,7 @@ int main(int argc, char *argv[]) struct test_params params = { .backing_src = DEFAULT_VM_MEM_SRC, .vcpu_memory_bytes = DEFAULT_PER_VCPU_MEM_SIZE, - .vcpus = 1, + .nr_vcpus = 1, }; int page_idle_fd; int opt; @@ -363,7 +364,7 @@ int main(int argc, char *argv[]) params.vcpu_memory_bytes = parse_size(optarg); break; case 'v': - params.vcpus = atoi(optarg); + params.nr_vcpus = atoi(optarg); break; case 'o': overlap_memory_access = true; diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index d8db0a37e973..c46110721088 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -44,28 +44,27 @@ static char *guest_data_prototype; static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) { - int ret; - int vcpu_id = vcpu_args->vcpu_id; + struct kvm_vcpu *vcpu = vcpu_args->vcpu; struct kvm_vm *vm = perf_test_args.vm; - struct kvm_run *run; + int vcpu_idx = vcpu_args->vcpu_idx; + struct kvm_run *run = vcpu->run; struct timespec start; struct timespec ts_diff; - - run = vcpu_state(vm, vcpu_id); + int ret; clock_gettime(CLOCK_MONOTONIC, &start); /* Let the guest access its memory */ - ret = _vcpu_run(vm, vcpu_id); + ret = _vcpu_run(vm, vcpu->id); TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); - if (get_ucall(vm, vcpu_id, NULL) != UCALL_SYNC) { + if (get_ucall(vm, vcpu->id, NULL) != UCALL_SYNC) { TEST_ASSERT(false, "Invalid guest sync status: exit_reason=%s\n", exit_reason_str(run->exit_reason)); } ts_diff = timespec_elapsed(start); - PER_VCPU_DEBUG("vCPU %d execution time: %ld.%.9lds\n", vcpu_id, + PER_VCPU_DEBUG("vCPU %d execution time: %ld.%.9lds\n", vcpu_idx, ts_diff.tv_sec, ts_diff.tv_nsec); } @@ -285,8 +284,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) struct timespec ts_diff; int *pipefds = NULL; struct kvm_vm *vm; - int vcpu_id; - int r; + int r, i; vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 1, p->src_type, p->partition_vcpu_memory_access); @@ -309,12 +307,12 @@ static void run_test(enum vm_guest_mode mode, void *arg) pipefds = malloc(sizeof(int) * nr_vcpus * 2); TEST_ASSERT(pipefds, "Unable to allocate memory for pipefd"); - for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) { + for (i = 0; i < nr_vcpus; i++) { struct perf_test_vcpu_args *vcpu_args; void *vcpu_hva; void *vcpu_alias; - vcpu_args = &perf_test_args.vcpu_args[vcpu_id]; + vcpu_args = &perf_test_args.vcpu_args[i]; /* Cache the host addresses of the region */ vcpu_hva = addr_gpa2hva(vm, vcpu_args->gpa); @@ -324,13 +322,13 @@ static void run_test(enum vm_guest_mode mode, void *arg) * Set up user fault fd to handle demand paging * requests. */ - r = pipe2(&pipefds[vcpu_id * 2], + r = pipe2(&pipefds[i * 2], O_CLOEXEC | O_NONBLOCK); TEST_ASSERT(!r, "Failed to set up pipefd"); - setup_demand_paging(vm, &uffd_handler_threads[vcpu_id], - pipefds[vcpu_id * 2], p->uffd_mode, - p->uffd_delay, &uffd_args[vcpu_id], + setup_demand_paging(vm, &uffd_handler_threads[i], + pipefds[i * 2], p->uffd_mode, + p->uffd_delay, &uffd_args[i], vcpu_hva, vcpu_alias, vcpu_args->pages * perf_test_args.guest_page_size); } @@ -350,11 +348,11 @@ static void run_test(enum vm_guest_mode mode, void *arg) char c; /* Tell the user fault fd handler threads to quit */ - for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) { - r = write(pipefds[vcpu_id * 2 + 1], &c, 1); + for (i = 0; i < nr_vcpus; i++) { + r = write(pipefds[i * 2 + 1], &c, 1); TEST_ASSERT(r == 1, "Unable to write to pipefd"); - pthread_join(uffd_handler_threads[vcpu_id], NULL); + pthread_join(uffd_handler_threads[i], NULL); } } diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c index 8aaa0949707a..24f6d836499b 100644 --- a/tools/testing/selftests/kvm/dirty_log_perf_test.c +++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c @@ -68,44 +68,45 @@ static int vcpu_last_completed_iteration[KVM_MAX_VCPUS]; static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) { - int ret; + struct kvm_vcpu *vcpu = vcpu_args->vcpu; struct kvm_vm *vm = perf_test_args.vm; + int vcpu_idx = vcpu_args->vcpu_idx; uint64_t pages_count = 0; struct kvm_run *run; struct timespec start; struct timespec ts_diff; struct timespec total = (struct timespec){0}; struct timespec avg; - int vcpu_id = vcpu_args->vcpu_id; + int ret; - run = vcpu_state(vm, vcpu_id); + run = vcpu->run; while (!READ_ONCE(host_quit)) { int current_iteration = READ_ONCE(iteration); clock_gettime(CLOCK_MONOTONIC, &start); - ret = _vcpu_run(vm, vcpu_id); + ret = _vcpu_run(vm, vcpu->id); ts_diff = timespec_elapsed(start); TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); - TEST_ASSERT(get_ucall(vm, vcpu_id, NULL) == UCALL_SYNC, + TEST_ASSERT(get_ucall(vm, vcpu->id, NULL) == UCALL_SYNC, "Invalid guest sync status: exit_reason=%s\n", exit_reason_str(run->exit_reason)); - pr_debug("Got sync event from vCPU %d\n", vcpu_id); - vcpu_last_completed_iteration[vcpu_id] = current_iteration; + pr_debug("Got sync event from vCPU %d\n", vcpu_idx); + vcpu_last_completed_iteration[vcpu_idx] = current_iteration; pr_debug("vCPU %d updated last completed iteration to %d\n", - vcpu_id, vcpu_last_completed_iteration[vcpu_id]); + vcpu->id, vcpu_last_completed_iteration[vcpu_idx]); if (current_iteration) { pages_count += vcpu_args->pages; total = timespec_add(total, ts_diff); pr_debug("vCPU %d iteration %d dirty memory time: %ld.%.9lds\n", - vcpu_id, current_iteration, ts_diff.tv_sec, + vcpu_idx, current_iteration, ts_diff.tv_sec, ts_diff.tv_nsec); } else { pr_debug("vCPU %d iteration %d populate memory time: %ld.%.9lds\n", - vcpu_id, current_iteration, ts_diff.tv_sec, + vcpu_idx, current_iteration, ts_diff.tv_sec, ts_diff.tv_nsec); } @@ -113,9 +114,9 @@ static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) !READ_ONCE(host_quit)) {} } - avg = timespec_div(total, vcpu_last_completed_iteration[vcpu_id]); + avg = timespec_div(total, vcpu_last_completed_iteration[vcpu_idx]); pr_debug("\nvCPU %d dirtied 0x%lx pages over %d iterations in %ld.%.9lds. (Avg %ld.%.9lds/iteration)\n", - vcpu_id, pages_count, vcpu_last_completed_iteration[vcpu_id], + vcpu_idx, pages_count, vcpu_last_completed_iteration[vcpu_idx], total.tv_sec, total.tv_nsec, avg.tv_sec, avg.tv_nsec); } @@ -207,13 +208,13 @@ static void run_test(enum vm_guest_mode mode, void *arg) uint64_t guest_num_pages; uint64_t host_num_pages; uint64_t pages_per_slot; - int vcpu_id; struct timespec start; struct timespec ts_diff; struct timespec get_dirty_log_total = (struct timespec){0}; struct timespec vcpu_dirty_total = (struct timespec){0}; struct timespec avg; struct timespec clear_dirty_log_total = (struct timespec){0}; + int i; vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size, p->slots, p->backing_src, @@ -239,15 +240,15 @@ static void run_test(enum vm_guest_mode mode, void *arg) host_quit = false; clock_gettime(CLOCK_MONOTONIC, &start); - for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) - vcpu_last_completed_iteration[vcpu_id] = -1; + for (i = 0; i < nr_vcpus; i++) + vcpu_last_completed_iteration[i] = -1; perf_test_start_vcpu_threads(nr_vcpus, vcpu_worker); /* Allow the vCPUs to populate memory */ pr_debug("Starting iteration %d - Populating\n", iteration); - for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) { - while (READ_ONCE(vcpu_last_completed_iteration[vcpu_id]) != + for (i = 0; i < nr_vcpus; i++) { + while (READ_ONCE(vcpu_last_completed_iteration[i]) != iteration) ; } @@ -272,8 +273,8 @@ static void run_test(enum vm_guest_mode mode, void *arg) iteration++; pr_debug("Starting iteration %d\n", iteration); - for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) { - while (READ_ONCE(vcpu_last_completed_iteration[vcpu_id]) + for (i = 0; i < nr_vcpus; i++) { + while (READ_ONCE(vcpu_last_completed_iteration[i]) != iteration) ; } diff --git a/tools/testing/selftests/kvm/include/perf_test_util.h b/tools/testing/selftests/kvm/include/perf_test_util.h index d822cb670f1c..eaa88df0555a 100644 --- a/tools/testing/selftests/kvm/include/perf_test_util.h +++ b/tools/testing/selftests/kvm/include/perf_test_util.h @@ -25,7 +25,8 @@ struct perf_test_vcpu_args { uint64_t pages; /* Only used by the host userspace part of the vCPU thread */ - int vcpu_id; + struct kvm_vcpu *vcpu; + int vcpu_idx; }; struct perf_test_args { @@ -44,7 +45,7 @@ struct perf_test_args { extern struct perf_test_args perf_test_args; -struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, +struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int nr_vcpus, uint64_t vcpu_memory_bytes, int slots, enum vm_mem_backing_src_type backing_src, bool partition_vcpu_memory_access); @@ -57,6 +58,6 @@ void perf_test_join_vcpu_threads(int vcpus); void perf_test_guest_code(uint32_t vcpu_id); uint64_t perf_test_nested_pages(int nr_vcpus); -void perf_test_setup_nested(struct kvm_vm *vm, int nr_vcpus); +void perf_test_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[]); #endif /* SELFTEST_KVM_PERF_TEST_UTIL_H */ diff --git a/tools/testing/selftests/kvm/lib/perf_test_util.c b/tools/testing/selftests/kvm/lib/perf_test_util.c index 05f65c9292eb..91a89553afdd 100644 --- a/tools/testing/selftests/kvm/lib/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/perf_test_util.c @@ -17,8 +17,8 @@ struct perf_test_args perf_test_args; static uint64_t guest_test_virt_mem = DEFAULT_GUEST_TEST_MEM; struct vcpu_thread { - /* The id of the vCPU. */ - int vcpu_id; + /* The index of the vCPU. */ + int vcpu_idx; /* The pthread backing the vCPU. */ pthread_t thread; @@ -36,24 +36,26 @@ static void (*vcpu_thread_fn)(struct perf_test_vcpu_args *); /* Set to true once all vCPU threads are up and running. */ static bool all_vcpu_threads_running; +static struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; + /* * Continuously write to the first 8 bytes of each page in the * specified region. */ -void perf_test_guest_code(uint32_t vcpu_id) +void perf_test_guest_code(uint32_t vcpu_idx) { struct perf_test_args *pta = &perf_test_args; - struct perf_test_vcpu_args *vcpu_args = &pta->vcpu_args[vcpu_id]; + struct perf_test_vcpu_args *vcpu_args = &pta->vcpu_args[vcpu_idx]; uint64_t gva; uint64_t pages; int i; - /* Make sure vCPU args data structure is not corrupt. */ - GUEST_ASSERT(vcpu_args->vcpu_id == vcpu_id); - gva = vcpu_args->gva; pages = vcpu_args->pages; + /* Make sure vCPU args data structure is not corrupt. */ + GUEST_ASSERT(vcpu_args->vcpu_idx == vcpu_idx); + while (true) { for (i = 0; i < pages; i++) { uint64_t addr = gva + (i * pta->guest_page_size); @@ -68,40 +70,43 @@ void perf_test_guest_code(uint32_t vcpu_id) } } -void perf_test_setup_vcpus(struct kvm_vm *vm, int vcpus, +void perf_test_setup_vcpus(struct kvm_vm *vm, int nr_vcpus, + struct kvm_vcpu *vcpus[], uint64_t vcpu_memory_bytes, bool partition_vcpu_memory_access) { struct perf_test_args *pta = &perf_test_args; struct perf_test_vcpu_args *vcpu_args; - int vcpu_id; + int i; - for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) { - vcpu_args = &pta->vcpu_args[vcpu_id]; + for (i = 0; i < nr_vcpus; i++) { + vcpu_args = &pta->vcpu_args[i]; + + vcpu_args->vcpu = vcpus[i]; + vcpu_args->vcpu_idx = i; - vcpu_args->vcpu_id = vcpu_id; if (partition_vcpu_memory_access) { vcpu_args->gva = guest_test_virt_mem + - (vcpu_id * vcpu_memory_bytes); + (i * vcpu_memory_bytes); vcpu_args->pages = vcpu_memory_bytes / pta->guest_page_size; - vcpu_args->gpa = pta->gpa + (vcpu_id * vcpu_memory_bytes); + vcpu_args->gpa = pta->gpa + (i * vcpu_memory_bytes); } else { vcpu_args->gva = guest_test_virt_mem; - vcpu_args->pages = (vcpus * vcpu_memory_bytes) / + vcpu_args->pages = (nr_vcpus * vcpu_memory_bytes) / pta->guest_page_size; vcpu_args->gpa = pta->gpa; } - vcpu_args_set(vm, vcpu_id, 1, vcpu_id); + vcpu_args_set(vm, vcpus[i]->id, 1, i); pr_debug("Added VCPU %d with test mem gpa [%lx, %lx)\n", - vcpu_id, vcpu_args->gpa, vcpu_args->gpa + + i, vcpu_args->gpa, vcpu_args->gpa + (vcpu_args->pages * pta->guest_page_size)); } } -struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, +struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int nr_vcpus, uint64_t vcpu_memory_bytes, int slots, enum vm_mem_backing_src_type backing_src, bool partition_vcpu_memory_access) @@ -125,7 +130,7 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, pta->guest_page_size = vm_guest_mode_params[mode].page_size; guest_num_pages = vm_adjust_num_guest_pages(mode, - (vcpus * vcpu_memory_bytes) / pta->guest_page_size); + (nr_vcpus * vcpu_memory_bytes) / pta->guest_page_size); TEST_ASSERT(vcpu_memory_bytes % getpagesize() == 0, "Guest memory size is not host page size aligned."); @@ -140,16 +145,16 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, * in-memory data structures. */ if (pta->nested) - slot0_pages += perf_test_nested_pages(vcpus); + slot0_pages += perf_test_nested_pages(nr_vcpus); /* * Pass guest_num_pages to populate the page tables for test memory. * The memory is also added to memslot 0, but that's a benign side * effect as KVM allows aliasing HVAs in meslots. */ - vm = __vm_create_with_vcpus(mode, vcpus, DEFAULT_GUEST_PHY_PAGES, + vm = __vm_create_with_vcpus(mode, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, slot0_pages + guest_num_pages, 0, - perf_test_guest_code, NULL); + perf_test_guest_code, vcpus); pta->vm = vm; @@ -171,11 +176,10 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, TEST_ASSERT(guest_num_pages < region_end_gfn, "Requested more guest memory than address space allows.\n" " guest pages: %" PRIx64 " max gfn: %" PRIx64 - " vcpus: %d wss: %" PRIx64 "]\n", - guest_num_pages, region_end_gfn - 1, vcpus, - vcpu_memory_bytes); + " nr_vcpus: %d wss: %" PRIx64 "]\n", + guest_num_pages, region_end_gfn - 1, nr_vcpus, vcpu_memory_bytes); - pta->gpa = (region_end_gfn - guest_num_pages) * pta->guest_page_size; + pta->gpa = (region_end_gfn - guest_num_pages - 1) * pta->guest_page_size; pta->gpa = align_down(pta->gpa, backing_src_pagesz); #ifdef __s390x__ /* Align to 1M (segment size) */ @@ -198,11 +202,12 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int vcpus, /* Do mapping for the demand paging memory slot */ virt_map(vm, guest_test_virt_mem, pta->gpa, guest_num_pages); - perf_test_setup_vcpus(vm, vcpus, vcpu_memory_bytes, partition_vcpu_memory_access); + perf_test_setup_vcpus(vm, nr_vcpus, vcpus, vcpu_memory_bytes, + partition_vcpu_memory_access); if (pta->nested) { pr_info("Configuring vCPUs to run in L2 (nested).\n"); - perf_test_setup_nested(vm, vcpus); + perf_test_setup_nested(vm, nr_vcpus, vcpus); } ucall_init(vm, NULL); @@ -230,7 +235,7 @@ uint64_t __weak perf_test_nested_pages(int nr_vcpus) return 0; } -void __weak perf_test_setup_nested(struct kvm_vm *vm, int nr_vcpus) +void __weak perf_test_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu **vcpus) { pr_info("%s() not support on this architecture, skipping.\n", __func__); exit(KSFT_SKIP); @@ -251,39 +256,40 @@ static void *vcpu_thread_main(void *data) while (!READ_ONCE(all_vcpu_threads_running)) ; - vcpu_thread_fn(&perf_test_args.vcpu_args[vcpu->vcpu_id]); + vcpu_thread_fn(&perf_test_args.vcpu_args[vcpu->vcpu_idx]); return NULL; } -void perf_test_start_vcpu_threads(int vcpus, void (*vcpu_fn)(struct perf_test_vcpu_args *)) +void perf_test_start_vcpu_threads(int nr_vcpus, + void (*vcpu_fn)(struct perf_test_vcpu_args *)) { - int vcpu_id; + int i; vcpu_thread_fn = vcpu_fn; WRITE_ONCE(all_vcpu_threads_running, false); - for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) { - struct vcpu_thread *vcpu = &vcpu_threads[vcpu_id]; + for (i = 0; i < nr_vcpus; i++) { + struct vcpu_thread *vcpu = &vcpu_threads[i]; - vcpu->vcpu_id = vcpu_id; + vcpu->vcpu_idx = i; WRITE_ONCE(vcpu->running, false); pthread_create(&vcpu->thread, NULL, vcpu_thread_main, vcpu); } - for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) { - while (!READ_ONCE(vcpu_threads[vcpu_id].running)) + for (i = 0; i < nr_vcpus; i++) { + while (!READ_ONCE(vcpu_threads[i].running)) ; } WRITE_ONCE(all_vcpu_threads_running, true); } -void perf_test_join_vcpu_threads(int vcpus) +void perf_test_join_vcpu_threads(int nr_vcpus) { - int vcpu_id; + int i; - for (vcpu_id = 0; vcpu_id < vcpus; vcpu_id++) - pthread_join(vcpu_threads[vcpu_id].thread, NULL); + for (i = 0; i < nr_vcpus; i++) + pthread_join(vcpu_threads[i].thread, NULL); } diff --git a/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c b/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c index f525427a37c4..446820a549ba 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c @@ -77,7 +77,7 @@ void perf_test_setup_ept(struct vmx_pages *vmx, struct kvm_vm *vm) nested_identity_map_1g(vmx, vm, start, end - start); } -void perf_test_setup_nested(struct kvm_vm *vm, int nr_vcpus) +void perf_test_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[]) { struct vmx_pages *vmx, *vmx0 = NULL; struct kvm_regs regs; @@ -103,9 +103,9 @@ void perf_test_setup_nested(struct kvm_vm *vm, int nr_vcpus) * Override the vCPU to run perf_test_l1_guest_code() which will * bounce it into L2 before calling perf_test_guest_code(). */ - vcpu_regs_get(vm, vcpu_id, ®s); + vcpu_regs_get(vm, vcpus[vcpu_id]->id, ®s); regs.rip = (unsigned long) perf_test_l1_guest_code; - vcpu_regs_set(vm, vcpu_id, ®s); - vcpu_args_set(vm, vcpu_id, 2, vmx_gva, vcpu_id); + vcpu_regs_set(vm, vcpus[vcpu_id]->id, ®s); + vcpu_args_set(vm, vcpus[vcpu_id]->id, 2, vmx_gva, vcpu_id); } } diff --git a/tools/testing/selftests/kvm/memslot_modification_stress_test.c b/tools/testing/selftests/kvm/memslot_modification_stress_test.c index 1410d0a9141a..a3efb3182119 100644 --- a/tools/testing/selftests/kvm/memslot_modification_stress_test.c +++ b/tools/testing/selftests/kvm/memslot_modification_stress_test.c @@ -38,19 +38,19 @@ static bool run_vcpus = true; static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) { - int ret; - int vcpu_id = vcpu_args->vcpu_id; + struct kvm_vcpu *vcpu = vcpu_args->vcpu; struct kvm_vm *vm = perf_test_args.vm; struct kvm_run *run; + int ret; - run = vcpu_state(vm, vcpu_id); + run = vcpu->run; /* Let the guest access its memory until a stop signal is received */ while (READ_ONCE(run_vcpus)) { - ret = _vcpu_run(vm, vcpu_id); + ret = _vcpu_run(vm, vcpu->id); TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); - if (get_ucall(vm, vcpu_id, NULL) == UCALL_SYNC) + if (get_ucall(vm, vcpu->id, NULL) == UCALL_SYNC) continue; TEST_ASSERT(false, From 64a1aacc89700f675c7648b0962519f57630b62a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 16:44:34 -0800 Subject: [PATCH 0438/1436] KVM: selftests: Remove vcpu_get() usage from dirty_log_test Grab the vCPU from vm_vcpu_add() directly instead of doing vcpu_get() after the fact. This will allow removing vcpu_get() entirely. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/dirty_log_test.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 1a5c01c65044..5db56140a995 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -665,7 +665,7 @@ static void vm_dirty_log_verify(enum vm_guest_mode mode, unsigned long *bmap) } } -static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, +static struct kvm_vm *create_vm(enum vm_guest_mode mode, struct kvm_vcpu **vcpu, uint64_t extra_mem_pages, void *guest_code) { struct kvm_vm *vm; @@ -676,7 +676,7 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, uint32_t vcpuid, vm = __vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); log_mode_create_vm_done(vm); - vm_vcpu_add(vm, vcpuid, guest_code); + *vcpu = vm_vcpu_add(vm, 0, guest_code); return vm; } @@ -710,10 +710,8 @@ static void run_test(enum vm_guest_mode mode, void *arg) * (e.g., 64K page size guest will need even less memory for * page tables). */ - vm = create_vm(mode, 0, - 2ul << (DIRTY_MEM_BITS - PAGE_SHIFT_4K), - guest_code); - vcpu = vcpu_get(vm, 0); + vm = create_vm(mode, &vcpu, + 2ul << (DIRTY_MEM_BITS - PAGE_SHIFT_4K), guest_code); guest_page_size = vm_get_page_size(vm); /* From 5260db3eb8f96c0dc631b0f41035a5f1957d9a58 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 13:53:23 -0800 Subject: [PATCH 0439/1436] KVM: selftests: Require vCPU output array when creating VM with vCPUs Require the caller of __vm_create_with_vcpus() to provide a non-NULL array of vCPUs now that all callers do so. It's extremely unlikely a test will have a legitimate use case for creating a VM with vCPUs without wanting to do something with those vCPUs, and if there is such a use case, requiring that one-off test to provide a dummy array is a minor annoyance. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/kvm_util.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index c338713d8245..351c167e7b99 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -302,10 +302,11 @@ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus struct kvm_vcpu *vcpus[]) { uint64_t vcpu_pages, extra_pg_pages, pages; - struct kvm_vcpu *vcpu; struct kvm_vm *vm; int i; + TEST_ASSERT(!nr_vcpus || vcpus, "Must provide vCPU array"); + /* Force slot0 memory size not small than DEFAULT_GUEST_PHY_PAGES */ if (slot0_mem_pages < DEFAULT_GUEST_PHY_PAGES) slot0_mem_pages = DEFAULT_GUEST_PHY_PAGES; @@ -326,11 +327,8 @@ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus vm = __vm_create(mode, pages); - for (i = 0; i < nr_vcpus; ++i) { - vcpu = vm_vcpu_add(vm, i, guest_code); - if (vcpus) - vcpus[i] = vcpu; - } + for (i = 0; i < nr_vcpus; ++i) + vcpus[i] = vm_vcpu_add(vm, i, guest_code); return vm; } From 768e9a61856b75de08f5efa5813bb3e7f16ec271 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 2 Jun 2022 13:41:33 -0700 Subject: [PATCH 0440/1436] KVM: selftests: Purge vm+vcpu_id == vcpu silliness Take a vCPU directly instead of a VM+vcpu pair in all vCPU-scoped helpers and ioctls. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/arch_timer.c | 10 +- .../selftests/kvm/aarch64/debug-exceptions.c | 8 +- .../selftests/kvm/aarch64/get-reg-list.c | 16 +- .../selftests/kvm/aarch64/hypercalls.c | 18 +- .../testing/selftests/kvm/aarch64/psci_test.c | 16 +- .../selftests/kvm/aarch64/vcpu_width_config.c | 8 +- .../testing/selftests/kvm/aarch64/vgic_init.c | 2 +- .../testing/selftests/kvm/aarch64/vgic_irq.c | 8 +- .../selftests/kvm/access_tracking_perf_test.c | 4 +- .../selftests/kvm/demand_paging_test.c | 5 +- .../selftests/kvm/dirty_log_perf_test.c | 7 +- tools/testing/selftests/kvm/dirty_log_test.c | 10 +- .../selftests/kvm/hardware_disable_test.c | 2 +- .../selftests/kvm/include/aarch64/processor.h | 4 +- .../selftests/kvm/include/kvm_util_base.h | 220 +++++++++--------- .../selftests/kvm/include/ucall_common.h | 2 +- .../selftests/kvm/include/x86_64/evmcs.h | 2 +- .../selftests/kvm/include/x86_64/processor.h | 77 +++--- .../selftests/kvm/kvm_binary_stats_test.c | 2 +- .../selftests/kvm/kvm_page_table_test.c | 7 +- .../selftests/kvm/lib/aarch64/processor.c | 47 ++-- .../testing/selftests/kvm/lib/aarch64/ucall.c | 8 +- tools/testing/selftests/kvm/lib/kvm_util.c | 162 ++++--------- .../selftests/kvm/lib/perf_test_util.c | 2 +- .../selftests/kvm/lib/riscv/processor.c | 94 ++++---- tools/testing/selftests/kvm/lib/riscv/ucall.c | 13 +- .../kvm/lib/s390x/diag318_test_handler.c | 2 +- .../selftests/kvm/lib/s390x/processor.c | 22 +- tools/testing/selftests/kvm/lib/s390x/ucall.c | 8 +- .../selftests/kvm/lib/x86_64/processor.c | 143 ++++++------ .../testing/selftests/kvm/lib/x86_64/ucall.c | 10 +- tools/testing/selftests/kvm/lib/x86_64/vmx.c | 4 +- .../selftests/kvm/max_guest_memory_test.c | 20 +- .../kvm/memslot_modification_stress_test.c | 5 +- .../testing/selftests/kvm/memslot_perf_test.c | 4 +- tools/testing/selftests/kvm/rseq_test.c | 4 +- tools/testing/selftests/kvm/s390x/memop.c | 8 +- tools/testing/selftests/kvm/s390x/resets.c | 28 +-- .../selftests/kvm/s390x/sync_regs_test.c | 22 +- tools/testing/selftests/kvm/s390x/tprot.c | 4 +- .../selftests/kvm/set_memory_region_test.c | 8 +- tools/testing/selftests/kvm/steal_time.c | 20 +- .../kvm/system_counter_offset_test.c | 13 +- tools/testing/selftests/kvm/x86_64/amx_test.c | 22 +- .../testing/selftests/kvm/x86_64/cpuid_test.c | 14 +- .../kvm/x86_64/cr4_cpuid_sync_test.c | 8 +- .../testing/selftests/kvm/x86_64/debug_regs.c | 30 +-- .../kvm/x86_64/emulator_error_test.c | 20 +- .../testing/selftests/kvm/x86_64/evmcs_test.c | 28 +-- .../selftests/kvm/x86_64/fix_hypercall_test.c | 6 +- .../selftests/kvm/x86_64/hyperv_clock.c | 14 +- .../selftests/kvm/x86_64/hyperv_cpuid.c | 8 +- .../selftests/kvm/x86_64/hyperv_features.c | 28 +-- .../selftests/kvm/x86_64/hyperv_svm_test.c | 8 +- .../selftests/kvm/x86_64/kvm_clock_test.c | 6 +- .../selftests/kvm/x86_64/kvm_pv_test.c | 10 +- .../selftests/kvm/x86_64/mmu_role_test.c | 10 +- .../selftests/kvm/x86_64/platform_info_test.c | 14 +- .../kvm/x86_64/pmu_event_filter_test.c | 8 +- .../selftests/kvm/x86_64/set_boot_cpu_id.c | 4 +- .../selftests/kvm/x86_64/set_sregs_test.c | 16 +- tools/testing/selftests/kvm/x86_64/smm_test.c | 18 +- .../testing/selftests/kvm/x86_64/state_test.c | 18 +- .../selftests/kvm/x86_64/svm_int_ctl_test.c | 8 +- .../kvm/x86_64/svm_nested_soft_inject_test.c | 10 +- .../selftests/kvm/x86_64/svm_vmcall_test.c | 6 +- .../selftests/kvm/x86_64/sync_regs_test.c | 36 +-- .../kvm/x86_64/triple_fault_event_test.c | 16 +- .../selftests/kvm/x86_64/tsc_msrs_test.c | 14 +- .../selftests/kvm/x86_64/tsc_scaling_sync.c | 6 +- .../selftests/kvm/x86_64/userspace_io_test.c | 8 +- .../kvm/x86_64/userspace_msr_exit_test.c | 22 +- .../kvm/x86_64/vmx_apic_access_test.c | 6 +- .../kvm/x86_64/vmx_close_while_nested_test.c | 6 +- .../selftests/kvm/x86_64/vmx_dirty_log_test.c | 6 +- .../vmx_exception_with_invalid_guest_state.c | 10 +- .../x86_64/vmx_invalid_nested_guest_state.c | 12 +- .../kvm/x86_64/vmx_nested_tsc_scaling_test.c | 11 +- .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 20 +- .../kvm/x86_64/vmx_preemption_timer_test.c | 18 +- .../kvm/x86_64/vmx_set_nested_state_test.c | 12 +- .../kvm/x86_64/vmx_tsc_adjust_test.c | 6 +- .../selftests/kvm/x86_64/xapic_ipi_test.c | 10 +- .../selftests/kvm/x86_64/xapic_state_test.c | 42 ++-- .../selftests/kvm/x86_64/xen_shinfo_test.c | 38 +-- .../selftests/kvm/x86_64/xen_vmcall_test.c | 6 +- .../selftests/kvm/x86_64/xss_msr_test.c | 6 +- 87 files changed, 793 insertions(+), 911 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index a873d9adc558..ca4c08b4e353 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -218,14 +218,14 @@ static void *test_vcpu_run(void *arg) struct kvm_vm *vm = vcpu->vm; struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[vcpu_idx]; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); /* Currently, any exit from guest is an indication of completion */ pthread_mutex_lock(&vcpu_done_map_lock); set_bit(vcpu_idx, vcpu_done_map); pthread_mutex_unlock(&vcpu_done_map_lock); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: case UCALL_DONE: break; @@ -345,9 +345,9 @@ static void test_run(struct kvm_vm *vm) static void test_init_timer_irq(struct kvm_vm *vm) { /* Timer initid should be same for all the vCPUs, so query only vCPU-0 */ - vcpu_device_attr_get(vm, vcpus[0]->id, KVM_ARM_VCPU_TIMER_CTRL, + vcpu_device_attr_get(vcpus[0], KVM_ARM_VCPU_TIMER_CTRL, KVM_ARM_VCPU_TIMER_IRQ_PTIMER, &ptimer_irq); - vcpu_device_attr_get(vm, vcpus[0]->id, KVM_ARM_VCPU_TIMER_CTRL, + vcpu_device_attr_get(vcpus[0], KVM_ARM_VCPU_TIMER_CTRL, KVM_ARM_VCPU_TIMER_IRQ_VTIMER, &vtimer_irq); sync_global_to_guest(vm, ptimer_irq); @@ -370,7 +370,7 @@ static struct kvm_vm *test_vm_create(void) vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT, guest_irq_handler); for (i = 0; i < nr_vcpus; i++) - vcpu_init_descriptor_tables(vm, vcpus[i]->id); + vcpu_init_descriptor_tables(vcpus[i]); ucall_init(vm, NULL); test_init_timer_irq(vm); diff --git a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c index 2fe13e117dba..c27352b90ccf 100644 --- a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c +++ b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c @@ -242,7 +242,7 @@ static int debug_version(struct kvm_vcpu *vcpu) { uint64_t id_aa64dfr0; - vcpu_get_reg(vcpu->vm, vcpu->id, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), &id_aa64dfr0); + vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_ID_AA64DFR0_EL1), &id_aa64dfr0); return id_aa64dfr0 & 0xf; } @@ -257,7 +257,7 @@ int main(int argc, char *argv[]) ucall_init(vm, NULL); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); if (debug_version(vcpu) < 6) { print_skip("Armv8 debug architecture not supported."); @@ -277,9 +277,9 @@ int main(int argc, char *argv[]) ESR_EC_SVC64, guest_svc_handler); for (stage = 0; stage < 11; stage++) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: TEST_ASSERT(uc.args[1] == stage, "Stage %d: Unexpected sync ucall, got %lx", diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index f0aec117faae..f0f83ffda344 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -377,7 +377,7 @@ static void prepare_vcpu_init(struct vcpu_config *c, struct kvm_vcpu_init *init) init->features[s->feature / 32] |= 1 << (s->feature % 32); } -static void finalize_vcpu(struct kvm_vm *vm, uint32_t vcpuid, struct vcpu_config *c) +static void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_config *c) { struct reg_sublist *s; int feature; @@ -385,7 +385,7 @@ static void finalize_vcpu(struct kvm_vm *vm, uint32_t vcpuid, struct vcpu_config for_each_sublist(c, s) { if (s->finalize) { feature = s->feature; - vcpu_ioctl(vm, vcpuid, KVM_ARM_VCPU_FINALIZE, &feature); + vcpu_ioctl(vcpu, KVM_ARM_VCPU_FINALIZE, &feature); } } } @@ -420,10 +420,10 @@ static void run_test(struct vcpu_config *c) vm = vm_create_barebones(); prepare_vcpu_init(c, &init); vcpu = __vm_vcpu_add(vm, 0); - aarch64_vcpu_setup(vm, vcpu->id, &init); - finalize_vcpu(vm, vcpu->id, c); + aarch64_vcpu_setup(vcpu, &init); + finalize_vcpu(vcpu, c); - reg_list = vcpu_get_reg_list(vm, vcpu->id); + reg_list = vcpu_get_reg_list(vcpu); if (fixup_core_regs) core_reg_fixup(); @@ -459,7 +459,7 @@ static void run_test(struct vcpu_config *c) bool reject_reg = false; int ret; - ret = __vcpu_get_reg(vm, vcpu->id, reg_list->reg[i], &addr); + ret = __vcpu_get_reg(vcpu, reg_list->reg[i], &addr); if (ret) { printf("%s: Failed to get ", config_name(c)); print_reg(c, reg.id); @@ -471,7 +471,7 @@ static void run_test(struct vcpu_config *c) for_each_sublist(c, s) { if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) { reject_reg = true; - ret = __vcpu_ioctl(vm, vcpu->id, KVM_SET_ONE_REG, ®); + ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); if (ret != -1 || errno != EPERM) { printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno); print_reg(c, reg.id); @@ -483,7 +483,7 @@ static void run_test(struct vcpu_config *c) } if (!reject_reg) { - ret = __vcpu_ioctl(vm, vcpu->id, KVM_SET_ONE_REG, ®); + ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); if (ret) { printf("%s: Failed to set ", config_name(c)); print_reg(c, reg.id); diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c index fefa39dc9bc8..5fce4969cbb9 100644 --- a/tools/testing/selftests/kvm/aarch64/hypercalls.c +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c @@ -158,7 +158,7 @@ static void steal_time_init(struct kvm_vcpu *vcpu) gpages = vm_calc_num_guest_pages(VM_MODE_DEFAULT, STEAL_TIME_SIZE); vm_userspace_mem_region_add(vcpu->vm, VM_MEM_SRC_ANONYMOUS, ST_GPA_BASE, 1, gpages, 0); - vcpu_device_attr_set(vcpu->vm, vcpu->id, KVM_ARM_VCPU_PVTIME_CTRL, + vcpu_device_attr_set(vcpu, KVM_ARM_VCPU_PVTIME_CTRL, KVM_ARM_VCPU_PVTIME_IPA, &st_ipa); } @@ -172,18 +172,18 @@ static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu) const struct kvm_fw_reg_info *reg_info = &fw_reg_info[i]; /* First 'read' should be an upper limit of the features supported */ - vcpu_get_reg(vcpu->vm, vcpu->id, reg_info->reg, &val); + vcpu_get_reg(vcpu, reg_info->reg, &val); TEST_ASSERT(val == FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), "Expected all the features to be set for reg: 0x%lx; expected: 0x%lx; read: 0x%lx\n", reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit), val); /* Test a 'write' by disabling all the features of the register map */ - ret = __vcpu_set_reg(vcpu->vm, vcpu->id, reg_info->reg, 0); + ret = __vcpu_set_reg(vcpu, reg_info->reg, 0); TEST_ASSERT(ret == 0, "Failed to clear all the features of reg: 0x%lx; ret: %d\n", reg_info->reg, errno); - vcpu_get_reg(vcpu->vm, vcpu->id, reg_info->reg, &val); + vcpu_get_reg(vcpu, reg_info->reg, &val); TEST_ASSERT(val == 0, "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg); @@ -192,7 +192,7 @@ static void test_fw_regs_before_vm_start(struct kvm_vcpu *vcpu) * Avoid this check if all the bits are occupied. */ if (reg_info->max_feat_bit < 63) { - ret = __vcpu_set_reg(vcpu->vm, vcpu->id, reg_info->reg, BIT(reg_info->max_feat_bit + 1)); + ret = __vcpu_set_reg(vcpu, reg_info->reg, BIT(reg_info->max_feat_bit + 1)); TEST_ASSERT(ret != 0 && errno == EINVAL, "Unexpected behavior or return value (%d) while setting an unsupported feature for reg: 0x%lx\n", errno, reg_info->reg); @@ -213,7 +213,7 @@ static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu) * Before starting the VM, the test clears all the bits. * Check if that's still the case. */ - vcpu_get_reg(vcpu->vm, vcpu->id, reg_info->reg, &val); + vcpu_get_reg(vcpu, reg_info->reg, &val); TEST_ASSERT(val == 0, "Expected all the features to be cleared for reg: 0x%lx\n", reg_info->reg); @@ -223,7 +223,7 @@ static void test_fw_regs_after_vm_start(struct kvm_vcpu *vcpu) * the registers and should return EBUSY. Set the registers and check for * the expected errno. */ - ret = __vcpu_set_reg(vcpu->vm, vcpu->id, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit)); + ret = __vcpu_set_reg(vcpu, reg_info->reg, FW_REG_ULIMIT_VAL(reg_info->max_feat_bit)); TEST_ASSERT(ret != 0 && errno == EBUSY, "Unexpected behavior or return value (%d) while setting a feature while VM is running for reg: 0x%lx\n", errno, reg_info->reg); @@ -281,9 +281,9 @@ static void test_run(void) test_fw_regs_before_vm_start(vcpu); while (!guest_done) { - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: test_guest_stage(&vm, &vcpu); break; diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index f4f73934351f..3e1bebe63adf 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -67,7 +67,7 @@ static void vcpu_power_off(struct kvm_vcpu *vcpu) .mp_state = KVM_MP_STATE_STOPPED, }; - vcpu_mp_state_set(vcpu->vm, vcpu->id, &mp_state); + vcpu_mp_state_set(vcpu, &mp_state); } static struct kvm_vm *setup_vm(void *guest_code, struct kvm_vcpu **source, @@ -92,8 +92,8 @@ static void enter_guest(struct kvm_vcpu *vcpu) { struct ucall uc; - vcpu_run(vcpu->vm, vcpu->id); - if (get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_ABORT) + vcpu_run(vcpu); + if (get_ucall(vcpu, &uc) == UCALL_ABORT) TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); } @@ -102,8 +102,8 @@ static void assert_vcpu_reset(struct kvm_vcpu *vcpu) { uint64_t obs_pc, obs_x0; - vcpu_get_reg(vcpu->vm, vcpu->id, ARM64_CORE_REG(regs.pc), &obs_pc); - vcpu_get_reg(vcpu->vm, vcpu->id, ARM64_CORE_REG(regs.regs[0]), &obs_x0); + vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc), &obs_pc); + vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.regs[0]), &obs_x0); TEST_ASSERT(obs_pc == CPU_ON_ENTRY_ADDR, "unexpected target cpu pc: %lx (expected: %lx)", @@ -143,11 +143,11 @@ static void host_test_cpu_on(void) */ vcpu_power_off(target); - vcpu_get_reg(vm, target->id, KVM_ARM64_SYS_REG(SYS_MPIDR_EL1), &target_mpidr); - vcpu_args_set(vm, source->id, 1, target_mpidr & MPIDR_HWID_BITMASK); + vcpu_get_reg(target, KVM_ARM64_SYS_REG(SYS_MPIDR_EL1), &target_mpidr); + vcpu_args_set(source, 1, target_mpidr & MPIDR_HWID_BITMASK); enter_guest(source); - if (get_ucall(vm, source->id, &uc) != UCALL_DONE) + if (get_ucall(source, &uc) != UCALL_DONE) TEST_FAIL("Unhandled ucall: %lu", uc.cmd); assert_vcpu_reset(target); diff --git a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c index e4e66632f05c..dd5a1c4b49e0 100644 --- a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c +++ b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c @@ -28,12 +28,12 @@ static int add_init_2vcpus(struct kvm_vcpu_init *init0, vm = vm_create_barebones(); vcpu0 = __vm_vcpu_add(vm, 0); - ret = __vcpu_ioctl(vm, vcpu0->id, KVM_ARM_VCPU_INIT, init0); + ret = __vcpu_ioctl(vcpu0, KVM_ARM_VCPU_INIT, init0); if (ret) goto free_exit; vcpu1 = __vm_vcpu_add(vm, 1); - ret = __vcpu_ioctl(vm, vcpu1->id, KVM_ARM_VCPU_INIT, init1); + ret = __vcpu_ioctl(vcpu1, KVM_ARM_VCPU_INIT, init1); free_exit: kvm_vm_free(vm); @@ -56,11 +56,11 @@ static int add_2vcpus_init_2vcpus(struct kvm_vcpu_init *init0, vcpu0 = __vm_vcpu_add(vm, 0); vcpu1 = __vm_vcpu_add(vm, 1); - ret = __vcpu_ioctl(vm, vcpu0->id, KVM_ARM_VCPU_INIT, init0); + ret = __vcpu_ioctl(vcpu0, KVM_ARM_VCPU_INIT, init0); if (ret) goto free_exit; - ret = __vcpu_ioctl(vm, vcpu1->id, KVM_ARM_VCPU_INIT, init1); + ret = __vcpu_ioctl(vcpu1, KVM_ARM_VCPU_INIT, init1); free_exit: kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 40504f05641d..6b9c9a391a01 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -70,7 +70,7 @@ static int run_vcpu(struct kvm_vcpu *vcpu) { ucall_init(vcpu->vm, NULL); - return __vcpu_run(vcpu->vm, vcpu->id) ? -errno : 0; + return __vcpu_run(vcpu) ? -errno : 0; } static struct vm_gic vm_gic_create_with_vcpus(uint32_t gic_dev_type, diff --git a/tools/testing/selftests/kvm/aarch64/vgic_irq.c b/tools/testing/selftests/kvm/aarch64/vgic_irq.c index 111170201e9b..90dbba61d72a 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_irq.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_irq.c @@ -759,12 +759,12 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) ucall_init(vm, NULL); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); /* Setup the guest args page (so it gets the args). */ args_gva = vm_vaddr_alloc_page(vm); memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args)); - vcpu_args_set(vm, vcpu->id, 1, args_gva); + vcpu_args_set(vcpu, 1, args_gva); gic_fd = vgic_v3_setup(vm, 1, nr_irqs, GICD_BASE_GPA, GICR_BASE_GPA); @@ -777,9 +777,9 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) guest_irq_handlers[args.eoi_split][args.level_sensitive]); while (1) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: kvm_inject_get_call(vm, &uc, &inject_args); run_guest_cmd(vcpu, gic_fd, &inject_args, &args); diff --git a/tools/testing/selftests/kvm/access_tracking_perf_test.c b/tools/testing/selftests/kvm/access_tracking_perf_test.c index 86a90222f913..1c771378f7f4 100644 --- a/tools/testing/selftests/kvm/access_tracking_perf_test.c +++ b/tools/testing/selftests/kvm/access_tracking_perf_test.c @@ -194,7 +194,7 @@ static void mark_vcpu_memory_idle(struct kvm_vm *vm, static void assert_ucall(struct kvm_vcpu *vcpu, uint64_t expected_ucall) { struct ucall uc; - uint64_t actual_ucall = get_ucall(vcpu->vm, vcpu->id, &uc); + uint64_t actual_ucall = get_ucall(vcpu, &uc); TEST_ASSERT(expected_ucall == actual_ucall, "Guest exited unexpectedly (expected ucall %" PRIu64 @@ -226,7 +226,7 @@ static void vcpu_thread_main(struct perf_test_vcpu_args *vcpu_args) while (spin_wait_for_next_iteration(¤t_iteration)) { switch (READ_ONCE(iteration_work)) { case ITERATION_ACCESS_MEMORY: - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); assert_ucall(vcpu, UCALL_SYNC); break; case ITERATION_MARK_IDLE: diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index c46110721088..779ae54f89c4 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -45,7 +45,6 @@ static char *guest_data_prototype; static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) { struct kvm_vcpu *vcpu = vcpu_args->vcpu; - struct kvm_vm *vm = perf_test_args.vm; int vcpu_idx = vcpu_args->vcpu_idx; struct kvm_run *run = vcpu->run; struct timespec start; @@ -55,9 +54,9 @@ static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) clock_gettime(CLOCK_MONOTONIC, &start); /* Let the guest access its memory */ - ret = _vcpu_run(vm, vcpu->id); + ret = _vcpu_run(vcpu); TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); - if (get_ucall(vm, vcpu->id, NULL) != UCALL_SYNC) { + if (get_ucall(vcpu, NULL) != UCALL_SYNC) { TEST_ASSERT(false, "Invalid guest sync status: exit_reason=%s\n", exit_reason_str(run->exit_reason)); diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c index 24f6d836499b..2027208e7d10 100644 --- a/tools/testing/selftests/kvm/dirty_log_perf_test.c +++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c @@ -69,7 +69,6 @@ static int vcpu_last_completed_iteration[KVM_MAX_VCPUS]; static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) { struct kvm_vcpu *vcpu = vcpu_args->vcpu; - struct kvm_vm *vm = perf_test_args.vm; int vcpu_idx = vcpu_args->vcpu_idx; uint64_t pages_count = 0; struct kvm_run *run; @@ -85,18 +84,18 @@ static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) int current_iteration = READ_ONCE(iteration); clock_gettime(CLOCK_MONOTONIC, &start); - ret = _vcpu_run(vm, vcpu->id); + ret = _vcpu_run(vcpu); ts_diff = timespec_elapsed(start); TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); - TEST_ASSERT(get_ucall(vm, vcpu->id, NULL) == UCALL_SYNC, + TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC, "Invalid guest sync status: exit_reason=%s\n", exit_reason_str(run->exit_reason)); pr_debug("Got sync event from vCPU %d\n", vcpu_idx); vcpu_last_completed_iteration[vcpu_idx] = current_iteration; pr_debug("vCPU %d updated last completed iteration to %d\n", - vcpu->id, vcpu_last_completed_iteration[vcpu_idx]); + vcpu_idx, vcpu_last_completed_iteration[vcpu_idx]); if (current_iteration) { pages_count += vcpu_args->pages; diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 5db56140a995..906e893375df 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -255,7 +255,7 @@ static void default_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) TEST_ASSERT(ret == 0 || (ret == -1 && err == EINTR), "vcpu run failed: errno=%d", err); - TEST_ASSERT(get_ucall(vcpu->vm, vcpu->id, NULL) == UCALL_SYNC, + TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC, "Invalid guest sync status: exit_reason=%s\n", exit_reason_str(run->exit_reason)); @@ -346,7 +346,7 @@ static void dirty_ring_collect_dirty_pages(struct kvm_vcpu *vcpu, int slot, } /* Only have one vcpu */ - count = dirty_ring_collect_one(vcpu_map_dirty_ring(vcpu->vm, vcpu->id), + count = dirty_ring_collect_one(vcpu_map_dirty_ring(vcpu), slot, bitmap, num_pages, &fetch_index); cleared = kvm_vm_reset_dirty_ring(vcpu->vm); @@ -369,7 +369,7 @@ static void dirty_ring_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) struct kvm_run *run = vcpu->run; /* A ucall-sync or ring-full event is allowed */ - if (get_ucall(vcpu->vm, vcpu->id, NULL) == UCALL_SYNC) { + if (get_ucall(vcpu, NULL) == UCALL_SYNC) { /* We should allow this to continue */ ; } else if (run->exit_reason == KVM_EXIT_DIRTY_RING_FULL || @@ -521,7 +521,7 @@ static void *vcpu_worker(void *data) sigmask->len = 8; pthread_sigmask(0, NULL, sigset); sigdelset(sigset, SIG_IPI); - vcpu_ioctl(vm, vcpu->id, KVM_SET_SIGNAL_MASK, sigmask); + vcpu_ioctl(vcpu, KVM_SET_SIGNAL_MASK, sigmask); sigemptyset(sigset); sigaddset(sigset, SIG_IPI); @@ -533,7 +533,7 @@ static void *vcpu_worker(void *data) generate_random_array(guest_array, TEST_PAGES_PER_LOOP); pages_count += TEST_PAGES_PER_LOOP; /* Let the guest dirty the random pages */ - ret = __vcpu_run(vm, vcpu->id); + ret = __vcpu_run(vcpu); if (ret == -1 && errno == EINTR) { int sig = -1; sigwait(sigset, &sig); diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c index 59bb43345a3e..2401577e3652 100644 --- a/tools/testing/selftests/kvm/hardware_disable_test.c +++ b/tools/testing/selftests/kvm/hardware_disable_test.c @@ -39,7 +39,7 @@ static void *run_vcpu(void *arg) struct kvm_vcpu *vcpu = arg; struct kvm_run *run = vcpu->run; - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(false, "%s: exited with reason %d: %s\n", __func__, run->exit_reason, diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index ba3e9066d990..a8124f9dd68a 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -47,7 +47,7 @@ #define MPIDR_HWID_BITMASK (0xff00fffffful) -void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init *init); +void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init); struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, struct kvm_vcpu_init *init, void *guest_code); @@ -101,7 +101,7 @@ void aarch64_get_supported_page_sizes(uint32_t ipa, bool *ps4k, bool *ps16k, bool *ps64k); void vm_init_descriptor_tables(struct kvm_vm *vm); -void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid); +void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu); typedef void(*handler_fn)(struct ex_regs *); void vm_install_exception_handler(struct kvm_vm *vm, diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index f409bae336d5..640634bdba9a 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -93,7 +93,7 @@ struct kvm_vm { continue; \ else -struct kvm_vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpuid); +struct kvm_vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpu_id); struct userspace_mem_region * memslot2region(struct kvm_vm *vm, uint32_t memslot); @@ -196,12 +196,12 @@ int __vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); void _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, const char *name, void *arg); #define vm_ioctl(vm, cmd, arg) _vm_ioctl(vm, cmd, #cmd, arg) -int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, +int __vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long cmd, void *arg); -void _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, +void _vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long cmd, const char *name, void *arg); -#define vcpu_ioctl(vm, vcpuid, cmd, arg) \ - _vcpu_ioctl(vm, vcpuid, cmd, #cmd, arg) +#define vcpu_ioctl(vcpu, cmd, arg) \ + _vcpu_ioctl(vcpu, cmd, #cmd, arg) /* * Looks up and returns the value corresponding to the capability @@ -288,7 +288,7 @@ void vm_userspace_mem_region_add(struct kvm_vm *vm, void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa); void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot); -struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid); +struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id); vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min); vm_vaddr_t vm_vaddr_alloc_pages(struct kvm_vm *vm, int nr_pages); vm_vaddr_t vm_vaddr_alloc_page(struct kvm_vm *vm); @@ -300,143 +300,132 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva); vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva); void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa); -struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid); -void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); -int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); +struct kvm_run *vcpu_state(struct kvm_vcpu *vcpu); +void vcpu_run(struct kvm_vcpu *vcpu); +int _vcpu_run(struct kvm_vcpu *vcpu); -static inline int __vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) +static inline int __vcpu_run(struct kvm_vcpu *vcpu) { - return __vcpu_ioctl(vm, vcpuid, KVM_RUN, NULL); + return __vcpu_ioctl(vcpu, KVM_RUN, NULL); } -void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid); -struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid); +void vcpu_run_complete_io(struct kvm_vcpu *vcpu); +struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vcpu *vcpu); -static inline void vcpu_enable_cap(struct kvm_vm *vm, uint32_t vcpu_id, - uint32_t cap, uint64_t arg0) +static inline void vcpu_enable_cap(struct kvm_vcpu *vcpu, uint32_t cap, + uint64_t arg0) { struct kvm_enable_cap enable_cap = { .cap = cap, .args = { arg0 } }; - vcpu_ioctl(vm, vcpu_id, KVM_ENABLE_CAP, &enable_cap); + vcpu_ioctl(vcpu, KVM_ENABLE_CAP, &enable_cap); } -static inline void vcpu_guest_debug_set(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_guest_debug_set(struct kvm_vcpu *vcpu, struct kvm_guest_debug *debug) { - vcpu_ioctl(vm, vcpuid, KVM_SET_GUEST_DEBUG, debug); + vcpu_ioctl(vcpu, KVM_SET_GUEST_DEBUG, debug); } -static inline void vcpu_mp_state_get(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_mp_state_get(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { - vcpu_ioctl(vm, vcpuid, KVM_GET_MP_STATE, mp_state); + vcpu_ioctl(vcpu, KVM_GET_MP_STATE, mp_state); } -static inline void vcpu_mp_state_set(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_mp_state_set(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { - vcpu_ioctl(vm, vcpuid, KVM_SET_MP_STATE, mp_state); + vcpu_ioctl(vcpu, KVM_SET_MP_STATE, mp_state); } -static inline void vcpu_regs_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_regs *regs) +static inline void vcpu_regs_get(struct kvm_vcpu *vcpu, struct kvm_regs *regs) { - vcpu_ioctl(vm, vcpuid, KVM_GET_REGS, regs); + vcpu_ioctl(vcpu, KVM_GET_REGS, regs); } -static inline void vcpu_regs_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_regs *regs) +static inline void vcpu_regs_set(struct kvm_vcpu *vcpu, struct kvm_regs *regs) { - vcpu_ioctl(vm, vcpuid, KVM_SET_REGS, regs); + vcpu_ioctl(vcpu, KVM_SET_REGS, regs); } -static inline void vcpu_sregs_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_sregs *sregs) +static inline void vcpu_sregs_get(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { - vcpu_ioctl(vm, vcpuid, KVM_GET_SREGS, sregs); + vcpu_ioctl(vcpu, KVM_GET_SREGS, sregs); } -static inline void vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_sregs *sregs) +static inline void vcpu_sregs_set(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { - vcpu_ioctl(vm, vcpuid, KVM_SET_SREGS, sregs); + vcpu_ioctl(vcpu, KVM_SET_SREGS, sregs); } -static inline int _vcpu_sregs_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_sregs *sregs) +static inline int _vcpu_sregs_set(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) { - return __vcpu_ioctl(vm, vcpuid, KVM_SET_SREGS, sregs); + return __vcpu_ioctl(vcpu, KVM_SET_SREGS, sregs); } -static inline void vcpu_fpu_get(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_fpu *fpu) +static inline void vcpu_fpu_get(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { - vcpu_ioctl(vm, vcpuid, KVM_GET_FPU, fpu); + vcpu_ioctl(vcpu, KVM_GET_FPU, fpu); } -static inline void vcpu_fpu_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_fpu *fpu) +static inline void vcpu_fpu_set(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) { - vcpu_ioctl(vm, vcpuid, KVM_SET_FPU, fpu); + vcpu_ioctl(vcpu, KVM_SET_FPU, fpu); } -static inline int __vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, - uint64_t reg_id, void *addr) +static inline int __vcpu_get_reg(struct kvm_vcpu *vcpu, uint64_t id, void *addr) { - struct kvm_one_reg reg = { .id = reg_id, .addr = (uint64_t)addr }; + struct kvm_one_reg reg = { .id = id, .addr = (uint64_t)addr }; - return __vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, ®); + return __vcpu_ioctl(vcpu, KVM_GET_ONE_REG, ®); } -static inline int __vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, - uint64_t reg_id, uint64_t val) +static inline int __vcpu_set_reg(struct kvm_vcpu *vcpu, uint64_t id, uint64_t val) { - struct kvm_one_reg reg = { .id = reg_id, .addr = (uint64_t)&val }; + struct kvm_one_reg reg = { .id = id, .addr = (uint64_t)&val }; - return __vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, ®); + return __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); } -static inline void vcpu_get_reg(struct kvm_vm *vm, uint32_t vcpuid, - uint64_t reg_id, void *addr) +static inline void vcpu_get_reg(struct kvm_vcpu *vcpu, uint64_t id, void *addr) { - struct kvm_one_reg reg = { .id = reg_id, .addr = (uint64_t)addr }; + struct kvm_one_reg reg = { .id = id, .addr = (uint64_t)addr }; - vcpu_ioctl(vm, vcpuid, KVM_GET_ONE_REG, ®); + vcpu_ioctl(vcpu, KVM_GET_ONE_REG, ®); } -static inline void vcpu_set_reg(struct kvm_vm *vm, uint32_t vcpuid, - uint64_t reg_id, uint64_t val) +static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, uint64_t id, uint64_t val) { - struct kvm_one_reg reg = { .id = reg_id, .addr = (uint64_t)&val }; + struct kvm_one_reg reg = { .id = id, .addr = (uint64_t)&val }; - vcpu_ioctl(vm, vcpuid, KVM_SET_ONE_REG, ®); + vcpu_ioctl(vcpu, KVM_SET_ONE_REG, ®); } #ifdef __KVM_HAVE_VCPU_EVENTS -static inline void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_events_get(struct kvm_vcpu *vcpu, struct kvm_vcpu_events *events) { - vcpu_ioctl(vm, vcpuid, KVM_GET_VCPU_EVENTS, events); + vcpu_ioctl(vcpu, KVM_GET_VCPU_EVENTS, events); } -static inline void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_events_set(struct kvm_vcpu *vcpu, struct kvm_vcpu_events *events) { - vcpu_ioctl(vm, vcpuid, KVM_SET_VCPU_EVENTS, events); + vcpu_ioctl(vcpu, KVM_SET_VCPU_EVENTS, events); } #endif #ifdef __x86_64__ -static inline void vcpu_nested_state_get(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_nested_state_get(struct kvm_vcpu *vcpu, struct kvm_nested_state *state) { - vcpu_ioctl(vm, vcpuid, KVM_GET_NESTED_STATE, state); + vcpu_ioctl(vcpu, KVM_GET_NESTED_STATE, state); } -static inline int __vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, +static inline int __vcpu_nested_state_set(struct kvm_vcpu *vcpu, struct kvm_nested_state *state) { - return __vcpu_ioctl(vm, vcpuid, KVM_SET_NESTED_STATE, state); + return __vcpu_ioctl(vcpu, KVM_SET_NESTED_STATE, state); } -static inline void vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_nested_state_set(struct kvm_vcpu *vcpu, struct kvm_nested_state *state) { - vcpu_ioctl(vm, vcpuid, KVM_SET_NESTED_STATE, state); + vcpu_ioctl(vcpu, KVM_SET_NESTED_STATE, state); } #endif -static inline int vcpu_get_stats_fd(struct kvm_vm *vm, uint32_t vcpuid) +static inline int vcpu_get_stats_fd(struct kvm_vcpu *vcpu) { - int fd = __vcpu_ioctl(vm, vcpuid, KVM_GET_STATS_FD, NULL); + int fd = __vcpu_ioctl(vcpu, KVM_GET_STATS_FD, NULL); TEST_ASSERT(fd >= 0, KVM_IOCTL_ERROR(KVM_GET_STATS_FD, fd)); return fd; @@ -471,25 +460,42 @@ static inline void kvm_device_attr_set(int dev_fd, uint32_t group, TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_SET_DEVICE_ATTR, ret)); } -int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr); - -static inline void vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, - uint32_t group, uint64_t attr) +static inline int __vcpu_has_device_attr(struct kvm_vcpu *vcpu, uint32_t group, + uint64_t attr) { - int ret = __vcpu_has_device_attr(vm, vcpuid, group, attr); - - TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_HAS_DEVICE_ATTR, ret)); + return __kvm_has_device_attr(vcpu->fd, group, attr); +} + +static inline void vcpu_has_device_attr(struct kvm_vcpu *vcpu, uint32_t group, + uint64_t attr) +{ + kvm_has_device_attr(vcpu->fd, group, attr); +} + +static inline int __vcpu_device_attr_get(struct kvm_vcpu *vcpu, uint32_t group, + uint64_t attr, void *val) +{ + return __kvm_device_attr_get(vcpu->fd, group, attr, val); +} + +static inline void vcpu_device_attr_get(struct kvm_vcpu *vcpu, uint32_t group, + uint64_t attr, void *val) +{ + kvm_device_attr_get(vcpu->fd, group, attr, val); +} + +static inline int __vcpu_device_attr_set(struct kvm_vcpu *vcpu, uint32_t group, + uint64_t attr, void *val) +{ + return __kvm_device_attr_set(vcpu->fd, group, attr, val); +} + +static inline void vcpu_device_attr_set(struct kvm_vcpu *vcpu, uint32_t group, + uint64_t attr, void *val) +{ + kvm_device_attr_set(vcpu->fd, group, attr, val); } -int __vcpu_device_attr_get(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val); -void vcpu_device_attr_get(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val); -int __vcpu_device_attr_set(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val); -void vcpu_device_attr_set(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val); int __kvm_test_create_device(struct kvm_vm *vm, uint64_t type); int __kvm_create_device(struct kvm_vm *vm, uint64_t type); @@ -501,14 +507,13 @@ static inline int kvm_create_device(struct kvm_vm *vm, uint64_t type) return fd; } -void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid); +void *vcpu_map_dirty_ring(struct kvm_vcpu *vcpu); /* * VM VCPU Args Set * * Input Args: * vm - Virtual Machine - * vcpuid - VCPU ID * num - number of arguments * ... - arguments, each of type uint64_t * @@ -516,12 +521,12 @@ void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid); * * Return: None * - * Sets the first @num function input registers of the VCPU with @vcpuid, - * per the C calling convention of the architecture, to the values given - * as variable args. Each of the variable args is expected to be of type - * uint64_t. The maximum @num can be is specific to the architecture. + * Sets the first @num input parameters for the function at @vcpu's entry point, + * per the C calling convention of the architecture, to the values given as + * variable args. Each of the variable args is expected to be of type uint64_t. + * The maximum @num can be is specific to the architecture. */ -void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); +void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...); void kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level); int _kvm_irq_line(struct kvm_vm *vm, uint32_t irq, int level); @@ -626,32 +631,15 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, memcpy(&(g), _p, sizeof(g)); \ }) -void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid); +void assert_on_unhandled_exception(struct kvm_vcpu *vcpu); -/* - * VM VCPU Dump - * - * Input Args: - * stream - Output FILE stream - * vm - Virtual Machine - * vcpuid - VCPU ID - * indent - Left margin indent amount - * - * Output Args: None - * - * Return: None - * - * Dumps the current state of the VCPU specified by @vcpuid, within the VM - * given by @vm, to the FILE stream given by @stream. - */ - -void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, +void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent); -static inline void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent) { - vcpu_arch_dump(stream, vm, vcpuid, indent); + vcpu_arch_dump(stream, vcpu, indent); } /* @@ -659,7 +647,7 @@ static inline void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, * * Input Args: * vm - Virtual Machine - * vcpuid - The id of the VCPU to add to the VM. + * vcpu_id - The id of the VCPU to add to the VM. * guest_code - The vCPU's entry point */ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index 9eecc9d40b79..98562f685151 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -26,7 +26,7 @@ struct ucall { void ucall_init(struct kvm_vm *vm, void *arg); void ucall_uninit(struct kvm_vm *vm); void ucall(uint64_t cmd, int nargs, ...); -uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc); +uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc); #define GUEST_SYNC_ARGS(stage, arg1, arg2, arg3, arg4) \ ucall(UCALL_SYNC, 6, "hello", stage, arg1, arg2, arg3, arg4) diff --git a/tools/testing/selftests/kvm/include/x86_64/evmcs.h b/tools/testing/selftests/kvm/include/x86_64/evmcs.h index cc5d14a45702..3c9260f8e116 100644 --- a/tools/testing/selftests/kvm/include/x86_64/evmcs.h +++ b/tools/testing/selftests/kvm/include/x86_64/evmcs.h @@ -241,7 +241,7 @@ struct hv_enlightened_vmcs { extern struct hv_enlightened_vmcs *current_evmcs; extern struct hv_vp_assist_page *current_vp_assist; -int vcpu_enable_evmcs(struct kvm_vm *vm, int vcpu_id); +int vcpu_enable_evmcs(struct kvm_vcpu *vcpu); static inline int enable_vp_assist(uint64_t vp_assist_pa, void *vp_assist) { diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index a19a52c50608..32964d7b2218 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -422,9 +422,8 @@ static inline unsigned int x86_model(unsigned int eax) return ((eax >> 12) & 0xf0) | ((eax >> 4) & 0x0f); } -struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid); -void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_x86_state *state); +struct kvm_x86_state *vcpu_save_state(struct kvm_vcpu *vcpu); +void vcpu_load_state(struct kvm_vcpu *vcpu, struct kvm_x86_state *state); void kvm_x86_state_cleanup(struct kvm_x86_state *state); const struct kvm_msr_list *kvm_get_msr_index_list(void); @@ -432,73 +431,71 @@ const struct kvm_msr_list *kvm_get_feature_msr_index_list(void); bool kvm_msr_is_in_save_restore_list(uint32_t msr_index); uint64_t kvm_get_feature_msr(uint64_t msr_index); -static inline void vcpu_msrs_get(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_msrs_get(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs) { - int r = __vcpu_ioctl(vm, vcpuid, KVM_GET_MSRS, msrs); + int r = __vcpu_ioctl(vcpu, KVM_GET_MSRS, msrs); TEST_ASSERT(r == msrs->nmsrs, "KVM_GET_MSRS failed, r: %i (failed on MSR %x)", r, r < 0 || r >= msrs->nmsrs ? -1 : msrs->entries[r].index); } -static inline void vcpu_msrs_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_msrs *msrs) +static inline void vcpu_msrs_set(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs) { - int r = __vcpu_ioctl(vm, vcpuid, KVM_SET_MSRS, msrs); + int r = __vcpu_ioctl(vcpu, KVM_SET_MSRS, msrs); TEST_ASSERT(r == msrs->nmsrs, "KVM_GET_MSRS failed, r: %i (failed on MSR %x)", r, r < 0 || r >= msrs->nmsrs ? -1 : msrs->entries[r].index); } -static inline void vcpu_debugregs_get(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_debugregs_get(struct kvm_vcpu *vcpu, struct kvm_debugregs *debugregs) { - vcpu_ioctl(vm, vcpuid, KVM_GET_DEBUGREGS, debugregs); + vcpu_ioctl(vcpu, KVM_GET_DEBUGREGS, debugregs); } -static inline void vcpu_debugregs_set(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_debugregs_set(struct kvm_vcpu *vcpu, struct kvm_debugregs *debugregs) { - vcpu_ioctl(vm, vcpuid, KVM_SET_DEBUGREGS, debugregs); + vcpu_ioctl(vcpu, KVM_SET_DEBUGREGS, debugregs); } -static inline void vcpu_xsave_get(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_xsave_get(struct kvm_vcpu *vcpu, struct kvm_xsave *xsave) { - vcpu_ioctl(vm, vcpuid, KVM_GET_XSAVE, xsave); + vcpu_ioctl(vcpu, KVM_GET_XSAVE, xsave); } -static inline void vcpu_xsave2_get(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_xsave2_get(struct kvm_vcpu *vcpu, struct kvm_xsave *xsave) { - vcpu_ioctl(vm, vcpuid, KVM_GET_XSAVE2, xsave); + vcpu_ioctl(vcpu, KVM_GET_XSAVE2, xsave); } -static inline void vcpu_xsave_set(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_xsave_set(struct kvm_vcpu *vcpu, struct kvm_xsave *xsave) { - vcpu_ioctl(vm, vcpuid, KVM_SET_XSAVE, xsave); + vcpu_ioctl(vcpu, KVM_SET_XSAVE, xsave); } -static inline void vcpu_xcrs_get(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_xcrs_get(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs) { - vcpu_ioctl(vm, vcpuid, KVM_GET_XCRS, xcrs); + vcpu_ioctl(vcpu, KVM_GET_XCRS, xcrs); } -static inline void vcpu_xcrs_set(struct kvm_vm *vm, uint32_t vcpuid, - struct kvm_xcrs *xcrs) +static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs) { - vcpu_ioctl(vm, vcpuid, KVM_SET_XCRS, xcrs); + vcpu_ioctl(vcpu, KVM_SET_XCRS, xcrs); } struct kvm_cpuid2 *kvm_get_supported_cpuid(void); -struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid); +struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu); -static inline int __vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, +static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) { - return __vcpu_ioctl(vm, vcpuid, KVM_SET_CPUID2, cpuid); + return __vcpu_ioctl(vcpu, KVM_SET_CPUID2, cpuid); } -static inline void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid, +static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) { - vcpu_ioctl(vm, vcpuid, KVM_SET_CPUID2, cpuid); + vcpu_ioctl(vcpu, KVM_SET_CPUID2, cpuid); } struct kvm_cpuid_entry2 * @@ -510,14 +507,13 @@ kvm_get_supported_cpuid_entry(uint32_t function) return kvm_get_supported_cpuid_index(function, 0); } -uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index); -int _vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, - uint64_t msr_value); +uint64_t vcpu_get_msr(struct kvm_vcpu *vcpu, uint64_t msr_index); +int _vcpu_set_msr(struct kvm_vcpu *vcpu, uint64_t msr_index, uint64_t msr_value); -static inline void vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, - uint64_t msr_index, uint64_t msr_value) +static inline void vcpu_set_msr(struct kvm_vcpu *vcpu, uint64_t msr_index, + uint64_t msr_value) { - int r = _vcpu_set_msr(vm, vcpuid, msr_index, msr_value); + int r = _vcpu_set_msr(vcpu, msr_index, msr_value); TEST_ASSERT(r == 1, KVM_IOCTL_ERROR(KVM_SET_MSRS, r)); } @@ -541,13 +537,14 @@ struct ex_regs { }; void vm_init_descriptor_tables(struct kvm_vm *vm); -void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid); +void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu); void vm_install_exception_handler(struct kvm_vm *vm, int vector, void (*handler)(struct ex_regs *)); -uint64_t vm_get_page_table_entry(struct kvm_vm *vm, int vcpuid, uint64_t vaddr); -void vm_set_page_table_entry(struct kvm_vm *vm, int vcpuid, uint64_t vaddr, - uint64_t pte); +uint64_t vm_get_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, + uint64_t vaddr); +void vm_set_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, + uint64_t vaddr, uint64_t pte); /* * get_cpuid() - find matching CPUID entry and return pointer to it. @@ -567,8 +564,8 @@ uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3); struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void); -void vcpu_set_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid); -struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid); +void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu); +struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu); void vm_xsave_req_perm(int bit); enum pg_level { diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index dfc3cf531ced..7f2ddc1535d7 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -174,7 +174,7 @@ static void vm_stats_test(struct kvm_vm *vm) static void vcpu_stats_test(struct kvm_vcpu *vcpu) { - int stats_fd = vcpu_get_stats_fd(vcpu->vm, vcpu->id); + int stats_fd = vcpu_get_stats_fd(vcpu); stats_test(stats_fd); close(stats_fd); diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c index b577b5999c95..8706ae358444 100644 --- a/tools/testing/selftests/kvm/kvm_page_table_test.c +++ b/tools/testing/selftests/kvm/kvm_page_table_test.c @@ -184,7 +184,6 @@ static void guest_code(bool do_write) static void *vcpu_worker(void *data) { - struct kvm_vm *vm = test_args.vm; struct kvm_vcpu *vcpu = data; bool do_write = !(vcpu->id % 2); struct timespec start; @@ -192,7 +191,7 @@ static void *vcpu_worker(void *data) enum test_stage stage; int ret; - vcpu_args_set(vm, vcpu->id, 1, do_write); + vcpu_args_set(vcpu, 1, do_write); while (!READ_ONCE(host_quit)) { ret = sem_wait(&test_stage_updated); @@ -202,11 +201,11 @@ static void *vcpu_worker(void *data) return NULL; clock_gettime(CLOCK_MONOTONIC_RAW, &start); - ret = _vcpu_run(vm, vcpu->id); + ret = _vcpu_run(vcpu); ts_diff = timespec_elapsed(start); TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); - TEST_ASSERT(get_ucall(vm, vcpu->id, NULL) == UCALL_SYNC, + TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC, "Invalid guest sync status: exit_reason=%s\n", exit_reason_str(vcpu->run->exit_reason)); diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index d158d5aa26e6..6bd27782f00c 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -212,9 +212,10 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) } } -void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init *init) +void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init) { struct kvm_vcpu_init default_init = { .target = -1, }; + struct kvm_vm *vm = vcpu->vm; uint64_t sctlr_el1, tcr_el1; if (!init) @@ -226,16 +227,16 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init init->target = preferred.target; } - vcpu_ioctl(vm, vcpuid, KVM_ARM_VCPU_INIT, init); + vcpu_ioctl(vcpu, KVM_ARM_VCPU_INIT, init); /* * Enable FP/ASIMD to avoid trapping when accessing Q0-Q15 * registers, which the variable argument list macros do. */ - vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_CPACR_EL1), 3 << 20); + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_CPACR_EL1), 3 << 20); - vcpu_get_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), &sctlr_el1); - vcpu_get_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TCR_EL1), &tcr_el1); + vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), &sctlr_el1); + vcpu_get_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), &tcr_el1); /* Configure base granule size */ switch (vm->mode) { @@ -296,19 +297,19 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init tcr_el1 |= (1 << 8) | (1 << 10) | (3 << 12); tcr_el1 |= (64 - vm->va_bits) /* T0SZ */; - vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1); - vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1); - vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_MAIR_EL1), DEFAULT_MAIR_EL1); - vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TTBR0_EL1), vm->pgd); - vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_TPIDR_EL1), vcpuid); + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_SCTLR_EL1), sctlr_el1); + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TCR_EL1), tcr_el1); + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_MAIR_EL1), DEFAULT_MAIR_EL1); + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TTBR0_EL1), vm->pgd); + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TPIDR_EL1), vcpu->id); } -void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) +void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent) { uint64_t pstate, pc; - vcpu_get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pstate), &pstate); - vcpu_get_reg(vm, vcpuid, ARM64_CORE_REG(regs.pc), &pc); + vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pstate), &pstate); + vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc), &pc); fprintf(stream, "%*spstate: 0x%.16lx pc: 0x%.16lx\n", indent, "", pstate, pc); @@ -324,10 +325,10 @@ struct kvm_vcpu *aarch64_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, DEFAULT_ARM64_GUEST_STACK_VADDR_MIN); struct kvm_vcpu *vcpu = __vm_vcpu_add(vm, vcpu_id); - aarch64_vcpu_setup(vm, vcpu_id, init); + aarch64_vcpu_setup(vcpu, init); - vcpu_set_reg(vm, vcpu_id, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); - vcpu_set_reg(vm, vcpu_id, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); + vcpu_set_reg(vcpu, ARM64_CORE_REG(sp_el1), stack_vaddr + stack_size); + vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.pc), (uint64_t)guest_code); return vcpu; } @@ -338,7 +339,7 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, return aarch64_vcpu_add(vm, vcpu_id, NULL, guest_code); } -void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) +void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) { va_list ap; int i; @@ -349,8 +350,8 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) va_start(ap, num); for (i = 0; i < num; i++) { - vcpu_set_reg(vm, vcpuid, ARM64_CORE_REG(regs.regs[i]), - va_arg(ap, uint64_t)); + vcpu_set_reg(vcpu, ARM64_CORE_REG(regs.regs[i]), + va_arg(ap, uint64_t)); } va_end(ap); @@ -363,11 +364,11 @@ void kvm_exit_unexpected_exception(int vector, uint64_t ec, bool valid_ec) ; } -void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid) +void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) { struct ucall uc; - if (get_ucall(vm, vcpuid, &uc) != UCALL_UNHANDLED) + if (get_ucall(vcpu, &uc) != UCALL_UNHANDLED) return; if (uc.args[2]) /* valid_ec */ { @@ -385,11 +386,11 @@ struct handlers { handler_fn exception_handlers[VECTOR_NUM][ESR_EC_NUM]; }; -void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid) +void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu) { extern char vectors; - vcpu_set_reg(vm, vcpuid, KVM_ARM64_SYS_REG(SYS_VBAR_EL1), (uint64_t)&vectors); + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_VBAR_EL1), (uint64_t)&vectors); } void route_exception(struct ex_regs *regs, int vector) diff --git a/tools/testing/selftests/kvm/lib/aarch64/ucall.c b/tools/testing/selftests/kvm/lib/aarch64/ucall.c index 868ebab5369e..0b949ee06b5e 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/ucall.c +++ b/tools/testing/selftests/kvm/lib/aarch64/ucall.c @@ -88,9 +88,9 @@ void ucall(uint64_t cmd, int nargs, ...) *ucall_exit_mmio_addr = (vm_vaddr_t)&uc; } -uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) +uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc) { - struct kvm_run *run = vcpu_state(vm, vcpu_id); + struct kvm_run *run = vcpu->run; struct ucall ucall = {}; if (uc) @@ -103,9 +103,9 @@ uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) TEST_ASSERT(run->mmio.is_write && run->mmio.len == 8, "Unexpected ucall exit mmio address access"); memcpy(&gva, run->mmio.data, sizeof(gva)); - memcpy(&ucall, addr_gva2hva(vm, gva), sizeof(ucall)); + memcpy(&ucall, addr_gva2hva(vcpu->vm, gva), sizeof(ucall)); - vcpu_run_complete_io(vm, vcpu_id); + vcpu_run_complete_io(vcpu); if (uc) memcpy(uc, &ucall, sizeof(ucall)); } diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 351c167e7b99..eb04b9c0a13c 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1395,88 +1395,49 @@ void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa) return (void *) ((uintptr_t) region->host_alias + offset); } -/* - * VM Create IRQ Chip - * - * Input Args: - * vm - Virtual Machine - * - * Output Args: None - * - * Return: None - * - * Creates an interrupt controller chip for the VM specified by vm. - */ +/* Create an interrupt controller chip for the specified VM. */ void vm_create_irqchip(struct kvm_vm *vm) { vm_ioctl(vm, KVM_CREATE_IRQCHIP, NULL); vm->has_irqchip = true; } - -/* - * VM VCPU State - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * - * Output Args: None - * - * Return: - * Pointer to structure that describes the state of the VCPU. - * - * Locates and returns a pointer to a structure that describes the - * state of the VCPU with the given vcpuid. - */ -struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) +struct kvm_run *vcpu_state(struct kvm_vcpu *vcpu) { - struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); - return vcpu->run; } -/* - * VM VCPU Run - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * - * Output Args: None - * - * Return: None - * - * Switch to executing the code for the VCPU given by vcpuid, within the VM - * given by vm. - */ -void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) -{ - int ret = _vcpu_run(vm, vcpuid); - TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_RUN, ret)); -} - -int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) +int _vcpu_run(struct kvm_vcpu *vcpu) { int rc; do { - rc = __vcpu_run(vm, vcpuid); + rc = __vcpu_run(vcpu); } while (rc == -1 && errno == EINTR); - assert_on_unhandled_exception(vm, vcpuid); + assert_on_unhandled_exception(vcpu); return rc; } -void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid) +/* + * Invoke KVM_RUN on a vCPU until KVM returns something other than -EINTR. + * Assert if the KVM returns an error (other than -EINTR). + */ +void vcpu_run(struct kvm_vcpu *vcpu) +{ + int ret = _vcpu_run(vcpu); + + TEST_ASSERT(!ret, KVM_IOCTL_ERROR(KVM_RUN, ret)); +} + +void vcpu_run_complete_io(struct kvm_vcpu *vcpu) { - struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); int ret; vcpu->run->immediate_exit = 1; - ret = __vcpu_run(vm, vcpuid); + ret = __vcpu_run(vcpu); vcpu->run->immediate_exit = 0; TEST_ASSERT(ret == -1 && errno == EINTR, @@ -1485,73 +1446,57 @@ void vcpu_run_complete_io(struct kvm_vm *vm, uint32_t vcpuid) } /* - * VM VCPU Get Reg List - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU ID - * - * Output Args: - * None - * - * Return: - * A pointer to an allocated struct kvm_reg_list - * * Get the list of guest registers which are supported for - * KVM_GET_ONE_REG/KVM_SET_ONE_REG calls + * KVM_GET_ONE_REG/KVM_SET_ONE_REG ioctls. Returns a kvm_reg_list pointer, + * it is the callers responsibility to free the list. */ -struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vm *vm, uint32_t vcpuid) +struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vcpu *vcpu) { struct kvm_reg_list reg_list_n = { .n = 0 }, *reg_list; int ret; - ret = __vcpu_ioctl(vm, vcpuid, KVM_GET_REG_LIST, ®_list_n); + ret = __vcpu_ioctl(vcpu, KVM_GET_REG_LIST, ®_list_n); TEST_ASSERT(ret == -1 && errno == E2BIG, "KVM_GET_REG_LIST n=0"); + reg_list = calloc(1, sizeof(*reg_list) + reg_list_n.n * sizeof(__u64)); reg_list->n = reg_list_n.n; - vcpu_ioctl(vm, vcpuid, KVM_GET_REG_LIST, reg_list); + vcpu_ioctl(vcpu, KVM_GET_REG_LIST, reg_list); return reg_list; } -int __vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, - unsigned long cmd, void *arg) +int __vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long cmd, void *arg) { - struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); - return ioctl(vcpu->fd, cmd, arg); } -void _vcpu_ioctl(struct kvm_vm *vm, uint32_t vcpuid, unsigned long cmd, - const char *name, void *arg) +void _vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long cmd, const char *name, + void *arg) { - int ret = __vcpu_ioctl(vm, vcpuid, cmd, arg); + int ret = __vcpu_ioctl(vcpu, cmd, arg); TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); } -void *vcpu_map_dirty_ring(struct kvm_vm *vm, uint32_t vcpuid) +void *vcpu_map_dirty_ring(struct kvm_vcpu *vcpu) { - struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); - uint32_t size = vm->dirty_ring_size; + uint32_t page_size = vcpu->vm->page_size; + uint32_t size = vcpu->vm->dirty_ring_size; TEST_ASSERT(size > 0, "Should enable dirty ring first"); if (!vcpu->dirty_gfns) { void *addr; - addr = mmap(NULL, size, PROT_READ, - MAP_PRIVATE, vcpu->fd, - vm->page_size * KVM_DIRTY_LOG_PAGE_OFFSET); + addr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, vcpu->fd, + page_size * KVM_DIRTY_LOG_PAGE_OFFSET); TEST_ASSERT(addr == MAP_FAILED, "Dirty ring mapped private"); - addr = mmap(NULL, size, PROT_READ | PROT_EXEC, - MAP_PRIVATE, vcpu->fd, - vm->page_size * KVM_DIRTY_LOG_PAGE_OFFSET); + addr = mmap(NULL, size, PROT_READ | PROT_EXEC, MAP_PRIVATE, vcpu->fd, + page_size * KVM_DIRTY_LOG_PAGE_OFFSET); TEST_ASSERT(addr == MAP_FAILED, "Dirty ring mapped exec"); - addr = mmap(NULL, size, PROT_READ | PROT_WRITE, - MAP_SHARED, vcpu->fd, - vm->page_size * KVM_DIRTY_LOG_PAGE_OFFSET); + addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, + page_size * KVM_DIRTY_LOG_PAGE_OFFSET); TEST_ASSERT(addr != MAP_FAILED, "Dirty ring map failed"); vcpu->dirty_gfns = addr; @@ -1636,36 +1581,6 @@ int __kvm_device_attr_set(int dev_fd, uint32_t group, uint64_t attr, void *val) return __kvm_ioctl(dev_fd, KVM_SET_DEVICE_ATTR, &kvmattr); } -int __vcpu_device_attr_get(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val) -{ - return __kvm_device_attr_get(vcpu_get(vm, vcpuid)->fd, group, attr, val); -} - -void vcpu_device_attr_get(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val) -{ - kvm_device_attr_get(vcpu_get(vm, vcpuid)->fd, group, attr, val); -} - -int __vcpu_device_attr_set(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val) -{ - return __kvm_device_attr_set(vcpu_get(vm, vcpuid)->fd, group, attr, val); -} - -void vcpu_device_attr_set(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr, void *val) -{ - kvm_device_attr_set(vcpu_get(vm, vcpuid)->fd, group, attr, val); -} - -int __vcpu_has_device_attr(struct kvm_vm *vm, uint32_t vcpuid, uint32_t group, - uint64_t attr) -{ - return __kvm_has_device_attr(vcpu_get(vm, vcpuid)->fd, group, attr); -} - /* * IRQ related functions. */ @@ -1781,8 +1696,9 @@ void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) virt_dump(stream, vm, indent + 4); } fprintf(stream, "%*sVCPUs:\n", indent, ""); + list_for_each_entry(vcpu, &vm->vcpus, list) - vcpu_dump(stream, vm, vcpu->id, indent + 2); + vcpu_dump(stream, vcpu, indent + 2); } /* Known KVM exit reasons */ diff --git a/tools/testing/selftests/kvm/lib/perf_test_util.c b/tools/testing/selftests/kvm/lib/perf_test_util.c index 91a89553afdd..a8c7b2785cc4 100644 --- a/tools/testing/selftests/kvm/lib/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/perf_test_util.c @@ -98,7 +98,7 @@ void perf_test_setup_vcpus(struct kvm_vm *vm, int nr_vcpus, vcpu_args->gpa = pta->gpa; } - vcpu_args_set(vm, vcpus[i]->id, 1, i); + vcpu_args_set(vcpus[i], 1, i); pr_debug("Added VCPU %d with test mem gpa [%lx, %lx)\n", i, vcpu_args->gpa, vcpu_args->gpa + diff --git a/tools/testing/selftests/kvm/lib/riscv/processor.c b/tools/testing/selftests/kvm/lib/riscv/processor.c index edbdc7bef05b..604478151212 100644 --- a/tools/testing/selftests/kvm/lib/riscv/processor.c +++ b/tools/testing/selftests/kvm/lib/riscv/processor.c @@ -178,8 +178,9 @@ void virt_arch_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) } } -void riscv_vcpu_mmu_setup(struct kvm_vm *vm, int vcpuid) +void riscv_vcpu_mmu_setup(struct kvm_vcpu *vcpu) { + struct kvm_vm *vm = vcpu->vm; unsigned long satp; /* @@ -198,46 +199,46 @@ void riscv_vcpu_mmu_setup(struct kvm_vm *vm, int vcpuid) satp = (vm->pgd >> PGTBL_PAGE_SIZE_SHIFT) & SATP_PPN; satp |= SATP_MODE_48; - vcpu_set_reg(vm, vcpuid, RISCV_CSR_REG(satp), satp); + vcpu_set_reg(vcpu, RISCV_CSR_REG(satp), satp); } -void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) +void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent) { struct kvm_riscv_core core; - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(mode), &core.mode); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.pc), &core.regs.pc); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.ra), &core.regs.ra); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.sp), &core.regs.sp); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.gp), &core.regs.gp); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.tp), &core.regs.tp); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t0), &core.regs.t0); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t1), &core.regs.t1); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t2), &core.regs.t2); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s0), &core.regs.s0); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s1), &core.regs.s1); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a0), &core.regs.a0); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a1), &core.regs.a1); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a2), &core.regs.a2); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a3), &core.regs.a3); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a4), &core.regs.a4); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a5), &core.regs.a5); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a6), &core.regs.a6); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.a7), &core.regs.a7); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s2), &core.regs.s2); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s3), &core.regs.s3); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s4), &core.regs.s4); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s5), &core.regs.s5); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s6), &core.regs.s6); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s7), &core.regs.s7); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s8), &core.regs.s8); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s9), &core.regs.s9); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s10), &core.regs.s10); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.s11), &core.regs.s11); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t3), &core.regs.t3); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t4), &core.regs.t4); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t5), &core.regs.t5); - vcpu_get_reg(vm, vcpuid, RISCV_CORE_REG(regs.t6), &core.regs.t6); + vcpu_get_reg(vcpu, RISCV_CORE_REG(mode), &core.mode); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.pc), &core.regs.pc); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.ra), &core.regs.ra); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.sp), &core.regs.sp); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.gp), &core.regs.gp); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.tp), &core.regs.tp); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.t0), &core.regs.t0); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.t1), &core.regs.t1); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.t2), &core.regs.t2); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s0), &core.regs.s0); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s1), &core.regs.s1); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.a0), &core.regs.a0); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.a1), &core.regs.a1); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.a2), &core.regs.a2); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.a3), &core.regs.a3); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.a4), &core.regs.a4); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.a5), &core.regs.a5); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.a6), &core.regs.a6); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.a7), &core.regs.a7); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s2), &core.regs.s2); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s3), &core.regs.s3); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s4), &core.regs.s4); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s5), &core.regs.s5); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s6), &core.regs.s6); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s7), &core.regs.s7); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s8), &core.regs.s8); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s9), &core.regs.s9); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s10), &core.regs.s10); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.s11), &core.regs.s11); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.t3), &core.regs.t3); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.t4), &core.regs.t4); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.t5), &core.regs.t5); + vcpu_get_reg(vcpu, RISCV_CORE_REG(regs.t6), &core.regs.t6); fprintf(stream, " MODE: 0x%lx\n", core.mode); @@ -288,7 +289,7 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, struct kvm_vcpu *vcpu; vcpu = __vm_vcpu_add(vm, vcpu_id); - riscv_vcpu_mmu_setup(vm, vcpu_id); + riscv_vcpu_mmu_setup(vcpu); /* * With SBI HSM support in KVM RISC-V, all secondary VCPUs are @@ -296,28 +297,25 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, * are powered-on using KVM_SET_MP_STATE ioctl(). */ mps.mp_state = KVM_MP_STATE_RUNNABLE; - r = __vcpu_ioctl(vm, vcpu_id, KVM_SET_MP_STATE, &mps); + r = __vcpu_ioctl(vcpu, KVM_SET_MP_STATE, &mps); TEST_ASSERT(!r, "IOCTL KVM_SET_MP_STATE failed (error %d)", r); /* Setup global pointer of guest to be same as the host */ asm volatile ( "add %0, gp, zero" : "=r" (current_gp) : : "memory"); - vcpu_set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.gp), current_gp); + vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.gp), current_gp); /* Setup stack pointer and program counter of guest */ - vcpu_set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.sp), - stack_vaddr + stack_size); - vcpu_set_reg(vm, vcpu_id, RISCV_CORE_REG(regs.pc), - (unsigned long)guest_code); + vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.sp), stack_vaddr + stack_size); + vcpu_set_reg(vcpu, RISCV_CORE_REG(regs.pc), (unsigned long)guest_code); /* Setup default exception vector of guest */ - vcpu_set_reg(vm, vcpu_id, RISCV_CSR_REG(stvec), - (unsigned long)guest_unexp_trap); + vcpu_set_reg(vcpu, RISCV_CSR_REG(stvec), (unsigned long)guest_unexp_trap); return vcpu; } -void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) +void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) { va_list ap; uint64_t id = RISCV_CORE_REG(regs.a0); @@ -355,12 +353,12 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) id = RISCV_CORE_REG(regs.a7); break; } - vcpu_set_reg(vm, vcpuid, id, va_arg(ap, uint64_t)); + vcpu_set_reg(vcpu, id, va_arg(ap, uint64_t)); } va_end(ap); } -void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid) +void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) { } diff --git a/tools/testing/selftests/kvm/lib/riscv/ucall.c b/tools/testing/selftests/kvm/lib/riscv/ucall.c index 48d91b77fa1d..087b9740bc8f 100644 --- a/tools/testing/selftests/kvm/lib/riscv/ucall.c +++ b/tools/testing/selftests/kvm/lib/riscv/ucall.c @@ -64,9 +64,9 @@ void ucall(uint64_t cmd, int nargs, ...) (vm_vaddr_t)&uc, 0, 0, 0, 0, 0); } -uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) +uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc) { - struct kvm_run *run = vcpu_state(vm, vcpu_id); + struct kvm_run *run = vcpu->run; struct ucall ucall = {}; if (uc) @@ -76,16 +76,17 @@ uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) run->riscv_sbi.extension_id == KVM_RISCV_SELFTESTS_SBI_EXT) { switch (run->riscv_sbi.function_id) { case KVM_RISCV_SELFTESTS_SBI_UCALL: - memcpy(&ucall, addr_gva2hva(vm, - run->riscv_sbi.args[0]), sizeof(ucall)); + memcpy(&ucall, + addr_gva2hva(vcpu->vm, run->riscv_sbi.args[0]), + sizeof(ucall)); - vcpu_run_complete_io(vm, vcpu_id); + vcpu_run_complete_io(vcpu); if (uc) memcpy(uc, &ucall, sizeof(ucall)); break; case KVM_RISCV_SELFTESTS_SBI_UNEXP: - vcpu_dump(stderr, vm, vcpu_id, 2); + vcpu_dump(stderr, vcpu, 2); TEST_ASSERT(0, "Unexpected trap taken by guest"); break; default: diff --git a/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c b/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c index 21c31fe10c1a..05283f8c9948 100644 --- a/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c +++ b/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c @@ -32,7 +32,7 @@ static uint64_t diag318_handler(void) uint64_t diag318_info; vm = vm_create_with_one_vcpu(&vcpu, guest_code); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); run = vcpu->run; TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, diff --git a/tools/testing/selftests/kvm/lib/s390x/processor.c b/tools/testing/selftests/kvm/lib/s390x/processor.c index f8170e97eeb7..89d7340d9cbd 100644 --- a/tools/testing/selftests/kvm/lib/s390x/processor.c +++ b/tools/testing/selftests/kvm/lib/s390x/processor.c @@ -173,23 +173,23 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, vcpu = __vm_vcpu_add(vm, vcpu_id); /* Setup guest registers */ - vcpu_regs_get(vm, vcpu_id, ®s); + vcpu_regs_get(vcpu, ®s); regs.gprs[15] = stack_vaddr + (DEFAULT_STACK_PGS * getpagesize()) - 160; - vcpu_regs_set(vm, vcpu_id, ®s); + vcpu_regs_set(vcpu, ®s); - vcpu_sregs_get(vm, vcpu_id, &sregs); + vcpu_sregs_get(vcpu, &sregs); sregs.crs[0] |= 0x00040000; /* Enable floating point regs */ sregs.crs[1] = vm->pgd | 0xf; /* Primary region table */ - vcpu_sregs_set(vm, vcpu_id, &sregs); + vcpu_sregs_set(vcpu, &sregs); - run = vcpu_state(vm, vcpu_id); + run = vcpu->run; run->psw_mask = 0x0400000180000000ULL; /* DAT enabled + 64 bit mode */ run->psw_addr = (uintptr_t)guest_code; return vcpu; } -void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) +void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) { va_list ap; struct kvm_regs regs; @@ -200,23 +200,21 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) num); va_start(ap, num); - vcpu_regs_get(vm, vcpuid, ®s); + vcpu_regs_get(vcpu, ®s); for (i = 0; i < num; i++) regs.gprs[i + 2] = va_arg(ap, uint64_t); - vcpu_regs_set(vm, vcpuid, ®s); + vcpu_regs_set(vcpu, ®s); va_end(ap); } -void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) +void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent) { - struct kvm_vcpu *vcpu = vcpu_get(vm, vcpuid); - fprintf(stream, "%*spstate: psw: 0x%.16llx:0x%.16llx\n", indent, "", vcpu->run->psw_mask, vcpu->run->psw_addr); } -void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid) +void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) { } diff --git a/tools/testing/selftests/kvm/lib/s390x/ucall.c b/tools/testing/selftests/kvm/lib/s390x/ucall.c index 665267c1135d..73dc4e21190f 100644 --- a/tools/testing/selftests/kvm/lib/s390x/ucall.c +++ b/tools/testing/selftests/kvm/lib/s390x/ucall.c @@ -33,9 +33,9 @@ void ucall(uint64_t cmd, int nargs, ...) asm volatile ("diag 0,%0,0x501" : : "a"(&uc) : "memory"); } -uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) +uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc) { - struct kvm_run *run = vcpu_state(vm, vcpu_id); + struct kvm_run *run = vcpu->run; struct ucall ucall = {}; if (uc) @@ -47,10 +47,10 @@ uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) (run->s390_sieic.ipb >> 16) == 0x501) { int reg = run->s390_sieic.ipa & 0xf; - memcpy(&ucall, addr_gva2hva(vm, run->s.regs.gprs[reg]), + memcpy(&ucall, addr_gva2hva(vcpu->vm, run->s.regs.gprs[reg]), sizeof(ucall)); - vcpu_run_complete_io(vm, vcpu_id); + vcpu_run_complete_io(vcpu); if (uc) memcpy(uc, &ucall, sizeof(ucall)); } diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index f89d67101bf1..a54910adea98 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -212,8 +212,9 @@ void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) __virt_pg_map(vm, vaddr, paddr, PG_LEVEL_4K); } -static uint64_t *_vm_get_page_table_entry(struct kvm_vm *vm, int vcpuid, - uint64_t vaddr) +static uint64_t *_vm_get_page_table_entry(struct kvm_vm *vm, + struct kvm_vcpu *vcpu, + uint64_t vaddr) { uint16_t index[4]; uint64_t *pml4e, *pdpe, *pde; @@ -235,7 +236,7 @@ static uint64_t *_vm_get_page_table_entry(struct kvm_vm *vm, int vcpuid, * If IA32_EFER.NXE = 0 and the P flag of a paging-structure entry is 1, * the XD flag (bit 63) is reserved. */ - vcpu_sregs_get(vm, vcpuid, &sregs); + vcpu_sregs_get(vcpu, &sregs); if ((sregs.efer & EFER_NX) == 0) { rsvd_mask |= PTE_NX_MASK; } @@ -287,17 +288,18 @@ static uint64_t *_vm_get_page_table_entry(struct kvm_vm *vm, int vcpuid, return &pte[index[0]]; } -uint64_t vm_get_page_table_entry(struct kvm_vm *vm, int vcpuid, uint64_t vaddr) +uint64_t vm_get_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, + uint64_t vaddr) { - uint64_t *pte = _vm_get_page_table_entry(vm, vcpuid, vaddr); + uint64_t *pte = _vm_get_page_table_entry(vm, vcpu, vaddr); return *(uint64_t *)pte; } -void vm_set_page_table_entry(struct kvm_vm *vm, int vcpuid, uint64_t vaddr, - uint64_t pte) +void vm_set_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, + uint64_t vaddr, uint64_t pte) { - uint64_t *new_pte = _vm_get_page_table_entry(vm, vcpuid, vaddr); + uint64_t *new_pte = _vm_get_page_table_entry(vm, vcpu, vaddr); *(uint64_t *)new_pte = pte; } @@ -546,12 +548,12 @@ static void kvm_setup_tss_64bit(struct kvm_vm *vm, struct kvm_segment *segp, kvm_seg_fill_gdt_64bit(vm, segp); } -static void vcpu_setup(struct kvm_vm *vm, int vcpuid) +static void vcpu_setup(struct kvm_vm *vm, struct kvm_vcpu *vcpu) { struct kvm_sregs sregs; /* Set mode specific system register values. */ - vcpu_sregs_get(vm, vcpuid, &sregs); + vcpu_sregs_get(vcpu, &sregs); sregs.idt.limit = 0; @@ -575,7 +577,7 @@ static void vcpu_setup(struct kvm_vm *vm, int vcpuid) } sregs.cr3 = vm->pgd; - vcpu_sregs_set(vm, vcpuid, &sregs); + vcpu_sregs_set(vcpu, &sregs); } #define CPUID_XFD_BIT (1 << 4) @@ -644,19 +646,19 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, DEFAULT_GUEST_STACK_VADDR_MIN); vcpu = __vm_vcpu_add(vm, vcpu_id); - vcpu_set_cpuid(vm, vcpu_id, kvm_get_supported_cpuid()); - vcpu_setup(vm, vcpu_id); + vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); + vcpu_setup(vm, vcpu); /* Setup guest general purpose registers */ - vcpu_regs_get(vm, vcpu_id, ®s); + vcpu_regs_get(vcpu, ®s); regs.rflags = regs.rflags | 0x2; regs.rsp = stack_vaddr + (DEFAULT_STACK_PGS * getpagesize()); regs.rip = (unsigned long) guest_code; - vcpu_regs_set(vm, vcpu_id, ®s); + vcpu_regs_set(vcpu, ®s); /* Setup the MP state */ mp_state.mp_state = 0; - vcpu_mp_state_set(vm, vcpu_id, &mp_state); + vcpu_mp_state_set(vcpu, &mp_state); return vcpu; } @@ -742,20 +744,7 @@ uint64_t kvm_get_feature_msr(uint64_t msr_index) return buffer.entry.data; } -/* - * VM VCPU CPUID Set - * - * Input Args: - * vm - Virtual Machine - * vcpuid - VCPU id - * - * Output Args: None - * - * Return: KVM CPUID (KVM_GET_CPUID2) - * - * Set the VCPU's CPUID. - */ -struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid) +struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu) { struct kvm_cpuid2 *cpuid; int max_ent; @@ -765,7 +754,7 @@ struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid) max_ent = cpuid->nent; for (cpuid->nent = 1; cpuid->nent <= max_ent; cpuid->nent++) { - rc = __vcpu_ioctl(vm, vcpuid, KVM_GET_CPUID2, cpuid); + rc = __vcpu_ioctl(vcpu, KVM_GET_CPUID2, cpuid); if (!rc) break; @@ -812,7 +801,7 @@ kvm_get_supported_cpuid_index(uint32_t function, uint32_t index) return entry; } -uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index) +uint64_t vcpu_get_msr(struct kvm_vcpu *vcpu, uint64_t msr_index) { struct { struct kvm_msrs header; @@ -822,13 +811,12 @@ uint64_t vcpu_get_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index) buffer.header.nmsrs = 1; buffer.entry.index = msr_index; - vcpu_msrs_get(vm, vcpuid, &buffer.header); + vcpu_msrs_get(vcpu, &buffer.header); return buffer.entry.data; } -int _vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, - uint64_t msr_value) +int _vcpu_set_msr(struct kvm_vcpu *vcpu, uint64_t msr_index, uint64_t msr_value) { struct { struct kvm_msrs header; @@ -840,10 +828,10 @@ int _vcpu_set_msr(struct kvm_vm *vm, uint32_t vcpuid, uint64_t msr_index, buffer.entry.index = msr_index; buffer.entry.data = msr_value; - return __vcpu_ioctl(vm, vcpuid, KVM_SET_MSRS, &buffer.header); + return __vcpu_ioctl(vcpu, KVM_SET_MSRS, &buffer.header); } -void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) +void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) { va_list ap; struct kvm_regs regs; @@ -853,7 +841,7 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) num); va_start(ap, num); - vcpu_regs_get(vm, vcpuid, ®s); + vcpu_regs_get(vcpu, ®s); if (num >= 1) regs.rdi = va_arg(ap, uint64_t); @@ -873,23 +861,23 @@ void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) if (num >= 6) regs.r9 = va_arg(ap, uint64_t); - vcpu_regs_set(vm, vcpuid, ®s); + vcpu_regs_set(vcpu, ®s); va_end(ap); } -void vcpu_arch_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent) +void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent) { struct kvm_regs regs; struct kvm_sregs sregs; - fprintf(stream, "%*scpuid: %u\n", indent, "", vcpuid); + fprintf(stream, "%*svCPU ID: %u\n", indent, "", vcpu->id); fprintf(stream, "%*sregs:\n", indent + 2, ""); - vcpu_regs_get(vm, vcpuid, ®s); + vcpu_regs_get(vcpu, ®s); regs_dump(stream, ®s, indent + 4); fprintf(stream, "%*ssregs:\n", indent + 2, ""); - vcpu_sregs_get(vm, vcpuid, &sregs); + vcpu_sregs_get(vcpu, &sregs); sregs_dump(stream, &sregs, indent + 4); } @@ -959,21 +947,21 @@ bool kvm_msr_is_in_save_restore_list(uint32_t msr_index) return false; } -static void vcpu_save_xsave_state(struct kvm_vm *vm, uint32_t vcpuid, +static void vcpu_save_xsave_state(struct kvm_vcpu *vcpu, struct kvm_x86_state *state) { - int size = vm_check_cap(vm, KVM_CAP_XSAVE2); + int size = vm_check_cap(vcpu->vm, KVM_CAP_XSAVE2); if (size) { state->xsave = malloc(size); - vcpu_xsave2_get(vm, vcpuid, state->xsave); + vcpu_xsave2_get(vcpu, state->xsave); } else { state->xsave = malloc(sizeof(struct kvm_xsave)); - vcpu_xsave_get(vm, vcpuid, state->xsave); + vcpu_xsave_get(vcpu, state->xsave); } } -struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) +struct kvm_x86_state *vcpu_save_state(struct kvm_vcpu *vcpu) { const struct kvm_msr_list *msr_list = kvm_get_msr_index_list(); struct kvm_x86_state *state; @@ -994,24 +982,24 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) * kernel with KVM_RUN. Complete IO prior to migrating state * to a new VM. */ - vcpu_run_complete_io(vm, vcpuid); + vcpu_run_complete_io(vcpu); state = malloc(sizeof(*state) + msr_list->nmsrs * sizeof(state->msrs.entries[0])); - vcpu_events_get(vm, vcpuid, &state->events); - vcpu_mp_state_get(vm, vcpuid, &state->mp_state); - vcpu_regs_get(vm, vcpuid, &state->regs); - vcpu_save_xsave_state(vm, vcpuid, state); + vcpu_events_get(vcpu, &state->events); + vcpu_mp_state_get(vcpu, &state->mp_state); + vcpu_regs_get(vcpu, &state->regs); + vcpu_save_xsave_state(vcpu, state); if (kvm_check_cap(KVM_CAP_XCRS)) - vcpu_xcrs_get(vm, vcpuid, &state->xcrs); + vcpu_xcrs_get(vcpu, &state->xcrs); - vcpu_sregs_get(vm, vcpuid, &state->sregs); + vcpu_sregs_get(vcpu, &state->sregs); if (nested_size) { state->nested.size = sizeof(state->nested_); - vcpu_nested_state_get(vm, vcpuid, &state->nested); + vcpu_nested_state_get(vcpu, &state->nested); TEST_ASSERT(state->nested.size <= nested_size, "Nested state size too big, %i (KVM_CHECK_CAP gave %i)", state->nested.size, nested_size); @@ -1022,29 +1010,29 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid) state->msrs.nmsrs = msr_list->nmsrs; for (i = 0; i < msr_list->nmsrs; i++) state->msrs.entries[i].index = msr_list->indices[i]; - vcpu_msrs_get(vm, vcpuid, &state->msrs); + vcpu_msrs_get(vcpu, &state->msrs); - vcpu_debugregs_get(vm, vcpuid, &state->debugregs); + vcpu_debugregs_get(vcpu, &state->debugregs); return state; } -void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *state) +void vcpu_load_state(struct kvm_vcpu *vcpu, struct kvm_x86_state *state) { - vcpu_sregs_set(vm, vcpuid, &state->sregs); - vcpu_msrs_set(vm, vcpuid, &state->msrs); + vcpu_sregs_set(vcpu, &state->sregs); + vcpu_msrs_set(vcpu, &state->msrs); if (kvm_check_cap(KVM_CAP_XCRS)) - vcpu_xcrs_set(vm, vcpuid, &state->xcrs); + vcpu_xcrs_set(vcpu, &state->xcrs); - vcpu_xsave_set(vm, vcpuid, state->xsave); - vcpu_events_set(vm, vcpuid, &state->events); - vcpu_mp_state_set(vm, vcpuid, &state->mp_state); - vcpu_debugregs_set(vm, vcpuid, &state->debugregs); - vcpu_regs_set(vm, vcpuid, &state->regs); + vcpu_xsave_set(vcpu, state->xsave); + vcpu_events_set(vcpu, &state->events); + vcpu_mp_state_set(vcpu, &state->mp_state); + vcpu_debugregs_set(vcpu, &state->debugregs); + vcpu_regs_set(vcpu, &state->regs); if (state->nested.size) - vcpu_nested_state_set(vm, vcpuid, &state->nested); + vcpu_nested_state_set(vcpu, &state->nested); } void kvm_x86_state_cleanup(struct kvm_x86_state *state) @@ -1170,17 +1158,18 @@ void vm_init_descriptor_tables(struct kvm_vm *vm) DEFAULT_CODE_SELECTOR); } -void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid) +void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu) { + struct kvm_vm *vm = vcpu->vm; struct kvm_sregs sregs; - vcpu_sregs_get(vm, vcpuid, &sregs); + vcpu_sregs_get(vcpu, &sregs); sregs.idt.base = vm->idt; sregs.idt.limit = NUM_INTERRUPTS * sizeof(struct idt_entry) - 1; sregs.gdt.base = vm->gdt; sregs.gdt.limit = getpagesize() - 1; kvm_seg_set_kernel_data_64bit(NULL, DEFAULT_DATA_SELECTOR, &sregs.gs); - vcpu_sregs_set(vm, vcpuid, &sregs); + vcpu_sregs_set(vcpu, &sregs); *(vm_vaddr_t *)addr_gva2hva(vm, (vm_vaddr_t)(&exception_handlers)) = vm->handlers; } @@ -1192,11 +1181,11 @@ void vm_install_exception_handler(struct kvm_vm *vm, int vector, handlers[vector] = (vm_vaddr_t)handler; } -void assert_on_unhandled_exception(struct kvm_vm *vm, uint32_t vcpuid) +void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) { struct ucall uc; - if (get_ucall(vm, vcpuid, &uc) == UCALL_UNHANDLED) { + if (get_ucall(vcpu, &uc) == UCALL_UNHANDLED) { uint64_t vector = uc.args[0]; TEST_FAIL("Unexpected vectored event in guest (vector:0x%lx)", @@ -1267,7 +1256,7 @@ struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void) return cpuid; } -void vcpu_set_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid) +void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu) { static struct kvm_cpuid2 *cpuid_full; struct kvm_cpuid2 *cpuid_sys, *cpuid_hv; @@ -1299,16 +1288,16 @@ void vcpu_set_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid) cpuid_full->nent = nent + cpuid_hv->nent; } - vcpu_set_cpuid(vm, vcpuid, cpuid_full); + vcpu_set_cpuid(vcpu, cpuid_full); } -struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vm *vm, uint32_t vcpuid) +struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu) { static struct kvm_cpuid2 *cpuid; cpuid = allocate_kvm_cpuid2(); - vcpu_ioctl(vm, vcpuid, KVM_GET_SUPPORTED_HV_CPUID, cpuid); + vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, cpuid); return cpuid; } diff --git a/tools/testing/selftests/kvm/lib/x86_64/ucall.c b/tools/testing/selftests/kvm/lib/x86_64/ucall.c index 2ea31a0ebe30..e5f0f9e0d3ee 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/ucall.c +++ b/tools/testing/selftests/kvm/lib/x86_64/ucall.c @@ -35,9 +35,9 @@ void ucall(uint64_t cmd, int nargs, ...) : : [port] "d" (UCALL_PIO_PORT), "D" (&uc) : "rax", "memory"); } -uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) +uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc) { - struct kvm_run *run = vcpu_state(vm, vcpu_id); + struct kvm_run *run = vcpu->run; struct ucall ucall = {}; if (uc) @@ -46,11 +46,11 @@ uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) { struct kvm_regs regs; - vcpu_regs_get(vm, vcpu_id, ®s); - memcpy(&ucall, addr_gva2hva(vm, (vm_vaddr_t)regs.rdi), + vcpu_regs_get(vcpu, ®s); + memcpy(&ucall, addr_gva2hva(vcpu->vm, (vm_vaddr_t)regs.rdi), sizeof(ucall)); - vcpu_run_complete_io(vm, vcpu_id); + vcpu_run_complete_io(vcpu); if (uc) memcpy(uc, &ucall, sizeof(ucall)); } diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c index a12c0e1224af..2cbfe9962fb1 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c @@ -42,11 +42,11 @@ struct eptPageTablePointer { uint64_t address:40; uint64_t reserved_63_52:12; }; -int vcpu_enable_evmcs(struct kvm_vm *vm, int vcpu_id) +int vcpu_enable_evmcs(struct kvm_vcpu *vcpu) { uint16_t evmcs_ver; - vcpu_enable_cap(vm, vcpu_id, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, + vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_ENLIGHTENED_VMCS, (unsigned long)&evmcs_ver); /* KVM should return supported EVMCS version range */ diff --git a/tools/testing/selftests/kvm/max_guest_memory_test.c b/tools/testing/selftests/kvm/max_guest_memory_test.c index d59918d5cbe2..8f34c5aca420 100644 --- a/tools/testing/selftests/kvm/max_guest_memory_test.c +++ b/tools/testing/selftests/kvm/max_guest_memory_test.c @@ -51,10 +51,10 @@ static void rendezvous_with_boss(void) } } -static void run_vcpu(struct kvm_vm *vm, uint32_t vcpu_id) +static void run_vcpu(struct kvm_vcpu *vcpu) { - vcpu_run(vm, vcpu_id); - ASSERT_EQ(get_ucall(vm, vcpu_id, NULL), UCALL_DONE); + vcpu_run(vcpu); + ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); } static void *vcpu_worker(void *data) @@ -65,25 +65,25 @@ static void *vcpu_worker(void *data) struct kvm_sregs sregs; struct kvm_regs regs; - vcpu_args_set(vm, vcpu->id, 3, info->start_gpa, info->end_gpa, + vcpu_args_set(vcpu, 3, info->start_gpa, info->end_gpa, vm_get_page_size(vm)); /* Snapshot regs before the first run. */ - vcpu_regs_get(vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); rendezvous_with_boss(); - run_vcpu(vm, vcpu->id); + run_vcpu(vcpu); rendezvous_with_boss(); - vcpu_regs_set(vm, vcpu->id, ®s); - vcpu_sregs_get(vm, vcpu->id, &sregs); + vcpu_regs_set(vcpu, ®s); + vcpu_sregs_get(vcpu, &sregs); #ifdef __x86_64__ /* Toggle CR0.WP to trigger a MMU context reset. */ sregs.cr0 ^= X86_CR0_WP; #endif - vcpu_sregs_set(vm, vcpu->id, &sregs); + vcpu_sregs_set(vcpu, &sregs); rendezvous_with_boss(); - run_vcpu(vm, vcpu->id); + run_vcpu(vcpu); rendezvous_with_boss(); return NULL; diff --git a/tools/testing/selftests/kvm/memslot_modification_stress_test.c b/tools/testing/selftests/kvm/memslot_modification_stress_test.c index a3efb3182119..1f9036cdcaa9 100644 --- a/tools/testing/selftests/kvm/memslot_modification_stress_test.c +++ b/tools/testing/selftests/kvm/memslot_modification_stress_test.c @@ -39,7 +39,6 @@ static bool run_vcpus = true; static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) { struct kvm_vcpu *vcpu = vcpu_args->vcpu; - struct kvm_vm *vm = perf_test_args.vm; struct kvm_run *run; int ret; @@ -47,10 +46,10 @@ static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) /* Let the guest access its memory until a stop signal is received */ while (READ_ONCE(run_vcpus)) { - ret = _vcpu_run(vm, vcpu->id); + ret = _vcpu_run(vcpu); TEST_ASSERT(ret == 0, "vcpu_run failed: %d\n", ret); - if (get_ucall(vm, vcpu->id, NULL) == UCALL_SYNC) + if (get_ucall(vcpu, NULL) == UCALL_SYNC) continue; TEST_ASSERT(false, diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c index 009eb19b28af..5f98489e4f4d 100644 --- a/tools/testing/selftests/kvm/memslot_perf_test.c +++ b/tools/testing/selftests/kvm/memslot_perf_test.c @@ -146,9 +146,9 @@ static void *vcpu_worker(void *__data) struct ucall uc; while (1) { - vcpu_run(data->vm, vcpu->id); + vcpu_run(vcpu); - switch (get_ucall(data->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: TEST_ASSERT(uc.args[1] == 0, "Unexpected sync ucall, got %lx", diff --git a/tools/testing/selftests/kvm/rseq_test.c b/tools/testing/selftests/kvm/rseq_test.c index fd754de0b74c..68c0c8bb206e 100644 --- a/tools/testing/selftests/kvm/rseq_test.c +++ b/tools/testing/selftests/kvm/rseq_test.c @@ -233,8 +233,8 @@ int main(int argc, char *argv[]) pthread_create(&migration_thread, NULL, migration_worker, 0); for (i = 0; !done; i++) { - vcpu_run(vm, vcpu->id); - TEST_ASSERT(get_ucall(vm, vcpu->id, NULL) == UCALL_SYNC, + vcpu_run(vcpu); + TEST_ASSERT(get_ucall(vcpu, NULL) == UCALL_SYNC, "Guest failed?"); /* diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c index 703bf137d6ac..22b0bb785591 100644 --- a/tools/testing/selftests/kvm/s390x/memop.c +++ b/tools/testing/selftests/kvm/s390x/memop.c @@ -152,7 +152,7 @@ static void memop_ioctl(struct test_info info, struct kvm_s390_mem_op *ksmo) if (!vcpu) vm_ioctl(info.vm, KVM_S390_MEM_OP, ksmo); else - vcpu_ioctl(vcpu->vm, vcpu->id, KVM_S390_MEM_OP, ksmo); + vcpu_ioctl(vcpu, KVM_S390_MEM_OP, ksmo); } static int err_memop_ioctl(struct test_info info, struct kvm_s390_mem_op *ksmo) @@ -162,7 +162,7 @@ static int err_memop_ioctl(struct test_info info, struct kvm_s390_mem_op *ksmo) if (!vcpu) return __vm_ioctl(info.vm, KVM_S390_MEM_OP, ksmo); else - return __vcpu_ioctl(vcpu->vm, vcpu->id, KVM_S390_MEM_OP, ksmo); + return __vcpu_ioctl(vcpu, KVM_S390_MEM_OP, ksmo); } #define MEMOP(err, info_p, mop_target_p, access_mode_p, buf_p, size_p, ...) \ @@ -250,8 +250,8 @@ enum stage { struct ucall uc; \ int __stage = (stage); \ \ - vcpu_run(__vcpu->vm, __vcpu->id); \ - get_ucall(__vcpu->vm, __vcpu->id, &uc); \ + vcpu_run(__vcpu); \ + get_ucall(__vcpu, &uc); \ ASSERT_EQ(uc.cmd, UCALL_SYNC); \ ASSERT_EQ(uc.args[1], __stage); \ }) \ diff --git a/tools/testing/selftests/kvm/s390x/resets.c b/tools/testing/selftests/kvm/s390x/resets.c index b2375d81571c..633ba9055231 100644 --- a/tools/testing/selftests/kvm/s390x/resets.c +++ b/tools/testing/selftests/kvm/s390x/resets.c @@ -61,7 +61,7 @@ static void test_one_reg(struct kvm_vcpu *vcpu, uint64_t id, uint64_t value) { uint64_t eval_reg; - vcpu_get_reg(vcpu->vm, vcpu->id, id, &eval_reg); + vcpu_get_reg(vcpu, id, &eval_reg); TEST_ASSERT(eval_reg == value, "value == 0x%lx", value); } @@ -72,7 +72,7 @@ static void assert_noirq(struct kvm_vcpu *vcpu) irq_state.len = sizeof(buf); irq_state.buf = (unsigned long)buf; - irqs = __vcpu_ioctl(vcpu->vm, vcpu->id, KVM_S390_GET_IRQ_STATE, &irq_state); + irqs = __vcpu_ioctl(vcpu, KVM_S390_GET_IRQ_STATE, &irq_state); /* * irqs contains the number of retrieved interrupts. Any interrupt * (notably, the emergency call interrupt we have injected) should @@ -89,13 +89,13 @@ static void assert_clear(struct kvm_vcpu *vcpu) struct kvm_regs regs; struct kvm_fpu fpu; - vcpu_regs_get(vcpu->vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); TEST_ASSERT(!memcmp(®s.gprs, regs_null, sizeof(regs.gprs)), "grs == 0"); - vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); TEST_ASSERT(!memcmp(&sregs.acrs, regs_null, sizeof(sregs.acrs)), "acrs == 0"); - vcpu_fpu_get(vcpu->vm, vcpu->id, &fpu); + vcpu_fpu_get(vcpu, &fpu); TEST_ASSERT(!memcmp(&fpu.fprs, regs_null, sizeof(fpu.fprs)), "fprs == 0"); /* sync regs */ @@ -133,7 +133,7 @@ static void assert_initial(struct kvm_vcpu *vcpu) struct kvm_fpu fpu; /* KVM_GET_SREGS */ - vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); TEST_ASSERT(sregs.crs[0] == 0xE0UL, "cr0 == 0xE0 (KVM_GET_SREGS)"); TEST_ASSERT(sregs.crs[14] == 0xC2000000UL, "cr14 == 0xC2000000 (KVM_GET_SREGS)"); @@ -159,7 +159,7 @@ static void assert_initial(struct kvm_vcpu *vcpu) TEST_ASSERT(vcpu->run->psw_addr == 0, "psw_addr == 0 (kvm_run)"); TEST_ASSERT(vcpu->run->psw_mask == 0, "psw_mask == 0 (kvm_run)"); - vcpu_fpu_get(vcpu->vm, vcpu->id, &fpu); + vcpu_fpu_get(vcpu, &fpu); TEST_ASSERT(!fpu.fpc, "fpc == 0"); test_one_reg(vcpu, KVM_REG_S390_GBEA, 1); @@ -198,7 +198,7 @@ static void inject_irq(struct kvm_vcpu *vcpu) irq_state.buf = (unsigned long)buf; irq->type = KVM_S390_INT_EMERGENCY; irq->u.emerg.code = vcpu->id; - irqs = __vcpu_ioctl(vcpu->vm, vcpu->id, KVM_S390_SET_IRQ_STATE, &irq_state); + irqs = __vcpu_ioctl(vcpu, KVM_S390_SET_IRQ_STATE, &irq_state); TEST_ASSERT(irqs >= 0, "Error injecting EMERGENCY IRQ errno %d\n", errno); } @@ -221,11 +221,11 @@ static void test_normal(void) ksft_print_msg("Testing normal reset\n"); vm = create_vm(&vcpu); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); inject_irq(vcpu); - vcpu_ioctl(vm, vcpu->id, KVM_S390_NORMAL_RESET, 0); + vcpu_ioctl(vcpu, KVM_S390_NORMAL_RESET, 0); /* must clears */ assert_normal(vcpu); @@ -244,11 +244,11 @@ static void test_initial(void) ksft_print_msg("Testing initial reset\n"); vm = create_vm(&vcpu); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); inject_irq(vcpu); - vcpu_ioctl(vm, vcpu->id, KVM_S390_INITIAL_RESET, 0); + vcpu_ioctl(vcpu, KVM_S390_INITIAL_RESET, 0); /* must clears */ assert_normal(vcpu); @@ -267,11 +267,11 @@ static void test_clear(void) ksft_print_msg("Testing clear reset\n"); vm = create_vm(&vcpu); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); inject_irq(vcpu); - vcpu_ioctl(vm, vcpu->id, KVM_S390_CLEAR_RESET, 0); + vcpu_ioctl(vcpu, KVM_S390_CLEAR_RESET, 0); /* must clears */ assert_normal(vcpu); diff --git a/tools/testing/selftests/kvm/s390x/sync_regs_test.c b/tools/testing/selftests/kvm/s390x/sync_regs_test.c index 7c4143141ca7..4b2eb5edde5e 100644 --- a/tools/testing/selftests/kvm/s390x/sync_regs_test.c +++ b/tools/testing/selftests/kvm/s390x/sync_regs_test.c @@ -80,14 +80,14 @@ void test_read_invalid(struct kvm_vcpu *vcpu) /* Request reading invalid register set from VCPU. */ run->kvm_valid_regs = INVALID_SYNC_FIELD; - rv = _vcpu_run(vcpu->vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", rv); run->kvm_valid_regs = 0; run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; - rv = _vcpu_run(vcpu->vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", rv); @@ -101,14 +101,14 @@ void test_set_invalid(struct kvm_vcpu *vcpu) /* Request setting invalid register set into VCPU. */ run->kvm_dirty_regs = INVALID_SYNC_FIELD; - rv = _vcpu_run(vcpu->vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", rv); run->kvm_dirty_regs = 0; run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; - rv = _vcpu_run(vcpu->vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", rv); @@ -124,7 +124,7 @@ void test_req_and_verify_all_valid_regs(struct kvm_vcpu *vcpu) /* Request and verify all valid register sets. */ run->kvm_valid_regs = TEST_SYNC_FIELDS; - rv = _vcpu_run(vcpu->vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, "Unexpected exit reason: %u (%s)\n", @@ -137,10 +137,10 @@ void test_req_and_verify_all_valid_regs(struct kvm_vcpu *vcpu) run->s390_sieic.icptcode, run->s390_sieic.ipa, run->s390_sieic.ipb); - vcpu_regs_get(vcpu->vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); compare_regs(®s, &run->s.regs); - vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); compare_sregs(&sregs, &run->s.regs); } @@ -163,7 +163,7 @@ void test_set_and_verify_various_reg_values(struct kvm_vcpu *vcpu) run->kvm_dirty_regs |= KVM_SYNC_DIAG318; } - rv = _vcpu_run(vcpu->vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, "Unexpected exit reason: %u (%s)\n", @@ -179,10 +179,10 @@ void test_set_and_verify_various_reg_values(struct kvm_vcpu *vcpu) "diag318 sync regs value incorrect 0x%llx.", run->s.regs.diag318); - vcpu_regs_get(vcpu->vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); compare_regs(®s, &run->s.regs); - vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); compare_sregs(&sregs, &run->s.regs); } @@ -198,7 +198,7 @@ void test_clear_kvm_dirty_regs_bits(struct kvm_vcpu *vcpu) run->kvm_dirty_regs = 0; run->s.regs.gprs[11] = 0xDEADBEEF; run->s.regs.diag318 = 0x4B1D; - rv = _vcpu_run(vcpu->vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv == 0, "vcpu_run failed: %d\n", rv); TEST_ASSERT(run->exit_reason == KVM_EXIT_S390_SIEIC, "Unexpected exit reason: %u (%s)\n", diff --git a/tools/testing/selftests/kvm/s390x/tprot.c b/tools/testing/selftests/kvm/s390x/tprot.c index a82a8d1dc6c8..015a13056503 100644 --- a/tools/testing/selftests/kvm/s390x/tprot.c +++ b/tools/testing/selftests/kvm/s390x/tprot.c @@ -187,8 +187,8 @@ static void guest_code(void) struct ucall uc; \ int __stage = (stage); \ \ - vcpu_run(__vcpu->vm, __vcpu->id); \ - get_ucall(__vcpu->vm, __vcpu->id, &uc); \ + vcpu_run(__vcpu); \ + get_ucall(__vcpu, &uc); \ if (uc.cmd == UCALL_ABORT) { \ TEST_FAIL("line %lu: %s, hints: %lu, %lu", uc.args[1], \ (const char *)uc.args[0], uc.args[2], uc.args[3]); \ diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index d832fc12984e..47b219dd60e4 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -63,10 +63,10 @@ static void *vcpu_worker(void *data) * has been deleted or while it is being moved . */ while (1) { - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); if (run->exit_reason == KVM_EXIT_IO) { - cmd = get_ucall(vcpu->vm, vcpu->id, &uc); + cmd = get_ucall(vcpu, &uc); if (cmd != UCALL_SYNC) break; @@ -291,7 +291,7 @@ static void test_delete_memory_region(void) run->exit_reason == KVM_EXIT_INTERNAL_ERROR, "Unexpected exit reason = %d", run->exit_reason); - vcpu_regs_get(vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); /* * On AMD, after KVM_EXIT_SHUTDOWN the VMCB has been reinitialized already, @@ -318,7 +318,7 @@ static void test_zero_memory_regions(void) vcpu = __vm_vcpu_add(vm, 0); vm_ioctl(vm, KVM_SET_NR_MMU_PAGES, (void *)64ul); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); run = vcpu->run; TEST_ASSERT(run->exit_reason == KVM_EXIT_INTERNAL_ERROR, diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index 7a6645464925..398819d4074f 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -73,11 +73,11 @@ static void steal_time_init(struct kvm_vcpu *vcpu, uint32_t i) st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE); sync_global_to_guest(vcpu->vm, st_gva[i]); - ret = _vcpu_set_msr(vcpu->vm, vcpu->id, MSR_KVM_STEAL_TIME, + ret = _vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_STEAL_RESERVED_MASK); TEST_ASSERT(ret == 0, "Bad GPA didn't fail"); - vcpu_set_msr(vcpu->vm, vcpu->id, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_MSR_ENABLED); + vcpu_set_msr(vcpu, MSR_KVM_STEAL_TIME, (ulong)st_gva[i] | KVM_MSR_ENABLED); } static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx) @@ -163,7 +163,7 @@ static bool is_steal_time_supported(struct kvm_vcpu *vcpu) .attr = KVM_ARM_VCPU_PVTIME_IPA, }; - return !__vcpu_ioctl(vcpu->vm, vcpu->id, KVM_HAS_DEVICE_ATTR, &dev); + return !__vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev); } static void steal_time_init(struct kvm_vcpu *vcpu, uint32_t i) @@ -178,20 +178,20 @@ static void steal_time_init(struct kvm_vcpu *vcpu, uint32_t i) .addr = (uint64_t)&st_ipa, }; - vcpu_ioctl(vm, vcpu->id, KVM_HAS_DEVICE_ATTR, &dev); + vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &dev); /* ST_GPA_BASE is identity mapped */ st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE); sync_global_to_guest(vm, st_gva[i]); st_ipa = (ulong)st_gva[i] | 1; - ret = __vcpu_ioctl(vm, vcpu->id, KVM_SET_DEVICE_ATTR, &dev); + ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); TEST_ASSERT(ret == -1 && errno == EINVAL, "Bad IPA didn't report EINVAL"); st_ipa = (ulong)st_gva[i]; - vcpu_ioctl(vm, vcpu->id, KVM_SET_DEVICE_ATTR, &dev); + vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); - ret = __vcpu_ioctl(vm, vcpu->id, KVM_SET_DEVICE_ATTR, &dev); + ret = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &dev); TEST_ASSERT(ret == -1 && errno == EEXIST, "Set IPA twice without EEXIST"); } @@ -227,9 +227,9 @@ static void run_vcpu(struct kvm_vcpu *vcpu) { struct ucall uc; - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: case UCALL_DONE: break; @@ -280,7 +280,7 @@ int main(int ac, char **av) for (i = 0; i < NR_VCPUS; ++i) { steal_time_init(vcpus[i], i); - vcpu_args_set(vm, vcpus[i]->id, 1, i); + vcpu_args_set(vcpus[i], 1, i); /* First VCPU run initializes steal-time */ run_vcpu(vcpus[i]); diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c b/tools/testing/selftests/kvm/system_counter_offset_test.c index 0690ce0ae4fa..7c8be0930737 100644 --- a/tools/testing/selftests/kvm/system_counter_offset_test.c +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c @@ -28,8 +28,7 @@ static struct test_case test_cases[] = { static void check_preconditions(struct kvm_vcpu *vcpu) { - if (!__vcpu_has_device_attr(vcpu->vm, vcpu->id, KVM_VCPU_TSC_CTRL, - KVM_VCPU_TSC_OFFSET)) + if (!__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET)) return; print_skip("KVM_VCPU_TSC_OFFSET not supported; skipping test"); @@ -38,8 +37,8 @@ static void check_preconditions(struct kvm_vcpu *vcpu) static void setup_system_counter(struct kvm_vcpu *vcpu, struct test_case *test) { - vcpu_device_attr_set(vcpu->vm, vcpu->id, KVM_VCPU_TSC_CTRL, - KVM_VCPU_TSC_OFFSET, &test->tsc_offset); + vcpu_device_attr_set(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET, + &test->tsc_offset); } static uint64_t guest_read_system_counter(struct test_case *test) @@ -101,10 +100,10 @@ static void enter_guest(struct kvm_vcpu *vcpu) setup_system_counter(vcpu, test); start = host_read_guest_system_counter(test); - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); end = host_read_guest_system_counter(test); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: handle_sync(&uc, start, end); break; @@ -113,7 +112,7 @@ static void enter_guest(struct kvm_vcpu *vcpu) return; default: TEST_ASSERT(0, "unhandled ucall %ld\n", - get_ucall(vcpu->vm, vcpu->id, &uc)); + get_ucall(vcpu, &uc)); } } } diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index 7755fe8fcffb..b421c8369dba 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -351,11 +351,11 @@ int main(int argc, char *argv[]) } run = vcpu->run; - vcpu_regs_get(vm, vcpu->id, ®s1); + vcpu_regs_get(vcpu, ®s1); /* Register #NM handler */ vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, NM_VECTOR, guest_nm_handler); /* amx cfg for guest_code */ @@ -369,16 +369,16 @@ int main(int argc, char *argv[]) /* xsave data for guest_code */ xsavedata = vm_vaddr_alloc_pages(vm, 3); memset(addr_gva2hva(vm, xsavedata), 0, 3 * getpagesize()); - vcpu_args_set(vm, vcpu->id, 3, amx_cfg, tiledata, xsavedata); + vcpu_args_set(vcpu, 3, amx_cfg, tiledata, xsavedata); for (stage = 1; ; stage++) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); @@ -403,7 +403,7 @@ int main(int argc, char *argv[]) * size subtract 8K amx size. */ amx_offset = xsave_restore_size - NUM_TILES*TILE_SIZE; - state = vcpu_save_state(vm, vcpu->id); + state = vcpu_save_state(vcpu); void *amx_start = (void *)state->xsave + amx_offset; void *tiles_data = (void *)addr_gva2hva(vm, tiledata); /* Only check TMM0 register, 1 tile */ @@ -424,21 +424,21 @@ int main(int argc, char *argv[]) TEST_FAIL("Unknown ucall %lu", uc.cmd); } - state = vcpu_save_state(vm, vcpu->id); + state = vcpu_save_state(vcpu); memset(®s1, 0, sizeof(regs1)); - vcpu_regs_get(vm, vcpu->id, ®s1); + vcpu_regs_get(vcpu, ®s1); kvm_vm_release(vm); /* Restore state in a new VM. */ vcpu = vm_recreate_with_one_vcpu(vm); - vcpu_set_cpuid(vm, vcpu->id, kvm_get_supported_cpuid()); - vcpu_load_state(vm, vcpu->id, state); + vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); + vcpu_load_state(vcpu, state); run = vcpu->run; kvm_x86_state_cleanup(state); memset(®s2, 0, sizeof(regs2)); - vcpu_regs_get(vm, vcpu->id, ®s2); + vcpu_regs_get(vcpu, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", (ulong) regs2.rdi, (ulong) regs2.rsi); diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index 76cdd0d10757..4aa784932597 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -120,9 +120,9 @@ static void run_vcpu(struct kvm_vcpu *vcpu, int stage) { struct ucall uc; - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage + 1, @@ -159,14 +159,14 @@ static void set_cpuid_after_run(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) u32 eax, ebx, x; /* Setting unmodified CPUID is allowed */ - rc = __vcpu_set_cpuid(vcpu->vm, vcpu->id, cpuid); + rc = __vcpu_set_cpuid(vcpu, cpuid); TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc); /* Changing CPU features is forbidden */ ent = get_cpuid(cpuid, 0x7, 0); ebx = ent->ebx; ent->ebx--; - rc = __vcpu_set_cpuid(vcpu->vm, vcpu->id, cpuid); + rc = __vcpu_set_cpuid(vcpu, cpuid); TEST_ASSERT(rc, "Changing CPU features should fail"); ent->ebx = ebx; @@ -175,7 +175,7 @@ static void set_cpuid_after_run(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) eax = ent->eax; x = eax & 0xff; ent->eax = (eax & ~0xffu) | (x - 1); - rc = __vcpu_set_cpuid(vcpu->vm, vcpu->id, cpuid); + rc = __vcpu_set_cpuid(vcpu, cpuid); TEST_ASSERT(rc, "Changing MAXPHYADDR should fail"); ent->eax = eax; } @@ -191,13 +191,13 @@ int main(void) vm = vm_create_with_one_vcpu(&vcpu, guest_main); supp_cpuid = kvm_get_supported_cpuid(); - cpuid2 = vcpu_get_cpuid(vm, vcpu->id); + cpuid2 = vcpu_get_cpuid(vcpu); compare_cpuids(supp_cpuid, cpuid2); vcpu_alloc_cpuid(vm, &cpuid_gva, cpuid2); - vcpu_args_set(vm, vcpu->id, 1, cpuid_gva); + vcpu_args_set(vcpu, 1, cpuid_gva); for (stage = 0; stage < 3; stage++) run_vcpu(vcpu, stage); diff --git a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c index d5615cd0b81b..1635aae970e9 100644 --- a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c +++ b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c @@ -82,19 +82,19 @@ int main(int argc, char *argv[]) run = vcpu->run; while (1) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: /* emulate hypervisor clearing CR4.OSXSAVE */ - vcpu_sregs_get(vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); sregs.cr4 &= ~X86_CR4_OSXSAVE; - vcpu_sregs_set(vm, vcpu->id, &sregs); + vcpu_sregs_set(vcpu, &sregs); break; case UCALL_ABORT: TEST_FAIL("Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit."); diff --git a/tools/testing/selftests/kvm/x86_64/debug_regs.c b/tools/testing/selftests/kvm/x86_64/debug_regs.c index 3cc25714d703..c16799b616e0 100644 --- a/tools/testing/selftests/kvm/x86_64/debug_regs.c +++ b/tools/testing/selftests/kvm/x86_64/debug_regs.c @@ -70,9 +70,9 @@ static void vcpu_skip_insn(struct kvm_vcpu *vcpu, int insn_len) { struct kvm_regs regs; - vcpu_regs_get(vcpu->vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); regs.rip += insn_len; - vcpu_regs_set(vcpu->vm, vcpu->id, ®s); + vcpu_regs_set(vcpu, ®s); } int main(void) @@ -106,8 +106,8 @@ int main(void) /* Test software BPs - int3 */ memset(&debug, 0, sizeof(debug)); debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; - vcpu_guest_debug_set(vm, vcpu->id, &debug); - vcpu_run(vm, vcpu->id); + vcpu_guest_debug_set(vcpu, &debug); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_DEBUG && run->debug.arch.exception == BP_VECTOR && run->debug.arch.pc == CAST_TO_RIP(sw_bp), @@ -122,8 +122,8 @@ int main(void) debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; debug.arch.debugreg[i] = CAST_TO_RIP(hw_bp); debug.arch.debugreg[7] = 0x400 | (1UL << (2*i+1)); - vcpu_guest_debug_set(vm, vcpu->id, &debug); - vcpu_run(vm, vcpu->id); + vcpu_guest_debug_set(vcpu, &debug); + vcpu_run(vcpu); target_dr6 = 0xffff0ff0 | (1UL << i); TEST_ASSERT(run->exit_reason == KVM_EXIT_DEBUG && run->debug.arch.exception == DB_VECTOR && @@ -145,8 +145,8 @@ int main(void) debug.arch.debugreg[i] = CAST_TO_RIP(guest_value); debug.arch.debugreg[7] = 0x00000400 | (1UL << (2*i+1)) | (0x000d0000UL << (4*i)); - vcpu_guest_debug_set(vm, vcpu->id, &debug); - vcpu_run(vm, vcpu->id); + vcpu_guest_debug_set(vcpu, &debug); + vcpu_run(vcpu); target_dr6 = 0xffff0ff0 | (1UL << i); TEST_ASSERT(run->exit_reason == KVM_EXIT_DEBUG && run->debug.arch.exception == DB_VECTOR && @@ -172,8 +172,8 @@ int main(void) debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_BLOCKIRQ; debug.arch.debugreg[7] = 0x00000400; - vcpu_guest_debug_set(vm, vcpu->id, &debug); - vcpu_run(vm, vcpu->id); + vcpu_guest_debug_set(vcpu, &debug); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_DEBUG && run->debug.arch.exception == DB_VECTOR && run->debug.arch.pc == target_rip && @@ -189,8 +189,8 @@ int main(void) memset(&debug, 0, sizeof(debug)); debug.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; debug.arch.debugreg[7] = 0x400 | DR7_GD; - vcpu_guest_debug_set(vm, vcpu->id, &debug); - vcpu_run(vm, vcpu->id); + vcpu_guest_debug_set(vcpu, &debug); + vcpu_run(vcpu); target_dr6 = 0xffff0ff0 | DR6_BD; TEST_ASSERT(run->exit_reason == KVM_EXIT_DEBUG && run->debug.arch.exception == DB_VECTOR && @@ -204,11 +204,11 @@ int main(void) /* Disable all debug controls, run to the end */ memset(&debug, 0, sizeof(debug)); - vcpu_guest_debug_set(vm, vcpu->id, &debug); + vcpu_guest_debug_set(vcpu, &debug); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "KVM_EXIT_IO"); - cmd = get_ucall(vm, vcpu->id, &uc); + cmd = get_ucall(vcpu, &uc); TEST_ASSERT(cmd == UCALL_DONE, "UCALL_DONE"); kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c index 08a95dab3a6b..fb2a2390b4af 100644 --- a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c +++ b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c @@ -83,9 +83,9 @@ static void process_exit_on_emulation_error(struct kvm_vcpu *vcpu) * contained an flds instruction that is 2-bytes in * length (ie: no prefix, no SIB, no displacement). */ - vcpu_regs_get(vcpu->vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); regs.rip += 2; - vcpu_regs_set(vcpu->vm, vcpu->id, ®s); + vcpu_regs_set(vcpu, ®s); } } } @@ -101,7 +101,7 @@ static void check_for_guest_assert(struct kvm_vcpu *vcpu) struct ucall uc; if (vcpu->run->exit_reason == KVM_EXIT_IO && - get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_ABORT) { + get_ucall(vcpu, &uc) == UCALL_ABORT) { do_guest_assert(&uc); } } @@ -118,7 +118,7 @@ static void process_ucall_done(struct kvm_vcpu *vcpu) run->exit_reason, exit_reason_str(run->exit_reason)); - TEST_ASSERT(get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_DONE, + TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_DONE, "Unexpected ucall command: %lu, expected UCALL_DONE (%d)", uc.cmd, UCALL_DONE); } @@ -133,7 +133,7 @@ static uint64_t process_ucall(struct kvm_vcpu *vcpu) run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: break; case UCALL_ABORT: @@ -175,7 +175,7 @@ int main(int argc, char *argv[]) entry->eax = (entry->eax & 0xffffff00) | MAXPHYADDR; set_cpuid(cpuid, entry); - vcpu_set_cpuid(vm, vcpu->id, cpuid); + vcpu_set_cpuid(vcpu, cpuid); rc = kvm_check_cap(KVM_CAP_EXIT_ON_EMULATION_FAILURE); TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable"); @@ -190,12 +190,12 @@ int main(int argc, char *argv[]) virt_map(vm, MEM_REGION_GVA, MEM_REGION_GPA, 1); hva = addr_gpa2hva(vm, MEM_REGION_GPA); memset(hva, 0, PAGE_SIZE); - pte = vm_get_page_table_entry(vm, vcpu->id, MEM_REGION_GVA); - vm_set_page_table_entry(vm, vcpu->id, MEM_REGION_GVA, pte | (1ull << 36)); + pte = vm_get_page_table_entry(vm, vcpu, MEM_REGION_GVA); + vm_set_page_table_entry(vm, vcpu, MEM_REGION_GVA, pte | (1ull << 36)); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); process_exit_on_emulation_error(vcpu); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(process_ucall(vcpu) == UCALL_DONE, "Expected UCALL_DONE"); diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c index ba39042a5d96..6c4e728d2d85 100644 --- a/tools/testing/selftests/kvm/x86_64/evmcs_test.c +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c @@ -161,12 +161,12 @@ void inject_nmi(struct kvm_vcpu *vcpu) { struct kvm_vcpu_events events; - vcpu_events_get(vcpu->vm, vcpu->id, &events); + vcpu_events_get(vcpu, &events); events.nmi.pending = 1; events.flags |= KVM_VCPUEVENT_VALID_NMI_PENDING; - vcpu_events_set(vcpu->vm, vcpu->id, &events); + vcpu_events_set(vcpu, &events); } static struct kvm_vcpu *save_restore_vm(struct kvm_vm *vm, @@ -175,21 +175,21 @@ static struct kvm_vcpu *save_restore_vm(struct kvm_vm *vm, struct kvm_regs regs1, regs2; struct kvm_x86_state *state; - state = vcpu_save_state(vm, vcpu->id); + state = vcpu_save_state(vcpu); memset(®s1, 0, sizeof(regs1)); - vcpu_regs_get(vm, vcpu->id, ®s1); + vcpu_regs_get(vcpu, ®s1); kvm_vm_release(vm); /* Restore state in a new VM. */ vcpu = vm_recreate_with_one_vcpu(vm); - vcpu_set_hv_cpuid(vm, vcpu->id); - vcpu_enable_evmcs(vm, vcpu->id); - vcpu_load_state(vm, vcpu->id, state); + vcpu_set_hv_cpuid(vcpu); + vcpu_enable_evmcs(vcpu); + vcpu_load_state(vcpu, state); kvm_x86_state_cleanup(state); memset(®s2, 0, sizeof(regs2)); - vcpu_regs_get(vm, vcpu->id, ®s2); + vcpu_regs_get(vcpu, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", (ulong) regs2.rdi, (ulong) regs2.rsi); @@ -215,14 +215,14 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - vcpu_set_hv_cpuid(vm, vcpu->id); - vcpu_enable_evmcs(vm, vcpu->id); + vcpu_set_hv_cpuid(vcpu); + vcpu_enable_evmcs(vcpu); vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); + vcpu_args_set(vcpu, 1, vmx_pages_gva); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler); @@ -231,13 +231,13 @@ int main(int argc, char *argv[]) for (stage = 1;; stage++) { run = vcpu->run; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); diff --git a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c index 108c3f75361d..137759547720 100644 --- a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c @@ -95,7 +95,7 @@ static void guest_main(void) static void setup_ud_vector(struct kvm_vcpu *vcpu) { vm_init_descriptor_tables(vcpu->vm); - vcpu_init_descriptor_tables(vcpu->vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vcpu->vm, UD_VECTOR, guest_ud_handler); } @@ -104,8 +104,8 @@ static void enter_guest(struct kvm_vcpu *vcpu) struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vcpu->vm, vcpu->id); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + vcpu_run(vcpu); + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: pr_info("%s: %016lx\n", (const char *)uc.args[2], uc.args[3]); break; diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c index 4f8f3999de2d..f7a9e29ff0c7 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c @@ -178,16 +178,16 @@ static void host_check_tsc_msr_rdtsc(struct kvm_vcpu *vcpu) u64 tsc_freq, r1, r2, t1, t2; s64 delta_ns; - tsc_freq = vcpu_get_msr(vcpu->vm, vcpu->id, HV_X64_MSR_TSC_FREQUENCY); + tsc_freq = vcpu_get_msr(vcpu, HV_X64_MSR_TSC_FREQUENCY); TEST_ASSERT(tsc_freq > 0, "TSC frequency must be nonzero"); /* For increased accuracy, take mean rdtsc() before and afrer ioctl */ r1 = rdtsc(); - t1 = vcpu_get_msr(vcpu->vm, vcpu->id, HV_X64_MSR_TIME_REF_COUNT); + t1 = vcpu_get_msr(vcpu, HV_X64_MSR_TIME_REF_COUNT); r1 = (r1 + rdtsc()) / 2; nop_loop(); r2 = rdtsc(); - t2 = vcpu_get_msr(vcpu->vm, vcpu->id, HV_X64_MSR_TIME_REF_COUNT); + t2 = vcpu_get_msr(vcpu, HV_X64_MSR_TIME_REF_COUNT); r2 = (r2 + rdtsc()) / 2; TEST_ASSERT(t2 > t1, "Time reference MSR is not monotonic (%ld <= %ld)", t1, t2); @@ -215,24 +215,24 @@ int main(void) vm = vm_create_with_one_vcpu(&vcpu, guest_main); run = vcpu->run; - vcpu_set_hv_cpuid(vm, vcpu->id); + vcpu_set_hv_cpuid(vcpu); tsc_page_gva = vm_vaddr_alloc_page(vm); memset(addr_gva2hva(vm, tsc_page_gva), 0x0, getpagesize()); TEST_ASSERT((addr_gva2gpa(vm, tsc_page_gva) & (getpagesize() - 1)) == 0, "TSC page has to be page aligned\n"); - vcpu_args_set(vm, vcpu->id, 2, tsc_page_gva, addr_gva2gpa(vm, tsc_page_gva)); + vcpu_args_set(vcpu, 2, tsc_page_gva, addr_gva2gpa(vm, tsc_page_gva)); host_check_tsc_msr_rdtsc(vcpu); for (stage = 1;; stage++) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c index d1a22ee98cf3..af13c48f0f30 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c @@ -119,7 +119,7 @@ void test_hv_cpuid_e2big(struct kvm_vm *vm, struct kvm_vcpu *vcpu) int ret; if (vcpu) - ret = __vcpu_ioctl(vm, vcpu->id, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); + ret = __vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); else ret = __kvm_ioctl(vm_get_kvm_fd(vm), KVM_GET_SUPPORTED_HV_CPUID, &cpuid); @@ -147,7 +147,7 @@ int main(int argc, char *argv[]) /* Test vCPU ioctl version */ test_hv_cpuid_e2big(vm, vcpu); - hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vm, vcpu->id); + hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vcpu); test_hv_cpuid(hv_cpuid_entries, false); free(hv_cpuid_entries); @@ -156,8 +156,8 @@ int main(int argc, char *argv[]) print_skip("Enlightened VMCS is unsupported"); goto do_sys; } - vcpu_enable_evmcs(vm, vcpu->id); - hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vm, vcpu->id); + vcpu_enable_evmcs(vcpu); + hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vcpu); test_hv_cpuid(hv_cpuid_entries, true); free(hv_cpuid_entries); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index d0bd9d5e8a99..d5f37495ade8 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -161,7 +161,7 @@ static void hv_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, "failed to set HYPERV_CPUID_ENLIGHTMENT_INFO leaf"); TEST_ASSERT(set_cpuid(cpuid, dbg), "failed to set HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES leaf"); - vcpu_set_cpuid(vcpu->vm, vcpu->id, cpuid); + vcpu_set_cpuid(vcpu, cpuid); } static void guest_test_msrs_access(void) @@ -191,15 +191,15 @@ static void guest_test_msrs_access(void) memset(addr_gva2hva(vm, msr_gva), 0x0, getpagesize()); msr = addr_gva2hva(vm, msr_gva); - vcpu_args_set(vm, vcpu->id, 1, msr_gva); - vcpu_enable_cap(vm, vcpu->id, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); + vcpu_args_set(vcpu, 1, msr_gva); + vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); - vcpu_set_hv_cpuid(vm, vcpu->id); + vcpu_set_hv_cpuid(vcpu); best = kvm_get_supported_hv_cpuid(); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); run = vcpu->run; @@ -333,7 +333,7 @@ static void guest_test_msrs_access(void) * Remains unavailable even with KVM_CAP_HYPERV_SYNIC2 * capability enabled and guest visible CPUID bit unset. */ - vcpu_enable_cap(vm, vcpu->id, KVM_CAP_HYPERV_SYNIC2, 0); + vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_SYNIC2, 0); break; case 22: feat.eax |= HV_MSR_SYNIC_AVAILABLE; @@ -471,12 +471,12 @@ static void guest_test_msrs_access(void) else pr_debug("Stage %d: finish\n", stage); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: TEST_ASSERT(uc.args[1] == 0, "Unexpected stage: %ld (0 expected)\n", @@ -520,7 +520,7 @@ static void guest_test_hcalls_access(void) vm = vm_create_with_one_vcpu(&vcpu, guest_hcall); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); /* Hypercall input/output */ @@ -531,10 +531,10 @@ static void guest_test_hcalls_access(void) hcall_params = vm_vaddr_alloc_page(vm); memset(addr_gva2hva(vm, hcall_params), 0x0, getpagesize()); - vcpu_args_set(vm, vcpu->id, 2, addr_gva2gpa(vm, hcall_page), hcall_params); - vcpu_enable_cap(vm, vcpu->id, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); + vcpu_args_set(vcpu, 2, addr_gva2gpa(vm, hcall_page), hcall_params); + vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); - vcpu_set_hv_cpuid(vm, vcpu->id); + vcpu_set_hv_cpuid(vcpu); best = kvm_get_supported_hv_cpuid(); @@ -641,12 +641,12 @@ static void guest_test_hcalls_access(void) else pr_debug("Stage %d: finish\n", stage); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: TEST_ASSERT(uc.args[1] == 0, "Unexpected stage: %ld (0 expected)\n", diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c index b6a749f5c766..171009184c3b 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c @@ -133,19 +133,19 @@ int main(int argc, char *argv[]) } /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, guest_code); - vcpu_set_hv_cpuid(vm, vcpu->id); + vcpu_set_hv_cpuid(vcpu); run = vcpu->run; vcpu_alloc_svm(vm, &nested_gva); - vcpu_args_set(vm, vcpu->id, 1, nested_gva); + vcpu_args_set(vcpu, 1, nested_gva); for (stage = 1;; stage++) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); diff --git a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c index 2c1f850c4053..6e3c4bd60b76 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c @@ -116,14 +116,14 @@ static void enter_guest(struct kvm_vcpu *vcpu) vm_ioctl(vm, KVM_GET_CLOCK, &start); - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); vm_ioctl(vm, KVM_GET_CLOCK, &end); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: handle_sync(&uc, &start, &end); break; @@ -193,7 +193,7 @@ int main(void) pvti_gva = vm_vaddr_alloc(vm, getpagesize(), 0x10000); pvti_gpa = addr_gva2gpa(vm, pvti_gva); - vcpu_args_set(vm, vcpu->id, 2, pvti_gpa, pvti_gva); + vcpu_args_set(vcpu, 2, pvti_gpa, pvti_gva); enter_guest(vcpu); kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index 734e71739d33..f497d6ecec25 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -177,12 +177,12 @@ static void enter_guest(struct kvm_vcpu *vcpu) struct ucall uc; while (true) { - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "unexpected exit reason: %u (%s)", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_PR_MSR: pr_msr(&uc); break; @@ -211,14 +211,14 @@ int main(void) vm = vm_create_with_one_vcpu(&vcpu, guest_main); - vcpu_enable_cap(vm, vcpu->id, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 1); + vcpu_enable_cap(vcpu, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 1); best = kvm_get_supported_cpuid(); clear_kvm_cpuid_features(best); - vcpu_set_cpuid(vm, vcpu->id, best); + vcpu_set_cpuid(vcpu, best); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); enter_guest(vcpu); diff --git a/tools/testing/selftests/kvm/x86_64/mmu_role_test.c b/tools/testing/selftests/kvm/x86_64/mmu_role_test.c index 829a5cf94f5c..1404dfda2e9f 100644 --- a/tools/testing/selftests/kvm/x86_64/mmu_role_test.c +++ b/tools/testing/selftests/kvm/x86_64/mmu_role_test.c @@ -35,7 +35,7 @@ static void mmu_role_test(u32 *cpuid_reg, u32 evil_cpuid_val) /* Map 1gb page without a backing memlot. */ __virt_pg_map(vm, MMIO_GPA, MMIO_GPA, PG_LEVEL_1G); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); /* Guest access to the 1gb page should trigger MMIO. */ TEST_ASSERT(run->exit_reason == KVM_EXIT_MMIO, @@ -54,7 +54,7 @@ static void mmu_role_test(u32 *cpuid_reg, u32 evil_cpuid_val) * returns the struct that contains the entry being modified. Eww. */ *cpuid_reg = evil_cpuid_val; - vcpu_set_cpuid(vm, vcpu->id, kvm_get_supported_cpuid()); + vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); /* * Add a dummy memslot to coerce KVM into bumping the MMIO generation. @@ -67,12 +67,12 @@ static void mmu_role_test(u32 *cpuid_reg, u32 evil_cpuid_val) /* Set up a #PF handler to eat the RSVD #PF and signal all done! */ vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, PF_VECTOR, guest_pf_handler); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); - cmd = get_ucall(vm, vcpu->id, NULL); + cmd = get_ucall(vcpu, NULL); TEST_ASSERT(cmd == UCALL_DONE, "Unexpected guest exit, exit_reason=%s, ucall.cmd = %lu\n", exit_reason_str(run->exit_reason), cmd); diff --git a/tools/testing/selftests/kvm/x86_64/platform_info_test.c b/tools/testing/selftests/kvm/x86_64/platform_info_test.c index eb5e1f972d76..3cb48e4b615b 100644 --- a/tools/testing/selftests/kvm/x86_64/platform_info_test.c +++ b/tools/testing/selftests/kvm/x86_64/platform_info_test.c @@ -40,12 +40,12 @@ static void test_msr_platform_info_enabled(struct kvm_vcpu *vcpu) struct ucall uc; vm_enable_cap(vcpu->vm, KVM_CAP_MSR_PLATFORM_INFO, true); - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Exit_reason other than KVM_EXIT_IO: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - get_ucall(vcpu->vm, vcpu->id, &uc); + get_ucall(vcpu, &uc); TEST_ASSERT(uc.cmd == UCALL_SYNC, "Received ucall other than UCALL_SYNC: %lu\n", uc.cmd); TEST_ASSERT((uc.args[1] & MSR_PLATFORM_INFO_MAX_TURBO_RATIO) == @@ -59,7 +59,7 @@ static void test_msr_platform_info_disabled(struct kvm_vcpu *vcpu) struct kvm_run *run = vcpu->run; vm_enable_cap(vcpu->vm, KVM_CAP_MSR_PLATFORM_INFO, false); - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_SHUTDOWN, "Exit_reason other than KVM_EXIT_SHUTDOWN: %u (%s)\n", run->exit_reason, @@ -84,12 +84,12 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); - msr_platform_info = vcpu_get_msr(vm, vcpu->id, MSR_PLATFORM_INFO); - vcpu_set_msr(vm, vcpu->id, MSR_PLATFORM_INFO, - msr_platform_info | MSR_PLATFORM_INFO_MAX_TURBO_RATIO); + msr_platform_info = vcpu_get_msr(vcpu, MSR_PLATFORM_INFO); + vcpu_set_msr(vcpu, MSR_PLATFORM_INFO, + msr_platform_info | MSR_PLATFORM_INFO_MAX_TURBO_RATIO); test_msr_platform_info_enabled(vcpu); test_msr_platform_info_disabled(vcpu); - vcpu_set_msr(vm, vcpu->id, MSR_PLATFORM_INFO, msr_platform_info); + vcpu_set_msr(vcpu, MSR_PLATFORM_INFO, msr_platform_info); kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index ffa9e267188c..c86b84b68ee3 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -177,12 +177,12 @@ static uint64_t run_vcpu_to_sync(struct kvm_vcpu *vcpu) struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - get_ucall(vcpu->vm, vcpu->id, &uc); + get_ucall(vcpu, &uc); TEST_ASSERT(uc.cmd == UCALL_SYNC, "Received ucall other than UCALL_SYNC: %lu", uc.cmd); return uc.args[1]; @@ -371,7 +371,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) vcpu = vm_vcpu_add(vm, 0, guest_code); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); TEST_ASSERT(!sanity_check_pmu(vcpu), "Guest should not be able to use disabled PMU."); @@ -470,7 +470,7 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); if (!sanity_check_pmu(vcpu)) { print_skip("Guest PMU is not functional"); diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index b11f12888fad..afc063178c6a 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -49,9 +49,9 @@ static void run_vcpu(struct kvm_vcpu *vcpu) for (stage = 0; stage < 2; stage++) { - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage + 1, diff --git a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c index 2e67df3a95ba..dd344439ad33 100644 --- a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c +++ b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c @@ -35,11 +35,11 @@ static void test_cr4_feature_bit(struct kvm_vcpu *vcpu, struct kvm_sregs *orig, memcpy(&sregs, orig, sizeof(sregs)); sregs.cr4 |= feature_bit; - rc = _vcpu_sregs_set(vcpu->vm, vcpu->id, &sregs); + rc = _vcpu_sregs_set(vcpu, &sregs); TEST_ASSERT(rc, "KVM allowed unsupported CR4 bit (0x%lx)", feature_bit); /* Sanity check that KVM didn't change anything. */ - vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); TEST_ASSERT(!memcmp(&sregs, orig, sizeof(sregs)), "KVM modified sregs"); } @@ -97,15 +97,15 @@ int main(int argc, char *argv[]) vm = vm_create_barebones(); vcpu = __vm_vcpu_add(vm, 0); - vcpu_sregs_get(vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); sregs.cr4 |= calc_cr4_feature_bits(vm); cr4 = sregs.cr4; - rc = _vcpu_sregs_set(vm, vcpu->id, &sregs); + rc = _vcpu_sregs_set(vcpu, &sregs); TEST_ASSERT(!rc, "Failed to set supported CR4 bits (0x%lx)", cr4); - vcpu_sregs_get(vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); TEST_ASSERT(sregs.cr4 == cr4, "sregs.CR4 (0x%llx) != CR4 (0x%lx)", sregs.cr4, cr4); @@ -125,13 +125,13 @@ int main(int argc, char *argv[]) /* Create a "real" VM and verify APIC_BASE can be set. */ vm = vm_create_with_one_vcpu(&vcpu, NULL); - vcpu_sregs_get(vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); sregs.apic_base = 1 << 10; - rc = _vcpu_sregs_set(vm, vcpu->id, &sregs); + rc = _vcpu_sregs_set(vcpu, &sregs); TEST_ASSERT(rc, "Set IA32_APIC_BASE to %llx (invalid)", sregs.apic_base); sregs.apic_base = 1 << 11; - rc = _vcpu_sregs_set(vm, vcpu->id, &sregs); + rc = _vcpu_sregs_set(vcpu, &sregs); TEST_ASSERT(!rc, "Couldn't set IA32_APIC_BASE to %llx (valid)", sregs.apic_base); diff --git a/tools/testing/selftests/kvm/x86_64/smm_test.c b/tools/testing/selftests/kvm/x86_64/smm_test.c index 36165b774a28..3cd1da388b52 100644 --- a/tools/testing/selftests/kvm/x86_64/smm_test.c +++ b/tools/testing/selftests/kvm/x86_64/smm_test.c @@ -118,12 +118,12 @@ void inject_smi(struct kvm_vcpu *vcpu) { struct kvm_vcpu_events events; - vcpu_events_get(vcpu->vm, vcpu->id, &events); + vcpu_events_get(vcpu, &events); events.smi.pending = 1; events.flags |= KVM_VCPUEVENT_VALID_SMM; - vcpu_events_set(vcpu->vm, vcpu->id, &events); + vcpu_events_set(vcpu, &events); } int main(int argc, char *argv[]) @@ -151,7 +151,7 @@ int main(int argc, char *argv[]) memcpy(addr_gpa2hva(vm, SMRAM_GPA) + 0x8000, smi_handler, sizeof(smi_handler)); - vcpu_set_msr(vm, vcpu->id, MSR_IA32_SMBASE, SMRAM_GPA); + vcpu_set_msr(vcpu, MSR_IA32_SMBASE, SMRAM_GPA); if (kvm_check_cap(KVM_CAP_NESTED_STATE)) { if (nested_svm_supported()) @@ -163,17 +163,17 @@ int main(int argc, char *argv[]) if (!nested_gva) pr_info("will skip SMM test with VMX enabled\n"); - vcpu_args_set(vm, vcpu->id, 1, nested_gva); + vcpu_args_set(vcpu, 1, nested_gva); for (stage = 1;; stage++) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); memset(®s, 0, sizeof(regs)); - vcpu_regs_get(vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); stage_reported = regs.rax & 0xff; @@ -201,12 +201,12 @@ int main(int argc, char *argv[]) if (stage == 10) inject_smi(vcpu); - state = vcpu_save_state(vm, vcpu->id); + state = vcpu_save_state(vcpu); kvm_vm_release(vm); vcpu = vm_recreate_with_one_vcpu(vm); - vcpu_set_cpuid(vm, vcpu->id, kvm_get_supported_cpuid()); - vcpu_load_state(vm, vcpu->id, state); + vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); + vcpu_load_state(vcpu, state); run = vcpu->run; kvm_x86_state_cleanup(state); } diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index b7869efad22a..0bcd78cf7c79 100644 --- a/tools/testing/selftests/kvm/x86_64/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -167,7 +167,7 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); run = vcpu->run; - vcpu_regs_get(vm, vcpu->id, ®s1); + vcpu_regs_get(vcpu, ®s1); if (kvm_check_cap(KVM_CAP_NESTED_STATE)) { if (nested_svm_supported()) @@ -179,16 +179,16 @@ int main(int argc, char *argv[]) if (!nested_gva) pr_info("will skip nested state checks\n"); - vcpu_args_set(vm, vcpu->id, 1, nested_gva); + vcpu_args_set(vcpu, 1, nested_gva); for (stage = 1;; stage++) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); @@ -206,21 +206,21 @@ int main(int argc, char *argv[]) uc.args[1] == stage, "Stage %d: Unexpected register values vmexit, got %lx", stage, (ulong)uc.args[1]); - state = vcpu_save_state(vm, vcpu->id); + state = vcpu_save_state(vcpu); memset(®s1, 0, sizeof(regs1)); - vcpu_regs_get(vm, vcpu->id, ®s1); + vcpu_regs_get(vcpu, ®s1); kvm_vm_release(vm); /* Restore state in a new VM. */ vcpu = vm_recreate_with_one_vcpu(vm); - vcpu_set_cpuid(vm, vcpu->id, kvm_get_supported_cpuid()); - vcpu_load_state(vm, vcpu->id, state); + vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); + vcpu_load_state(vcpu, state); run = vcpu->run; kvm_x86_state_cleanup(state); memset(®s2, 0, sizeof(regs2)); - vcpu_regs_get(vm, vcpu->id, ®s2); + vcpu_regs_get(vcpu, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", (ulong) regs2.rdi, (ulong) regs2.rsi); diff --git a/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c b/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c index 8e90e463895a..9c68a47b69e1 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c @@ -95,23 +95,23 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, VINTR_IRQ_NUMBER, vintr_irq_handler); vm_install_exception_handler(vm, INTR_IRQ_NUMBER, intr_irq_handler); vcpu_alloc_svm(vm, &svm_gva); - vcpu_args_set(vm, vcpu->id, 1, svm_gva); + vcpu_args_set(vcpu, 1, svm_gva); run = vcpu->run; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); break; diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c index a337ab2ec101..1c3f457aa3aa 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -145,7 +145,7 @@ static void run_test(bool is_nmi) vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, NMI_VECTOR, guest_nmi_handler); vm_install_exception_handler(vm, BP_VECTOR, guest_bp_handler); @@ -163,23 +163,23 @@ static void run_test(bool is_nmi) } else { idt_alt_vm = 0; } - vcpu_args_set(vm, vcpu->id, 3, svm_gva, (uint64_t)is_nmi, (uint64_t)idt_alt_vm); + vcpu_args_set(vcpu, 3, svm_gva, (uint64_t)is_nmi, (uint64_t)idt_alt_vm); memset(&debug, 0, sizeof(debug)); - vcpu_guest_debug_set(vm, vcpu->id, &debug); + vcpu_guest_debug_set(vcpu, &debug); struct kvm_run *run = vcpu->run; struct ucall uc; alarm(2); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); alarm(0); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld, vals = 0x%lx 0x%lx 0x%lx", (const char *)uc.args[0], __FILE__, uc.args[1], uc.args[2], uc.args[3], uc.args[4]); diff --git a/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c index 15e389a7cd31..e6d7191866a5 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c @@ -44,19 +44,19 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vcpu_alloc_svm(vm, &svm_gva); - vcpu_args_set(vm, vcpu->id, 1, svm_gva); + vcpu_args_set(vcpu, 1, svm_gva); for (;;) { volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ diff --git a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c index c971706b49f5..773db9d4f228 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -109,14 +109,14 @@ int main(int argc, char *argv[]) /* Request reading invalid register set from VCPU. */ run->kvm_valid_regs = INVALID_SYNC_FIELD; - rv = _vcpu_run(vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", rv); run->kvm_valid_regs = 0; run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; - rv = _vcpu_run(vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", rv); @@ -124,14 +124,14 @@ int main(int argc, char *argv[]) /* Request setting invalid register set into VCPU. */ run->kvm_dirty_regs = INVALID_SYNC_FIELD; - rv = _vcpu_run(vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", rv); run->kvm_dirty_regs = 0; run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS; - rv = _vcpu_run(vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(rv < 0 && errno == EINVAL, "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", rv); @@ -140,19 +140,19 @@ int main(int argc, char *argv[]) /* Request and verify all valid register sets. */ /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */ run->kvm_valid_regs = TEST_SYNC_FIELDS; - rv = _vcpu_run(vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - vcpu_regs_get(vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); compare_regs(®s, &run->s.regs.regs); - vcpu_sregs_get(vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); compare_sregs(&sregs, &run->s.regs.sregs); - vcpu_events_get(vm, vcpu->id, &events); + vcpu_events_get(vcpu, &events); compare_vcpu_events(&events, &run->s.regs.events); /* Set and verify various register values. */ @@ -162,7 +162,7 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = TEST_SYNC_FIELDS; run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS; - rv = _vcpu_run(vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, @@ -174,13 +174,13 @@ int main(int argc, char *argv[]) "apic_base sync regs value incorrect 0x%llx.", run->s.regs.sregs.apic_base); - vcpu_regs_get(vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); compare_regs(®s, &run->s.regs.regs); - vcpu_sregs_get(vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); compare_sregs(&sregs, &run->s.regs.sregs); - vcpu_events_get(vm, vcpu->id, &events); + vcpu_events_get(vcpu, &events); compare_vcpu_events(&events, &run->s.regs.events); /* Clear kvm_dirty_regs bits, verify new s.regs values are @@ -189,7 +189,7 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = TEST_SYNC_FIELDS; run->kvm_dirty_regs = 0; run->s.regs.regs.rbx = 0xDEADBEEF; - rv = _vcpu_run(vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, @@ -206,8 +206,8 @@ int main(int argc, char *argv[]) run->kvm_dirty_regs = 0; run->s.regs.regs.rbx = 0xAAAA; regs.rbx = 0xBAC0; - vcpu_regs_set(vm, vcpu->id, ®s); - rv = _vcpu_run(vm, vcpu->id); + vcpu_regs_set(vcpu, ®s); + rv = _vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, @@ -215,7 +215,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(run->s.regs.regs.rbx == 0xAAAA, "rbx sync regs value incorrect 0x%llx.", run->s.regs.regs.rbx); - vcpu_regs_get(vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); TEST_ASSERT(regs.rbx == 0xBAC0 + 1, "rbx guest value incorrect 0x%llx.", regs.rbx); @@ -227,7 +227,7 @@ int main(int argc, char *argv[]) run->kvm_valid_regs = 0; run->kvm_dirty_regs = TEST_SYNC_FIELDS; run->s.regs.regs.rbx = 0xBBBB; - rv = _vcpu_run(vm, vcpu->id); + rv = _vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, @@ -235,7 +235,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(run->s.regs.regs.rbx == 0xBBBB, "rbx sync regs value incorrect 0x%llx.", run->s.regs.regs.rbx); - vcpu_regs_get(vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); TEST_ASSERT(regs.rbx == 0xBBBB + 1, "rbx guest value incorrect 0x%llx.", regs.rbx); diff --git a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c index 2b0f19ddbc8b..01d491f849c2 100644 --- a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c +++ b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c @@ -61,8 +61,8 @@ int main(void) run = vcpu->run; vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); - vcpu_run(vm, vcpu->id); + vcpu_args_set(vcpu, 1, vmx_pages_gva); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Expected KVM_EXIT_IO, got: %u (%s)\n", @@ -70,21 +70,21 @@ int main(void) TEST_ASSERT(run->io.port == ARBITRARY_IO_PORT, "Expected IN from port %d from L2, got port %d", ARBITRARY_IO_PORT, run->io.port); - vcpu_events_get(vm, vcpu->id, &events); + vcpu_events_get(vcpu, &events); events.flags |= KVM_VCPUEVENT_VALID_TRIPLE_FAULT; events.triple_fault.pending = true; - vcpu_events_set(vm, vcpu->id, &events); + vcpu_events_set(vcpu, &events); run->immediate_exit = true; - vcpu_run_complete_io(vm, vcpu->id); + vcpu_run_complete_io(vcpu); - vcpu_events_get(vm, vcpu->id, &events); + vcpu_events_get(vcpu, &events); TEST_ASSERT(events.flags & KVM_VCPUEVENT_VALID_TRIPLE_FAULT, "Triple fault event invalid"); TEST_ASSERT(events.triple_fault.pending, "No triple fault pending"); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_DONE: break; case UCALL_ABORT: diff --git a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c index 3b7bf660eced..3165d3f7e065 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c @@ -14,7 +14,7 @@ #define GUEST_STEP (UNITY * 4) #define ROUND(x) ((x + UNITY / 2) & -UNITY) #define rounded_rdmsr(x) ROUND(rdmsr(x)) -#define rounded_host_rdmsr(x) ROUND(vcpu_get_msr(vm, vcpu->id, x)) +#define rounded_host_rdmsr(x) ROUND(vcpu_get_msr(vcpu, x)) static void guest_code(void) { @@ -68,9 +68,9 @@ static void run_vcpu(struct kvm_vcpu *vcpu, int stage) { struct ucall uc; - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") && uc.args[1] == stage + 1, "Stage %d: Unexpected register values vmexit, got %lx", @@ -116,18 +116,18 @@ int main(void) * Host: writes to MSR_IA32_TSC set the host-side offset * and therefore do not change MSR_IA32_TSC_ADJUST. */ - vcpu_set_msr(vm, vcpu->id, MSR_IA32_TSC, HOST_ADJUST + val); + vcpu_set_msr(vcpu, MSR_IA32_TSC, HOST_ADJUST + val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); run_vcpu(vcpu, 3); /* Host: writes to MSR_IA32_TSC_ADJUST do not modify the TSC. */ - vcpu_set_msr(vm, vcpu->id, MSR_IA32_TSC_ADJUST, UNITY * 123456); + vcpu_set_msr(vcpu, MSR_IA32_TSC_ADJUST, UNITY * 123456); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); - ASSERT_EQ(vcpu_get_msr(vm, vcpu->id, MSR_IA32_TSC_ADJUST), UNITY * 123456); + ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_TSC_ADJUST), UNITY * 123456); /* Restore previous value. */ - vcpu_set_msr(vm, vcpu->id, MSR_IA32_TSC_ADJUST, val); + vcpu_set_msr(vcpu, MSR_IA32_TSC_ADJUST, val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC), HOST_ADJUST + val); ASSERT_EQ(rounded_host_rdmsr(MSR_IA32_TSC_ADJUST), val); diff --git a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c index 728b252597cc..e416af887ca0 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c @@ -58,7 +58,7 @@ static void *run_vcpu(void *_cpu_nr) if (!first_cpu_done) { first_cpu_done = true; - vcpu_set_msr(vm, vcpu->id, MSR_IA32_TSC, TEST_TSC_OFFSET); + vcpu_set_msr(vcpu, MSR_IA32_TSC, TEST_TSC_OFFSET); } pthread_spin_unlock(&create_lock); @@ -67,13 +67,13 @@ static void *run_vcpu(void *_cpu_nr) volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_DONE: goto out; diff --git a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c index 0ba774ed6476..7538d57a41d5 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c @@ -65,14 +65,14 @@ int main(int argc, char *argv[]) memset(®s, 0, sizeof(regs)); while (1) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - if (get_ucall(vm, vcpu->id, &uc)) + if (get_ucall(vcpu, &uc)) break; TEST_ASSERT(run->io.port == 0x80, @@ -85,13 +85,13 @@ int main(int argc, char *argv[]) * scope from a testing perspective as it's not ABI in any way, * i.e. it really is abusing internal KVM knowledge. */ - vcpu_regs_get(vm, vcpu->id, ®s); + vcpu_regs_get(vcpu, ®s); if (regs.rcx == 2) regs.rcx = 1; if (regs.rcx == 3) regs.rcx = 8192; memset((void *)run + run->io.data_offset, 0xaa, 4096); - vcpu_regs_set(vm, vcpu->id, ®s); + vcpu_regs_set(vcpu, ®s); } switch (uc.cmd) { diff --git a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c index a0d35e578b25..f84dc37426f5 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c @@ -399,7 +399,7 @@ static void check_for_guest_assert(struct kvm_vcpu *vcpu) struct ucall uc; if (vcpu->run->exit_reason == KVM_EXIT_IO && - get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_ABORT) { + get_ucall(vcpu, &uc) == UCALL_ABORT) { TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); } @@ -483,7 +483,7 @@ static void process_ucall_done(struct kvm_vcpu *vcpu) run->exit_reason, exit_reason_str(run->exit_reason)); - TEST_ASSERT(get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_DONE, + TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_DONE, "Unexpected ucall command: %lu, expected UCALL_DONE (%d)", uc.cmd, UCALL_DONE); } @@ -500,7 +500,7 @@ static uint64_t process_ucall(struct kvm_vcpu *vcpu) run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_SYNC: break; case UCALL_ABORT: @@ -519,26 +519,26 @@ static uint64_t process_ucall(struct kvm_vcpu *vcpu) static void run_guest_then_process_rdmsr(struct kvm_vcpu *vcpu, uint32_t msr_index) { - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); process_rdmsr(vcpu, msr_index); } static void run_guest_then_process_wrmsr(struct kvm_vcpu *vcpu, uint32_t msr_index) { - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); process_wrmsr(vcpu, msr_index); } static uint64_t run_guest_then_process_ucall(struct kvm_vcpu *vcpu) { - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); return process_ucall(vcpu); } static void run_guest_then_process_ucall_done(struct kvm_vcpu *vcpu) { - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); process_ucall_done(vcpu); } @@ -560,7 +560,7 @@ static void test_msr_filter_allow(void) vm_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter_allow); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); @@ -577,7 +577,7 @@ static void test_msr_filter_allow(void) run_guest_then_process_rdmsr(vcpu, MSR_NON_EXISTENT); vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); vm_install_exception_handler(vm, UD_VECTOR, NULL); if (process_ucall(vcpu) != UCALL_DONE) { @@ -608,7 +608,7 @@ static int handle_ucall(struct kvm_vcpu *vcpu) { struct ucall uc; - switch (get_ucall(vcpu->vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("Guest assertion not met"); break; @@ -684,7 +684,7 @@ static void test_msr_filter_deny(void) vm_ioctl(vm, KVM_X86_SET_MSR_FILTER, &filter_deny); while (1) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); switch (run->exit_reason) { case KVM_EXIT_X86_RDMSR: diff --git a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c index 10f9c86029e6..ef7514376b1e 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c @@ -95,13 +95,13 @@ int main(int argc, char *argv[]) vmx = vcpu_alloc_vmx(vm, &vmx_pages_gva); prepare_virtualize_apic_accesses(vmx, vm); - vcpu_args_set(vm, vcpu->id, 2, vmx_pages_gva, high_gpa); + vcpu_args_set(vcpu, 2, vmx_pages_gva, high_gpa); while (!done) { volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); if (apic_access_addr == high_gpa) { TEST_ASSERT(run->exit_reason == KVM_EXIT_INTERNAL_ERROR, @@ -119,7 +119,7 @@ int main(int argc, char *argv[]) run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c b/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c index da0363076fba..40c77bb706a1 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c @@ -57,13 +57,13 @@ int main(int argc, char *argv[]) /* Allocate VMX pages and shared descriptors (vmx_pages). */ vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); + vcpu_args_set(vcpu, 1, vmx_pages_gva); for (;;) { volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) if (run->io.port == PORT_L0_EXIT) break; - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ diff --git a/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c index fb8c7f7236f7..215ffa0589d4 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c @@ -82,7 +82,7 @@ int main(int argc, char *argv[]) /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vmx = vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); + vcpu_args_set(vcpu, 1, vmx_pages_gva); run = vcpu->run; /* Add an extra memory slot for testing dirty logging */ @@ -115,13 +115,13 @@ int main(int argc, char *argv[]) while (!done) { memset(host_test_mem, 0xaa, TEST_MEM_PAGES * 4096); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Unexpected exit reason: %u (%s),\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c index 70b30583e50d..5bc2cee0d613 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c @@ -24,7 +24,7 @@ static void __run_vcpu_with_invalid_state(struct kvm_vcpu *vcpu) { struct kvm_run *run = vcpu->run; - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_INTERNAL_ERROR, "Expected KVM_EXIT_INTERNAL_ERROR, got %d (%s)\n", @@ -60,9 +60,9 @@ static void set_or_clear_invalid_guest_state(struct kvm_vcpu *vcpu, bool set) static struct kvm_sregs sregs; if (!sregs.cr0) - vcpu_sregs_get(vcpu->vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); sregs.tr.unusable = !!set; - vcpu_sregs_set(vcpu->vm, vcpu->id, &sregs); + vcpu_sregs_set(vcpu, &sregs); } static void set_invalid_guest_state(struct kvm_vcpu *vcpu) @@ -91,7 +91,7 @@ static void sigalrm_handler(int sig) TEST_ASSERT(sig == SIGALRM, "Unexpected signal = %d", sig); - vcpu_events_get(vcpu->vm, vcpu->id, &events); + vcpu_events_get(vcpu, &events); /* * If an exception is pending, attempt KVM_RUN with invalid guest, @@ -120,7 +120,7 @@ int main(int argc, char *argv[]) get_set_sigalrm_vcpu(vcpu); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c index ba534be498f9..683f4f0a1616 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c @@ -64,9 +64,9 @@ int main(int argc, char *argv[]) /* Allocate VMX pages and shared descriptors (vmx_pages). */ vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); + vcpu_args_set(vcpu, 1, vmx_pages_gva); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); run = vcpu->run; @@ -88,13 +88,13 @@ int main(int argc, char *argv[]) * emulating invalid guest state for L2. */ memset(&sregs, 0, sizeof(sregs)); - vcpu_sregs_get(vm, vcpu->id, &sregs); + vcpu_sregs_get(vcpu, &sregs); sregs.tr.unusable = 1; - vcpu_sregs_set(vm, vcpu->id, &sregs); + vcpu_sregs_set(vcpu, &sregs); - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_DONE: break; case UCALL_ABORT: diff --git a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c index c9cb29f06244..647a4320d3bc 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c @@ -182,26 +182,25 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); + vcpu_args_set(vcpu, 1, vmx_pages_gva); - tsc_khz = __vcpu_ioctl(vm, vcpu->id, KVM_GET_TSC_KHZ, NULL); + tsc_khz = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL); TEST_ASSERT(tsc_khz != -1, "vcpu ioctl KVM_GET_TSC_KHZ failed"); /* scale down L1's TSC frequency */ - vcpu_ioctl(vm, vcpu->id, KVM_SET_TSC_KHZ, - (void *) (tsc_khz / l1_scale_factor)); + vcpu_ioctl(vcpu, KVM_SET_TSC_KHZ, (void *) (tsc_khz / l1_scale_factor)); for (;;) { volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *) uc.args[0]); case UCALL_SYNC: diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c index 63129ff5d003..a308442458b8 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c @@ -87,27 +87,27 @@ int main(int argc, char *argv[]) } /* testcase 1, set capabilities when we have PDCM bit */ - vcpu_set_cpuid(vm, vcpu->id, cpuid); - vcpu_set_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES); + vcpu_set_cpuid(vcpu, cpuid); + vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES); /* check capabilities can be retrieved with KVM_GET_MSR */ - ASSERT_EQ(vcpu_get_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES); + ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES); /* check whatever we write with KVM_SET_MSR is _not_ modified */ - vcpu_run(vm, vcpu->id); - ASSERT_EQ(vcpu_get_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES); + vcpu_run(vcpu); + ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), PMU_CAP_FW_WRITES); /* testcase 2, check valid LBR formats are accepted */ - vcpu_set_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES, 0); - ASSERT_EQ(vcpu_get_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES), 0); + vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0); + ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), 0); - vcpu_set_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES, host_cap.lbr_format); - ASSERT_EQ(vcpu_get_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES), (u64)host_cap.lbr_format); + vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.lbr_format); + ASSERT_EQ(vcpu_get_msr(vcpu, MSR_IA32_PERF_CAPABILITIES), (u64)host_cap.lbr_format); /* testcase 3, check invalid LBR format is rejected */ /* Note, on Arch LBR capable platforms, LBR_FMT in perf capability msr is 0x3f, * to avoid the failure, use a true invalid format 0x30 for the test. */ - ret = _vcpu_set_msr(vm, vcpu->id, MSR_IA32_PERF_CAPABILITIES, 0x30); + ret = _vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, 0x30); TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail."); printf("Completed perf capability tests.\n"); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c index 168adc5b2272..b775a11ec08b 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c @@ -178,19 +178,19 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); run = vcpu->run; - vcpu_regs_get(vm, vcpu->id, ®s1); + vcpu_regs_get(vcpu, ®s1); vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); + vcpu_args_set(vcpu, 1, vmx_pages_gva); for (stage = 1;; stage++) { - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Stage %d: unexpected exit reason: %u (%s),\n", stage, run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); @@ -232,22 +232,22 @@ int main(int argc, char *argv[]) stage, uc.args[4], uc.args[5]); } - state = vcpu_save_state(vm, vcpu->id); + state = vcpu_save_state(vcpu); memset(®s1, 0, sizeof(regs1)); - vcpu_regs_get(vm, vcpu->id, ®s1); + vcpu_regs_get(vcpu, ®s1); kvm_vm_release(vm); /* Restore state in a new VM. */ vcpu = vm_recreate_with_one_vcpu(vm); - vcpu_set_cpuid(vm, vcpu->id, kvm_get_supported_cpuid()); - vcpu_load_state(vm, vcpu->id, state); + vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); + vcpu_load_state(vcpu, state); run = vcpu->run; kvm_x86_state_cleanup(state); memset(®s2, 0, sizeof(regs2)); - vcpu_regs_get(vm, vcpu->id, ®s2); + vcpu_regs_get(vcpu, ®s2); TEST_ASSERT(!memcmp(®s1, ®s2, sizeof(regs2)), "Unexpected register values after vcpu_load_state; rdi: %lx rsi: %lx", (ulong) regs2.rdi, (ulong) regs2.rsi); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c index de38f0e68153..ba783ceb007f 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c @@ -28,7 +28,7 @@ bool have_evmcs; void test_nested_state(struct kvm_vcpu *vcpu, struct kvm_nested_state *state) { - vcpu_nested_state_set(vcpu->vm, vcpu->id, state); + vcpu_nested_state_set(vcpu, state); } void test_nested_state_expect_errno(struct kvm_vcpu *vcpu, @@ -37,7 +37,7 @@ void test_nested_state_expect_errno(struct kvm_vcpu *vcpu, { int rv; - rv = __vcpu_nested_state_set(vcpu->vm, vcpu->id, state); + rv = __vcpu_nested_state_set(vcpu, state); TEST_ASSERT(rv == -1 && errno == expected_errno, "Expected %s (%d) from vcpu_nested_state_set but got rv: %i errno: %s (%d)", strerror(expected_errno), expected_errno, rv, strerror(errno), @@ -121,7 +121,7 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu) test_nested_state(vcpu, state); /* Enable VMX in the guest CPUID. */ - vcpu_set_cpuid(vcpu->vm, vcpu->id, kvm_get_supported_cpuid()); + vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); /* * Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without @@ -137,7 +137,7 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu) state->flags &= KVM_STATE_NESTED_EVMCS; if (have_evmcs) { test_nested_state_expect_einval(vcpu, state); - vcpu_enable_evmcs(vcpu->vm, vcpu->id); + vcpu_enable_evmcs(vcpu); } test_nested_state(vcpu, state); @@ -233,7 +233,7 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu) state->hdr.vmx.vmcs12_pa = -1ull; state->flags = 0; test_nested_state(vcpu, state); - vcpu_nested_state_get(vcpu->vm, vcpu->id, state); + vcpu_nested_state_get(vcpu, state); TEST_ASSERT(state->size >= sizeof(*state) && state->size <= state_sz, "Size must be between %ld and %d. The size returned was %d.", sizeof(*state), state_sz, state->size); @@ -255,7 +255,7 @@ void disable_vmx(struct kvm_vcpu *vcpu) TEST_ASSERT(i != cpuid->nent, "CPUID function 1 not found"); cpuid->entries[i].ecx &= ~CPUID_VMX; - vcpu_set_cpuid(vcpu->vm, vcpu->id, cpuid); + vcpu_set_cpuid(vcpu, cpuid); cpuid->entries[i].ecx |= CPUID_VMX; } diff --git a/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c index 29699d7c16c3..e32bfb102699 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c @@ -133,19 +133,19 @@ int main(int argc, char *argv[]) /* Allocate VMX pages and shared descriptors (vmx_pages). */ vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vm, vcpu->id, 1, vmx_pages_gva); + vcpu_args_set(vcpu, 1, vmx_pages_gva); for (;;) { volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ diff --git a/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c b/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c index 4484ee563b18..3d272d7f961e 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_ipi_test.c @@ -206,14 +206,14 @@ static void *vcpu_thread(void *arg) vcpu->id, r); fprintf(stderr, "vCPU thread running vCPU %u\n", vcpu->id); - vcpu_run(vcpu->vm, vcpu->id); + vcpu_run(vcpu); exit_reason = vcpu->run->exit_reason; TEST_ASSERT(exit_reason == KVM_EXIT_IO, "vCPU %u exited with unexpected exit reason %u-%s, expected KVM_EXIT_IO", vcpu->id, exit_reason, exit_reason_str(exit_reason)); - if (get_ucall(vcpu->vm, vcpu->id, &uc) == UCALL_ABORT) { + if (get_ucall(vcpu, &uc) == UCALL_ABORT) { TEST_ASSERT(false, "vCPU %u exited with error: %s.\n" "Sending vCPU sent %lu IPIs to halting vCPU\n" @@ -415,7 +415,7 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(¶ms[0].vcpu, halter_guest_code); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, params[0].vcpu->id); + vcpu_init_descriptor_tables(params[0].vcpu); vm_install_exception_handler(vm, IPI_VECTOR, guest_ipi_handler); virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); @@ -428,8 +428,8 @@ int main(int argc, char *argv[]) params[0].data = data; params[1].data = data; - vcpu_args_set(vm, params[0].vcpu->id, 1, test_data_page_vaddr); - vcpu_args_set(vm, params[1].vcpu->id, 1, test_data_page_vaddr); + vcpu_args_set(params[0].vcpu, 1, test_data_page_vaddr); + vcpu_args_set(params[1].vcpu, 1, test_data_page_vaddr); pipis_rcvd = (uint64_t *)addr_gva2hva(vm, (uint64_t)&ipis_rcvd); params[0].pipis_rcvd = pipis_rcvd; diff --git a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c index 56301ee1adee..5c5dc7bbb4e2 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c @@ -47,7 +47,7 @@ static void x2apic_guest_code(void) } while (1); } -static void ____test_icr(struct kvm_vm *vm, struct xapic_vcpu *x, uint64_t val) +static void ____test_icr(struct xapic_vcpu *x, uint64_t val) { struct kvm_vcpu *vcpu = x->vcpu; struct kvm_lapic_state xapic; @@ -59,16 +59,16 @@ static void ____test_icr(struct kvm_vm *vm, struct xapic_vcpu *x, uint64_t val) * all bits are valid and should not be modified by KVM (ignoring the * fact that vectors 0-15 are technically illegal). */ - vcpu_ioctl(vm, vcpu->id, KVM_GET_LAPIC, &xapic); + vcpu_ioctl(vcpu, KVM_GET_LAPIC, &xapic); *((u32 *)&xapic.regs[APIC_IRR]) = val; *((u32 *)&xapic.regs[APIC_IRR + 0x10]) = val >> 32; - vcpu_ioctl(vm, vcpu->id, KVM_SET_LAPIC, &xapic); + vcpu_ioctl(vcpu, KVM_SET_LAPIC, &xapic); - vcpu_run(vm, vcpu->id); - ASSERT_EQ(get_ucall(vm, vcpu->id, &uc), UCALL_SYNC); + vcpu_run(vcpu); + ASSERT_EQ(get_ucall(vcpu, &uc), UCALL_SYNC); ASSERT_EQ(uc.args[1], val); - vcpu_ioctl(vm, vcpu->id, KVM_GET_LAPIC, &xapic); + vcpu_ioctl(vcpu, KVM_GET_LAPIC, &xapic); icr = (u64)(*((u32 *)&xapic.regs[APIC_ICR])) | (u64)(*((u32 *)&xapic.regs[APIC_ICR2])) << 32; if (!x->is_x2apic) @@ -76,24 +76,24 @@ static void ____test_icr(struct kvm_vm *vm, struct xapic_vcpu *x, uint64_t val) ASSERT_EQ(icr, val & ~APIC_ICR_BUSY); } -static void __test_icr(struct kvm_vm *vm, struct xapic_vcpu *x, uint64_t val) +static void __test_icr(struct xapic_vcpu *x, uint64_t val) { - ____test_icr(vm, x, val | APIC_ICR_BUSY); - ____test_icr(vm, x, val & ~(u64)APIC_ICR_BUSY); + ____test_icr(x, val | APIC_ICR_BUSY); + ____test_icr(x, val & ~(u64)APIC_ICR_BUSY); } -static void test_icr(struct kvm_vm *vm, struct xapic_vcpu *x) +static void test_icr(struct xapic_vcpu *x) { struct kvm_vcpu *vcpu = x->vcpu; uint64_t icr, i, j; icr = APIC_DEST_SELF | APIC_INT_ASSERT | APIC_DM_FIXED; for (i = 0; i <= 0xff; i++) - __test_icr(vm, x, icr | i); + __test_icr(x, icr | i); icr = APIC_INT_ASSERT | APIC_DM_FIXED; for (i = 0; i <= 0xff; i++) - __test_icr(vm, x, icr | i); + __test_icr(x, icr | i); /* * Send all flavors of IPIs to non-existent vCPUs. TODO: use number of @@ -102,18 +102,18 @@ static void test_icr(struct kvm_vm *vm, struct xapic_vcpu *x) icr = APIC_INT_ASSERT | 0xff; for (i = vcpu->id + 1; i < 0xff; i++) { for (j = 0; j < 8; j++) - __test_icr(vm, x, i << (32 + 24) | APIC_INT_ASSERT | (j << 8)); + __test_icr(x, i << (32 + 24) | APIC_INT_ASSERT | (j << 8)); } /* And again with a shorthand destination for all types of IPIs. */ icr = APIC_DEST_ALLBUT | APIC_INT_ASSERT; for (i = 0; i < 8; i++) - __test_icr(vm, x, icr | (i << 8)); + __test_icr(x, icr | (i << 8)); /* And a few garbage value, just make sure it's an IRQ (blocked). */ - __test_icr(vm, x, 0xa5a5a5a5a5a5a5a5 & ~APIC_DM_FIXED_MASK); - __test_icr(vm, x, 0x5a5a5a5a5a5a5a5a & ~APIC_DM_FIXED_MASK); - __test_icr(vm, x, -1ull & ~APIC_DM_FIXED_MASK); + __test_icr(x, 0xa5a5a5a5a5a5a5a5 & ~APIC_DM_FIXED_MASK); + __test_icr(x, 0x5a5a5a5a5a5a5a5a & ~APIC_DM_FIXED_MASK); + __test_icr(x, -1ull & ~APIC_DM_FIXED_MASK); } int main(int argc, char *argv[]) @@ -127,7 +127,7 @@ int main(int argc, char *argv[]) int i; vm = vm_create_with_one_vcpu(&x.vcpu, x2apic_guest_code); - test_icr(vm, &x); + test_icr(&x); kvm_vm_free(vm); /* @@ -138,15 +138,15 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&x.vcpu, xapic_guest_code); x.is_x2apic = false; - cpuid = vcpu_get_cpuid(vm, x.vcpu->id); + cpuid = vcpu_get_cpuid(x.vcpu); for (i = 0; i < cpuid->nent; i++) { if (cpuid->entries[i].function == 1) break; } cpuid->entries[i].ecx &= ~BIT(21); - vcpu_set_cpuid(vm, x.vcpu->id, cpuid); + vcpu_set_cpuid(x.vcpu, cpuid); virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); - test_icr(vm, &x); + test_icr(&x); kvm_vm_free(vm); } diff --git a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c index 5c0abaf0eb60..4340c2f2300f 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c @@ -348,7 +348,7 @@ static void handle_alrm(int sig) { if (vinfo) printf("evtchn_upcall_pending 0x%x\n", vinfo->evtchn_upcall_pending); - vcpu_dump(stdout, vcpu->vm, vcpu->id, 0); + vcpu_dump(stdout, vcpu, 0); TEST_FAIL("IRQ delivery timed out"); } @@ -423,13 +423,13 @@ int main(int argc, char *argv[]) .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, .u.gpa = VCPU_INFO_ADDR, }; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &vi); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &vi); struct kvm_xen_vcpu_attr pvclock = { .type = KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO, .u.gpa = PVTIME_ADDR, }; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &pvclock); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &pvclock); struct kvm_xen_hvm_attr vec = { .type = KVM_XEN_ATTR_TYPE_UPCALL_VECTOR, @@ -438,7 +438,7 @@ int main(int argc, char *argv[]) vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &vec); vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vm, vcpu->id); + vcpu_init_descriptor_tables(vcpu); vm_install_exception_handler(vm, EVTCHN_VECTOR, evtchn_handler); if (do_runstate_tests) { @@ -446,7 +446,7 @@ int main(int argc, char *argv[]) .type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, .u.gpa = RUNSTATE_ADDR, }; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &st); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &st); } int irq_fd[2] = { -1, -1 }; @@ -522,7 +522,7 @@ int main(int argc, char *argv[]) inj.u.evtchn.flags = 0; vm_ioctl(vm, KVM_XEN_HVM_SET_ATTR, &inj); - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &tmr); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); } vinfo = addr_gpa2hva(vm, VCPU_INFO_VADDR); vinfo->evtchn_upcall_pending = 0; @@ -536,14 +536,14 @@ int main(int argc, char *argv[]) volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ @@ -572,7 +572,7 @@ int main(int argc, char *argv[]) printf("Testing runstate %s\n", runstate_names[uc.args[1]]); rst.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT; rst.u.runstate.state = uc.args[1]; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &rst); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &rst); break; case 4: @@ -587,7 +587,7 @@ int main(int argc, char *argv[]) 0x6b6b - rs->time[RUNSTATE_offline]; rst.u.runstate.time_runnable = -rst.u.runstate.time_blocked - rst.u.runstate.time_offline; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &rst); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &rst); break; case 5: @@ -599,7 +599,7 @@ int main(int argc, char *argv[]) rst.u.runstate.state_entry_time = 0x6b6b + 0x5a; rst.u.runstate.time_blocked = 0x6b6b; rst.u.runstate.time_offline = 0x5a; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &rst); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &rst); break; case 6: @@ -700,7 +700,7 @@ int main(int argc, char *argv[]) case 14: memset(&tmr, 0, sizeof(tmr)); tmr.type = KVM_XEN_VCPU_ATTR_TYPE_TIMER; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_GET_ATTR, &tmr); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &tmr); TEST_ASSERT(tmr.u.timer.port == EVTCHN_TIMER, "Timer port not returned"); TEST_ASSERT(tmr.u.timer.priority == KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL, @@ -720,7 +720,7 @@ int main(int argc, char *argv[]) printf("Testing restored oneshot timer\n"); tmr.u.timer.expires_ns = rs->state_entry_time + 100000000, - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &tmr); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); evtchn_irq_expected = true; alarm(1); break; @@ -747,7 +747,7 @@ int main(int argc, char *argv[]) printf("Testing SCHEDOP_poll wake on masked event\n"); tmr.u.timer.expires_ns = rs->state_entry_time + 100000000, - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &tmr); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); alarm(1); break; @@ -758,11 +758,11 @@ int main(int argc, char *argv[]) evtchn_irq_expected = true; tmr.u.timer.expires_ns = rs->state_entry_time + 100000000; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &tmr); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); /* Read it back and check the pending time is reported correctly */ tmr.u.timer.expires_ns = 0; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_GET_ATTR, &tmr); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &tmr); TEST_ASSERT(tmr.u.timer.expires_ns == rs->state_entry_time + 100000000, "Timer not reported pending"); alarm(1); @@ -772,7 +772,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(!evtchn_irq_expected, "Expected event channel IRQ but it didn't happen"); /* Read timer and check it is no longer pending */ - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_GET_ATTR, &tmr); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &tmr); TEST_ASSERT(!tmr.u.timer.expires_ns, "Timer still reported pending"); shinfo->evtchn_pending[0] = 0; @@ -781,7 +781,7 @@ int main(int argc, char *argv[]) evtchn_irq_expected = true; tmr.u.timer.expires_ns = rs->state_entry_time - 100000000ULL; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_SET_ATTR, &tmr); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); alarm(1); break; @@ -851,7 +851,7 @@ int main(int argc, char *argv[]) struct kvm_xen_vcpu_attr rst = { .type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA, }; - vcpu_ioctl(vm, vcpu->id, KVM_XEN_VCPU_GET_ATTR, &rst); + vcpu_ioctl(vcpu, KVM_XEN_VCPU_GET_ATTR, &rst); if (verbose) { printf("Runstate: %s(%d), entry %" PRIu64 " ns\n", diff --git a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c index 1411ead620fe..a91f11fb26f4 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) } vm = vm_create_with_one_vcpu(&vcpu, guest_code); - vcpu_set_hv_cpuid(vm, vcpu->id); + vcpu_set_hv_cpuid(vcpu); struct kvm_xen_hvm_config hvmc = { .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL, @@ -107,7 +107,7 @@ int main(int argc, char *argv[]) volatile struct kvm_run *run = vcpu->run; struct ucall uc; - vcpu_run(vm, vcpu->id); + vcpu_run(vcpu); if (run->exit_reason == KVM_EXIT_XEN) { ASSERT_EQ(run->xen.type, KVM_EXIT_XEN_HCALL); @@ -129,7 +129,7 @@ int main(int argc, char *argv[]) run->exit_reason, exit_reason_str(run->exit_reason)); - switch (get_ucall(vm, vcpu->id, &uc)) { + switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ diff --git a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c index a89d49ae79a6..1e3506c3deed 100644 --- a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c +++ b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c @@ -38,11 +38,11 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - xss_val = vcpu_get_msr(vm, vcpu->id, MSR_IA32_XSS); + xss_val = vcpu_get_msr(vcpu, MSR_IA32_XSS); TEST_ASSERT(xss_val == 0, "MSR_IA32_XSS should be initialized to zero\n"); - vcpu_set_msr(vm, vcpu->id, MSR_IA32_XSS, xss_val); + vcpu_set_msr(vcpu, MSR_IA32_XSS, xss_val); /* * At present, KVM only supports a guest IA32_XSS value of 0. Verify @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) */ xss_in_msr_list = kvm_msr_is_in_save_restore_list(MSR_IA32_XSS); for (i = 0; i < MSR_BITS; ++i) { - r = _vcpu_set_msr(vm, vcpu->id, MSR_IA32_XSS, 1ull << i); + r = _vcpu_set_msr(vcpu, MSR_IA32_XSS, 1ull << i); /* * Setting a list of MSRs returns the entry that "faulted", or From fce542992b5d8baaf6f7a4d61a3273de3a2ff10b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 16:46:46 -0800 Subject: [PATCH 0441/1436] KVM: selftests: Drop vcpu_get(), rename vcpu_find() => vcpu_exists() Drop vcpu_get() and rename vcpu_find() to vcpu_exists() to make it that much harder for a test to give meaning to a vCPU ID. I.e. force tests to capture a vCPU when the vCPU is created. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 2 -- tools/testing/selftests/kvm/lib/kvm_util.c | 34 +++++++------------ 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 640634bdba9a..2da9db060378 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -93,8 +93,6 @@ struct kvm_vm { continue; \ else -struct kvm_vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpu_id); - struct userspace_mem_region * memslot2region(struct kvm_vm *vm, uint32_t memslot); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index eb04b9c0a13c..60051258a3a3 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -459,26 +459,6 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, return ®ion->region; } -static struct kvm_vcpu *vcpu_find(struct kvm_vm *vm, uint32_t vcpu_id) -{ - struct kvm_vcpu *vcpu; - - list_for_each_entry(vcpu, &vm->vcpus, list) { - if (vcpu->id == vcpu_id) - return vcpu; - } - - return NULL; -} - -struct kvm_vcpu *vcpu_get(struct kvm_vm *vm, uint32_t vcpu_id) -{ - struct kvm_vcpu *vcpu = vcpu_find(vm, vcpu_id); - - TEST_ASSERT(vcpu, "vCPU %d does not exist", vcpu_id); - return vcpu; -} - /* * VM VCPU Remove * @@ -1049,6 +1029,18 @@ static int vcpu_mmap_sz(void) return ret; } +static bool vcpu_exists(struct kvm_vm *vm, uint32_t vcpu_id) +{ + struct kvm_vcpu *vcpu; + + list_for_each_entry(vcpu, &vm->vcpus, list) { + if (vcpu->id == vcpu_id) + return true; + } + + return false; +} + /* * Adds a virtual CPU to the VM specified by vm with the ID given by vcpu_id. * No additional vCPU setup is done. Returns the vCPU. @@ -1058,7 +1050,7 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id) struct kvm_vcpu *vcpu; /* Confirm a vcpu with the specified id doesn't already exist. */ - TEST_ASSERT(!vcpu_find(vm, vcpu_id), "vCPU%d already exists\n", vcpu_id); + TEST_ASSERT(!vcpu_exists(vm, vcpu_id), "vCPU%d already exists\n", vcpu_id); /* Allocate and initialize new vcpu structure. */ vcpu = calloc(1, sizeof(*vcpu)); From 96a96e1ad06f8fc380a69954f5511e950a5eeb23 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 16:48:13 -0800 Subject: [PATCH 0442/1436] KVM: selftests: Remove vcpu_state() helper Drop vcpu_state() now that all tests reference vcpu->run directly. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 1 - tools/testing/selftests/kvm/lib/kvm_util.c | 19 +------------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 2da9db060378..5741a999aca1 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -298,7 +298,6 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva); vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva); void *addr_gpa2alias(struct kvm_vm *vm, vm_paddr_t gpa); -struct kvm_run *vcpu_state(struct kvm_vcpu *vcpu); void vcpu_run(struct kvm_vcpu *vcpu); int _vcpu_run(struct kvm_vcpu *vcpu); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 60051258a3a3..ec4642f79fa3 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1001,19 +1001,7 @@ void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot) __vm_mem_region_delete(vm, memslot2region(vm, slot), true); } -/* - * VCPU mmap Size - * - * Input Args: None - * - * Output Args: None - * - * Return: - * Size of VCPU state - * - * Returns the size of the structure pointed to by the return value - * of vcpu_state(). - */ +/* Returns the size of a vCPU's kvm_run structure. */ static int vcpu_mmap_sz(void) { int dev_fd, ret; @@ -1394,11 +1382,6 @@ void vm_create_irqchip(struct kvm_vm *vm) vm->has_irqchip = true; } -struct kvm_run *vcpu_state(struct kvm_vcpu *vcpu) -{ - return vcpu->run; -} - int _vcpu_run(struct kvm_vcpu *vcpu) { From 68c1b3e910c0451ed9a51093c603cc4898d643ce Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 16 Feb 2022 16:51:20 -0800 Subject: [PATCH 0443/1436] KVM: selftests: Open code and drop 'struct kvm_vm' accessors Drop a variety of 'struct kvm_vm' accessors that wrap a single variable now that tests can simply reference the variable directly. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/dirty_log_perf_test.c | 2 +- tools/testing/selftests/kvm/dirty_log_test.c | 9 +++---- .../selftests/kvm/include/kvm_util_base.h | 6 ----- .../selftests/kvm/kvm_page_table_test.c | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 25 ------------------- .../selftests/kvm/lib/perf_test_util.c | 2 +- .../selftests/kvm/max_guest_memory_test.c | 11 ++++---- .../kvm/memslot_modification_stress_test.c | 2 +- .../selftests/kvm/x86_64/hyperv_cpuid.c | 2 +- 9 files changed, 14 insertions(+), 47 deletions(-) diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c index 2027208e7d10..808a36dbf0c0 100644 --- a/tools/testing/selftests/kvm/dirty_log_perf_test.c +++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c @@ -221,7 +221,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) perf_test_set_wr_fract(vm, p->wr_fract); - guest_num_pages = (nr_vcpus * guest_percpu_mem_size) >> vm_get_page_shift(vm); + guest_num_pages = (nr_vcpus * guest_percpu_mem_size) >> vm->page_shift; guest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages); host_num_pages = vm_num_host_pages(mode, guest_num_pages); pages_per_slot = host_num_pages / p->slots; diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 906e893375df..ca584b9bf5c0 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -713,21 +713,20 @@ static void run_test(enum vm_guest_mode mode, void *arg) vm = create_vm(mode, &vcpu, 2ul << (DIRTY_MEM_BITS - PAGE_SHIFT_4K), guest_code); - guest_page_size = vm_get_page_size(vm); + guest_page_size = vm->page_size; /* * A little more than 1G of guest page sized pages. Cover the * case where the size is not aligned to 64 pages. */ - guest_num_pages = (1ul << (DIRTY_MEM_BITS - - vm_get_page_shift(vm))) + 3; + guest_num_pages = (1ul << (DIRTY_MEM_BITS - vm->page_shift)) + 3; guest_num_pages = vm_adjust_num_guest_pages(mode, guest_num_pages); host_page_size = getpagesize(); host_num_pages = vm_num_host_pages(mode, guest_num_pages); if (!p->phys_offset) { - guest_test_phys_mem = (vm_get_max_gfn(vm) - - guest_num_pages) * guest_page_size; + guest_test_phys_mem = (vm->max_gfn - guest_num_pages) * + guest_page_size; guest_test_phys_mem = align_down(guest_test_phys_mem, host_page_size); } else { guest_test_phys_mem = p->phys_offset; diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 5741a999aca1..45f536f99399 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -592,13 +592,7 @@ static inline struct kvm_vm *vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm); -unsigned int vm_get_page_size(struct kvm_vm *vm); -unsigned int vm_get_page_shift(struct kvm_vm *vm); unsigned long vm_compute_max_gfn(struct kvm_vm *vm); -uint64_t vm_get_max_gfn(struct kvm_vm *vm); -int vm_get_kvm_fd(struct kvm_vm *vm); -int vm_get_fd(struct kvm_vm *vm); - unsigned int vm_calc_num_guest_pages(enum vm_guest_mode mode, size_t size); unsigned int vm_num_host_pages(enum vm_guest_mode mode, unsigned int num_guest_pages); unsigned int vm_num_guest_pages(enum vm_guest_mode mode, unsigned int num_host_pages); diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c index 8706ae358444..0f8792aa0366 100644 --- a/tools/testing/selftests/kvm/kvm_page_table_test.c +++ b/tools/testing/selftests/kvm/kvm_page_table_test.c @@ -260,7 +260,7 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg) /* Align down GPA of the testing memslot */ if (!p->phys_offset) - guest_test_phys_mem = (vm_get_max_gfn(vm) - guest_num_pages) * + guest_test_phys_mem = (vm->max_gfn - guest_num_pages) * guest_page_size; else guest_test_phys_mem = p->phys_offset; diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index ec4642f79fa3..548c3c366bf5 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1827,36 +1827,11 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva) return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); } -unsigned int vm_get_page_size(struct kvm_vm *vm) -{ - return vm->page_size; -} - -unsigned int vm_get_page_shift(struct kvm_vm *vm) -{ - return vm->page_shift; -} - unsigned long __attribute__((weak)) vm_compute_max_gfn(struct kvm_vm *vm) { return ((1ULL << vm->pa_bits) >> vm->page_shift) - 1; } -uint64_t vm_get_max_gfn(struct kvm_vm *vm) -{ - return vm->max_gfn; -} - -int vm_get_kvm_fd(struct kvm_vm *vm) -{ - return vm->kvm_fd; -} - -int vm_get_fd(struct kvm_vm *vm) -{ - return vm->fd; -} - static unsigned int vm_calc_num_pages(unsigned int num_pages, unsigned int page_shift, unsigned int new_page_shift, diff --git a/tools/testing/selftests/kvm/lib/perf_test_util.c b/tools/testing/selftests/kvm/lib/perf_test_util.c index a8c7b2785cc4..2649595194ad 100644 --- a/tools/testing/selftests/kvm/lib/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/perf_test_util.c @@ -159,7 +159,7 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int nr_vcpus, pta->vm = vm; /* Put the test region at the top guest physical memory. */ - region_end_gfn = vm_get_max_gfn(vm) + 1; + region_end_gfn = vm->max_gfn + 1; #ifdef __x86_64__ /* diff --git a/tools/testing/selftests/kvm/max_guest_memory_test.c b/tools/testing/selftests/kvm/max_guest_memory_test.c index 8f34c5aca420..9a6e4f3ad6b5 100644 --- a/tools/testing/selftests/kvm/max_guest_memory_test.c +++ b/tools/testing/selftests/kvm/max_guest_memory_test.c @@ -65,8 +65,7 @@ static void *vcpu_worker(void *data) struct kvm_sregs sregs; struct kvm_regs regs; - vcpu_args_set(vcpu, 3, info->start_gpa, info->end_gpa, - vm_get_page_size(vm)); + vcpu_args_set(vcpu, 3, info->start_gpa, info->end_gpa, vm->page_size); /* Snapshot regs before the first run. */ vcpu_regs_get(vcpu, ®s); @@ -104,7 +103,7 @@ static pthread_t *spawn_workers(struct kvm_vm *vm, struct kvm_vcpu **vcpus, TEST_ASSERT(info, "Failed to allocate vCPU gpa ranges"); nr_bytes = ((end_gpa - start_gpa) / nr_vcpus) & - ~((uint64_t)vm_get_page_size(vm) - 1); + ~((uint64_t)vm->page_size - 1); TEST_ASSERT(nr_bytes, "C'mon, no way you have %d CPUs", nr_vcpus); for (i = 0, gpa = start_gpa; i < nr_vcpus; i++, gpa += nr_bytes) { @@ -220,7 +219,7 @@ int main(int argc, char *argv[]) vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus); - max_gpa = vm_get_max_gfn(vm) << vm_get_page_shift(vm); + max_gpa = vm->max_gfn << vm->page_shift; TEST_ASSERT(max_gpa > (4 * slot_size), "MAXPHYADDR <4gb "); fd = kvm_memfd_alloc(slot_size, hugepages); @@ -230,7 +229,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(!madvise(mem, slot_size, MADV_NOHUGEPAGE), "madvise() failed"); /* Pre-fault the memory to avoid taking mmap_sem on guest page faults. */ - for (i = 0; i < slot_size; i += vm_get_page_size(vm)) + for (i = 0; i < slot_size; i += vm->page_size) ((uint8_t *)mem)[i] = 0xaa; gpa = 0; @@ -249,7 +248,7 @@ int main(int argc, char *argv[]) for (i = 0; i < slot_size; i += size_1gb) __virt_pg_map(vm, gpa + i, gpa + i, PG_LEVEL_1G); #else - for (i = 0; i < slot_size; i += vm_get_page_size(vm)) + for (i = 0; i < slot_size; i += vm->page_size) virt_pg_map(vm, gpa + i, gpa + i); #endif } diff --git a/tools/testing/selftests/kvm/memslot_modification_stress_test.c b/tools/testing/selftests/kvm/memslot_modification_stress_test.c index 1f9036cdcaa9..6ee7e1dde404 100644 --- a/tools/testing/selftests/kvm/memslot_modification_stress_test.c +++ b/tools/testing/selftests/kvm/memslot_modification_stress_test.c @@ -75,7 +75,7 @@ static void add_remove_memslot(struct kvm_vm *vm, useconds_t delay, * Add the dummy memslot just below the perf_test_util memslot, which is * at the top of the guest physical address space. */ - gpa = perf_test_args.gpa - pages * vm_get_page_size(vm); + gpa = perf_test_args.gpa - pages * vm->page_size; for (i = 0; i < nr_modifications; i++) { usleep(delay); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c index af13c48f0f30..6df5a6356181 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c @@ -121,7 +121,7 @@ void test_hv_cpuid_e2big(struct kvm_vm *vm, struct kvm_vcpu *vcpu) if (vcpu) ret = __vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); else - ret = __kvm_ioctl(vm_get_kvm_fd(vm), KVM_GET_SUPPORTED_HV_CPUID, &cpuid); + ret = __kvm_ioctl(vm->kvm_fd, KVM_GET_SUPPORTED_HV_CPUID, &cpuid); TEST_ASSERT(ret == -1 && errno == E2BIG, "%s KVM_GET_SUPPORTED_HV_CPUID didn't fail with -E2BIG when" From 3222d0264fb60a9aa359a58a059a7fb0d2b3c467 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 2 May 2022 17:25:17 -0700 Subject: [PATCH 0444/1436] KVM: selftests: Drop @slot0_mem_pages from __vm_create_with_vcpus() All callers of __vm_create_with_vcpus() pass DEFAULT_GUEST_PHY_PAGES for @slot_mem_pages; drop the param and just hardcode the "default" as the base number of pages for slot0. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 9 +++----- .../selftests/kvm/kvm_page_table_test.c | 5 ++--- tools/testing/selftests/kvm/lib/kvm_util.c | 21 +++++++------------ .../selftests/kvm/lib/perf_test_util.c | 5 ++--- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 45f536f99399..f84e01612c52 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -561,18 +561,15 @@ static inline struct kvm_vm *vm_create(uint64_t nr_pages) return __vm_create(VM_MODE_DEFAULT, nr_pages); } -/* Like vm_create_default_with_vcpus, but accepts mode and slot0 memory as a parameter */ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, - uint64_t slot0_mem_pages, uint64_t extra_mem_pages, - uint32_t num_percpu_pages, void *guest_code, - struct kvm_vcpu *vcpus[]); + uint64_t extra_mem_pages, uint32_t num_percpu_pages, + void *guest_code, struct kvm_vcpu *vcpus[]); static inline struct kvm_vm *vm_create_with_vcpus(uint32_t nr_vcpus, void *guest_code, struct kvm_vcpu *vcpus[]) { - return __vm_create_with_vcpus(VM_MODE_DEFAULT, nr_vcpus, - DEFAULT_GUEST_PHY_PAGES, 0, 0, + return __vm_create_with_vcpus(VM_MODE_DEFAULT, nr_vcpus, 0, 0, guest_code, vcpus); } diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c index 0f8792aa0366..a68c57572ab4 100644 --- a/tools/testing/selftests/kvm/kvm_page_table_test.c +++ b/tools/testing/selftests/kvm/kvm_page_table_test.c @@ -254,9 +254,8 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg) /* Create a VM with enough guest pages */ guest_num_pages = test_mem_size / guest_page_size; - vm = __vm_create_with_vcpus(mode, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, - guest_num_pages, 0, guest_code, - test_args.vcpus); + vm = __vm_create_with_vcpus(mode, nr_vcpus, guest_num_pages, 0, + guest_code, test_args.vcpus); /* Align down GPA of the testing memslot */ if (!p->phys_offset) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 548c3c366bf5..342bcd576ad6 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -280,7 +280,6 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t nr_pages) * Input Args: * mode - VM Mode (e.g. VM_MODE_P52V48_4K) * nr_vcpus - VCPU count - * slot0_mem_pages - Slot0 physical memory size * extra_mem_pages - Non-slot0 physical memory total size * num_percpu_pages - Per-cpu physical memory pages * guest_code - Guest entry point @@ -291,15 +290,13 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t nr_pages) * Return: * Pointer to opaque structure that describes the created VM. * - * Creates a VM with the mode specified by mode (e.g. VM_MODE_P52V48_4K), - * with customized slot0 memory size, at least 512 pages currently. + * Creates a VM with the mode specified by mode (e.g. VM_MODE_P52V48_4K). * extra_mem_pages is only used to calculate the maximum page table size, * no real memory allocation for non-slot0 memory in this function. */ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, - uint64_t slot0_mem_pages, uint64_t extra_mem_pages, - uint32_t num_percpu_pages, void *guest_code, - struct kvm_vcpu *vcpus[]) + uint64_t extra_mem_pages, uint32_t num_percpu_pages, + void *guest_code, struct kvm_vcpu *vcpus[]) { uint64_t vcpu_pages, extra_pg_pages, pages; struct kvm_vm *vm; @@ -307,10 +304,6 @@ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus TEST_ASSERT(!nr_vcpus || vcpus, "Must provide vCPU array"); - /* Force slot0 memory size not small than DEFAULT_GUEST_PHY_PAGES */ - if (slot0_mem_pages < DEFAULT_GUEST_PHY_PAGES) - slot0_mem_pages = DEFAULT_GUEST_PHY_PAGES; - /* The maximum page table size for a memory region will be when the * smallest pages are used. Considering each page contains x page * table descriptors, the total extra size for page tables (for extra @@ -318,8 +311,8 @@ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus * than N/x*2. */ vcpu_pages = (DEFAULT_STACK_PGS + num_percpu_pages) * nr_vcpus; - extra_pg_pages = (slot0_mem_pages + extra_mem_pages + vcpu_pages) / PTES_PER_MIN_PAGE * 2; - pages = slot0_mem_pages + vcpu_pages + extra_pg_pages; + extra_pg_pages = (DEFAULT_GUEST_PHY_PAGES + extra_mem_pages + vcpu_pages) / PTES_PER_MIN_PAGE * 2; + pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages; TEST_ASSERT(nr_vcpus <= kvm_check_cap(KVM_CAP_MAX_VCPUS), "nr_vcpus = %d too large for host, max-vcpus = %d", @@ -340,8 +333,8 @@ struct kvm_vm *__vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, struct kvm_vcpu *vcpus[1]; struct kvm_vm *vm; - vm = __vm_create_with_vcpus(VM_MODE_DEFAULT, 1, DEFAULT_GUEST_PHY_PAGES, - extra_mem_pages, 0, guest_code, vcpus); + vm = __vm_create_with_vcpus(VM_MODE_DEFAULT, 1, extra_mem_pages, 0, + guest_code, vcpus); *vcpu = vcpus[0]; return vm; diff --git a/tools/testing/selftests/kvm/lib/perf_test_util.c b/tools/testing/selftests/kvm/lib/perf_test_util.c index 2649595194ad..20d1b2ad75d1 100644 --- a/tools/testing/selftests/kvm/lib/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/perf_test_util.c @@ -113,7 +113,7 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int nr_vcpus, { struct perf_test_args *pta = &perf_test_args; struct kvm_vm *vm; - uint64_t guest_num_pages, slot0_pages = DEFAULT_GUEST_PHY_PAGES; + uint64_t guest_num_pages, slot0_pages = 0; uint64_t backing_src_pagesz = get_backing_src_pagesz(backing_src); uint64_t region_end_gfn; int i; @@ -152,8 +152,7 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int nr_vcpus, * The memory is also added to memslot 0, but that's a benign side * effect as KVM allows aliasing HVAs in meslots. */ - vm = __vm_create_with_vcpus(mode, nr_vcpus, DEFAULT_GUEST_PHY_PAGES, - slot0_pages + guest_num_pages, 0, + vm = __vm_create_with_vcpus(mode, nr_vcpus, slot0_pages + guest_num_pages, 0, perf_test_guest_code, vcpus); pta->vm = vm; From acaf50ad6dcb69a9857ef6c9a42100f6270f5f03 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 2 May 2022 17:39:47 -0700 Subject: [PATCH 0445/1436] KVM: selftests: Drop @num_percpu_pages from __vm_create_with_vcpus() Drop @num_percpu_pages from __vm_create_with_vcpus(), all callers pass '0' and there's unlikely to be a test that allocates just enough memory that it needs a per-CPU allocation, but not so much that it won't just do its own memory management. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/include/kvm_util_base.h | 4 ++-- tools/testing/selftests/kvm/kvm_page_table_test.c | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 7 +++---- tools/testing/selftests/kvm/lib/perf_test_util.c | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index f84e01612c52..6143d45a02a7 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -562,14 +562,14 @@ static inline struct kvm_vm *vm_create(uint64_t nr_pages) } struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, - uint64_t extra_mem_pages, uint32_t num_percpu_pages, + uint64_t extra_mem_pages, void *guest_code, struct kvm_vcpu *vcpus[]); static inline struct kvm_vm *vm_create_with_vcpus(uint32_t nr_vcpus, void *guest_code, struct kvm_vcpu *vcpus[]) { - return __vm_create_with_vcpus(VM_MODE_DEFAULT, nr_vcpus, 0, 0, + return __vm_create_with_vcpus(VM_MODE_DEFAULT, nr_vcpus, 0, guest_code, vcpus); } diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c index a68c57572ab4..f42c6ac6d71d 100644 --- a/tools/testing/selftests/kvm/kvm_page_table_test.c +++ b/tools/testing/selftests/kvm/kvm_page_table_test.c @@ -254,7 +254,7 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg) /* Create a VM with enough guest pages */ guest_num_pages = test_mem_size / guest_page_size; - vm = __vm_create_with_vcpus(mode, nr_vcpus, guest_num_pages, 0, + vm = __vm_create_with_vcpus(mode, nr_vcpus, guest_num_pages, guest_code, test_args.vcpus); /* Align down GPA of the testing memslot */ diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 342bcd576ad6..afefc48757e6 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -281,7 +281,6 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t nr_pages) * mode - VM Mode (e.g. VM_MODE_P52V48_4K) * nr_vcpus - VCPU count * extra_mem_pages - Non-slot0 physical memory total size - * num_percpu_pages - Per-cpu physical memory pages * guest_code - Guest entry point * vcpuids - VCPU IDs * @@ -295,7 +294,7 @@ struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t nr_pages) * no real memory allocation for non-slot0 memory in this function. */ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, - uint64_t extra_mem_pages, uint32_t num_percpu_pages, + uint64_t extra_mem_pages, void *guest_code, struct kvm_vcpu *vcpus[]) { uint64_t vcpu_pages, extra_pg_pages, pages; @@ -310,7 +309,7 @@ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus * N pages) will be: N/x+N/x^2+N/x^3+... which is definitely smaller * than N/x*2. */ - vcpu_pages = (DEFAULT_STACK_PGS + num_percpu_pages) * nr_vcpus; + vcpu_pages = nr_vcpus * DEFAULT_STACK_PGS; extra_pg_pages = (DEFAULT_GUEST_PHY_PAGES + extra_mem_pages + vcpu_pages) / PTES_PER_MIN_PAGE * 2; pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages; @@ -333,7 +332,7 @@ struct kvm_vm *__vm_create_with_one_vcpu(struct kvm_vcpu **vcpu, struct kvm_vcpu *vcpus[1]; struct kvm_vm *vm; - vm = __vm_create_with_vcpus(VM_MODE_DEFAULT, 1, extra_mem_pages, 0, + vm = __vm_create_with_vcpus(VM_MODE_DEFAULT, 1, extra_mem_pages, guest_code, vcpus); *vcpu = vcpus[0]; diff --git a/tools/testing/selftests/kvm/lib/perf_test_util.c b/tools/testing/selftests/kvm/lib/perf_test_util.c index 20d1b2ad75d1..9618b37c66f7 100644 --- a/tools/testing/selftests/kvm/lib/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/perf_test_util.c @@ -152,7 +152,7 @@ struct kvm_vm *perf_test_create_vm(enum vm_guest_mode mode, int nr_vcpus, * The memory is also added to memslot 0, but that's a benign side * effect as KVM allows aliasing HVAs in meslots. */ - vm = __vm_create_with_vcpus(mode, nr_vcpus, slot0_pages + guest_num_pages, 0, + vm = __vm_create_with_vcpus(mode, nr_vcpus, slot0_pages + guest_num_pages, perf_test_guest_code, vcpus); pta->vm = vm; From 6e1d13bf3815d6058620dd72135be292d9f44bc9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 3 May 2022 09:52:48 -0700 Subject: [PATCH 0446/1436] KVM: selftests: Move per-VM/per-vCPU nr pages calculation to __vm_create() Handle all memslot0 size adjustments in __vm_create(). Currently, the adjustments reside in __vm_create_with_vcpus(), which means tests that call vm_create() or __vm_create() directly are left to their own devices. Some tests just pass DEFAULT_GUEST_PHY_PAGES and don't bother with any adjustments, while others mimic the per-vCPU calculations. For vm_create(), and thus __vm_create(), take the number of vCPUs that will be runnable to calculate that number of per-vCPU pages needed for memslot0. To give readers a hint that neither vm_create() nor __vm_create() create vCPUs, name the parameter @nr_runnable_vcpus instead of @nr_vcpus. That also gives readers a hint as to why tests that create larger numbers of vCPUs but never actually run those vCPUs can skip straight to the vm_create_barebones() variant. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/aarch64/psci_test.c | 2 +- .../testing/selftests/kvm/aarch64/vgic_init.c | 4 +- tools/testing/selftests/kvm/dirty_log_test.c | 3 +- .../selftests/kvm/hardware_disable_test.c | 2 +- .../selftests/kvm/include/kvm_util_base.h | 9 ++- tools/testing/selftests/kvm/lib/kvm_util.c | 57 ++++++++++++------- tools/testing/selftests/kvm/s390x/resets.c | 2 +- .../kvm/x86_64/pmu_event_filter_test.c | 2 +- .../selftests/kvm/x86_64/set_boot_cpu_id.c | 5 +- .../selftests/kvm/x86_64/tsc_scaling_sync.c | 2 +- 10 files changed, 53 insertions(+), 35 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index 3e1bebe63adf..7928c62635fd 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -76,7 +76,7 @@ static struct kvm_vm *setup_vm(void *guest_code, struct kvm_vcpu **source, struct kvm_vcpu_init init; struct kvm_vm *vm; - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(2); ucall_init(vm, NULL); vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init); diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 6b9c9a391a01..02402802b163 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -419,7 +419,7 @@ static void test_v3_typer_accesses(void) uint64_t addr; int ret, i; - v.vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + v.vm = vm_create(NR_VCPUS); (void)vm_vcpu_add(v.vm, 0, guest_code); v.gic_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_V3); @@ -479,7 +479,7 @@ static struct vm_gic vm_gic_v3_create_with_vcpuids(int nr_vcpus, struct vm_gic v; int i; - v.vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + v.vm = vm_create(nr_vcpus); for (i = 0; i < nr_vcpus; i++) vm_vcpu_add(v.vm, vcpuids[i], guest_code); diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index ca584b9bf5c0..8542f713a101 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -669,11 +669,10 @@ static struct kvm_vm *create_vm(enum vm_guest_mode mode, struct kvm_vcpu **vcpu, uint64_t extra_mem_pages, void *guest_code) { struct kvm_vm *vm; - uint64_t extra_pg_pages = extra_mem_pages / 512 * 2; pr_info("Testing guest mode: %s\n", vm_guest_mode_string(mode)); - vm = __vm_create(mode, DEFAULT_GUEST_PHY_PAGES + extra_pg_pages); + vm = __vm_create(mode, 1, extra_mem_pages); log_mode_create_vm_done(vm); *vcpu = vm_vcpu_add(vm, 0, guest_code); diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c index 2401577e3652..f5d59b9934f1 100644 --- a/tools/testing/selftests/kvm/hardware_disable_test.c +++ b/tools/testing/selftests/kvm/hardware_disable_test.c @@ -98,7 +98,7 @@ static void run_test(uint32_t run) for (i = 0; i < VCPU_NUM; i++) CPU_SET(i, &cpu_set); - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(VCPU_NUM); pr_debug("%s: [%d] start vcpus\n", __func__, run); for (i = 0; i < VCPU_NUM; ++i) { diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 6143d45a02a7..db9c00a7af4e 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -547,18 +547,21 @@ vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm); /* * ____vm_create() does KVM_CREATE_VM and little else. __vm_create() also * loads the test binary into guest memory and creates an IRQ chip (x86 only). + * __vm_create() does NOT create vCPUs, @nr_runnable_vcpus is used purely to + * calculate the amount of memory needed for per-vCPU data, e.g. stacks. */ struct kvm_vm *____vm_create(enum vm_guest_mode mode, uint64_t nr_pages); -struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t nr_pages); +struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint32_t nr_runnable_vcpus, + uint64_t nr_extra_pages); static inline struct kvm_vm *vm_create_barebones(void) { return ____vm_create(VM_MODE_DEFAULT, 0); } -static inline struct kvm_vm *vm_create(uint64_t nr_pages) +static inline struct kvm_vm *vm_create(uint32_t nr_runnable_vcpus) { - return __vm_create(VM_MODE_DEFAULT, nr_pages); + return __vm_create(VM_MODE_DEFAULT, nr_runnable_vcpus, 0); } struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus, diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index afefc48757e6..620c35561122 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -258,11 +258,45 @@ struct kvm_vm *____vm_create(enum vm_guest_mode mode, uint64_t nr_pages) return vm; } -struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint64_t nr_pages) +static uint64_t vm_nr_pages_required(enum vm_guest_mode mode, + uint32_t nr_runnable_vcpus, + uint64_t extra_mem_pages) { - struct kvm_vm *vm; + uint64_t nr_pages; - nr_pages = vm_adjust_num_guest_pages(mode, nr_pages); + TEST_ASSERT(nr_runnable_vcpus, + "Use vm_create_barebones() for VMs that _never_ have vCPUs\n"); + + TEST_ASSERT(nr_runnable_vcpus <= kvm_check_cap(KVM_CAP_MAX_VCPUS), + "nr_vcpus = %d too large for host, max-vcpus = %d", + nr_runnable_vcpus, kvm_check_cap(KVM_CAP_MAX_VCPUS)); + + nr_pages = DEFAULT_GUEST_PHY_PAGES; + nr_pages += nr_runnable_vcpus * DEFAULT_STACK_PGS; + + /* + * Account for the number of pages needed for the page tables. The + * maximum page table size for a memory region will be when the + * smallest page size is used. Considering each page contains x page + * table descriptors, the total extra size for page tables (for extra + * N pages) will be: N/x+N/x^2+N/x^3+... which is definitely smaller + * than N/x*2. + */ + nr_pages += (nr_pages + extra_mem_pages) / PTES_PER_MIN_PAGE * 2; + + TEST_ASSERT(nr_runnable_vcpus <= kvm_check_cap(KVM_CAP_MAX_VCPUS), + "Host doesn't support %d vCPUs, max-vcpus = %d", + nr_runnable_vcpus, kvm_check_cap(KVM_CAP_MAX_VCPUS)); + + return vm_adjust_num_guest_pages(mode, nr_pages); +} + +struct kvm_vm *__vm_create(enum vm_guest_mode mode, uint32_t nr_runnable_vcpus, + uint64_t nr_extra_pages) +{ + uint64_t nr_pages = vm_nr_pages_required(mode, nr_runnable_vcpus, + nr_extra_pages); + struct kvm_vm *vm; vm = ____vm_create(mode, nr_pages); @@ -297,27 +331,12 @@ struct kvm_vm *__vm_create_with_vcpus(enum vm_guest_mode mode, uint32_t nr_vcpus uint64_t extra_mem_pages, void *guest_code, struct kvm_vcpu *vcpus[]) { - uint64_t vcpu_pages, extra_pg_pages, pages; struct kvm_vm *vm; int i; TEST_ASSERT(!nr_vcpus || vcpus, "Must provide vCPU array"); - /* The maximum page table size for a memory region will be when the - * smallest pages are used. Considering each page contains x page - * table descriptors, the total extra size for page tables (for extra - * N pages) will be: N/x+N/x^2+N/x^3+... which is definitely smaller - * than N/x*2. - */ - vcpu_pages = nr_vcpus * DEFAULT_STACK_PGS; - extra_pg_pages = (DEFAULT_GUEST_PHY_PAGES + extra_mem_pages + vcpu_pages) / PTES_PER_MIN_PAGE * 2; - pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages; - - TEST_ASSERT(nr_vcpus <= kvm_check_cap(KVM_CAP_MAX_VCPUS), - "nr_vcpus = %d too large for host, max-vcpus = %d", - nr_vcpus, kvm_check_cap(KVM_CAP_MAX_VCPUS)); - - vm = __vm_create(mode, pages); + vm = __vm_create(mode, nr_vcpus, extra_mem_pages); for (i = 0; i < nr_vcpus; ++i) vcpus[i] = vm_vcpu_add(vm, i, guest_code); diff --git a/tools/testing/selftests/kvm/s390x/resets.c b/tools/testing/selftests/kvm/s390x/resets.c index 633ba9055231..e1737411accc 100644 --- a/tools/testing/selftests/kvm/s390x/resets.c +++ b/tools/testing/selftests/kvm/s390x/resets.c @@ -206,7 +206,7 @@ static struct kvm_vm *create_vm(struct kvm_vcpu **vcpu) { struct kvm_vm *vm; - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(1); *vcpu = vm_vcpu_add(vm, ARBITRARY_NON_ZERO_VCPU_ID, guest_code_initial); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index c86b84b68ee3..07fa68a1fdc4 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -365,7 +365,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) if (!(r & KVM_PMU_CAP_DISABLE)) return; - vm = vm_create(DEFAULT_GUEST_PHY_PAGES); + vm = vm_create(1); vm_enable_cap(vm, KVM_CAP_PMU_CAPABILITY, KVM_PMU_CAP_DISABLE); diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index afc063178c6a..8bcaf4421dc5 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -78,13 +78,10 @@ static void run_vcpu(struct kvm_vcpu *vcpu) static struct kvm_vm *create_vm(uint32_t nr_vcpus, uint32_t bsp_vcpu_id, struct kvm_vcpu *vcpus[]) { - uint64_t vcpu_pages = (DEFAULT_STACK_PGS) * nr_vcpus; - uint64_t extra_pg_pages = vcpu_pages / PTES_PER_MIN_PAGE * nr_vcpus; - uint64_t pages = DEFAULT_GUEST_PHY_PAGES + vcpu_pages + extra_pg_pages; struct kvm_vm *vm; uint32_t i; - vm = vm_create(pages); + vm = vm_create(nr_vcpus); vm_ioctl(vm, KVM_SET_BOOT_CPU_ID, (void *)(unsigned long)bsp_vcpu_id); diff --git a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c index e416af887ca0..4a962952212e 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) exit(KSFT_SKIP); } - vm = vm_create(DEFAULT_GUEST_PHY_PAGES + DEFAULT_STACK_PGS * NR_TEST_VCPUS); + vm = vm_create(NR_TEST_VCPUS); vm_ioctl(vm, KVM_SET_TSC_KHZ, (void *) TEST_TSC_KHZ); pthread_spin_init(&create_lock, PTHREAD_PROCESS_PRIVATE); From 38081d28835c84e73ff414f23663d57946cc2234 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 3 May 2022 14:48:59 -0700 Subject: [PATCH 0447/1436] KVM: selftests: Trust that MAXPHYADDR > memslot0 in vmx_apic_access_test Use vm->max_gfn to compute the highest gpa in vmx_apic_access_test, and blindly trust that the highest gfn/gpa will be well above the memory carved out for memslot0. The existing check is beyond paranoid; KVM doesn't support CPUs with host.MAXPHYADDR < 32, and the selftests are all kinds of hosed if memslot0 overlaps the local xAPIC, which resides above "lower" (below 4gb) DRAM. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../testing/selftests/kvm/x86_64/vmx_apic_access_test.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c index ef7514376b1e..ccb05ef7234e 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c @@ -72,8 +72,6 @@ static void l1_guest_code(struct vmx_pages *vmx_pages, unsigned long high_gpa) int main(int argc, char *argv[]) { unsigned long apic_access_addr = ~0ul; - unsigned int paddr_width; - unsigned int vaddr_width; vm_vaddr_t vmx_pages_gva; unsigned long high_gpa; struct vmx_pages *vmx; @@ -86,12 +84,7 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); - kvm_get_cpu_address_width(&paddr_width, &vaddr_width); - high_gpa = (1ul << paddr_width) - getpagesize(); - if ((unsigned long)DEFAULT_GUEST_PHY_PAGES * getpagesize() > high_gpa) { - print_skip("No unbacked physical page available"); - exit(KSFT_SKIP); - } + high_gpa = (vm->max_gfn - 1) << vm->page_shift; vmx = vcpu_alloc_vmx(vm, &vmx_pages_gva); prepare_virtualize_apic_accesses(vmx, vm); From 032604529827cf889e470dc9b3ad18b2a40311b3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 3 May 2022 15:26:02 -0700 Subject: [PATCH 0448/1436] KVM: selftests: Drop DEFAULT_GUEST_PHY_PAGES, open code the magic number Remove DEFAULT_GUEST_PHY_PAGES and open code the magic number (with a comment) in vm_nr_pages_required(). Exposing DEFAULT_GUEST_PHY_PAGES to tests was a symptom of the VM creation APIs not cleanly supporting tests that create runnable vCPUs, but can't do so immediately. Now that tests don't have to manually compute the amount of memory needed for basic operation, make it harder for tests to do things that should be handled by the framework, i.e. force developers to improve the framework instead of hacking around flaws in individual tests. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/include/kvm_util_base.h | 1 - tools/testing/selftests/kvm/lib/kvm_util.c | 8 +++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index db9c00a7af4e..1c762988ab9c 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -100,7 +100,6 @@ memslot2region(struct kvm_vm *vm, uint32_t memslot); #define KVM_UTIL_MIN_VADDR 0x2000 #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 -#define DEFAULT_GUEST_PHY_PAGES 512 #define DEFAULT_GUEST_STACK_VADDR_MIN 0xab6000 #define DEFAULT_STACK_PGS 5 diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 620c35561122..86e7f5afce63 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -271,7 +271,13 @@ static uint64_t vm_nr_pages_required(enum vm_guest_mode mode, "nr_vcpus = %d too large for host, max-vcpus = %d", nr_runnable_vcpus, kvm_check_cap(KVM_CAP_MAX_VCPUS)); - nr_pages = DEFAULT_GUEST_PHY_PAGES; + /* + * Arbitrarily allocate 512 pages (2mb when page size is 4kb) for the + * test code and other per-VM assets that will be loaded into memslot0. + */ + nr_pages = 512; + + /* Account for the per-vCPU stacks on behalf of the test. */ nr_pages += nr_runnable_vcpus * DEFAULT_STACK_PGS; /* From d8ba3f14a50e4bc9745bb8f66a599c6be8ad0cda Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 27 May 2022 15:09:52 -0700 Subject: [PATCH 0449/1436] KVM: selftests: Return an 'unsigned int' from kvm_check_cap() Return an 'unsigned int' instead of a signed 'int' from kvm_check_cap(), to make it more obvious that kvm_check_cap() can never return a negative value due to its assertion that the return is ">= 0". Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/include/kvm_util_base.h | 2 +- tools/testing/selftests/kvm/kvm_binary_stats_test.c | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 1c762988ab9c..72cc0ecda067 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -167,7 +167,7 @@ extern const struct vm_guest_mode_params vm_guest_mode_params[]; int open_path_or_exit(const char *path, int flags); int open_kvm_dev_path_or_exit(void); -int kvm_check_cap(long cap); +unsigned int kvm_check_cap(long cap); #define __KVM_SYSCALL_ERROR(_name, _ret) \ "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno) diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 7f2ddc1535d7..982bf3f7d9c5 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -213,7 +213,7 @@ int main(int argc, char *argv[]) } /* Check the extension for binary stats */ - if (kvm_check_cap(KVM_CAP_BINARY_STATS_FD) <= 0) { + if (!kvm_check_cap(KVM_CAP_BINARY_STATS_FD)) { print_skip("Binary form statistics interface is not supported"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 86e7f5afce63..4cf0e6bf33bb 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -69,7 +69,7 @@ int open_kvm_dev_path_or_exit(void) * Looks up and returns the value corresponding to the capability * (KVM_CAP_*) given by cap. */ -int kvm_check_cap(long cap) +unsigned int kvm_check_cap(long cap) { int ret; int kvm_fd; From 3ea9b809650b4eda5d4ae18ed7bb080e499af154 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 27 May 2022 15:13:03 -0700 Subject: [PATCH 0450/1436] KVM: selftests: Add kvm_has_cap() to provide syntactic sugar Add kvm_has_cap() to wrap kvm_check_cap() and return a bool for the use cases where the caller only wants check if a capability is supported, i.e. doesn't care about the value beyond whether or not it's non-zero. The "check" terminology is somewhat ambiguous as the non-boolean return suggests that '0' might mean "success", i.e. suggests that the ioctl uses the 0/-errno pattern. Provide a wrapper instead of trying to find a new name for the raw helper; the "check" terminology is derived from the name of the ioctl, so using e.g. "get" isn't a clear win. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/get-reg-list.c | 2 +- tools/testing/selftests/kvm/aarch64/vcpu_width_config.c | 2 +- tools/testing/selftests/kvm/dirty_log_test.c | 4 ++-- tools/testing/selftests/kvm/include/kvm_util_base.h | 5 +++++ tools/testing/selftests/kvm/kvm_binary_stats_test.c | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 4 ++-- .../testing/selftests/kvm/lib/s390x/diag318_test_handler.c | 2 +- tools/testing/selftests/kvm/x86_64/debug_regs.c | 2 +- tools/testing/selftests/kvm/x86_64/emulator_error_test.c | 2 +- tools/testing/selftests/kvm/x86_64/evmcs_test.c | 4 ++-- tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c | 6 +++--- tools/testing/selftests/kvm/x86_64/kvm_pv_test.c | 2 +- tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c | 2 +- tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c | 4 ++-- .../testing/selftests/kvm/x86_64/triple_fault_event_test.c | 2 +- tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c | 2 +- .../selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c | 2 +- .../selftests/kvm/x86_64/vmx_preemption_timer_test.c | 2 +- .../selftests/kvm/x86_64/vmx_set_nested_state_test.c | 2 +- 19 files changed, 29 insertions(+), 24 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index f0f83ffda344..8bc10b9acbbc 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -395,7 +395,7 @@ static void check_supported(struct vcpu_config *c) struct reg_sublist *s; for_each_sublist(c, s) { - if (s->capability && !kvm_check_cap(s->capability)) { + if (s->capability && !kvm_has_cap(s->capability)) { fprintf(stderr, "%s: %s not available, skipping tests\n", config_name(c), s->name); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c index dd5a1c4b49e0..fff02c442610 100644 --- a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c +++ b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c @@ -82,7 +82,7 @@ int main(void) struct kvm_vm *vm; int ret; - if (!kvm_check_cap(KVM_CAP_ARM_EL1_32BIT)) { + if (!kvm_has_cap(KVM_CAP_ARM_EL1_32BIT)) { print_skip("KVM_CAP_ARM_EL1_32BIT is not supported"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c index 8542f713a101..9c883c94d478 100644 --- a/tools/testing/selftests/kvm/dirty_log_test.c +++ b/tools/testing/selftests/kvm/dirty_log_test.c @@ -210,7 +210,7 @@ static void sem_wait_until(sem_t *sem) static bool clear_log_supported(void) { - return kvm_check_cap(KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2); + return kvm_has_cap(KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2); } static void clear_log_create_vm_done(struct kvm_vm *vm) @@ -264,7 +264,7 @@ static void default_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err) static bool dirty_ring_supported(void) { - return kvm_check_cap(KVM_CAP_DIRTY_LOG_RING); + return kvm_has_cap(KVM_CAP_DIRTY_LOG_RING); } static void dirty_ring_create_vm_done(struct kvm_vm *vm) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 72cc0ecda067..04ddab322b6b 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -169,6 +169,11 @@ int open_path_or_exit(const char *path, int flags); int open_kvm_dev_path_or_exit(void); unsigned int kvm_check_cap(long cap); +static inline bool kvm_has_cap(long cap) +{ + return kvm_check_cap(cap); +} + #define __KVM_SYSCALL_ERROR(_name, _ret) \ "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno) diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 982bf3f7d9c5..8754b78ae785 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -213,7 +213,7 @@ int main(int argc, char *argv[]) } /* Check the extension for binary stats */ - if (!kvm_check_cap(KVM_CAP_BINARY_STATS_FD)) { + if (!kvm_has_cap(KVM_CAP_BINARY_STATS_FD)) { print_skip("Binary form statistics interface is not supported"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 4cf0e6bf33bb..f93b0d9334e5 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -80,7 +80,7 @@ unsigned int kvm_check_cap(long cap) close(kvm_fd); - return ret; + return (unsigned int)ret; } void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size) @@ -93,7 +93,7 @@ static void vm_open(struct kvm_vm *vm) { vm->kvm_fd = _open_kvm_dev_path_or_exit(O_RDWR); - if (!kvm_check_cap(KVM_CAP_IMMEDIATE_EXIT)) { + if (!kvm_has_cap(KVM_CAP_IMMEDIATE_EXIT)) { print_skip("immediate_exit not available"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c b/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c index 05283f8c9948..cdb7daeed5fd 100644 --- a/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c +++ b/tools/testing/selftests/kvm/lib/s390x/diag318_test_handler.c @@ -61,7 +61,7 @@ uint64_t get_diag318_info(void) * If KVM does not support diag318, then return 0 to * ensure tests do not break. */ - if (!kvm_check_cap(KVM_CAP_S390_DIAG318)) { + if (!kvm_has_cap(KVM_CAP_S390_DIAG318)) { if (!printed_skip) { fprintf(stdout, "KVM_CAP_S390_DIAG318 not supported. " "Skipping diag318 test.\n"); diff --git a/tools/testing/selftests/kvm/x86_64/debug_regs.c b/tools/testing/selftests/kvm/x86_64/debug_regs.c index c16799b616e0..bba811edef96 100644 --- a/tools/testing/selftests/kvm/x86_64/debug_regs.c +++ b/tools/testing/selftests/kvm/x86_64/debug_regs.c @@ -95,7 +95,7 @@ int main(void) 1, /* cli */ }; - if (!kvm_check_cap(KVM_CAP_SET_GUEST_DEBUG)) { + if (!kvm_has_cap(KVM_CAP_SET_GUEST_DEBUG)) { print_skip("KVM_CAP_SET_GUEST_DEBUG not supported"); return 0; } diff --git a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c index fb2a2390b4af..119bcb1158d5 100644 --- a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c +++ b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c @@ -162,7 +162,7 @@ int main(int argc, char *argv[]) /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - if (!kvm_check_cap(KVM_CAP_SMALLER_MAXPHYADDR)) { + if (!kvm_has_cap(KVM_CAP_SMALLER_MAXPHYADDR)) { printf("module parameter 'allow_smaller_maxphyaddr' is not set. Skipping test.\n"); return 0; } diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c index 6c4e728d2d85..a6da1ccbee4e 100644 --- a/tools/testing/selftests/kvm/x86_64/evmcs_test.c +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c @@ -209,8 +209,8 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); if (!nested_vmx_supported() || - !kvm_check_cap(KVM_CAP_NESTED_STATE) || - !kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { + !kvm_has_cap(KVM_CAP_NESTED_STATE) || + !kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { print_skip("Enlightened VMCS is unsupported"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c index 6df5a6356181..e2fac752d354 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c @@ -137,7 +137,7 @@ int main(int argc, char *argv[]) /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - if (!kvm_check_cap(KVM_CAP_HYPERV_CPUID)) { + if (!kvm_has_cap(KVM_CAP_HYPERV_CPUID)) { print_skip("KVM_CAP_HYPERV_CPUID not supported"); exit(KSFT_SKIP); } @@ -152,7 +152,7 @@ int main(int argc, char *argv[]) free(hv_cpuid_entries); if (!nested_vmx_supported() || - !kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { + !kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { print_skip("Enlightened VMCS is unsupported"); goto do_sys; } @@ -163,7 +163,7 @@ int main(int argc, char *argv[]) do_sys: /* Test system ioctl version */ - if (!kvm_check_cap(KVM_CAP_SYS_HYPERV_CPUID)) { + if (!kvm_has_cap(KVM_CAP_SYS_HYPERV_CPUID)) { print_skip("KVM_CAP_SYS_HYPERV_CPUID not supported"); goto out; } diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index f497d6ecec25..24dad3a47206 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -204,7 +204,7 @@ int main(void) struct kvm_vcpu *vcpu; struct kvm_vm *vm; - if (!kvm_check_cap(KVM_CAP_ENFORCE_PV_FEATURE_CPUID)) { + if (!kvm_has_cap(KVM_CAP_ENFORCE_PV_FEATURE_CPUID)) { print_skip("KVM_CAP_ENFORCE_PV_FEATURE_CPUID not supported"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index 8bcaf4421dc5..abf740f08d68 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -123,7 +123,7 @@ static void check_set_bsp_busy(void) int main(int argc, char *argv[]) { - if (!kvm_check_cap(KVM_CAP_SET_BOOT_CPU_ID)) { + if (!kvm_has_cap(KVM_CAP_SET_BOOT_CPU_ID)) { print_skip("set_boot_cpu_id not available"); return 0; } diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index ec418b823273..ffd8613987ae 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -400,8 +400,8 @@ int main(int argc, char *argv[]) { struct kvm_cpuid_entry2 *cpuid; - if (!kvm_check_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM) && - !kvm_check_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) { + if (!kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM) && + !kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) { print_skip("Capabilities not available"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c index 01d491f849c2..078bd7a0bbb1 100644 --- a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c +++ b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c @@ -51,7 +51,7 @@ int main(void) exit(KSFT_SKIP); } - if (!kvm_check_cap(KVM_CAP_X86_TRIPLE_FAULT_EVENT)) { + if (!kvm_has_cap(KVM_CAP_X86_TRIPLE_FAULT_EVENT)) { print_skip("KVM_CAP_X86_TRIPLE_FAULT_EVENT not supported"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c index 4a962952212e..fcc713ff75ff 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c @@ -93,7 +93,7 @@ static void *run_vcpu(void *_cpu_nr) int main(int argc, char *argv[]) { - if (!kvm_check_cap(KVM_CAP_VM_TSC_CONTROL)) { + if (!kvm_has_cap(KVM_CAP_VM_TSC_CONTROL)) { print_skip("KVM_CAP_VM_TSC_CONTROL not available"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c index 647a4320d3bc..190af8124677 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c @@ -118,7 +118,7 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) static void tsc_scaling_check_supported(void) { - if (!kvm_check_cap(KVM_CAP_TSC_CONTROL)) { + if (!kvm_has_cap(KVM_CAP_TSC_CONTROL)) { print_skip("TSC scaling not supported by the HW"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c index b775a11ec08b..7438258511da 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c @@ -169,7 +169,7 @@ int main(int argc, char *argv[]) */ nested_vmx_check_supported(); - if (!kvm_check_cap(KVM_CAP_NESTED_STATE)) { + if (!kvm_has_cap(KVM_CAP_NESTED_STATE)) { print_skip("KVM_CAP_NESTED_STATE not supported"); exit(KSFT_SKIP); } diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c index ba783ceb007f..21f280a7c5e1 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c @@ -267,7 +267,7 @@ int main(int argc, char *argv[]) have_evmcs = kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS); - if (!kvm_check_cap(KVM_CAP_NESTED_STATE)) { + if (!kvm_has_cap(KVM_CAP_NESTED_STATE)) { print_skip("KVM_CAP_NESTED_STATE not available"); exit(KSFT_SKIP); } From 7ed397d107d461a53e350e5025d68ec3c4a8934d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 27 May 2022 16:24:02 -0700 Subject: [PATCH 0451/1436] KVM: selftests: Add TEST_REQUIRE macros to reduce skipping copy+paste Add TEST_REQUIRE() and __TEST_REQUIRE() to replace the myriad open coded instances of selftests exiting with KSFT_SKIP after printing an informational message. In addition to reducing the amount of boilerplate code in selftests, the UPPERCASE macro names make it easier to visually identify a test's requirements. Convert usage that erroneously uses something other than print_skip() and/or "exits" with '0' or some other non-KSFT_SKIP value. Intentionally drop a kvm_vm_free() in aarch64/debug-exceptions.c as part of the conversion. All memory and file descriptors are freed on process exit, so the explicit free is superfluous. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/aarch64/arch_timer.c | 11 +++----- .../selftests/kvm/aarch64/debug-exceptions.c | 7 ++---- .../selftests/kvm/aarch64/get-reg-list.c | 10 +++++--- .../testing/selftests/kvm/aarch64/psci_test.c | 5 +--- .../selftests/kvm/aarch64/vcpu_width_config.c | 5 +--- .../testing/selftests/kvm/aarch64/vgic_init.c | 10 +++----- .../testing/selftests/kvm/aarch64/vgic_irq.c | 5 +--- .../selftests/kvm/access_tracking_perf_test.c | 11 +++----- .../testing/selftests/kvm/include/test_util.h | 9 +++++++ .../selftests/kvm/kvm_binary_stats_test.c | 5 +--- .../selftests/kvm/kvm_create_max_vcpus.c | 6 ++--- tools/testing/selftests/kvm/lib/kvm_util.c | 10 ++------ .../selftests/kvm/lib/x86_64/processor.c | 8 +++--- tools/testing/selftests/kvm/lib/x86_64/svm.c | 5 +--- tools/testing/selftests/kvm/lib/x86_64/vmx.c | 5 +--- tools/testing/selftests/kvm/rseq_test.c | 13 ++++------ tools/testing/selftests/kvm/s390x/memop.c | 11 +++----- .../selftests/kvm/s390x/sync_regs_test.c | 5 ++-- tools/testing/selftests/kvm/steal_time.c | 5 +--- .../kvm/system_counter_offset_test.c | 8 +++--- tools/testing/selftests/kvm/x86_64/amx_test.c | 23 ++++++----------- .../kvm/x86_64/cr4_cpuid_sync_test.c | 5 +--- .../testing/selftests/kvm/x86_64/debug_regs.c | 5 +--- .../kvm/x86_64/emulator_error_test.c | 5 +--- .../testing/selftests/kvm/x86_64/evmcs_test.c | 9 +++---- .../selftests/kvm/x86_64/fix_hypercall_test.c | 5 +--- .../kvm/x86_64/get_msr_index_features.c | 5 +--- .../selftests/kvm/x86_64/hyperv_cpuid.c | 5 +--- .../selftests/kvm/x86_64/hyperv_svm_test.c | 6 ++--- .../selftests/kvm/x86_64/kvm_clock_test.c | 6 +---- .../selftests/kvm/x86_64/kvm_pv_test.c | 5 +--- .../selftests/kvm/x86_64/mmio_warning_test.c | 10 ++------ .../selftests/kvm/x86_64/mmu_role_test.c | 10 ++------ .../selftests/kvm/x86_64/platform_info_test.c | 7 +----- .../kvm/x86_64/pmu_event_filter_test.c | 25 ++++--------------- .../selftests/kvm/x86_64/set_boot_cpu_id.c | 5 +--- .../selftests/kvm/x86_64/sev_migrate_tests.c | 19 +++++--------- .../selftests/kvm/x86_64/sync_regs_test.c | 10 ++------ .../kvm/x86_64/triple_fault_event_test.c | 10 ++------ .../selftests/kvm/x86_64/tsc_scaling_sync.c | 5 +--- .../vmx_exception_with_invalid_guest_state.c | 6 ++--- .../kvm/x86_64/vmx_nested_tsc_scaling_test.c | 10 +------- .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 23 ++++++----------- .../kvm/x86_64/vmx_preemption_timer_test.c | 5 +--- .../kvm/x86_64/vmx_set_nested_state_test.c | 5 +--- .../selftests/kvm/x86_64/xen_shinfo_test.c | 5 +--- .../selftests/kvm/x86_64/xen_vmcall_test.c | 8 +++--- .../selftests/kvm/x86_64/xss_msr_test.c | 13 +++------- 48 files changed, 119 insertions(+), 290 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index ca4c08b4e353..f68019be67c0 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -375,10 +375,7 @@ static struct kvm_vm *test_vm_create(void) ucall_init(vm, NULL); test_init_timer_irq(vm); gic_fd = vgic_v3_setup(vm, nr_vcpus, 64, GICD_BASE_GPA, GICR_BASE_GPA); - if (gic_fd < 0) { - print_skip("Failed to create vgic-v3"); - exit(KSFT_SKIP); - } + __TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3"); /* Make all the test's cmdline args visible to the guest */ sync_global_to_guest(vm, test_args); @@ -468,10 +465,8 @@ int main(int argc, char *argv[]) if (!parse_args(argc, argv)) exit(KSFT_SKIP); - if (test_args.migration_freq_ms && get_nprocs() < 2) { - print_skip("At least two physical CPUs needed for vCPU migration"); - exit(KSFT_SKIP); - } + __TEST_REQUIRE(!test_args.migration_freq_ms || get_nprocs() >= 2, + "At least two physical CPUs needed for vCPU migration"); vm = test_vm_create(); test_run(vm); diff --git a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c index c27352b90ccf..b8072b40ccc8 100644 --- a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c +++ b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c @@ -259,11 +259,8 @@ int main(int argc, char *argv[]) vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); - if (debug_version(vcpu) < 6) { - print_skip("Armv8 debug architecture not supported."); - kvm_vm_free(vm); - exit(KSFT_SKIP); - } + __TEST_REQUIRE(debug_version(vcpu) >= 6, + "Armv8 debug architecture not supported."); vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT, ESR_EC_BRK_INS, guest_sw_bp_handler); diff --git a/tools/testing/selftests/kvm/aarch64/get-reg-list.c b/tools/testing/selftests/kvm/aarch64/get-reg-list.c index 8bc10b9acbbc..d287dd2cac0a 100644 --- a/tools/testing/selftests/kvm/aarch64/get-reg-list.c +++ b/tools/testing/selftests/kvm/aarch64/get-reg-list.c @@ -395,10 +395,12 @@ static void check_supported(struct vcpu_config *c) struct reg_sublist *s; for_each_sublist(c, s) { - if (s->capability && !kvm_has_cap(s->capability)) { - fprintf(stderr, "%s: %s not available, skipping tests\n", config_name(c), s->name); - exit(KSFT_SKIP); - } + if (!s->capability) + continue; + + __TEST_REQUIRE(kvm_has_cap(s->capability), + "%s: %s not available, skipping tests\n", + config_name(c), s->name); } } diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index 7928c62635fd..a889e1cf5e4d 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -192,10 +192,7 @@ static void host_test_system_suspend(void) int main(void) { - if (!kvm_check_cap(KVM_CAP_ARM_SYSTEM_SUSPEND)) { - print_skip("KVM_CAP_ARM_SYSTEM_SUSPEND not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_check_cap(KVM_CAP_ARM_SYSTEM_SUSPEND)); host_test_cpu_on(); host_test_system_suspend(); diff --git a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c index fff02c442610..80b74c6f152b 100644 --- a/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c +++ b/tools/testing/selftests/kvm/aarch64/vcpu_width_config.c @@ -82,10 +82,7 @@ int main(void) struct kvm_vm *vm; int ret; - if (!kvm_has_cap(KVM_CAP_ARM_EL1_32BIT)) { - print_skip("KVM_CAP_ARM_EL1_32BIT is not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_EL1_32BIT)); /* Get the preferred target type and copy that to init1 for later use */ vm = vm_create_barebones(); diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 02402802b163..e8cab9840aa3 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -703,13 +703,9 @@ int main(int ac, char **av) } ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V2); - if (!ret) { - pr_info("Running GIC_v2 tests.\n"); - run_tests(KVM_DEV_TYPE_ARM_VGIC_V2); - return 0; - } + __TEST_REQUIRE(!ret, "No GICv2 nor GICv3 support"); - print_skip("No GICv2 nor GICv3 support"); - exit(KSFT_SKIP); + pr_info("Running GIC_v2 tests.\n"); + run_tests(KVM_DEV_TYPE_ARM_VGIC_V2); return 0; } diff --git a/tools/testing/selftests/kvm/aarch64/vgic_irq.c b/tools/testing/selftests/kvm/aarch64/vgic_irq.c index 90dbba61d72a..046ba4fde648 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_irq.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_irq.c @@ -768,10 +768,7 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) gic_fd = vgic_v3_setup(vm, 1, nr_irqs, GICD_BASE_GPA, GICR_BASE_GPA); - if (gic_fd < 0) { - print_skip("Failed to create vgic-v3, skipping"); - exit(KSFT_SKIP); - } + __TEST_REQUIRE(gic_fd >= 0, "Failed to create vgic-v3, skipping"); vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT, guest_irq_handlers[args.eoi_split][args.level_sensitive]); diff --git a/tools/testing/selftests/kvm/access_tracking_perf_test.c b/tools/testing/selftests/kvm/access_tracking_perf_test.c index 1c771378f7f4..1c2749b1481a 100644 --- a/tools/testing/selftests/kvm/access_tracking_perf_test.c +++ b/tools/testing/selftests/kvm/access_tracking_perf_test.c @@ -104,10 +104,7 @@ static uint64_t lookup_pfn(int pagemap_fd, struct kvm_vm *vm, uint64_t gva) return 0; pfn = entry & PAGEMAP_PFN_MASK; - if (!pfn) { - print_skip("Looking up PFNs requires CAP_SYS_ADMIN"); - exit(KSFT_SKIP); - } + __TEST_REQUIRE(pfn, "Looking up PFNs requires CAP_SYS_ADMIN"); return pfn; } @@ -380,10 +377,8 @@ int main(int argc, char *argv[]) } page_idle_fd = open("/sys/kernel/mm/page_idle/bitmap", O_RDWR); - if (page_idle_fd < 0) { - print_skip("CONFIG_IDLE_PAGE_TRACKING is not enabled"); - exit(KSFT_SKIP); - } + __TEST_REQUIRE(page_idle_fd >= 0, + "CONFIG_IDLE_PAGE_TRACKING is not enabled"); close(page_idle_fd); for_each_guest_mode(run_test, ¶ms); diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index 99e0dcdc923f..493b2a799a61 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -34,6 +34,15 @@ static inline int _no_printf(const char *format, ...) { return 0; } #endif void print_skip(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +#define __TEST_REQUIRE(f, fmt, ...) \ +do { \ + if (!(f)) { \ + print_skip(fmt, ##__VA_ARGS__); \ + exit(KSFT_SKIP); \ + } \ +} while (0) + +#define TEST_REQUIRE(f) __TEST_REQUIRE(f, "Requirement not met: %s", #f) ssize_t test_write(int fd, const void *buf, size_t count); ssize_t test_read(int fd, void *buf, size_t count); diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 8754b78ae785..1baabf955d63 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -213,10 +213,7 @@ int main(int argc, char *argv[]) } /* Check the extension for binary stats */ - if (!kvm_has_cap(KVM_CAP_BINARY_STATS_FD)) { - print_skip("Binary form statistics interface is not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_BINARY_STATS_FD)); /* Create VMs and VCPUs */ vms = malloc(sizeof(vms[0]) * max_vm); diff --git a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c index 3ae0237e96b2..31b3cb24b9a7 100644 --- a/tools/testing/selftests/kvm/kvm_create_max_vcpus.c +++ b/tools/testing/selftests/kvm/kvm_create_max_vcpus.c @@ -64,11 +64,9 @@ int main(int argc, char *argv[]) rl.rlim_max = nr_fds_wanted; int r = setrlimit(RLIMIT_NOFILE, &rl); - if (r < 0) { - printf("RLIMIT_NOFILE hard limit is too low (%d, wanted %d)\n", + __TEST_REQUIRE(r >= 0, + "RLIMIT_NOFILE hard limit is too low (%d, wanted %d)\n", old_rlim_max, nr_fds_wanted); - exit(KSFT_SKIP); - } } else { TEST_ASSERT(!setrlimit(RLIMIT_NOFILE, &rl), "setrlimit() failed!"); } diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index f93b0d9334e5..cca89d9a83ea 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -26,10 +26,7 @@ int open_path_or_exit(const char *path, int flags) int fd; fd = open(path, flags); - if (fd < 0) { - print_skip("%s not available (errno: %d)", path, errno); - exit(KSFT_SKIP); - } + __TEST_REQUIRE(fd >= 0, "%s not available (errno: %d)", path, errno); return fd; } @@ -93,10 +90,7 @@ static void vm_open(struct kvm_vm *vm) { vm->kvm_fd = _open_kvm_dev_path_or_exit(O_RDWR); - if (!kvm_has_cap(KVM_CAP_IMMEDIATE_EXIT)) { - print_skip("immediate_exit not available"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_IMMEDIATE_EXIT)); vm->fd = __kvm_ioctl(vm->kvm_fd, KVM_CREATE_VM, vm->type); TEST_ASSERT(vm->fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, vm->fd)); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index a54910adea98..4a7de11d6f37 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -609,14 +609,14 @@ void vm_xsave_req_perm(int bit) kvm_fd = open_kvm_dev_path_or_exit(); rc = __kvm_ioctl(kvm_fd, KVM_GET_DEVICE_ATTR, &attr); close(kvm_fd); + if (rc == -1 && (errno == ENXIO || errno == EINVAL)) exit(KSFT_SKIP); TEST_ASSERT(rc == 0, "KVM_GET_DEVICE_ATTR(0, KVM_X86_XCOMP_GUEST_SUPP) error: %ld", rc); - if (!(bitmask & (1ULL << bit))) - exit(KSFT_SKIP); - if (!is_xfd_supported()) - exit(KSFT_SKIP); + TEST_REQUIRE(bitmask & (1ULL << bit)); + + TEST_REQUIRE(is_xfd_supported()); rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, bit); diff --git a/tools/testing/selftests/kvm/lib/x86_64/svm.c b/tools/testing/selftests/kvm/lib/x86_64/svm.c index 01a9d831da13..37e9c0a923e0 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/svm.c +++ b/tools/testing/selftests/kvm/lib/x86_64/svm.c @@ -174,10 +174,7 @@ bool nested_svm_supported(void) void nested_svm_check_supported(void) { - if (!nested_svm_supported()) { - print_skip("nested SVM not enabled"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(nested_svm_supported()); } /* diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c index 2cbfe9962fb1..381432741df4 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c @@ -391,10 +391,7 @@ bool nested_vmx_supported(void) void nested_vmx_check_supported(void) { - if (!nested_vmx_supported()) { - print_skip("nested VMX not enabled"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(nested_vmx_supported()); } static void nested_create_pte(struct kvm_vm *vm, diff --git a/tools/testing/selftests/kvm/rseq_test.c b/tools/testing/selftests/kvm/rseq_test.c index 68c0c8bb206e..aba7be178dab 100644 --- a/tools/testing/selftests/kvm/rseq_test.c +++ b/tools/testing/selftests/kvm/rseq_test.c @@ -171,12 +171,11 @@ static void *migration_worker(void *ign) return NULL; } -static int calc_min_max_cpu(void) +static void calc_min_max_cpu(void) { int i, cnt, nproc; - if (CPU_COUNT(&possible_mask) < 2) - return -EINVAL; + TEST_REQUIRE(CPU_COUNT(&possible_mask) >= 2); /* * CPU_SET doesn't provide a FOR_EACH helper, get the min/max CPU that @@ -198,7 +197,8 @@ static int calc_min_max_cpu(void) cnt++; } - return (cnt < 2) ? -EINVAL : 0; + __TEST_REQUIRE(cnt >= 2, + "Only one usable CPU, task migration not possible"); } int main(int argc, char *argv[]) @@ -215,10 +215,7 @@ int main(int argc, char *argv[]) TEST_ASSERT(!r, "sched_getaffinity failed, errno = %d (%s)", errno, strerror(errno)); - if (calc_min_max_cpu()) { - print_skip("Only one usable CPU, task migration not possible"); - exit(KSFT_SKIP); - } + calc_min_max_cpu(); sys_rseq(0); diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c index 22b0bb785591..a8f9b74b9144 100644 --- a/tools/testing/selftests/kvm/s390x/memop.c +++ b/tools/testing/selftests/kvm/s390x/memop.c @@ -756,20 +756,17 @@ struct testdef { int main(int argc, char *argv[]) { - int memop_cap, extension_cap, idx; + int extension_cap, idx; + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_S390_MEM_OP)); setbuf(stdout, NULL); /* Tell stdout not to buffer its content */ ksft_print_header(); - memop_cap = kvm_check_cap(KVM_CAP_S390_MEM_OP); - extension_cap = kvm_check_cap(KVM_CAP_S390_MEM_OP_EXTENSION); - if (!memop_cap) { - ksft_exit_skip("CAP_S390_MEM_OP not supported.\n"); - } - ksft_set_plan(ARRAY_SIZE(testlist)); + extension_cap = kvm_check_cap(KVM_CAP_S390_MEM_OP_EXTENSION); for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) { if (testlist[idx].extension >= extension_cap) { testlist[idx].test(); diff --git a/tools/testing/selftests/kvm/s390x/sync_regs_test.c b/tools/testing/selftests/kvm/s390x/sync_regs_test.c index 4b2eb5edde5e..b69710822c47 100644 --- a/tools/testing/selftests/kvm/s390x/sync_regs_test.c +++ b/tools/testing/selftests/kvm/s390x/sync_regs_test.c @@ -229,14 +229,13 @@ int main(int argc, char *argv[]) struct kvm_vm *vm; int idx; + TEST_REQUIRE(kvm_check_cap(KVM_CAP_SYNC_REGS)); + /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); ksft_print_header(); - if (!kvm_check_cap(KVM_CAP_SYNC_REGS)) - ksft_exit_skip("CAP_SYNC_REGS not supported"); - ksft_set_plan(ARRAY_SIZE(testlist)); /* Create VM */ diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index 398819d4074f..d122f1e05cdd 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -271,10 +271,7 @@ int main(int ac, char **av) virt_map(vm, ST_GPA_BASE, ST_GPA_BASE, gpages); ucall_init(vm, NULL); - if (!is_steal_time_supported(vcpus[0])) { - print_skip("steal-time not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(is_steal_time_supported(vcpus[0])); /* Run test on each VCPU */ for (i = 0; i < NR_VCPUS; ++i) { diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c b/tools/testing/selftests/kvm/system_counter_offset_test.c index 7c8be0930737..862a8e93e070 100644 --- a/tools/testing/selftests/kvm/system_counter_offset_test.c +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c @@ -28,11 +28,9 @@ static struct test_case test_cases[] = { static void check_preconditions(struct kvm_vcpu *vcpu) { - if (!__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL, KVM_VCPU_TSC_OFFSET)) - return; - - print_skip("KVM_VCPU_TSC_OFFSET not supported; skipping test"); - exit(KSFT_SKIP); + __TEST_REQUIRE(!__vcpu_has_device_attr(vcpu, KVM_VCPU_TSC_CTRL, + KVM_VCPU_TSC_OFFSET), + "KVM_VCPU_TSC_OFFSET not supported; skipping test"); } static void setup_system_counter(struct kvm_vcpu *vcpu, struct test_case *test) diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index b421c8369dba..dab4ca16a2df 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -317,7 +317,6 @@ int main(int argc, char *argv[]) { struct kvm_cpuid_entry2 *entry; struct kvm_regs regs1, regs2; - bool amx_supported = false; struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; @@ -334,21 +333,15 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); entry = kvm_get_supported_cpuid_entry(1); - if (!(entry->ecx & X86_FEATURE_XSAVE)) { - print_skip("XSAVE feature not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(entry->ecx & X86_FEATURE_XSAVE); - if (kvm_get_cpuid_max_basic() >= 0xd) { - entry = kvm_get_supported_cpuid_index(0xd, 0); - amx_supported = entry && !!(entry->eax & XFEATURE_MASK_XTILE); - if (!amx_supported) { - print_skip("AMX is not supported by the vCPU (eax=0x%x)", entry->eax); - exit(KSFT_SKIP); - } - /* Get xsave/restore max size */ - xsave_restore_size = entry->ecx; - } + TEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xd); + + entry = kvm_get_supported_cpuid_index(0xd, 0); + TEST_REQUIRE(entry->eax & XFEATURE_MASK_XTILE); + + /* Get xsave/restore max size */ + xsave_restore_size = entry->ecx; run = vcpu->run; vcpu_regs_get(vcpu, ®s1); diff --git a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c index 1635aae970e9..a80940ac420f 100644 --- a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c +++ b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c @@ -70,10 +70,7 @@ int main(int argc, char *argv[]) struct ucall uc; entry = kvm_get_supported_cpuid_entry(1); - if (!(entry->ecx & X86_FEATURE_XSAVE)) { - print_skip("XSAVE feature not supported"); - return 0; - } + TEST_REQUIRE(entry->ecx & X86_FEATURE_XSAVE); /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); diff --git a/tools/testing/selftests/kvm/x86_64/debug_regs.c b/tools/testing/selftests/kvm/x86_64/debug_regs.c index bba811edef96..7ef99c3359a0 100644 --- a/tools/testing/selftests/kvm/x86_64/debug_regs.c +++ b/tools/testing/selftests/kvm/x86_64/debug_regs.c @@ -95,10 +95,7 @@ int main(void) 1, /* cli */ }; - if (!kvm_has_cap(KVM_CAP_SET_GUEST_DEBUG)) { - print_skip("KVM_CAP_SET_GUEST_DEBUG not supported"); - return 0; - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_SET_GUEST_DEBUG)); vm = vm_create_with_one_vcpu(&vcpu, guest_code); run = vcpu->run; diff --git a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c index 119bcb1158d5..bfff2d271c48 100644 --- a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c +++ b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c @@ -162,10 +162,7 @@ int main(int argc, char *argv[]) /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - if (!kvm_has_cap(KVM_CAP_SMALLER_MAXPHYADDR)) { - printf("module parameter 'allow_smaller_maxphyaddr' is not set. Skipping test.\n"); - return 0; - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_SMALLER_MAXPHYADDR)); vm = vm_create_with_one_vcpu(&vcpu, guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c index a6da1ccbee4e..8dda527cc080 100644 --- a/tools/testing/selftests/kvm/x86_64/evmcs_test.c +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c @@ -208,12 +208,9 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); - if (!nested_vmx_supported() || - !kvm_has_cap(KVM_CAP_NESTED_STATE) || - !kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { - print_skip("Enlightened VMCS is unsupported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(nested_vmx_supported()); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE)); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)); vcpu_set_hv_cpuid(vcpu); vcpu_enable_evmcs(vcpu); diff --git a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c index 137759547720..f6f251ce59e1 100644 --- a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c @@ -156,10 +156,7 @@ static void test_fix_hypercall_disabled(void) int main(void) { - if (!(kvm_check_cap(KVM_CAP_DISABLE_QUIRKS2) & KVM_X86_QUIRK_FIX_HYPERCALL_INSN)) { - print_skip("KVM_X86_QUIRK_HYPERCALL_INSN not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_check_cap(KVM_CAP_DISABLE_QUIRKS2) & KVM_X86_QUIRK_FIX_HYPERCALL_INSN); test_fix_hypercall(); test_fix_hypercall_disabled(); diff --git a/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c b/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c index 1e366fdfe7be..d09b3cbcadc6 100644 --- a/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c +++ b/tools/testing/selftests/kvm/x86_64/get_msr_index_features.c @@ -25,10 +25,7 @@ int main(int argc, char *argv[]) * will cover the "regular" list of MSRs, the coverage here is purely * opportunistic and not interesting on its own. */ - if (!kvm_check_cap(KVM_CAP_GET_MSR_FEATURES)) { - print_skip("KVM_CAP_GET_MSR_FEATURES not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_GET_MSR_FEATURES)); (void)kvm_get_msr_index_list(); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c index e2fac752d354..cbd4a7d36189 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c @@ -137,10 +137,7 @@ int main(int argc, char *argv[]) /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - if (!kvm_has_cap(KVM_CAP_HYPERV_CPUID)) { - print_skip("KVM_CAP_HYPERV_CPUID not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_CPUID)); vm = vm_create_with_one_vcpu(&vcpu, guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c index 171009184c3b..c5cd9835dbd6 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c @@ -127,10 +127,8 @@ int main(int argc, char *argv[]) struct ucall uc; int stage; - if (!nested_svm_supported()) { - print_skip("Nested SVM not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(nested_svm_supported()); + /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, guest_code); vcpu_set_hv_cpuid(vcpu); diff --git a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c index 6e3c4bd60b76..138455575a11 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c @@ -181,11 +181,7 @@ int main(void) int flags; flags = kvm_check_cap(KVM_CAP_ADJUST_CLOCK); - if (!(flags & KVM_CLOCK_REALTIME)) { - print_skip("KVM_CLOCK_REALTIME not supported; flags: %x", - flags); - exit(KSFT_SKIP); - } + TEST_REQUIRE(flags & KVM_CLOCK_REALTIME); check_clocksource(); diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index 24dad3a47206..5901ccec7079 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -204,10 +204,7 @@ int main(void) struct kvm_vcpu *vcpu; struct kvm_vm *vm; - if (!kvm_has_cap(KVM_CAP_ENFORCE_PV_FEATURE_CPUID)) { - print_skip("KVM_CAP_ENFORCE_PV_FEATURE_CPUID not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_ENFORCE_PV_FEATURE_CPUID)); vm = vm_create_with_one_vcpu(&vcpu, guest_main); diff --git a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c index 31ae837fedb1..0e4590afd0e1 100644 --- a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c +++ b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c @@ -93,15 +93,9 @@ int main(void) { int warnings_before, warnings_after; - if (!is_intel_cpu()) { - print_skip("Must be run on an Intel CPU"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(is_intel_cpu()); - if (vm_is_unrestricted_guest(NULL)) { - print_skip("Unrestricted guest must be disabled"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(!vm_is_unrestricted_guest(NULL)); warnings_before = get_warnings_count(); diff --git a/tools/testing/selftests/kvm/x86_64/mmu_role_test.c b/tools/testing/selftests/kvm/x86_64/mmu_role_test.c index 1404dfda2e9f..383fff2c9587 100644 --- a/tools/testing/selftests/kvm/x86_64/mmu_role_test.c +++ b/tools/testing/selftests/kvm/x86_64/mmu_role_test.c @@ -117,16 +117,10 @@ int main(int argc, char *argv[]) } } - if (!do_gbpages && !do_maxphyaddr) { - print_skip("No sub-tests selected"); - return 0; - } + __TEST_REQUIRE(do_gbpages || do_maxphyaddr, "No sub-tests selected"); entry = kvm_get_supported_cpuid_entry(0x80000001); - if (!(entry->edx & CPUID_GBPAGES)) { - print_skip("1gb hugepages not supported"); - return 0; - } + TEST_REQUIRE(entry->edx & CPUID_GBPAGES); if (do_gbpages) { pr_info("Test MMIO after toggling CPUID.GBPAGES\n\n"); diff --git a/tools/testing/selftests/kvm/x86_64/platform_info_test.c b/tools/testing/selftests/kvm/x86_64/platform_info_test.c index 3cb48e4b615b..76417c7d687b 100644 --- a/tools/testing/selftests/kvm/x86_64/platform_info_test.c +++ b/tools/testing/selftests/kvm/x86_64/platform_info_test.c @@ -70,17 +70,12 @@ int main(int argc, char *argv[]) { struct kvm_vcpu *vcpu; struct kvm_vm *vm; - int rv; uint64_t msr_platform_info; /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - rv = kvm_check_cap(KVM_CAP_MSR_PLATFORM_INFO); - if (!rv) { - print_skip("KVM_CAP_MSR_PLATFORM_INFO not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_MSR_PLATFORM_INFO)); vm = vm_create_with_one_vcpu(&vcpu, guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 07fa68a1fdc4..656fb2227a81 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -443,39 +443,24 @@ static bool use_amd_pmu(void) int main(int argc, char *argv[]) { - void (*guest_code)(void) = NULL; + void (*guest_code)(void); struct kvm_vcpu *vcpu; struct kvm_vm *vm; - int r; /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - r = kvm_check_cap(KVM_CAP_PMU_EVENT_FILTER); - if (!r) { - print_skip("KVM_CAP_PMU_EVENT_FILTER not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_check_cap(KVM_CAP_PMU_EVENT_FILTER)); - if (use_intel_pmu()) - guest_code = intel_guest_code; - else if (use_amd_pmu()) - guest_code = amd_guest_code; - - if (!guest_code) { - print_skip("Don't know how to test this guest PMU"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(use_intel_pmu() || use_amd_pmu()); + guest_code = use_intel_pmu() ? intel_guest_code : amd_guest_code; vm = vm_create_with_one_vcpu(&vcpu, guest_code); vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); - if (!sanity_check_pmu(vcpu)) { - print_skip("Guest PMU is not functional"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(sanity_check_pmu(vcpu)); if (use_amd_pmu()) test_amd_deny_list(vcpu); diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index abf740f08d68..7ef713fdd0a5 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -123,10 +123,7 @@ static void check_set_bsp_busy(void) int main(int argc, char *argv[]) { - if (!kvm_has_cap(KVM_CAP_SET_BOOT_CPU_ID)) { - print_skip("set_boot_cpu_id not available"); - return 0; - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_SET_BOOT_CPU_ID)); run_vm_bsp(0); run_vm_bsp(1); diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index ffd8613987ae..76ba6fc80e37 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -400,22 +400,15 @@ int main(int argc, char *argv[]) { struct kvm_cpuid_entry2 *cpuid; - if (!kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM) && - !kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) { - print_skip("Capabilities not available"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM)); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)); cpuid = kvm_get_supported_cpuid_entry(0x80000000); - if (cpuid->eax < 0x8000001f) { - print_skip("AMD memory encryption not available"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(cpuid->eax >= 0x8000001f); + cpuid = kvm_get_supported_cpuid_entry(0x8000001f); - if (!(cpuid->eax & X86_FEATURE_SEV)) { - print_skip("AMD SEV not available"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(cpuid->eax & X86_FEATURE_SEV); + have_sev_es = !!(cpuid->eax & X86_FEATURE_SEV_ES); if (kvm_check_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM)) { diff --git a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c index 773db9d4f228..9b6db0b0b13e 100644 --- a/tools/testing/selftests/kvm/x86_64/sync_regs_test.c +++ b/tools/testing/selftests/kvm/x86_64/sync_regs_test.c @@ -94,14 +94,8 @@ int main(int argc, char *argv[]) setbuf(stdout, NULL); cap = kvm_check_cap(KVM_CAP_SYNC_REGS); - if ((cap & TEST_SYNC_FIELDS) != TEST_SYNC_FIELDS) { - print_skip("KVM_CAP_SYNC_REGS not supported"); - exit(KSFT_SKIP); - } - if ((cap & INVALID_SYNC_FIELD) != 0) { - print_skip("The \"invalid\" field is not invalid"); - exit(KSFT_SKIP); - } + TEST_REQUIRE((cap & TEST_SYNC_FIELDS) == TEST_SYNC_FIELDS); + TEST_REQUIRE(!(cap & INVALID_SYNC_FIELD)); vm = vm_create_with_one_vcpu(&vcpu, guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c index 078bd7a0bbb1..5a202ecb8ea0 100644 --- a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c +++ b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c @@ -46,15 +46,9 @@ int main(void) vm_vaddr_t vmx_pages_gva; struct ucall uc; - if (!nested_vmx_supported()) { - print_skip("Nested VMX not supported"); - exit(KSFT_SKIP); - } + nested_vmx_check_supported(); - if (!kvm_has_cap(KVM_CAP_X86_TRIPLE_FAULT_EVENT)) { - print_skip("KVM_CAP_X86_TRIPLE_FAULT_EVENT not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_X86_TRIPLE_FAULT_EVENT)); vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); vm_enable_cap(vm, KVM_CAP_X86_TRIPLE_FAULT_EVENT, 1); diff --git a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c index fcc713ff75ff..47139aab7408 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_scaling_sync.c @@ -93,10 +93,7 @@ static void *run_vcpu(void *_cpu_nr) int main(int argc, char *argv[]) { - if (!kvm_has_cap(KVM_CAP_VM_TSC_CONTROL)) { - print_skip("KVM_CAP_VM_TSC_CONTROL not available"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_TSC_CONTROL)); vm = vm_create(NR_TEST_VCPUS); vm_ioctl(vm, KVM_SET_TSC_KHZ, (void *) TEST_TSC_KHZ); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c index 5bc2cee0d613..2641b286b4ed 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_exception_with_invalid_guest_state.c @@ -111,10 +111,8 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu; struct kvm_vm *vm; - if (!is_intel_cpu() || vm_is_unrestricted_guest(NULL)) { - print_skip("Must be run with kvm_intel.unrestricted_guest=0"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(is_intel_cpu()); + TEST_REQUIRE(!vm_is_unrestricted_guest(NULL)); vm = vm_create_with_one_vcpu(&vcpu, guest_code); get_set_sigalrm_vcpu(vcpu); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c index 190af8124677..ff4644038c55 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c @@ -116,14 +116,6 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_DONE(); } -static void tsc_scaling_check_supported(void) -{ - if (!kvm_has_cap(KVM_CAP_TSC_CONTROL)) { - print_skip("TSC scaling not supported by the HW"); - exit(KSFT_SKIP); - } -} - static void stable_tsc_check_supported(void) { FILE *fp; @@ -159,7 +151,7 @@ int main(int argc, char *argv[]) uint64_t l2_tsc_freq = 0; nested_vmx_check_supported(); - tsc_scaling_check_supported(); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL)); stable_tsc_check_supported(); /* diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c index a308442458b8..eb592fae44ef 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c @@ -57,7 +57,6 @@ int main(int argc, char *argv[]) struct kvm_cpuid2 *cpuid; struct kvm_cpuid_entry2 *entry_1_0; struct kvm_cpuid_entry2 *entry_a_0; - bool pdcm_supported = false; struct kvm_vm *vm; struct kvm_vcpu *vcpu; int ret; @@ -71,20 +70,14 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); cpuid = kvm_get_supported_cpuid(); - if (kvm_get_cpuid_max_basic() >= 0xa) { - entry_1_0 = kvm_get_supported_cpuid_index(1, 0); - entry_a_0 = kvm_get_supported_cpuid_index(0xa, 0); - pdcm_supported = entry_1_0 && !!(entry_1_0->ecx & X86_FEATURE_PDCM); - eax.full = entry_a_0->eax; - } - if (!pdcm_supported) { - print_skip("MSR_IA32_PERF_CAPABILITIES is not supported by the vCPU"); - exit(KSFT_SKIP); - } - if (!eax.split.version_id) { - print_skip("PMU is not supported by the vCPU"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xa); + + entry_1_0 = kvm_get_supported_cpuid_index(1, 0); + entry_a_0 = kvm_get_supported_cpuid_index(0xa, 0); + TEST_REQUIRE(entry_1_0->ecx & X86_FEATURE_PDCM); + + eax.full = entry_a_0->eax; + __TEST_REQUIRE(eax.split.version_id, "PMU is not supported by the vCPU"); /* testcase 1, set capabilities when we have PDCM bit */ vcpu_set_cpuid(vcpu, cpuid); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c index 7438258511da..99e57b0cc2c9 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c @@ -169,10 +169,7 @@ int main(int argc, char *argv[]) */ nested_vmx_check_supported(); - if (!kvm_has_cap(KVM_CAP_NESTED_STATE)) { - print_skip("KVM_CAP_NESTED_STATE not supported"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE)); /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c index 21f280a7c5e1..b564b86dfc1d 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c @@ -267,10 +267,7 @@ int main(int argc, char *argv[]) have_evmcs = kvm_check_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS); - if (!kvm_has_cap(KVM_CAP_NESTED_STATE)) { - print_skip("KVM_CAP_NESTED_STATE not available"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE)); /* * AMD currently does not implement set_nested_state, so for now we diff --git a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c index 4340c2f2300f..bdcb28186ccc 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c @@ -362,10 +362,7 @@ int main(int argc, char *argv[]) !strncmp(argv[1], "--verbose", 10)); int xen_caps = kvm_check_cap(KVM_CAP_XEN_HVM); - if (!(xen_caps & KVM_XEN_HVM_CONFIG_SHARED_INFO) ) { - print_skip("KVM_XEN_HVM_CONFIG_SHARED_INFO not available"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(xen_caps & KVM_XEN_HVM_CONFIG_SHARED_INFO); bool do_runstate_tests = !!(xen_caps & KVM_XEN_HVM_CONFIG_RUNSTATE); bool do_eventfd_tests = !!(xen_caps & KVM_XEN_HVM_CONFIG_EVTCHN_2LEVEL); diff --git a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c index a91f11fb26f4..8b76cade9bcd 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c @@ -80,14 +80,12 @@ static void guest_code(void) int main(int argc, char *argv[]) { + unsigned int xen_caps; struct kvm_vcpu *vcpu; struct kvm_vm *vm; - if (!(kvm_check_cap(KVM_CAP_XEN_HVM) & - KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL) ) { - print_skip("KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL not available"); - exit(KSFT_SKIP); - } + xen_caps = kvm_check_cap(KVM_CAP_XEN_HVM); + TEST_REQUIRE(xen_caps & KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL); vm = vm_create_with_one_vcpu(&vcpu, guest_code); vcpu_set_hv_cpuid(vcpu); diff --git a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c index 1e3506c3deed..4e2e08059b95 100644 --- a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c +++ b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c @@ -19,7 +19,6 @@ int main(int argc, char *argv[]) { struct kvm_cpuid_entry2 *entry; - bool xss_supported = false; bool xss_in_msr_list; struct kvm_vm *vm; struct kvm_vcpu *vcpu; @@ -29,14 +28,10 @@ int main(int argc, char *argv[]) /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, NULL); - if (kvm_get_cpuid_max_basic() >= 0xd) { - entry = kvm_get_supported_cpuid_index(0xd, 1); - xss_supported = entry && !!(entry->eax & X86_FEATURE_XSAVES); - } - if (!xss_supported) { - print_skip("IA32_XSS is not supported by the vCPU"); - exit(KSFT_SKIP); - } + TEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xd); + + entry = kvm_get_supported_cpuid_index(0xd, 1); + TEST_REQUIRE(entry->eax & X86_FEATURE_XSAVES); xss_val = vcpu_get_msr(vcpu, MSR_IA32_XSS); TEST_ASSERT(xss_val == 0, From 5321270b2362a85a74c3d52c00c3c6730a228f0c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 9 Jun 2022 17:03:19 -0700 Subject: [PATCH 0452/1436] KVM: selftests: Use TAP-friendly ksft_exit_skip() in __TEST_REQUIRE Use the TAP-friendly ksft_exit_skip() instead of KVM's custom print_skip() when skipping a test via __TEST_REQUIRE. KVM's "skipping test" has no known benefit, whereas some setups rely on TAP output. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/include/test_util.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index 493b2a799a61..5c5a88180b6c 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -34,12 +34,10 @@ static inline int _no_printf(const char *format, ...) { return 0; } #endif void print_skip(const char *fmt, ...) __attribute__((format(printf, 1, 2))); -#define __TEST_REQUIRE(f, fmt, ...) \ -do { \ - if (!(f)) { \ - print_skip(fmt, ##__VA_ARGS__); \ - exit(KSFT_SKIP); \ - } \ +#define __TEST_REQUIRE(f, fmt, ...) \ +do { \ + if (!(f)) \ + ksft_exit_skip("- " fmt "\n", ##__VA_ARGS__); \ } while (0) #define TEST_REQUIRE(f) __TEST_REQUIRE(f, "Requirement not met: %s", #f) From fcba483e82462830dd368951c0df03a95676f34d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 1 Jun 2022 11:01:58 -0700 Subject: [PATCH 0453/1436] KVM: selftests: Sanity check input to ioctls() at build time Add a static assert to the KVM/VM/vCPU ioctl() helpers to verify that the size of the argument provided matches the expected size of the IOCTL. Because ioctl() ultimately takes a "void *", it's all too easy to pass in garbage and not detect the error until runtime. E.g. while working on a CPUID rework, selftests happily compiled when vcpu_set_cpuid() unintentionally passed the cpuid() function as the parameter to ioctl() (a local "cpuid" parameter was removed, but its use was not replaced with "vcpu->cpuid" as intended). Tweak a variety of benign issues that aren't compatible with the sanity check, e.g. passing a non-pointer for ioctls(). Note, static_assert() requires a string on older versions of GCC. Feed it an empty string to make the compiler happy. Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 59 ++++++++++++++----- .../selftests/kvm/lib/aarch64/processor.c | 2 +- tools/testing/selftests/kvm/lib/guest_modes.c | 2 +- tools/testing/selftests/kvm/lib/kvm_util.c | 29 +-------- .../selftests/kvm/lib/x86_64/perf_test_util.c | 6 +- tools/testing/selftests/kvm/s390x/resets.c | 6 +- .../selftests/kvm/x86_64/mmio_warning_test.c | 2 +- .../kvm/x86_64/pmu_event_filter_test.c | 2 +- .../selftests/kvm/x86_64/xen_shinfo_test.c | 6 +- 9 files changed, 58 insertions(+), 56 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 04ddab322b6b..cdaea2383543 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -180,29 +180,56 @@ static inline bool kvm_has_cap(long cap) #define __KVM_IOCTL_ERROR(_name, _ret) __KVM_SYSCALL_ERROR(_name, _ret) #define KVM_IOCTL_ERROR(_ioctl, _ret) __KVM_IOCTL_ERROR(#_ioctl, _ret) -#define __kvm_ioctl(kvm_fd, cmd, arg) \ - ioctl(kvm_fd, cmd, arg) +#define kvm_do_ioctl(fd, cmd, arg) \ +({ \ + static_assert(!_IOC_SIZE(cmd) || sizeof(*arg) == _IOC_SIZE(cmd), ""); \ + ioctl(fd, cmd, arg); \ +}) -static inline void _kvm_ioctl(int kvm_fd, unsigned long cmd, const char *name, - void *arg) -{ - int ret = __kvm_ioctl(kvm_fd, cmd, arg); +#define __kvm_ioctl(kvm_fd, cmd, arg) \ + kvm_do_ioctl(kvm_fd, cmd, arg) - TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); -} + +#define _kvm_ioctl(kvm_fd, cmd, name, arg) \ +({ \ + int ret = __kvm_ioctl(kvm_fd, cmd, arg); \ + \ + TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \ +}) #define kvm_ioctl(kvm_fd, cmd, arg) \ _kvm_ioctl(kvm_fd, cmd, #cmd, arg) -int __vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg); -void _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, const char *name, void *arg); -#define vm_ioctl(vm, cmd, arg) _vm_ioctl(vm, cmd, #cmd, arg) +#define __vm_ioctl(vm, cmd, arg) \ +({ \ + static_assert(sizeof(*(vm)) == sizeof(struct kvm_vm), ""); \ + kvm_do_ioctl((vm)->fd, cmd, arg); \ +}) -int __vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long cmd, - void *arg); -void _vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long cmd, - const char *name, void *arg); -#define vcpu_ioctl(vcpu, cmd, arg) \ +#define _vm_ioctl(vm, cmd, name, arg) \ +({ \ + int ret = __vm_ioctl(vm, cmd, arg); \ + \ + TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \ +}) + +#define vm_ioctl(vm, cmd, arg) \ + _vm_ioctl(vm, cmd, #cmd, arg) + +#define __vcpu_ioctl(vcpu, cmd, arg) \ +({ \ + static_assert(sizeof(*(vcpu)) == sizeof(struct kvm_vcpu), ""); \ + kvm_do_ioctl((vcpu)->fd, cmd, arg); \ +}) + +#define _vcpu_ioctl(vcpu, cmd, name, arg) \ +({ \ + int ret = __vcpu_ioctl(vcpu, cmd, arg); \ + \ + TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \ +}) + +#define vcpu_ioctl(vcpu, cmd, arg) \ _vcpu_ioctl(vcpu, cmd, #cmd, arg) /* diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 6bd27782f00c..6f5551368944 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -472,7 +472,7 @@ void aarch64_get_supported_page_sizes(uint32_t ipa, }; kvm_fd = open_kvm_dev_path_or_exit(); - vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, ipa); + vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, (void *)(unsigned long)ipa); TEST_ASSERT(vm_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, vm_fd)); vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0); diff --git a/tools/testing/selftests/kvm/lib/guest_modes.c b/tools/testing/selftests/kvm/lib/guest_modes.c index 0be56c63aed6..99a575bbbc52 100644 --- a/tools/testing/selftests/kvm/lib/guest_modes.c +++ b/tools/testing/selftests/kvm/lib/guest_modes.c @@ -65,7 +65,7 @@ void guest_modes_append_default(void) struct kvm_s390_vm_cpu_processor info; kvm_fd = open_kvm_dev_path_or_exit(); - vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, 0); + vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, NULL); kvm_device_attr_get(vm_fd, KVM_S390_VM_CPU_MODEL, KVM_S390_VM_CPU_PROCESSOR, &info); close(vm_fd); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index cca89d9a83ea..39f2f5f1338f 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -72,7 +72,7 @@ unsigned int kvm_check_cap(long cap) int kvm_fd; kvm_fd = open_kvm_dev_path_or_exit(); - ret = __kvm_ioctl(kvm_fd, KVM_CHECK_EXTENSION, cap); + ret = __kvm_ioctl(kvm_fd, KVM_CHECK_EXTENSION, (void *)cap); TEST_ASSERT(ret >= 0, KVM_IOCTL_ERROR(KVM_CHECK_EXTENSION, ret)); close(kvm_fd); @@ -92,7 +92,7 @@ static void vm_open(struct kvm_vm *vm) TEST_REQUIRE(kvm_has_cap(KVM_CAP_IMMEDIATE_EXIT)); - vm->fd = __kvm_ioctl(vm->kvm_fd, KVM_CREATE_VM, vm->type); + vm->fd = __kvm_ioctl(vm->kvm_fd, KVM_CREATE_VM, (void *)vm->type); TEST_ASSERT(vm->fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, vm->fd)); } @@ -1450,19 +1450,6 @@ struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vcpu *vcpu) return reg_list; } -int __vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long cmd, void *arg) -{ - return ioctl(vcpu->fd, cmd, arg); -} - -void _vcpu_ioctl(struct kvm_vcpu *vcpu, unsigned long cmd, const char *name, - void *arg) -{ - int ret = __vcpu_ioctl(vcpu, cmd, arg); - - TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); -} - void *vcpu_map_dirty_ring(struct kvm_vcpu *vcpu) { uint32_t page_size = vcpu->vm->page_size; @@ -1492,18 +1479,6 @@ void *vcpu_map_dirty_ring(struct kvm_vcpu *vcpu) return vcpu->dirty_gfns; } -int __vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) -{ - return ioctl(vm->fd, cmd, arg); -} - -void _vm_ioctl(struct kvm_vm *vm, unsigned long cmd, const char *name, void *arg) -{ - int ret = __vm_ioctl(vm, cmd, arg); - - TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); -} - /* * Device Ioctl */ diff --git a/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c b/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c index 446820a549ba..bfe85c8c2f6e 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c @@ -103,9 +103,9 @@ void perf_test_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vc * Override the vCPU to run perf_test_l1_guest_code() which will * bounce it into L2 before calling perf_test_guest_code(). */ - vcpu_regs_get(vm, vcpus[vcpu_id]->id, ®s); + vcpu_regs_get(vcpus[vcpu_id], ®s); regs.rip = (unsigned long) perf_test_l1_guest_code; - vcpu_regs_set(vm, vcpus[vcpu_id]->id, ®s); - vcpu_args_set(vm, vcpus[vcpu_id]->id, 2, vmx_gva, vcpu_id); + vcpu_regs_set(vcpus[vcpu_id], ®s); + vcpu_args_set(vcpus[vcpu_id], 2, vmx_gva, vcpu_id); } } diff --git a/tools/testing/selftests/kvm/s390x/resets.c b/tools/testing/selftests/kvm/s390x/resets.c index e1737411accc..19486084eb30 100644 --- a/tools/testing/selftests/kvm/s390x/resets.c +++ b/tools/testing/selftests/kvm/s390x/resets.c @@ -225,7 +225,7 @@ static void test_normal(void) inject_irq(vcpu); - vcpu_ioctl(vcpu, KVM_S390_NORMAL_RESET, 0); + vcpu_ioctl(vcpu, KVM_S390_NORMAL_RESET, NULL); /* must clears */ assert_normal(vcpu); @@ -248,7 +248,7 @@ static void test_initial(void) inject_irq(vcpu); - vcpu_ioctl(vcpu, KVM_S390_INITIAL_RESET, 0); + vcpu_ioctl(vcpu, KVM_S390_INITIAL_RESET, NULL); /* must clears */ assert_normal(vcpu); @@ -271,7 +271,7 @@ static void test_clear(void) inject_irq(vcpu); - vcpu_ioctl(vcpu, KVM_S390_CLEAR_RESET, 0); + vcpu_ioctl(vcpu, KVM_S390_CLEAR_RESET, NULL); /* must clears */ assert_normal(vcpu); diff --git a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c index 0e4590afd0e1..fb02581953a3 100644 --- a/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c +++ b/tools/testing/selftests/kvm/x86_64/mmio_warning_test.c @@ -59,7 +59,7 @@ void test(void) kvm = open("/dev/kvm", O_RDWR); TEST_ASSERT(kvm != -1, "failed to open /dev/kvm"); - kvmvm = __kvm_ioctl(kvm, KVM_CREATE_VM, 0); + kvmvm = __kvm_ioctl(kvm, KVM_CREATE_VM, NULL); TEST_ASSERT(kvmvm > 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, kvmvm)); kvmcpu = ioctl(kvmvm, KVM_CREATE_VCPU, 0); TEST_ASSERT(kvmcpu != -1, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, kvmcpu)); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 656fb2227a81..786b3a794f84 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -276,7 +276,7 @@ static void test_without_filter(struct kvm_vcpu *vcpu) static uint64_t test_with_filter(struct kvm_vcpu *vcpu, struct kvm_pmu_event_filter *f) { - vm_ioctl(vcpu->vm, KVM_SET_PMU_EVENT_FILTER, (void *)f); + vm_ioctl(vcpu->vm, KVM_SET_PMU_EVENT_FILTER, f); return run_vcpu_to_sync(vcpu); } diff --git a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c index bdcb28186ccc..a4a78637c35a 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c @@ -472,7 +472,7 @@ int main(int argc, char *argv[]) irq_routes.entries[1].u.xen_evtchn.vcpu = vcpu->id; irq_routes.entries[1].u.xen_evtchn.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL; - vm_ioctl(vm, KVM_SET_GSI_ROUTING, &irq_routes); + vm_ioctl(vm, KVM_SET_GSI_ROUTING, &irq_routes.info); struct kvm_irqfd ifd = { }; @@ -716,7 +716,7 @@ int main(int argc, char *argv[]) if (verbose) printf("Testing restored oneshot timer\n"); - tmr.u.timer.expires_ns = rs->state_entry_time + 100000000, + tmr.u.timer.expires_ns = rs->state_entry_time + 100000000; vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); evtchn_irq_expected = true; alarm(1); @@ -743,7 +743,7 @@ int main(int argc, char *argv[]) if (verbose) printf("Testing SCHEDOP_poll wake on masked event\n"); - tmr.u.timer.expires_ns = rs->state_entry_time + 100000000, + tmr.u.timer.expires_ns = rs->state_entry_time + 100000000; vcpu_ioctl(vcpu, KVM_XEN_VCPU_SET_ATTR, &tmr); alarm(1); break; From f061f43d7418cb62b8d073e221ec75d3f5b89e17 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Tue, 7 Jun 2022 13:45:22 +0200 Subject: [PATCH 0454/1436] usb: hub: port: add sysfs entry to switch port power In some cases the port of an hub needs to be disabled or switched off and on again. E.g. when the connected device needs to be re-enumerated. Or it needs to be explicitly disabled while the rest of the usb tree stays working. For this purpose this patch adds an sysfs switch to enable/disable the port on any hub. In the case the hub is supporting power switching, the power line will be disabled to the connected device. When the port gets disabled, the associated device gets disconnected and removed from the logical usb tree. No further device will be enumerated on that port until the port gets enabled again. Reviewed-by: Alan Stern Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20220607114522.3359148-1-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-usb | 11 ++++ drivers/usb/core/hub.c | 39 ++++++------ drivers/usb/core/hub.h | 3 + drivers/usb/core/port.c | 83 +++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 19 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb index 7efe31ed3a25..568103d3376e 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb +++ b/Documentation/ABI/testing/sysfs-bus-usb @@ -253,6 +253,17 @@ Description: only if the system firmware is capable of describing the connection between a port and its connector. +What: /sys/bus/usb/devices/...//port/disable +Date: June 2022 +Contact: Michael Grzeschik +Description: + This file controls the state of a USB port, including + Vbus power output (but only on hubs that support + power switching -- most hubs don't support it). If + a port is disabled, the port is unusable: Devices + attached to the port will not be detected, initialized, + or enumerated. + What: /sys/bus/usb/devices/.../power/usb2_lpm_l1_timeout Date: May 2013 Contact: Mathias Nyman diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 68e9121c1878..ba406b8d688d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -613,7 +613,7 @@ static int hub_ext_port_status(struct usb_hub *hub, int port1, int type, return ret; } -static int hub_port_status(struct usb_hub *hub, int port1, +int usb_hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change) { return hub_ext_port_status(hub, port1, HUB_PORT_STATUS, @@ -1126,7 +1126,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) u16 portstatus, portchange; portstatus = portchange = 0; - status = hub_port_status(hub, port1, &portstatus, &portchange); + status = usb_hub_port_status(hub, port1, &portstatus, &portchange); if (status) goto abort; @@ -2855,7 +2855,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1, &portstatus, &portchange, &ext_portstatus); else - ret = hub_port_status(hub, port1, &portstatus, + ret = usb_hub_port_status(hub, port1, &portstatus, &portchange); if (ret < 0) return ret; @@ -2956,7 +2956,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1, * If the caller hasn't explicitly requested a warm reset, * double check and see if one is needed. */ - if (hub_port_status(hub, port1, &portstatus, &portchange) == 0) + if (usb_hub_port_status(hub, port1, &portstatus, + &portchange) == 0) if (hub_port_warm_reset_required(hub, port1, portstatus)) warm = true; @@ -3008,7 +3009,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1, * If a USB 3.0 device migrates from reset to an error * state, re-issue the warm reset. */ - if (hub_port_status(hub, port1, + if (usb_hub_port_status(hub, port1, &portstatus, &portchange) < 0) goto done; @@ -3074,7 +3075,7 @@ done: } /* Check if a port is power on */ -static int port_is_power_on(struct usb_hub *hub, unsigned portstatus) +int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus) { int ret = 0; @@ -3140,13 +3141,13 @@ static int check_port_resume_type(struct usb_device *udev, } /* Is the device still present? */ else if (status || port_is_suspended(hub, portstatus) || - !port_is_power_on(hub, portstatus)) { + !usb_port_is_power_on(hub, portstatus)) { if (status >= 0) status = -ENODEV; } else if (!(portstatus & USB_PORT_STAT_CONNECTION)) { if (retries--) { usleep_range(200, 300); - status = hub_port_status(hub, port1, &portstatus, + status = usb_hub_port_status(hub, port1, &portstatus, &portchange); goto retry; } @@ -3409,7 +3410,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) u16 portstatus, portchange; portstatus = portchange = 0; - ret = hub_port_status(hub, port1, &portstatus, + ret = usb_hub_port_status(hub, port1, &portstatus, &portchange); dev_dbg(&port_dev->dev, @@ -3587,13 +3588,13 @@ static int wait_for_connected(struct usb_device *udev, while (delay_ms < 2000) { if (status || *portstatus & USB_PORT_STAT_CONNECTION) break; - if (!port_is_power_on(hub, *portstatus)) { + if (!usb_port_is_power_on(hub, *portstatus)) { status = -ENODEV; break; } msleep(20); delay_ms += 20; - status = hub_port_status(hub, port1, portstatus, portchange); + status = usb_hub_port_status(hub, port1, portstatus, portchange); } dev_dbg(&udev->dev, "Waited %dms for CONNECT\n", delay_ms); return status; @@ -3653,7 +3654,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) usb_lock_port(port_dev); /* Skip the initial Clear-Suspend step for a remote wakeup */ - status = hub_port_status(hub, port1, &portstatus, &portchange); + status = usb_hub_port_status(hub, port1, &portstatus, &portchange); if (status == 0 && !port_is_suspended(hub, portstatus)) { if (portchange & USB_PORT_STAT_C_SUSPEND) pm_wakeup_event(&udev->dev, 0); @@ -3678,7 +3679,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) * stop resume signaling. Then finish the resume * sequence. */ - status = hub_port_status(hub, port1, &portstatus, &portchange); + status = usb_hub_port_status(hub, port1, &portstatus, &portchange); } SuspendCleared: @@ -3791,7 +3792,7 @@ static int check_ports_changed(struct usb_hub *hub) u16 portstatus, portchange; int status; - status = hub_port_status(hub, port1, &portstatus, &portchange); + status = usb_hub_port_status(hub, port1, &portstatus, &portchange); if (!status && portchange) return 1; } @@ -4554,7 +4555,7 @@ int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected) struct usb_port *port_dev = hub->ports[port1 - 1]; for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { - ret = hub_port_status(hub, port1, &portstatus, &portchange); + ret = usb_hub_port_status(hub, port1, &portstatus, &portchange); if (ret < 0) return ret; @@ -5240,7 +5241,7 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, * but only if the port isn't owned by someone else. */ if (hub_is_port_power_switchable(hub) - && !port_is_power_on(hub, portstatus) + && !usb_port_is_power_on(hub, portstatus) && !port_dev->port_owner) set_port_feature(hdev, port1, USB_PORT_FEAT_POWER); @@ -5557,7 +5558,7 @@ static void port_event(struct usb_hub *hub, int port1) clear_bit(port1, hub->event_bits); clear_bit(port1, hub->wakeup_bits); - if (hub_port_status(hub, port1, &portstatus, &portchange) < 0) + if (usb_hub_port_status(hub, port1, &portstatus, &portchange) < 0) return; if (portchange & USB_PORT_STAT_C_CONNECTION) { @@ -5594,7 +5595,7 @@ static void port_event(struct usb_hub *hub, int port1) USB_PORT_FEAT_C_OVER_CURRENT); msleep(100); /* Cool down */ hub_power_on(hub, true); - hub_port_status(hub, port1, &status, &unused); + usb_hub_port_status(hub, port1, &status, &unused); if (status & USB_PORT_STAT_OVERCURRENT) dev_err(&port_dev->dev, "over-current condition\n"); } @@ -5638,7 +5639,7 @@ static void port_event(struct usb_hub *hub, int port1) u16 unused; msleep(20); - hub_port_status(hub, port1, &portstatus, &unused); + usb_hub_port_status(hub, port1, &portstatus, &unused); dev_dbg(&port_dev->dev, "Wait for inactive link disconnect detect\n"); continue; } else if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 22ea1f4f2d66..3fcb38099ce3 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -121,6 +121,9 @@ extern int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected); extern int usb_clear_port_feature(struct usb_device *hdev, int port1, int feature); +extern int usb_hub_port_status(struct usb_hub *hub, int port1, + u16 *status, u16 *change); +extern int usb_port_is_power_on(struct usb_hub *hub, unsigned int portstatus); static inline bool hub_is_port_power_switchable(struct usb_hub *hub) { diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index d5bc36ca5b1f..38c1a4f4fdea 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -17,6 +17,88 @@ static int usb_port_block_power_off; static const struct attribute_group *port_dev_group[]; +static ssize_t disable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_port *port_dev = to_usb_port(dev); + struct usb_device *hdev = to_usb_device(dev->parent->parent); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + struct usb_interface *intf = to_usb_interface(hub->intfdev); + int port1 = port_dev->portnum; + u16 portstatus, unused; + bool disabled; + int rc; + + rc = usb_autopm_get_interface(intf); + if (rc < 0) + return rc; + + usb_lock_device(hdev); + if (hub->disconnected) { + rc = -ENODEV; + goto out_hdev_lock; + } + + usb_hub_port_status(hub, port1, &portstatus, &unused); + disabled = !usb_port_is_power_on(hub, portstatus); + +out_hdev_lock: + usb_unlock_device(hdev); + usb_autopm_put_interface(intf); + + if (rc) + return rc; + + return sysfs_emit(buf, "%s\n", disabled ? "1" : "0"); +} + +static ssize_t disable_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct usb_port *port_dev = to_usb_port(dev); + struct usb_device *hdev = to_usb_device(dev->parent->parent); + struct usb_hub *hub = usb_hub_to_struct_hub(hdev); + struct usb_interface *intf = to_usb_interface(hub->intfdev); + int port1 = port_dev->portnum; + bool disabled; + int rc; + + rc = strtobool(buf, &disabled); + if (rc) + return rc; + + rc = usb_autopm_get_interface(intf); + if (rc < 0) + return rc; + + usb_lock_device(hdev); + if (hub->disconnected) { + rc = -ENODEV; + goto out_hdev_lock; + } + + if (disabled && port_dev->child) + usb_disconnect(&port_dev->child); + + rc = usb_hub_set_port_power(hdev, hub, port1, !disabled); + + if (disabled) { + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); + if (!port_dev->is_superspeed) + usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); + } + + if (!rc) + rc = count; + +out_hdev_lock: + usb_unlock_device(hdev); + usb_autopm_put_interface(intf); + + return rc; +} +static DEVICE_ATTR_RW(disable); + static ssize_t location_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -153,6 +235,7 @@ static struct attribute *port_dev_attrs[] = { &dev_attr_location.attr, &dev_attr_quirks.attr, &dev_attr_over_current_count.attr, + &dev_attr_disable.attr, NULL, }; From 662a60102c122e44fdaf5c826f7f415eb57d48ad Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 2 May 2022 16:20:56 +0300 Subject: [PATCH 0455/1436] usb: typec: Separate USB Power Delivery from USB Type-C Introducing a small device class for USB Power Delivery. The idea with it is that we do not mix any more USB Power Delivery information into the USB Type-C connectors only. This separation will make it possible to register USB Power Delivery devices also from other places, for example from USB Type-C Bridges (see USB Type-C Bridge Specification). The device class will not always deal with only the messages and objects that were negotiated with the partner, but instead messages and objects that can be used in the negotiation. That allows the USB PD devices to be shared and reconfigured. The ports can decide which objects are to be advertised to the partner before the contract is negotiated. It is also possible to allow the user space to make that decision if needed. Signed-off-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220502132058.86236-2-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- .../testing/sysfs-class-usb_power_delivery | 240 ++++++ drivers/usb/typec/Makefile | 2 +- drivers/usb/typec/pd.c | 708 ++++++++++++++++++ drivers/usb/typec/pd.h | 30 + include/linux/usb/pd.h | 38 + include/linux/usb/typec.h | 10 + 6 files changed, 1027 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-class-usb_power_delivery create mode 100644 drivers/usb/typec/pd.c create mode 100644 drivers/usb/typec/pd.h diff --git a/Documentation/ABI/testing/sysfs-class-usb_power_delivery b/Documentation/ABI/testing/sysfs-class-usb_power_delivery new file mode 100644 index 000000000000..ce2b1b563cb3 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-usb_power_delivery @@ -0,0 +1,240 @@ +What: /sys/class/usb_power_delivery +Date: May 2022 +Contact: Heikki Krogerus +Description: + Directory for USB Power Delivery devices. + +What: /sys/class/usb_power_delivery/.../revision +Date: May 2022 +Contact: Heikki Krogerus +Description: + File showing the USB Power Delivery Specification Revision used + in communication. + +What: /sys/class/usb_power_delivery/.../version +Date: May 2022 +Contact: Heikki Krogerus +Description: + This is an optional attribute file showing the version of the + specific revision of the USB Power Delivery Specification. In + most cases the specification version is not known and the file + is not available. + +What: /sys/class/usb_power_delivery/.../source-capabilities +Date: May 2022 +Contact: Heikki Krogerus +Description: + The source capabilities message "Source_Capabilities" contains a + set of Power Data Objects (PDO), each representing a type of + power supply. The order of the PDO objects is defined in the USB + Power Delivery Specification. Each PDO - power supply - will + have its own device, and the PDO device name will start with the + object position number as the first character followed by the + power supply type name (":" as delimiter). + + /sys/class/usb_power_delivery/.../source_capabilities/: + +What: /sys/class/usb_power_delivery/.../sink-capabilities +Date: May 2022 +Contact: Heikki Krogerus +Description: + The sink capability message "Sink_Capabilities" contains a set + of Power Data Objects (PDO) just like with source capabilities, + but instead of describing the power capabilities, these objects + describe the power requirements. + + The order of the objects in the sink capability message is the + same as with the source capabilities message. + +Fixed Supplies + +What: /sys/class/usb_power_delivery/...//:fixed_supply +Date: May 2022 +Contact: Heikki Krogerus +Description: + Devices containing the attributes (the bit fields) defined for + Fixed Supplies. + + The device "1:fixed_supply" is special. USB Power Delivery + Specification dictates that the first PDO (at object position + 1), and the only mandatory PDO, is always the vSafe5V Fixed + Supply Object. vSafe5V Object has additional fields defined for + it that the other Fixed Supply Objects do not have and that are + related to the USB capabilities rather than power capabilities. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/dual_role_power +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file contains boolean value that tells does the device + support both source and sink power roles. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/usb_suspend_supported +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file shows the value of the USB Suspend Supported bit in + vSafe5V Fixed Supply Object. If the bit is set then the device + will follow the USB 2.0 and USB 3.2 rules for suspend and + resume. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/unconstrained_power +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file shows the value of the Unconstrained Power bit in + vSafe5V Fixed Supply Object. The bit is set when an external + source of power, powerful enough to power the entire system on + its own, is available for the device. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/usb_communication_capable +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file shows the value of the USB Communication Capable bit in + vSafe5V Fixed Supply Object. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/dual_role_data +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file shows the value of the Dual-Role Data bit in vSafe5V + Fixed Supply Object. Dual role data means ability act as both + USB host and USB device. + +What: /sys/class/usb_power_delivery/...//1:fixed_supply/unchunked_extended_messages_supported +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file shows the value of the Unchunked Extended Messages + Supported bit in vSafe5V Fixed Supply Object. + +What: /sys/class/usb_power_delivery/...//:fixed_supply/voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + The voltage the supply supports in millivolts. + +What: /sys/class/usb_power_delivery/.../source-capabilities/:fixed_supply/maximum_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum current of the fixed source supply in milliamperes. + +What: /sys/class/usb_power_delivery/.../sink-capabilities/:fixed_supply/operational_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + Operational current of the sink in milliamperes. + +What: /sys/class/usb_power_delivery/.../sink-capabilities/:fixed_supply/fast_role_swap_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + This file contains the value of the "Fast Role Swap USB Type-C + Current" field that tells the current level the sink requires + after a Fast Role Swap. + 0 - Fast Swap not supported" + 1 - Default USB Power" + 2 - 1.5A@5V" + 3 - 3.0A@5V" + +Variable Supplies + +What: /sys/class/usb_power_delivery/...//:variable_supply +Date: May 2022 +Contact: Heikki Krogerus +Description: + Variable Power Supply PDO. + +What: /sys/class/usb_power_delivery/...//:variable_supply/maximum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/...//:variable_supply/minimum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Minimum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/.../source-capabilities/:variable_supply/maximum_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + The maximum current in milliamperes that the source can supply + at the given Voltage range. + +What: /sys/class/usb_power_delivery/.../sink-capabilities/:variable_supply/operational_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + The operational current in milliamperes that the sink requires + at the given Voltage range. + +Battery Supplies + +What: /sys/class/usb_power_delivery/...//:battery +Date: May 2022 +Contact: Heikki Krogerus +Description: + Battery PDO. + +What: /sys/class/usb_power_delivery/...//:battery/maximum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/...//:battery/minimum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Minimum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/.../source-capabilities/:battery/maximum_power +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum allowable Power in milliwatts. + +What: /sys/class/usb_power_delivery/.../sink-capabilities/:battery/operational_power +Date: May 2022 +Contact: Heikki Krogerus +Description: + The operational power that the sink requires at the given + voltage range. + +Standard Power Range (SPR) Programmable Power Supplies + +What: /sys/class/usb_power_delivery/...//:programmable_supply +Date: May 2022 +Contact: Heikki Krogerus +Description: + Programmable Power Supply (PPS) Augmented PDO (APDO). + +What: /sys/class/usb_power_delivery/...//:programmable_supply/maximum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/...//:programmable_supply/minimum_voltage +Date: May 2022 +Contact: Heikki Krogerus +Description: + Minimum Voltage in millivolts. + +What: /sys/class/usb_power_delivery/...//:programmable_supply/maximum_current +Date: May 2022 +Contact: Heikki Krogerus +Description: + Maximum Current in milliamperes. + +What: /sys/class/usb_power_delivery/.../source-capabilities/:programmable_supply/pps_power_limited +Date: May 2022 +Contact: Heikki Krogerus +Description: + The PPS Power Limited bit indicates whether or not the source + supply will exceed the rated output power if requested. diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile index 43626acc0aaf..2f174cd3e5df 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_TYPEC) += typec.o -typec-y := class.o mux.o bus.o +typec-y := class.o mux.o bus.o pd.o typec-$(CONFIG_ACPI) += port-mapper.o obj-$(CONFIG_TYPEC) += altmodes/ obj-$(CONFIG_TYPEC_TCPM) += tcpm/ diff --git a/drivers/usb/typec/pd.c b/drivers/usb/typec/pd.c new file mode 100644 index 000000000000..dc72005d68db --- /dev/null +++ b/drivers/usb/typec/pd.c @@ -0,0 +1,708 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * USB Power Delivery sysfs entries + * + * Copyright (C) 2022, Intel Corporation + * Author: Heikki Krogerus + */ + +#include +#include + +#include "pd.h" + +static DEFINE_IDA(pd_ida); + +static struct class pd_class = { + .name = "usb_power_delivery", + .owner = THIS_MODULE, +}; + +#define to_pdo(o) container_of(o, struct pdo, dev) + +struct pdo { + struct device dev; + int object_position; + u32 pdo; +}; + +static void pdo_release(struct device *dev) +{ + kfree(to_pdo(dev)); +} + +/* -------------------------------------------------------------------------- */ +/* Fixed Supply */ + +static ssize_t +dual_role_power_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DUAL_ROLE)); +} +static DEVICE_ATTR_RO(dual_role_power); + +static ssize_t +usb_suspend_supported_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_SUSPEND)); +} +static DEVICE_ATTR_RO(usb_suspend_supported); + +static ssize_t +unconstrained_power_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_EXTPOWER)); +} +static DEVICE_ATTR_RO(unconstrained_power); + +static ssize_t +usb_communication_capable_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_USB_COMM)); +} +static DEVICE_ATTR_RO(usb_communication_capable); + +static ssize_t +dual_role_data_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_DATA_SWAP)); +} +static DEVICE_ATTR_RO(dual_role_data); + +static ssize_t +unchunked_extended_messages_supported_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & PDO_FIXED_UNCHUNK_EXT)); +} +static DEVICE_ATTR_RO(unchunked_extended_messages_supported); + +/* + * REVISIT: Peak Current requires access also to the RDO. +static ssize_t +peak_current_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ... +} +*/ + +static ssize_t +fast_role_swap_current_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3; +} +static DEVICE_ATTR_RO(fast_role_swap_current); + +static ssize_t voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umV\n", pdo_fixed_voltage(to_pdo(dev)->pdo)); +} +static DEVICE_ATTR_RO(voltage); + +/* Shared with Variable supplies, both source and sink */ +static ssize_t current_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umA\n", pdo_max_current(to_pdo(dev)->pdo)); +} + +/* Shared with Variable type supplies */ +static struct device_attribute maximum_current_attr = { + .attr = { + .name = "maximum_current", + .mode = 0444, + }, + .show = current_show, +}; + +static struct device_attribute operational_current_attr = { + .attr = { + .name = "operational_current", + .mode = 0444, + }, + .show = current_show, +}; + +static struct attribute *source_fixed_supply_attrs[] = { + &dev_attr_dual_role_power.attr, + &dev_attr_usb_suspend_supported.attr, + &dev_attr_unconstrained_power.attr, + &dev_attr_usb_communication_capable.attr, + &dev_attr_dual_role_data.attr, + &dev_attr_unchunked_extended_messages_supported.attr, + /*&dev_attr_peak_current.attr,*/ + &dev_attr_voltage.attr, + &maximum_current_attr.attr, + NULL +}; + +static umode_t fixed_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) +{ + if (to_pdo(kobj_to_dev(kobj))->object_position && + /*attr != &dev_attr_peak_current.attr &&*/ + attr != &dev_attr_voltage.attr && + attr != &maximum_current_attr.attr && + attr != &operational_current_attr.attr) + return 0; + + return attr->mode; +} + +static const struct attribute_group source_fixed_supply_group = { + .is_visible = fixed_attr_is_visible, + .attrs = source_fixed_supply_attrs, +}; +__ATTRIBUTE_GROUPS(source_fixed_supply); + +static struct device_type source_fixed_supply_type = { + .name = "pdo", + .release = pdo_release, + .groups = source_fixed_supply_groups, +}; + +static struct attribute *sink_fixed_supply_attrs[] = { + &dev_attr_dual_role_power.attr, + &dev_attr_usb_suspend_supported.attr, + &dev_attr_unconstrained_power.attr, + &dev_attr_usb_communication_capable.attr, + &dev_attr_dual_role_data.attr, + &dev_attr_unchunked_extended_messages_supported.attr, + &dev_attr_fast_role_swap_current.attr, + &dev_attr_voltage.attr, + &operational_current_attr.attr, + NULL +}; + +static const struct attribute_group sink_fixed_supply_group = { + .is_visible = fixed_attr_is_visible, + .attrs = sink_fixed_supply_attrs, +}; +__ATTRIBUTE_GROUPS(sink_fixed_supply); + +static struct device_type sink_fixed_supply_type = { + .name = "pdo", + .release = pdo_release, + .groups = sink_fixed_supply_groups, +}; + +/* -------------------------------------------------------------------------- */ +/* Variable Supply */ + +static ssize_t +maximum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umV\n", pdo_max_voltage(to_pdo(dev)->pdo)); +} +static DEVICE_ATTR_RO(maximum_voltage); + +static ssize_t +minimum_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umV\n", pdo_min_voltage(to_pdo(dev)->pdo)); +} +static DEVICE_ATTR_RO(minimum_voltage); + +static struct attribute *source_variable_supply_attrs[] = { + &dev_attr_maximum_voltage.attr, + &dev_attr_minimum_voltage.attr, + &maximum_current_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(source_variable_supply); + +static struct device_type source_variable_supply_type = { + .name = "pdo", + .release = pdo_release, + .groups = source_variable_supply_groups, +}; + +static struct attribute *sink_variable_supply_attrs[] = { + &dev_attr_maximum_voltage.attr, + &dev_attr_minimum_voltage.attr, + &operational_current_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(sink_variable_supply); + +static struct device_type sink_variable_supply_type = { + .name = "pdo", + .release = pdo_release, + .groups = sink_variable_supply_groups, +}; + +/* -------------------------------------------------------------------------- */ +/* Battery */ + +static ssize_t +maximum_power_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo)); +} +static DEVICE_ATTR_RO(maximum_power); + +static ssize_t +operational_power_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umW\n", pdo_max_power(to_pdo(dev)->pdo)); +} +static DEVICE_ATTR_RO(operational_power); + +static struct attribute *source_battery_attrs[] = { + &dev_attr_maximum_voltage.attr, + &dev_attr_minimum_voltage.attr, + &dev_attr_maximum_power.attr, + NULL +}; +ATTRIBUTE_GROUPS(source_battery); + +static struct device_type source_battery_type = { + .name = "pdo", + .release = pdo_release, + .groups = source_battery_groups, +}; + +static struct attribute *sink_battery_attrs[] = { + &dev_attr_maximum_voltage.attr, + &dev_attr_minimum_voltage.attr, + &dev_attr_operational_power.attr, + NULL +}; +ATTRIBUTE_GROUPS(sink_battery); + +static struct device_type sink_battery_type = { + .name = "pdo", + .release = pdo_release, + .groups = sink_battery_groups, +}; + +/* -------------------------------------------------------------------------- */ +/* Standard Power Range (SPR) Programmable Power Supply (PPS) */ + +static ssize_t +pps_power_limited_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%u\n", !!(to_pdo(dev)->pdo & BIT(27))); +} +static DEVICE_ATTR_RO(pps_power_limited); + +static ssize_t +pps_max_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_max_voltage(to_pdo(dev)->pdo)); +} + +static ssize_t +pps_min_voltage_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umV\n", pdo_pps_apdo_min_voltage(to_pdo(dev)->pdo)); +} + +static ssize_t +pps_max_current_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sysfs_emit(buf, "%umA\n", pdo_pps_apdo_max_current(to_pdo(dev)->pdo)); +} + +static struct device_attribute pps_max_voltage_attr = { + .attr = { + .name = "maximum_voltage", + .mode = 0444, + }, + .show = pps_max_voltage_show, +}; + +static struct device_attribute pps_min_voltage_attr = { + .attr = { + .name = "minimum_voltage", + .mode = 0444, + }, + .show = pps_min_voltage_show, +}; + +static struct device_attribute pps_max_current_attr = { + .attr = { + .name = "maximum_current", + .mode = 0444, + }, + .show = pps_max_current_show, +}; + +static struct attribute *source_pps_attrs[] = { + &dev_attr_pps_power_limited.attr, + &pps_max_voltage_attr.attr, + &pps_min_voltage_attr.attr, + &pps_max_current_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(source_pps); + +static struct device_type source_pps_type = { + .name = "pdo", + .release = pdo_release, + .groups = source_pps_groups, +}; + +static struct attribute *sink_pps_attrs[] = { + &pps_max_voltage_attr.attr, + &pps_min_voltage_attr.attr, + &pps_max_current_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(sink_pps); + +static struct device_type sink_pps_type = { + .name = "pdo", + .release = pdo_release, + .groups = sink_pps_groups, +}; + +/* -------------------------------------------------------------------------- */ + +static const char * const supply_name[] = { + [PDO_TYPE_FIXED] = "fixed_supply", + [PDO_TYPE_BATT] = "battery", + [PDO_TYPE_VAR] = "variable_supply", +}; + +static const char * const apdo_supply_name[] = { + [APDO_TYPE_PPS] = "programmable_supply", +}; + +static struct device_type *source_type[] = { + [PDO_TYPE_FIXED] = &source_fixed_supply_type, + [PDO_TYPE_BATT] = &source_battery_type, + [PDO_TYPE_VAR] = &source_variable_supply_type, +}; + +static struct device_type *source_apdo_type[] = { + [APDO_TYPE_PPS] = &source_pps_type, +}; + +static struct device_type *sink_type[] = { + [PDO_TYPE_FIXED] = &sink_fixed_supply_type, + [PDO_TYPE_BATT] = &sink_battery_type, + [PDO_TYPE_VAR] = &sink_variable_supply_type, +}; + +static struct device_type *sink_apdo_type[] = { + [APDO_TYPE_PPS] = &sink_pps_type, +}; + +/* REVISIT: Export when EPR_*_Capabilities need to be supported. */ +static int add_pdo(struct usb_power_delivery_capabilities *cap, u32 pdo, int position) +{ + struct device_type *type; + const char *name; + struct pdo *p; + int ret; + + p = kzalloc(sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + p->pdo = pdo; + p->object_position = position; + + if (pdo_type(pdo) == PDO_TYPE_APDO) { + /* FIXME: Only PPS supported for now! Skipping others. */ + if (pdo_apdo_type(pdo) > APDO_TYPE_PPS) { + dev_warn(&cap->dev, "Unknown APDO type. PDO 0x%08x\n", pdo); + kfree(p); + return 0; + } + + if (is_source(cap->role)) + type = source_apdo_type[pdo_apdo_type(pdo)]; + else + type = sink_apdo_type[pdo_apdo_type(pdo)]; + + name = apdo_supply_name[pdo_apdo_type(pdo)]; + } else { + if (is_source(cap->role)) + type = source_type[pdo_type(pdo)]; + else + type = sink_type[pdo_type(pdo)]; + + name = supply_name[pdo_type(pdo)]; + } + + p->dev.parent = &cap->dev; + p->dev.type = type; + dev_set_name(&p->dev, "%u:%s", position + 1, name); + + ret = device_register(&p->dev); + if (ret) { + put_device(&p->dev); + return ret; + } + + return 0; +} + +static int remove_pdo(struct device *dev, void *data) +{ + device_unregister(dev); + return 0; +} + +/* -------------------------------------------------------------------------- */ + +static const char * const cap_name[] = { + [TYPEC_SINK] = "sink-capabilities", + [TYPEC_SOURCE] = "source-capabilities", +}; + +static void pd_capabilities_release(struct device *dev) +{ + kfree(to_usb_power_delivery_capabilities(dev)); +} + +static struct device_type pd_capabilities_type = { + .name = "capabilities", + .release = pd_capabilities_release, +}; + +/** + * usb_power_delivery_register_capabilities - Register a set of capabilities. + * @pd: The USB PD instance that the capabilities belong to. + * @desc: Description of the Capablities Message. + * + * This function registers a Capabilities Message described in @desc. The + * capabilities will have their own sub-directory under @pd in sysfs. + * + * The function returns pointer to struct usb_power_delivery_capabilities, or + * ERR_PRT(errno). + */ +struct usb_power_delivery_capabilities * +usb_power_delivery_register_capabilities(struct usb_power_delivery *pd, + struct usb_power_delivery_capabilities_desc *desc) +{ + struct usb_power_delivery_capabilities *cap; + int ret; + int i; + + cap = kzalloc(sizeof(*cap), GFP_KERNEL); + if (!cap) + return ERR_PTR(-ENOMEM); + + cap->pd = pd; + cap->role = desc->role; + + cap->dev.parent = &pd->dev; + cap->dev.type = &pd_capabilities_type; + dev_set_name(&cap->dev, "%s", cap_name[cap->role]); + + ret = device_register(&cap->dev); + if (ret) { + put_device(&cap->dev); + return ERR_PTR(ret); + } + + for (i = 0; i < PDO_MAX_OBJECTS && desc->pdo[i]; i++) { + ret = add_pdo(cap, desc->pdo[i], i); + if (ret) { + usb_power_delivery_unregister_capabilities(cap); + return ERR_PTR(ret); + } + } + + return cap; +} +EXPORT_SYMBOL_GPL(usb_power_delivery_register_capabilities); + +/** + * usb_power_delivery_unregister_capabilities - Unregister a set of capabilities + * @cap: The capabilities + */ +void usb_power_delivery_unregister_capabilities(struct usb_power_delivery_capabilities *cap) +{ + if (!cap) + return; + + device_for_each_child(&cap->dev, NULL, remove_pdo); + device_unregister(&cap->dev); +} +EXPORT_SYMBOL_GPL(usb_power_delivery_unregister_capabilities); + +/* -------------------------------------------------------------------------- */ + +static ssize_t revision_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_power_delivery *pd = to_usb_power_delivery(dev); + + return sysfs_emit(buf, "%u.%u\n", (pd->revision >> 8) & 0xff, (pd->revision >> 4) & 0xf); +} +static DEVICE_ATTR_RO(revision); + +static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct usb_power_delivery *pd = to_usb_power_delivery(dev); + + return sysfs_emit(buf, "%u.%u\n", (pd->version >> 8) & 0xff, (pd->version >> 4) & 0xf); +} +static DEVICE_ATTR_RO(version); + +static struct attribute *pd_attrs[] = { + &dev_attr_revision.attr, + &dev_attr_version.attr, + NULL +}; + +static umode_t pd_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) +{ + struct usb_power_delivery *pd = to_usb_power_delivery(kobj_to_dev(kobj)); + + if (attr == &dev_attr_version.attr && !pd->version) + return 0; + + return attr->mode; +} + +static const struct attribute_group pd_group = { + .is_visible = pd_attr_is_visible, + .attrs = pd_attrs, +}; +__ATTRIBUTE_GROUPS(pd); + +static void pd_release(struct device *dev) +{ + struct usb_power_delivery *pd = to_usb_power_delivery(dev); + + ida_simple_remove(&pd_ida, pd->id); + kfree(pd); +} + +static struct device_type pd_type = { + .name = "usb_power_delivery", + .release = pd_release, + .groups = pd_groups, +}; + +struct usb_power_delivery *usb_power_delivery_find(const char *name) +{ + struct device *dev; + + dev = class_find_device_by_name(&pd_class, name); + + return dev ? to_usb_power_delivery(dev) : NULL; +} + +/** + * usb_power_delivery_register - Register USB Power Delivery Support. + * @parent: Parent device. + * @desc: Description of the USB PD contract. + * + * This routine can be used to register USB Power Delivery capabilities that a + * device or devices can support. These capabilities represent all the + * capabilities that can be negotiated with a partner, so not only the Power + * Capabilities that are negotiated using the USB PD Capabilities Message. + * + * The USB Power Delivery Support object that this routine generates can be used + * as the parent object for all the actual USB Power Delivery Messages and + * objects that can be negotiated with the partner. + * + * Returns handle to struct usb_power_delivery or ERR_PTR. + */ +struct usb_power_delivery * +usb_power_delivery_register(struct device *parent, struct usb_power_delivery_desc *desc) +{ + struct usb_power_delivery *pd; + int ret; + + pd = kzalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) + return ERR_PTR(-ENOMEM); + + ret = ida_simple_get(&pd_ida, 0, 0, GFP_KERNEL); + if (ret < 0) { + kfree(pd); + return ERR_PTR(ret); + } + + pd->id = ret; + pd->revision = desc->revision; + pd->version = desc->version; + + pd->dev.parent = parent; + pd->dev.type = &pd_type; + pd->dev.class = &pd_class; + dev_set_name(&pd->dev, "pd%d", pd->id); + + ret = device_register(&pd->dev); + if (ret) { + put_device(&pd->dev); + return ERR_PTR(ret); + } + + return pd; +} +EXPORT_SYMBOL_GPL(usb_power_delivery_register); + +/** + * usb_power_delivery_unregister - Unregister USB Power Delivery Support. + * @pd: The USB PD contract. + */ +void usb_power_delivery_unregister(struct usb_power_delivery *pd) +{ + if (IS_ERR_OR_NULL(pd)) + return; + + device_unregister(&pd->dev); +} +EXPORT_SYMBOL_GPL(usb_power_delivery_unregister); + +/** + * usb_power_delivery_link_device - Link device to its USB PD object. + * @pd: The USB PD instance. + * @dev: The device. + * + * This function can be used to create a symlink named "usb_power_delivery" for + * @dev that points to @pd. + */ +int usb_power_delivery_link_device(struct usb_power_delivery *pd, struct device *dev) +{ + int ret; + + if (IS_ERR_OR_NULL(pd) || !dev) + return 0; + + ret = sysfs_create_link(&dev->kobj, &pd->dev.kobj, "usb_power_delivery"); + if (ret) + return ret; + + get_device(&pd->dev); + get_device(dev); + + return 0; +} +EXPORT_SYMBOL_GPL(usb_power_delivery_link_device); + +/** + * usb_power_delivery_unlink_device - Unlink device from its USB PD object. + * @pd: The USB PD instance. + * @dev: The device. + * + * Remove the symlink that was previously created with pd_link_device(). + */ +void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct device *dev) +{ + if (IS_ERR_OR_NULL(pd) || !dev) + return; + + sysfs_remove_link(&dev->kobj, "usb_power_delivery"); + put_device(&pd->dev); + put_device(dev); +} +EXPORT_SYMBOL_GPL(usb_power_delivery_unlink_device); + +/* -------------------------------------------------------------------------- */ + +int __init usb_power_delivery_init(void) +{ + return class_register(&pd_class); +} + +void __exit usb_power_delivery_exit(void) +{ + ida_destroy(&pd_ida); + class_unregister(&pd_class); +} diff --git a/drivers/usb/typec/pd.h b/drivers/usb/typec/pd.h new file mode 100644 index 000000000000..049a1aad440a --- /dev/null +++ b/drivers/usb/typec/pd.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __USB_POWER_DELIVERY__ +#define __USB_POWER_DELIVERY__ + +#include +#include + +struct usb_power_delivery { + struct device dev; + int id; + u16 revision; + u16 version; +}; + +struct usb_power_delivery_capabilities { + struct device dev; + struct usb_power_delivery *pd; + enum typec_role role; +}; + +#define to_usb_power_delivery_capabilities(o) container_of(o, struct usb_power_delivery_capabilities, dev) +#define to_usb_power_delivery(o) container_of(o, struct usb_power_delivery, dev) + +struct usb_power_delivery *usb_power_delivery_find(const char *name); + +int usb_power_delivery_init(void); +void usb_power_delivery_exit(void); + +#endif /* __USB_POWER_DELIVERY__ */ diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h index 96b7ff66f074..c59fb79a42e8 100644 --- a/include/linux/usb/pd.h +++ b/include/linux/usb/pd.h @@ -495,4 +495,42 @@ static inline unsigned int rdo_max_power(u32 rdo) #define PD_P_SNK_STDBY_MW 2500 /* 2500 mW */ +#if IS_ENABLED(CONFIG_TYPEC) + +struct usb_power_delivery; + +/** + * usb_power_delivery_desc - USB Power Delivery Descriptor + * @revision: USB Power Delivery Specification Revision + * @version: USB Power Delivery Specicication Version - optional + */ +struct usb_power_delivery_desc { + u16 revision; + u16 version; +}; + +/** + * usb_power_delivery_capabilities_desc - Description of USB Power Delivery Capabilities Message + * @pdo: The Power Data Objects in the Capability Message + * @role: Power role of the capabilities + */ +struct usb_power_delivery_capabilities_desc { + u32 pdo[PDO_MAX_OBJECTS]; + enum typec_role role; +}; + +struct usb_power_delivery_capabilities * +usb_power_delivery_register_capabilities(struct usb_power_delivery *pd, + struct usb_power_delivery_capabilities_desc *desc); +void usb_power_delivery_unregister_capabilities(struct usb_power_delivery_capabilities *cap); + +struct usb_power_delivery *usb_power_delivery_register(struct device *parent, + struct usb_power_delivery_desc *desc); +void usb_power_delivery_unregister(struct usb_power_delivery *pd); + +int usb_power_delivery_link_device(struct usb_power_delivery *pd, struct device *dev); +void usb_power_delivery_unlink_device(struct usb_power_delivery *pd, struct device *dev); + +#endif /* CONFIG_TYPEC */ + #endif /* __LINUX_USB_PD_H */ diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h index fdf737d48b3b..45e28d14ae56 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -52,6 +52,16 @@ enum typec_role { TYPEC_SOURCE, }; +static inline int is_sink(enum typec_role role) +{ + return role == TYPEC_SINK; +} + +static inline int is_source(enum typec_role role) +{ + return role == TYPEC_SOURCE; +} + enum typec_pwr_opmode { TYPEC_PWR_MODE_USB, TYPEC_PWR_MODE_1_5A, From a7cff92f0635c794e2198a69a7ff4ecfe0decab9 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 2 May 2022 16:20:57 +0300 Subject: [PATCH 0456/1436] usb: typec: USB Power Delivery helpers for ports and partners All the USB Type-C Connector Class devices are protected, so the drivers can not directly access them. This will adds a few helpers that can be used to link the ports and partners to the correct USB Power Delivery objects. For ports a new optional sysfs attribute file is also added that can be used to select the USB Power Delivery capabilities that the port will advertise to the partner. Signed-off-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220502132058.86236-3-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-class-typec | 8 ++ drivers/usb/typec/class.c | 149 ++++++++++++++++++++ drivers/usb/typec/class.h | 4 + include/linux/usb/typec.h | 13 ++ 4 files changed, 174 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-typec b/Documentation/ABI/testing/sysfs-class-typec index 75088ecad202..281b995beb05 100644 --- a/Documentation/ABI/testing/sysfs-class-typec +++ b/Documentation/ABI/testing/sysfs-class-typec @@ -141,6 +141,14 @@ Description: - "reverse": CC2 orientation - "unknown": Orientation cannot be determined. +What: /sys/class/typec//select_usb_power_delivery +Date: May 2022 +Contact: Heikki Krogerus +Description: + Lists the USB Power Delivery Capabilities that the port can + advertise to the partner. The currently used capabilities are in + brackets. Selection happens by writing to the file. + USB Type-C partner devices (eg. /sys/class/typec/port0-partner/) What: /sys/class/typec/-partner/accessory_mode diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index ee0e520707dd..bbc46b14f99a 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -15,6 +15,7 @@ #include "bus.h" #include "class.h" +#include "pd.h" static DEFINE_IDA(typec_index_ida); @@ -720,6 +721,39 @@ void typec_partner_set_pd_revision(struct typec_partner *partner, u16 pd_revisio } EXPORT_SYMBOL_GPL(typec_partner_set_pd_revision); +/** + * typec_partner_set_usb_power_delivery - Declare USB Power Delivery Contract. + * @partner: The partner device. + * @pd: The USB PD instance. + * + * This routine can be used to declare USB Power Delivery Contract with @partner + * by linking @partner to @pd which contains the objects that were used during the + * negotiation of the contract. + * + * If @pd is NULL, the link is removed and the contract with @partner has ended. + */ +int typec_partner_set_usb_power_delivery(struct typec_partner *partner, + struct usb_power_delivery *pd) +{ + int ret; + + if (IS_ERR_OR_NULL(partner) || partner->pd == pd) + return 0; + + if (pd) { + ret = usb_power_delivery_link_device(pd, &partner->dev); + if (ret) + return ret; + } else { + usb_power_delivery_unlink_device(partner->pd, &partner->dev); + } + + partner->pd = pd; + + return 0; +} +EXPORT_SYMBOL_GPL(typec_partner_set_usb_power_delivery); + /** * typec_partner_set_num_altmodes - Set the number of available partner altmodes * @partner: The partner to be updated. @@ -1170,6 +1204,104 @@ EXPORT_SYMBOL_GPL(typec_unregister_cable); /* ------------------------------------------------------------------------- */ /* USB Type-C ports */ +/** + * typec_port_set_usb_power_delivery - Assign USB PD for port. + * @port: USB Type-C port. + * @pd: USB PD instance. + * + * This routine can be used to set the USB Power Delivery Capabilities for @port + * that it will advertise to the partner. + * + * If @pd is NULL, the assignment is removed. + */ +int typec_port_set_usb_power_delivery(struct typec_port *port, struct usb_power_delivery *pd) +{ + int ret; + + if (IS_ERR_OR_NULL(port) || port->pd == pd) + return 0; + + if (pd) { + ret = usb_power_delivery_link_device(pd, &port->dev); + if (ret) + return ret; + } else { + usb_power_delivery_unlink_device(port->pd, &port->dev); + } + + port->pd = pd; + + return 0; +} +EXPORT_SYMBOL_GPL(typec_port_set_usb_power_delivery); + +static ssize_t select_usb_power_delivery_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct typec_port *port = to_typec_port(dev); + struct usb_power_delivery *pd; + + if (!port->ops || !port->ops->pd_set) + return -EOPNOTSUPP; + + pd = usb_power_delivery_find(buf); + if (!pd) + return -EINVAL; + + return port->ops->pd_set(port, pd); +} + +static ssize_t select_usb_power_delivery_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct typec_port *port = to_typec_port(dev); + struct usb_power_delivery **pds; + struct usb_power_delivery *pd; + int ret = 0; + + if (!port->ops || !port->ops->pd_get) + return -EOPNOTSUPP; + + pds = port->ops->pd_get(port); + if (!pds) + return 0; + + for (pd = pds[0]; pd; pd++) { + if (pd == port->pd) + ret += sysfs_emit(buf + ret, "[%s] ", dev_name(&pd->dev)); + else + ret += sysfs_emit(buf + ret, "%s ", dev_name(&pd->dev)); + } + + buf[ret - 1] = '\n'; + + return ret; +} +static DEVICE_ATTR_RW(select_usb_power_delivery); + +static struct attribute *port_attrs[] = { + &dev_attr_select_usb_power_delivery.attr, + NULL +}; + +static umode_t port_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) +{ + struct typec_port *port = to_typec_port(kobj_to_dev(kobj)); + + if (!port->pd || !port->ops || !port->ops->pd_get) + return 0; + if (!port->ops->pd_set) + return 0444; + + return attr->mode; +} + +static const struct attribute_group pd_group = { + .is_visible = port_attr_is_visible, + .attrs = port_attrs, +}; + static const char * const typec_orientations[] = { [TYPEC_ORIENTATION_NONE] = "unknown", [TYPEC_ORIENTATION_NORMAL] = "normal", @@ -1581,6 +1713,7 @@ static const struct attribute_group typec_group = { static const struct attribute_group *typec_groups[] = { &typec_group, + &pd_group, NULL }; @@ -2123,6 +2256,13 @@ struct typec_port *typec_register_port(struct device *parent, return ERR_PTR(ret); } + ret = typec_port_set_usb_power_delivery(port, cap->pd); + if (ret) { + dev_err(&port->dev, "failed to link pd\n"); + device_unregister(&port->dev); + return ERR_PTR(ret); + } + ret = typec_link_ports(port); if (ret) dev_warn(&port->dev, "failed to create symlinks (%d)\n", ret); @@ -2141,6 +2281,7 @@ void typec_unregister_port(struct typec_port *port) { if (!IS_ERR_OR_NULL(port)) { typec_unlink_ports(port); + typec_port_set_usb_power_delivery(port, NULL); device_unregister(&port->dev); } } @@ -2162,8 +2303,15 @@ static int __init typec_init(void) if (ret) goto err_unregister_mux_class; + ret = usb_power_delivery_init(); + if (ret) + goto err_unregister_class; + return 0; +err_unregister_class: + class_unregister(&typec_class); + err_unregister_mux_class: class_unregister(&typec_mux_class); @@ -2176,6 +2324,7 @@ subsys_initcall(typec_init); static void __exit typec_exit(void) { + usb_power_delivery_exit(); class_unregister(&typec_class); ida_destroy(&typec_index_ida); bus_unregister(&typec_bus); diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h index 0f1bd6d19d67..b531f9853bc0 100644 --- a/drivers/usb/typec/class.h +++ b/drivers/usb/typec/class.h @@ -33,6 +33,8 @@ struct typec_partner { int num_altmodes; u16 pd_revision; /* 0300H = "3.0" */ enum usb_pd_svdm_ver svdm_version; + + struct usb_power_delivery *pd; }; struct typec_port { @@ -40,6 +42,8 @@ struct typec_port { struct device dev; struct ida mode_ids; + struct usb_power_delivery *pd; + int prefer_role; enum typec_data_role data_role; enum typec_role pwr_role; diff --git a/include/linux/usb/typec.h b/include/linux/usb/typec.h index 45e28d14ae56..7751bedcae5d 100644 --- a/include/linux/usb/typec.h +++ b/include/linux/usb/typec.h @@ -22,6 +22,8 @@ struct typec_altmode_ops; struct fwnode_handle; struct device; +struct usb_power_delivery; + enum typec_port_type { TYPEC_PORT_SRC, TYPEC_PORT_SNK, @@ -223,6 +225,8 @@ struct typec_partner_desc { * @pr_set: Set Power Role * @vconn_set: Source VCONN * @port_type_set: Set port type + * @pd_get: Get available USB Power Delivery Capabilities. + * @pd_set: Set USB Power Delivery Capabilities. */ struct typec_operations { int (*try_role)(struct typec_port *port, int role); @@ -231,6 +235,8 @@ struct typec_operations { int (*vconn_set)(struct typec_port *port, enum typec_role role); int (*port_type_set)(struct typec_port *port, enum typec_port_type type); + struct usb_power_delivery **(*pd_get)(struct typec_port *port); + int (*pd_set)(struct typec_port *port, struct usb_power_delivery *pd); }; enum usb_pd_svdm_ver { @@ -250,6 +256,7 @@ enum usb_pd_svdm_ver { * @accessory: Supported Accessory Modes * @fwnode: Optional fwnode of the port * @driver_data: Private pointer for driver specific info + * @pd: Optional USB Power Delivery Support * @ops: Port operations vector * * Static capabilities of a single USB Type-C port. @@ -267,6 +274,8 @@ struct typec_capability { struct fwnode_handle *fwnode; void *driver_data; + struct usb_power_delivery *pd; + const struct typec_operations *ops; }; @@ -318,4 +327,8 @@ void typec_partner_set_svdm_version(struct typec_partner *partner, enum usb_pd_svdm_ver svdm_version); int typec_get_negotiated_svdm_version(struct typec_port *port); +int typec_port_set_usb_power_delivery(struct typec_port *port, struct usb_power_delivery *pd); +int typec_partner_set_usb_power_delivery(struct typec_partner *partner, + struct usb_power_delivery *pd); + #endif /* __LINUX_USB_TYPEC_H */ From 8203d26905eee083fbe76ec449f32953aa729193 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 2 May 2022 16:20:58 +0300 Subject: [PATCH 0457/1436] usb: typec: tcpm: Register USB Power Delivery Capabilities Register both the port and partner USB Power Delivery Capabilities so they are exposed to the user space. Signed-off-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220502132058.86236-4-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 142 +++++++++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 7039383eac6d..e1126a6c8e46 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -394,6 +394,14 @@ struct tcpm_port { bool explicit_contract; unsigned int rx_msgid; + /* USB PD objects */ + struct usb_power_delivery *pd; + struct usb_power_delivery_capabilities *port_source_caps; + struct usb_power_delivery_capabilities *port_sink_caps; + struct usb_power_delivery *partner_pd; + struct usb_power_delivery_capabilities *partner_source_caps; + struct usb_power_delivery_capabilities *partner_sink_caps; + /* Partner capabilities/requests */ u32 sink_request; u32 source_caps[PDO_MAX_OBJECTS]; @@ -2352,6 +2360,52 @@ static void tcpm_pd_handle_msg(struct tcpm_port *port, } } +static int tcpm_register_source_caps(struct tcpm_port *port) +{ + struct usb_power_delivery_desc desc = { port->negotiated_rev }; + struct usb_power_delivery_capabilities_desc caps = { }; + struct usb_power_delivery_capabilities *cap; + + if (!port->partner_pd) + port->partner_pd = usb_power_delivery_register(NULL, &desc); + if (IS_ERR(port->partner_pd)) + return PTR_ERR(port->partner_pd); + + memcpy(caps.pdo, port->source_caps, sizeof(u32) * port->nr_source_caps); + caps.role = TYPEC_SOURCE; + + cap = usb_power_delivery_register_capabilities(port->partner_pd, &caps); + if (IS_ERR(cap)) + return PTR_ERR(cap); + + port->partner_source_caps = cap; + + return 0; +} + +static int tcpm_register_sink_caps(struct tcpm_port *port) +{ + struct usb_power_delivery_desc desc = { port->negotiated_rev }; + struct usb_power_delivery_capabilities_desc caps = { }; + struct usb_power_delivery_capabilities *cap; + + if (!port->partner_pd) + port->partner_pd = usb_power_delivery_register(NULL, &desc); + if (IS_ERR(port->partner_pd)) + return PTR_ERR(port->partner_pd); + + memcpy(caps.pdo, port->sink_caps, sizeof(u32) * port->nr_sink_caps); + caps.role = TYPEC_SINK; + + cap = usb_power_delivery_register_capabilities(port->partner_pd, &caps); + if (IS_ERR(cap)) + return PTR_ERR(cap); + + port->partner_sink_caps = cap; + + return 0; +} + static void tcpm_pd_data_request(struct tcpm_port *port, const struct pd_message *msg) { @@ -2381,6 +2435,8 @@ static void tcpm_pd_data_request(struct tcpm_port *port, tcpm_validate_caps(port, port->source_caps, port->nr_source_caps); + tcpm_register_source_caps(port); + /* * Adjust revision in subsequent message headers, as required, * to comply with 6.2.1.1.5 of the USB PD 3.0 spec. We don't @@ -2488,6 +2544,8 @@ static void tcpm_pd_data_request(struct tcpm_port *port, port->nr_sink_caps = cnt; port->sink_cap_done = true; + tcpm_register_sink_caps(port); + if (port->ams == GET_SINK_CAPABILITIES) tcpm_set_state(port, ready_state(port), 0); /* Unexpected Sink Capabilities */ @@ -3554,6 +3612,7 @@ static void tcpm_typec_connect(struct tcpm_port *port) port->partner = typec_register_partner(port->typec_port, &port->partner_desc); port->connected = true; + typec_partner_set_usb_power_delivery(port->partner, port->partner_pd); } } @@ -3622,6 +3681,7 @@ out_disable_mux: static void tcpm_typec_disconnect(struct tcpm_port *port) { if (port->connected) { + typec_partner_set_usb_power_delivery(port->partner, NULL); typec_unregister_partner(port->partner); port->partner = NULL; port->connected = false; @@ -3684,6 +3744,13 @@ static void tcpm_reset_port(struct tcpm_port *port) port->sink_cap_done = false; if (port->tcpc->enable_frs) port->tcpc->enable_frs(port->tcpc, false); + + usb_power_delivery_unregister_capabilities(port->partner_sink_caps); + port->partner_sink_caps = NULL; + usb_power_delivery_unregister_capabilities(port->partner_source_caps); + port->partner_source_caps = NULL; + usb_power_delivery_unregister(port->partner_pd); + port->partner_pd = NULL; } static void tcpm_detach(struct tcpm_port *port) @@ -5924,6 +5991,68 @@ void tcpm_tcpc_reset(struct tcpm_port *port) } EXPORT_SYMBOL_GPL(tcpm_tcpc_reset); +static void tcpm_port_unregister_pd(struct tcpm_port *port) +{ + usb_power_delivery_unregister_capabilities(port->port_sink_caps); + port->port_sink_caps = NULL; + usb_power_delivery_unregister_capabilities(port->port_source_caps); + port->port_source_caps = NULL; + usb_power_delivery_unregister(port->pd); + port->pd = NULL; +} + +static int tcpm_port_register_pd(struct tcpm_port *port) +{ + struct usb_power_delivery_desc desc = { port->typec_caps.pd_revision }; + struct usb_power_delivery_capabilities_desc caps = { }; + struct usb_power_delivery_capabilities *cap; + int ret; + + if (!port->nr_src_pdo && !port->nr_snk_pdo) + return 0; + + port->pd = usb_power_delivery_register(port->dev, &desc); + if (IS_ERR(port->pd)) { + ret = PTR_ERR(port->pd); + goto err_unregister; + } + + if (port->nr_src_pdo) { + memcpy_and_pad(caps.pdo, sizeof(caps.pdo), port->src_pdo, + port->nr_src_pdo * sizeof(u32), 0); + caps.role = TYPEC_SOURCE; + + cap = usb_power_delivery_register_capabilities(port->pd, &caps); + if (IS_ERR(cap)) { + ret = PTR_ERR(cap); + goto err_unregister; + } + + port->port_source_caps = cap; + } + + if (port->nr_snk_pdo) { + memcpy_and_pad(caps.pdo, sizeof(caps.pdo), port->snk_pdo, + port->nr_snk_pdo * sizeof(u32), 0); + caps.role = TYPEC_SINK; + + cap = usb_power_delivery_register_capabilities(port->pd, &caps); + if (IS_ERR(cap)) { + ret = PTR_ERR(cap); + goto err_unregister; + } + + port->port_sink_caps = cap; + } + + return 0; + +err_unregister: + tcpm_port_unregister_pd(port); + + return ret; +} + static int tcpm_fw_get_caps(struct tcpm_port *port, struct fwnode_handle *fwnode) { @@ -6382,10 +6511,16 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) goto out_role_sw_put; power_supply_changed(port->psy); + err = tcpm_port_register_pd(port); + if (err) + goto out_role_sw_put; + + port->typec_caps.pd = port->pd; + port->typec_port = typec_register_port(port->dev, &port->typec_caps); if (IS_ERR(port->typec_port)) { err = PTR_ERR(port->typec_port); - goto out_role_sw_put; + goto out_unregister_pd; } typec_port_register_altmodes(port->typec_port, @@ -6400,6 +6535,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) tcpm_log(port, "%s: registered", dev_name(dev)); return port; +out_unregister_pd: + tcpm_port_unregister_pd(port); out_role_sw_put: usb_role_switch_put(port->role_sw); out_destroy_wq: @@ -6422,6 +6559,9 @@ void tcpm_unregister_port(struct tcpm_port *port) hrtimer_cancel(&port->state_machine_timer); tcpm_reset_port(port); + + tcpm_port_unregister_pd(port); + for (i = 0; i < ARRAY_SIZE(port->port_altmode); i++) typec_unregister_altmode(port->port_altmode[i]); typec_unregister_port(port->typec_port); From ca80ca61863f70df1eb055bcccb302013d2d6308 Mon Sep 17 00:00:00 2001 From: Kushagra Verma Date: Fri, 20 May 2022 17:40:45 +0530 Subject: [PATCH 0458/1436] usb: dwc3: Fix bare use of unsigned checkpatch warning Fixes the bare use of unsigned warning from checkpatch.pl in core.c by changing 'unsigned' to 'unsigned int'. Signed-off-by: Kushagra Verma Link: https://lore.kernel.org/r/HK0PR01MB280160BCA168FA9FE159F02AF8D39@HK0PR01MB2801.apcprd01.prod.exchangelabs.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a8b42530b603..2c12bbbcd55c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -426,7 +426,7 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc, * otherwise ERR_PTR(errno). */ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, - unsigned length) + unsigned int length) { struct dwc3_event_buffer *evt; @@ -469,7 +469,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) * Returns 0 on success otherwise negative errno. In the error case, dwc * may contain some buffers allocated but not all which were requested. */ -static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) +static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned int length) { struct dwc3_event_buffer *evt; From d1b39dd5819a0ea5e09fb2c7f7bcb2e127cdbd89 Mon Sep 17 00:00:00 2001 From: Kushagra Verma Date: Fri, 20 May 2022 17:40:46 +0530 Subject: [PATCH 0459/1436] usb: dwc3: Fix a repeated word checkpatch warning Fixes a repeated word checkpatch warning in ep0.c by removing the repeated 'only' word. Signed-off-by: Kushagra Verma Link: https://lore.kernel.org/r/HK0PR01MB2801996E815208393170010FF8D39@HK0PR01MB2801.apcprd01.prod.exchangelabs.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/ep0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 5d642660fd15..2a510e84eef4 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -473,7 +473,7 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc, case USB_DEVICE_REMOTE_WAKEUP: break; /* - * 9.4.1 says only only for SS, in AddressState only for + * 9.4.1 says only for SS, in AddressState only for * default control pipe */ case USB_DEVICE_U1_ENABLE: From 3085d1bd47f2bfdd0b34b8399011f2ed6292fe8c Mon Sep 17 00:00:00 2001 From: Kushagra Verma Date: Fri, 20 May 2022 17:40:47 +0530 Subject: [PATCH 0460/1436] usb: dwc3: Fix typos in Kconfig Fixes the following 2 typos in Kconfig: 1. is -> as 2. progammed -> programmed Signed-off-by: Kushagra Verma Link: https://lore.kernel.org/r/HK0PR01MB280151A3B2CF6C3E4DC2F9CAF8D39@HK0PR01MB2801.apcprd01.prod.exchangelabs.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index cd9a734522a7..03ededa86da1 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -9,7 +9,7 @@ config USB_DWC3 Say Y or M here if your system has a Dual Role SuperSpeed USB controller based on the DesignWare USB3 IP Core. - If you choose to build this driver is a dynamically linked + If you choose to build this driver as a dynamically linked module, the module will be called dwc3.ko. if USB_DWC3 @@ -165,7 +165,7 @@ config USB_DWC3_AM62 default USB_DWC3 help Support TI's AM62 platforms with DesignWare Core USB3 IP. - The Designware Core USB3 IP is progammed to operate in + The Designware Core USB3 IP is programmed to operate in in USB 2.0 mode only. Say 'Y' or 'M' here if you have one such device endif From e146caf303493c4f2458173d7f1598b76a9b1396 Mon Sep 17 00:00:00 2001 From: Mathias Nyman Date: Fri, 6 May 2022 19:18:07 +0300 Subject: [PATCH 0461/1436] usb: Avoid extra usb SET_SEL requests when enabling link power management The host needs to tell the device the exit latencies using the SET_SEL request before device initiated link powermanagement can be enabled. The exit latency values do not change after enumeration, it's enough to set them once. So do like Windows 10 and issue the SET_SEL request once just before setting the configuration. This is also the sequence described in USB 3.2 specs "9.1.2 Bus enumeration". SET_SEL is issued once before the Set Configuration request, and won't be cleared by the Set Configuration, Set Interface or ClearFeature (STALL) requests. Only warm reset, hot reset, set Address 0 clears the exit latencies. See USB 3.2 section 9.4.14 Table 9-10 Device parameters and events Add udev->lpm_devinit_allow, and set it if SET_SEL was successful. If not set, then don't try to enable device initiated LPM We used to issue a SET_SEL request every time lpm is enabled for either U1 or U2 link states, meaning a SET_SEL was issued twice after every Set Configuration and Set Interface requests, easily accumulating to over 15 SET_SEL requets during a USB3 webcam enumeration. Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20220506161807.3369439-1-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 60 +++++++++++++++--------------------------- include/linux/usb.h | 2 ++ 2 files changed, 23 insertions(+), 39 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ba406b8d688d..b7f66dcd1fe0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -3947,7 +3947,7 @@ static const char * const usb3_lpm_names[] = { * This function will fail if the SEL or PEL values for udev are greater than * the maximum allowed values for the link state to be enabled. */ -static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) +static int usb_req_set_sel(struct usb_device *udev) { struct usb_set_sel_req *sel_values; unsigned long long u1_sel; @@ -3956,7 +3956,7 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) unsigned long long u2_pel; int ret; - if (udev->state != USB_STATE_CONFIGURED) + if (!udev->parent || udev->speed < USB_SPEED_SUPER || !udev->lpm_capable) return 0; /* Convert SEL and PEL stored in ns to us */ @@ -3973,34 +3973,14 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) * latency for the link state, and could start a device-initiated * U1/U2 when the exit latencies are too high. */ - if ((state == USB3_LPM_U1 && - (u1_sel > USB3_LPM_MAX_U1_SEL_PEL || - u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) || - (state == USB3_LPM_U2 && - (u2_sel > USB3_LPM_MAX_U2_SEL_PEL || - u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) { - dev_dbg(&udev->dev, "Device-initiated %s disabled due to long SEL %llu us or PEL %llu us\n", - usb3_lpm_names[state], u1_sel, u1_pel); + if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL || + u1_pel > USB3_LPM_MAX_U1_SEL_PEL || + u2_sel > USB3_LPM_MAX_U2_SEL_PEL || + u2_pel > USB3_LPM_MAX_U2_SEL_PEL) { + dev_dbg(&udev->dev, "Device-initiated U1/U2 disabled due to long SEL or PEL\n"); return -EINVAL; } - /* - * If we're enabling device-initiated LPM for one link state, - * but the other link state has a too high SEL or PEL value, - * just set those values to the max in the Set SEL request. - */ - if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL) - u1_sel = USB3_LPM_MAX_U1_SEL_PEL; - - if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL) - u1_pel = USB3_LPM_MAX_U1_SEL_PEL; - - if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL) - u2_sel = USB3_LPM_MAX_U2_SEL_PEL; - - if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL) - u2_pel = USB3_LPM_MAX_U2_SEL_PEL; - /* * usb_enable_lpm() can be called as part of a failed device reset, * which may be initiated by an error path of a mass storage driver. @@ -4022,6 +4002,10 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) sel_values, sizeof *(sel_values), USB_CTRL_SET_TIMEOUT); kfree(sel_values); + + if (ret > 0) + udev->lpm_devinit_allow = 1; + return ret; } @@ -4137,6 +4121,9 @@ static bool usb_device_may_initiate_lpm(struct usb_device *udev, unsigned int sel; /* us */ int i, j; + if (!udev->lpm_devinit_allow) + return false; + if (state == USB3_LPM_U1) sel = DIV_ROUND_UP(udev->u1_params.sel, 1000); else if (state == USB3_LPM_U2) @@ -4185,7 +4172,7 @@ static bool usb_device_may_initiate_lpm(struct usb_device *udev, static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, enum usb3_link_state state) { - int timeout, ret; + int timeout; __u8 u1_mel = udev->bos->ss_cap->bU1devExitLat; __le16 u2_mel = udev->bos->ss_cap->bU2DevExitLat; @@ -4197,17 +4184,6 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, (state == USB3_LPM_U2 && u2_mel == 0)) return; - /* - * First, let the device know about the exit latencies - * associated with the link state we're about to enable. - */ - ret = usb_req_set_sel(udev, state); - if (ret < 0) { - dev_warn(&udev->dev, "Set SEL for device-initiated %s failed.\n", - usb3_lpm_names[state]); - return; - } - /* We allow the host controller to set the U1/U2 timeout internally * first, so that it can change its schedule to account for the * additional latency to send data to a device in a lower power @@ -4487,6 +4463,11 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, return 0; } +static int usb_req_set_sel(struct usb_device *udev) +{ + return 0; +} + #endif /* CONFIG_PM */ /* @@ -5012,6 +4993,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, udev->lpm_capable = usb_device_supports_lpm(udev); udev->lpm_disable_count = 1; usb_set_lpm_parameters(udev); + usb_req_set_sel(udev); } } diff --git a/include/linux/usb.h b/include/linux/usb.h index 60bee864d897..f7a9914fc97f 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -584,6 +584,7 @@ struct usb3_lpm_parameters { * @authenticated: Crypto authentication passed * @wusb: device is Wireless USB * @lpm_capable: device supports LPM + * @lpm_devinit_allow: Allow USB3 device initiated LPM, exit latency is in range * @usb2_hw_lpm_capable: device can perform USB2 hardware LPM * @usb2_hw_lpm_besl_capable: device can perform USB2 hardware BESL LPM * @usb2_hw_lpm_enabled: USB2 hardware LPM is enabled @@ -666,6 +667,7 @@ struct usb_device { unsigned authenticated:1; unsigned wusb:1; unsigned lpm_capable:1; + unsigned lpm_devinit_allow:1; unsigned usb2_hw_lpm_capable:1; unsigned usb2_hw_lpm_besl_capable:1; unsigned usb2_hw_lpm_enabled:1; From 055276c1320564b0192b3af323b8cc67f9b665e1 Mon Sep 17 00:00:00 2001 From: Neal Liu Date: Mon, 23 May 2022 11:01:32 +0800 Subject: [PATCH 0462/1436] usb: gadget: add Aspeed ast2600 udc driver Aspeed udc is compliant with USB2.0, supports USB High Speed and Full Speed, backward compatible with USB1.1. Supports independent DMA channel for each generic endpoint. Supports 32/256 stages descriptor mode for all generic endpoints. This driver supports full functionality including single/multiple stages descriptor mode, and exposes 1 UDC gadget driver. Signed-off-by: Neal Liu Link: https://lore.kernel.org/r/20220523030134.2977116-2-neal_liu@aspeedtech.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 7 + drivers/usb/gadget/udc/Kconfig | 13 + drivers/usb/gadget/udc/Makefile | 1 + drivers/usb/gadget/udc/aspeed_udc.c | 1596 +++++++++++++++++++++++++++ 4 files changed, 1617 insertions(+) create mode 100644 drivers/usb/gadget/udc/aspeed_udc.c diff --git a/MAINTAINERS b/MAINTAINERS index a6d3bd9d2a8d..fc5d2780d04c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3136,6 +3136,13 @@ S: Maintained F: Documentation/devicetree/bindings/media/aspeed-video.txt F: drivers/media/platform/aspeed/ +ASPEED USB UDC DRIVER +M: Neal Liu +L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) +S: Maintained +F: Documentation/devicetree/bindings/usb/aspeed,udc.yaml +F: drivers/usb/gadget/udc/aspeed_udc.c + ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS M: Corentin Chary L: acpi4asus-user@lists.sourceforge.net diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 69394dc1cdfb..03535f33511b 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -463,6 +463,19 @@ config USB_TEGRA_XUDC dynamically linked module called "tegra_xudc" and force all gadget drivers to also be dynamically linked. +config USB_ASPEED_UDC + tristate "Aspeed UDC driver support" + depends on ARCH_ASPEED || COMPILE_TEST + depends on USB_LIBCOMPOSITE + help + Enables Aspeed USB2.0 Device Controller driver for AST260x + family SoCs. The controller supports 1 control endpoint and + 4 programmable endpoints. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "aspeed_udc" and force all + gadget drivers to also be dynamically linked. + source "drivers/usb/gadget/udc/aspeed-vhub/Kconfig" # diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile index a21f2224e7eb..12f9e4c9eb0c 100644 --- a/drivers/usb/gadget/udc/Makefile +++ b/drivers/usb/gadget/udc/Makefile @@ -40,5 +40,6 @@ obj-$(CONFIG_USB_GR_UDC) += gr_udc.o obj-$(CONFIG_USB_GADGET_XILINX) += udc-xilinx.o obj-$(CONFIG_USB_SNP_UDC_PLAT) += snps_udc_plat.o obj-$(CONFIG_USB_ASPEED_VHUB) += aspeed-vhub/ +obj-$(CONFIG_USB_ASPEED_UDC) += aspeed_udc.o obj-$(CONFIG_USB_BDC_UDC) += bdc/ obj-$(CONFIG_USB_MAX3420_UDC) += max3420_udc.o diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c new file mode 100644 index 000000000000..1fc15228ff15 --- /dev/null +++ b/drivers/usb/gadget/udc/aspeed_udc.c @@ -0,0 +1,1596 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 Aspeed Technology Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define AST_UDC_NUM_ENDPOINTS (1 + 4) +#define AST_UDC_EP0_MAX_PACKET 64 /* EP0's max packet size */ +#define AST_UDC_EPn_MAX_PACKET 1024 /* Generic EPs max packet size */ +#define AST_UDC_DESCS_COUNT 256 /* Use 256 stages descriptor mode (32/256) */ +#define AST_UDC_DESC_MODE 1 /* Single/Multiple Stage(s) Descriptor Mode */ + +#define AST_UDC_EP_DMA_SIZE (AST_UDC_EPn_MAX_PACKET + 8 * AST_UDC_DESCS_COUNT) + +/***************************** + * * + * UDC register definitions * + * * + *****************************/ + +#define AST_UDC_FUNC_CTRL 0x00 /* Root Function Control & Status Register */ +#define AST_UDC_CONFIG 0x04 /* Root Configuration Setting Register */ +#define AST_UDC_IER 0x08 /* Interrupt Control Register */ +#define AST_UDC_ISR 0x0C /* Interrupt Status Register */ +#define AST_UDC_EP_ACK_IER 0x10 /* Programmable ep Pool ACK Interrupt Enable Reg */ +#define AST_UDC_EP_NAK_IER 0x14 /* Programmable ep Pool NAK Interrupt Enable Reg */ +#define AST_UDC_EP_ACK_ISR 0x18 /* Programmable ep Pool ACK Interrupt Status Reg */ +#define AST_UDC_EP_NAK_ISR 0x1C /* Programmable ep Pool NAK Interrupt Status Reg */ +#define AST_UDC_DEV_RESET 0x20 /* Device Controller Soft Reset Enable Register */ +#define AST_UDC_STS 0x24 /* USB Status Register */ +#define AST_VHUB_EP_DATA 0x28 /* Programmable ep Pool Data Toggle Value Set */ +#define AST_VHUB_ISO_TX_FAIL 0x2C /* Isochronous Transaction Fail Accumulator */ +#define AST_UDC_EP0_CTRL 0x30 /* Endpoint 0 Control/Status Register */ +#define AST_UDC_EP0_DATA_BUFF 0x34 /* Base Address of ep0 IN/OUT Data Buffer Reg */ +#define AST_UDC_SETUP0 0x80 /* Root Device Setup Data Buffer0 */ +#define AST_UDC_SETUP1 0x84 /* Root Device Setup Data Buffer1 */ + + +/* Main control reg */ +#define USB_PHY_CLK_EN BIT(31) +#define USB_FIFO_DYN_PWRD_EN BIT(19) +#define USB_EP_LONG_DESC BIT(18) +#define USB_BIST_TEST_PASS BIT(13) +#define USB_BIST_TURN_ON BIT(12) +#define USB_PHY_RESET_DIS BIT(11) +#define USB_TEST_MODE(x) ((x) << 8) +#define USB_FORCE_TIMER_HS BIT(7) +#define USB_FORCE_HS BIT(6) +#define USB_REMOTE_WAKEUP_12MS BIT(5) +#define USB_REMOTE_WAKEUP_EN BIT(4) +#define USB_AUTO_REMOTE_WAKEUP_EN BIT(3) +#define USB_STOP_CLK_IN_SUPEND BIT(2) +#define USB_UPSTREAM_FS BIT(1) +#define USB_UPSTREAM_EN BIT(0) + +/* Main config reg */ +#define UDC_CFG_SET_ADDR(x) ((x) & 0x3f) +#define UDC_CFG_ADDR_MASK (0x3f) + +/* Interrupt ctrl & status reg */ +#define UDC_IRQ_EP_POOL_NAK BIT(17) +#define UDC_IRQ_EP_POOL_ACK_STALL BIT(16) +#define UDC_IRQ_BUS_RESUME BIT(8) +#define UDC_IRQ_BUS_SUSPEND BIT(7) +#define UDC_IRQ_BUS_RESET BIT(6) +#define UDC_IRQ_EP0_IN_DATA_NAK BIT(4) +#define UDC_IRQ_EP0_IN_ACK_STALL BIT(3) +#define UDC_IRQ_EP0_OUT_NAK BIT(2) +#define UDC_IRQ_EP0_OUT_ACK_STALL BIT(1) +#define UDC_IRQ_EP0_SETUP BIT(0) +#define UDC_IRQ_ACK_ALL (0x1ff) + +/* EP isr reg */ +#define USB_EP3_ISR BIT(3) +#define USB_EP2_ISR BIT(2) +#define USB_EP1_ISR BIT(1) +#define USB_EP0_ISR BIT(0) +#define UDC_IRQ_EP_ACK_ALL (0xf) + +/*Soft reset reg */ +#define ROOT_UDC_SOFT_RESET BIT(0) + +/* USB status reg */ +#define UDC_STS_HIGHSPEED BIT(27) + +/* Programmable EP data toggle */ +#define EP_TOGGLE_SET_EPNUM(x) ((x) & 0x3) + +/* EP0 ctrl reg */ +#define EP0_GET_RX_LEN(x) ((x >> 16) & 0x7f) +#define EP0_TX_LEN(x) ((x & 0x7f) << 8) +#define EP0_RX_BUFF_RDY BIT(2) +#define EP0_TX_BUFF_RDY BIT(1) +#define EP0_STALL BIT(0) + +/************************************* + * * + * per-endpoint register definitions * + * * + *************************************/ + +#define AST_UDC_EP_CONFIG 0x00 /* Endpoint Configuration Register */ +#define AST_UDC_EP_DMA_CTRL 0x04 /* DMA Descriptor List Control/Status Register */ +#define AST_UDC_EP_DMA_BUFF 0x08 /* DMA Descriptor/Buffer Base Address */ +#define AST_UDC_EP_DMA_STS 0x0C /* DMA Descriptor List R/W Pointer and Status */ + +#define AST_UDC_EP_BASE 0x200 +#define AST_UDC_EP_OFFSET 0x10 + +/* EP config reg */ +#define EP_SET_MAX_PKT(x) ((x & 0x3ff) << 16) +#define EP_DATA_FETCH_CTRL(x) ((x & 0x3) << 14) +#define EP_AUTO_DATA_DISABLE (0x1 << 13) +#define EP_SET_EP_STALL (0x1 << 12) +#define EP_SET_EP_NUM(x) ((x & 0xf) << 8) +#define EP_SET_TYPE_MASK(x) ((x) << 5) +#define EP_TYPE_BULK (0x1) +#define EP_TYPE_INT (0x2) +#define EP_TYPE_ISO (0x3) +#define EP_DIR_OUT (0x1 << 4) +#define EP_ALLOCATED_MASK (0x7 << 1) +#define EP_ENABLE BIT(0) + +/* EP DMA ctrl reg */ +#define EP_DMA_CTRL_GET_PROC_STS(x) ((x >> 4) & 0xf) +#define EP_DMA_CTRL_STS_RX_IDLE 0x0 +#define EP_DMA_CTRL_STS_TX_IDLE 0x8 +#define EP_DMA_CTRL_IN_LONG_MODE (0x1 << 3) +#define EP_DMA_CTRL_RESET (0x1 << 2) +#define EP_DMA_SINGLE_STAGE (0x1 << 1) +#define EP_DMA_DESC_MODE (0x1 << 0) + +/* EP DMA status reg */ +#define EP_DMA_SET_TX_SIZE(x) ((x & 0x7ff) << 16) +#define EP_DMA_GET_TX_SIZE(x) (((x) >> 16) & 0x7ff) +#define EP_DMA_GET_RPTR(x) (((x) >> 8) & 0xff) +#define EP_DMA_GET_WPTR(x) ((x) & 0xff) +#define EP_DMA_SINGLE_KICK (1 << 0) /* WPTR = 1 for single mode */ + +/* EP desc reg */ +#define AST_EP_DMA_DESC_INTR_ENABLE BIT(31) +#define AST_EP_DMA_DESC_PID_DATA0 (0 << 14) +#define AST_EP_DMA_DESC_PID_DATA2 BIT(14) +#define AST_EP_DMA_DESC_PID_DATA1 (2 << 14) +#define AST_EP_DMA_DESC_PID_MDATA (3 << 14) +#define EP_DESC1_IN_LEN(x) ((x) & 0x1fff) +#define AST_EP_DMA_DESC_MAX_LEN (7680) /* Max packet length for trasmit in 1 desc */ + +struct ast_udc_request { + struct usb_request req; + struct list_head queue; + unsigned mapped:1; + unsigned int actual_dma_length; + u32 saved_dma_wptr; +}; + +#define to_ast_req(__req) container_of(__req, struct ast_udc_request, req) + +struct ast_dma_desc { + u32 des_0; + u32 des_1; +}; + +struct ast_udc_ep { + struct usb_ep ep; + + /* Request queue */ + struct list_head queue; + + struct ast_udc_dev *udc; + void __iomem *ep_reg; + void *epn_buf; + dma_addr_t epn_buf_dma; + const struct usb_endpoint_descriptor *desc; + + /* DMA Descriptors */ + struct ast_dma_desc *descs; + dma_addr_t descs_dma; + u32 descs_wptr; + u32 chunk_max; + + bool dir_in:1; + unsigned stopped:1; + bool desc_mode:1; +}; + +#define to_ast_ep(__ep) container_of(__ep, struct ast_udc_ep, ep) + +struct ast_udc_dev { + struct platform_device *pdev; + void __iomem *reg; + int irq; + spinlock_t lock; + struct clk *clk; + struct work_struct wake_work; + + /* EP0 DMA buffers allocated in one chunk */ + void *ep0_buf; + dma_addr_t ep0_buf_dma; + struct ast_udc_ep ep[AST_UDC_NUM_ENDPOINTS]; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + void __iomem *creq; + enum usb_device_state suspended_from; + int desc_mode; + + /* Force full speed only */ + bool force_usb1:1; + unsigned is_control_tx:1; + bool wakeup_en:1; +}; + +#define to_ast_dev(__g) container_of(__g, struct ast_udc_dev, gadget) + +static const char * const ast_ep_name[] = { + "ep0", "ep1", "ep2", "ep3", "ep4" +}; + +#ifdef AST_UDC_DEBUG_ALL +#define AST_UDC_DEBUG +#define AST_SETUP_DEBUG +#define AST_EP_DEBUG +#define AST_ISR_DEBUG +#endif + +#ifdef AST_SETUP_DEBUG +#define SETUP_DBG(u, fmt, ...) \ + dev_dbg(&(u)->pdev->dev, "%s() " fmt, __func__, ##__VA_ARGS__) +#else +#define SETUP_DBG(u, fmt, ...) +#endif + +#ifdef AST_EP_DEBUG +#define EP_DBG(e, fmt, ...) \ + dev_dbg(&(e)->udc->pdev->dev, "%s():%s " fmt, __func__, \ + (e)->ep.name, ##__VA_ARGS__) +#else +#define EP_DBG(ep, fmt, ...) ((void)(ep)) +#endif + +#ifdef AST_UDC_DEBUG +#define UDC_DBG(u, fmt, ...) \ + dev_dbg(&(u)->pdev->dev, "%s() " fmt, __func__, ##__VA_ARGS__) +#else +#define UDC_DBG(u, fmt, ...) +#endif + +#ifdef AST_ISR_DEBUG +#define ISR_DBG(u, fmt, ...) \ + dev_dbg(&(u)->pdev->dev, "%s() " fmt, __func__, ##__VA_ARGS__) +#else +#define ISR_DBG(u, fmt, ...) +#endif + +/*-------------------------------------------------------------------------*/ +#define ast_udc_read(udc, offset) \ + readl((udc)->reg + (offset)) +#define ast_udc_write(udc, val, offset) \ + writel((val), (udc)->reg + (offset)) + +#define ast_ep_read(ep, reg) \ + readl((ep)->ep_reg + (reg)) +#define ast_ep_write(ep, val, reg) \ + writel((val), (ep)->ep_reg + (reg)) + +/*-------------------------------------------------------------------------*/ + +static void ast_udc_done(struct ast_udc_ep *ep, struct ast_udc_request *req, + int status) +{ + struct ast_udc_dev *udc = ep->udc; + + EP_DBG(ep, "req @%p, len (%d/%d), buf:0x%x, dir:0x%x\n", + req, req->req.actual, req->req.length, + (u32)req->req.buf, ep->dir_in); + + list_del(&req->queue); + + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + + if (status && status != -ESHUTDOWN) + EP_DBG(ep, "done req:%p, status:%d\n", req, status); + + spin_unlock(&udc->lock); + usb_gadget_giveback_request(&ep->ep, &req->req); + spin_lock(&udc->lock); +} + +static void ast_udc_nuke(struct ast_udc_ep *ep, int status) +{ + int count = 0; + + while (!list_empty(&ep->queue)) { + struct ast_udc_request *req; + + req = list_entry(ep->queue.next, struct ast_udc_request, + queue); + ast_udc_done(ep, req, status); + count++; + } + + if (count) + EP_DBG(ep, "Nuked %d request(s)\n", count); +} + +/* + * Stop activity on all endpoints. + * Device controller for which EP activity is to be stopped. + * + * All the endpoints are stopped and any pending transfer requests if any on + * the endpoint are terminated. + */ +static void ast_udc_stop_activity(struct ast_udc_dev *udc) +{ + struct ast_udc_ep *ep; + int i; + + for (i = 0; i < AST_UDC_NUM_ENDPOINTS; i++) { + ep = &udc->ep[i]; + ep->stopped = 1; + ast_udc_nuke(ep, -ESHUTDOWN); + } +} + +static int ast_udc_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + u16 maxpacket = usb_endpoint_maxp(desc); + struct ast_udc_ep *ep = to_ast_ep(_ep); + struct ast_udc_dev *udc = ep->udc; + u8 epnum = usb_endpoint_num(desc); + unsigned long flags; + u32 ep_conf = 0; + u8 dir_in; + u8 type; + + if (!_ep || !ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT || + maxpacket == 0 || maxpacket > ep->ep.maxpacket) { + EP_DBG(ep, "Failed, invalid EP enable param\n"); + return -EINVAL; + } + + if (!udc->driver) { + EP_DBG(ep, "bogus device state\n"); + return -ESHUTDOWN; + } + + EP_DBG(ep, "maxpacket:0x%x\n", maxpacket); + + spin_lock_irqsave(&udc->lock, flags); + + ep->desc = desc; + ep->stopped = 0; + ep->ep.maxpacket = maxpacket; + ep->chunk_max = AST_EP_DMA_DESC_MAX_LEN; + + if (maxpacket < AST_UDC_EPn_MAX_PACKET) + ep_conf = EP_SET_MAX_PKT(maxpacket); + + ep_conf |= EP_SET_EP_NUM(epnum); + + type = usb_endpoint_type(desc); + dir_in = usb_endpoint_dir_in(desc); + ep->dir_in = dir_in; + if (!ep->dir_in) + ep_conf |= EP_DIR_OUT; + + EP_DBG(ep, "type %d, dir_in %d\n", type, dir_in); + switch (type) { + case USB_ENDPOINT_XFER_ISOC: + ep_conf |= EP_SET_TYPE_MASK(EP_TYPE_ISO); + break; + + case USB_ENDPOINT_XFER_BULK: + ep_conf |= EP_SET_TYPE_MASK(EP_TYPE_BULK); + break; + + case USB_ENDPOINT_XFER_INT: + ep_conf |= EP_SET_TYPE_MASK(EP_TYPE_INT); + break; + } + + ep->desc_mode = udc->desc_mode && ep->descs_dma && ep->dir_in; + if (ep->desc_mode) { + ast_ep_write(ep, EP_DMA_CTRL_RESET, AST_UDC_EP_DMA_CTRL); + ast_ep_write(ep, 0, AST_UDC_EP_DMA_STS); + ast_ep_write(ep, ep->descs_dma, AST_UDC_EP_DMA_BUFF); + + /* Enable Long Descriptor Mode */ + ast_ep_write(ep, EP_DMA_CTRL_IN_LONG_MODE | EP_DMA_DESC_MODE, + AST_UDC_EP_DMA_CTRL); + + ep->descs_wptr = 0; + + } else { + ast_ep_write(ep, EP_DMA_CTRL_RESET, AST_UDC_EP_DMA_CTRL); + ast_ep_write(ep, EP_DMA_SINGLE_STAGE, AST_UDC_EP_DMA_CTRL); + ast_ep_write(ep, 0, AST_UDC_EP_DMA_STS); + } + + /* Cleanup data toggle just in case */ + ast_udc_write(udc, EP_TOGGLE_SET_EPNUM(epnum), AST_VHUB_EP_DATA); + + /* Enable EP */ + ast_ep_write(ep, ep_conf | EP_ENABLE, AST_UDC_EP_CONFIG); + + EP_DBG(ep, "ep_config: 0x%x\n", ast_ep_read(ep, AST_UDC_EP_CONFIG)); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int ast_udc_ep_disable(struct usb_ep *_ep) +{ + struct ast_udc_ep *ep = to_ast_ep(_ep); + struct ast_udc_dev *udc = ep->udc; + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + + ep->ep.desc = NULL; + ep->stopped = 1; + + ast_udc_nuke(ep, -ESHUTDOWN); + ast_ep_write(ep, 0, AST_UDC_EP_CONFIG); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static struct usb_request *ast_udc_ep_alloc_request(struct usb_ep *_ep, + gfp_t gfp_flags) +{ + struct ast_udc_ep *ep = to_ast_ep(_ep); + struct ast_udc_request *req; + + req = kzalloc(sizeof(struct ast_udc_request), gfp_flags); + if (!req) { + EP_DBG(ep, "request allocation failed\n"); + return NULL; + } + + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +static void ast_udc_ep_free_request(struct usb_ep *_ep, + struct usb_request *_req) +{ + struct ast_udc_request *req = to_ast_req(_req); + + kfree(req); +} + +static int ast_dma_descriptor_setup(struct ast_udc_ep *ep, u32 dma_buf, + u16 tx_len, struct ast_udc_request *req) +{ + struct ast_udc_dev *udc = ep->udc; + struct device *dev = &udc->pdev->dev; + u32 offset, chunk; + int count, last; + + if (!ep->descs) { + dev_warn(dev, "%s: Empty DMA descs list failure\n", + ep->ep.name); + return -EINVAL; + } + + chunk = tx_len; + offset = count = last = 0; + + EP_DBG(ep, "req @%p, %s:%d, %s:0x%x, %s:0x%x\n", req, + "wptr", ep->descs_wptr, "dma_buf", dma_buf, + "tx_len", tx_len); + + /* Create Descriptor Lists */ + while (chunk >= 0 && !last && count < AST_UDC_DESCS_COUNT) { + + ep->descs[ep->descs_wptr].des_0 = dma_buf + offset; + + if (chunk <= ep->chunk_max) { + ep->descs[ep->descs_wptr].des_1 = chunk; + last = 1; + } else { + ep->descs[ep->descs_wptr].des_1 = ep->chunk_max; + chunk -= ep->chunk_max; + } + + EP_DBG(ep, "descs[%d]: 0x%x 0x%x, last:%d\n", + ep->descs_wptr, + ep->descs[ep->descs_wptr].des_0, + ep->descs[ep->descs_wptr].des_1, + last); + + if (count == 0) + req->saved_dma_wptr = ep->descs_wptr; + + ep->descs_wptr++; + count++; + + if (ep->descs_wptr >= AST_UDC_DESCS_COUNT) + ep->descs_wptr = 0; + + offset = ep->chunk_max * count; + } + + return 0; +} + +static void ast_udc_epn_kick(struct ast_udc_ep *ep, struct ast_udc_request *req) +{ + u32 tx_len; + u32 last; + + last = req->req.length - req->req.actual; + tx_len = last > ep->ep.maxpacket ? ep->ep.maxpacket : last; + + EP_DBG(ep, "kick req @%p, len:%d, dir:%d\n", + req, tx_len, ep->dir_in); + + ast_ep_write(ep, req->req.dma + req->req.actual, AST_UDC_EP_DMA_BUFF); + + /* Start DMA */ + ast_ep_write(ep, EP_DMA_SET_TX_SIZE(tx_len), AST_UDC_EP_DMA_STS); + ast_ep_write(ep, EP_DMA_SET_TX_SIZE(tx_len) | EP_DMA_SINGLE_KICK, + AST_UDC_EP_DMA_STS); +} + +static void ast_udc_epn_kick_desc(struct ast_udc_ep *ep, + struct ast_udc_request *req) +{ + u32 descs_max_size; + u32 tx_len; + u32 last; + + descs_max_size = AST_EP_DMA_DESC_MAX_LEN * AST_UDC_DESCS_COUNT; + + last = req->req.length - req->req.actual; + tx_len = last > descs_max_size ? descs_max_size : last; + + EP_DBG(ep, "kick req @%p, %s:%d, %s:0x%x, %s:0x%x (%d/%d), %s:0x%x\n", + req, "tx_len", tx_len, "dir_in", ep->dir_in, + "dma", req->req.dma + req->req.actual, + req->req.actual, req->req.length, + "descs_max_size", descs_max_size); + + if (!ast_dma_descriptor_setup(ep, req->req.dma + req->req.actual, + tx_len, req)) + req->actual_dma_length += tx_len; + + /* make sure CPU done everything before triggering DMA */ + mb(); + + ast_ep_write(ep, ep->descs_wptr, AST_UDC_EP_DMA_STS); + + EP_DBG(ep, "descs_wptr:%d, dstat:0x%x, dctrl:0x%x\n", + ep->descs_wptr, + ast_ep_read(ep, AST_UDC_EP_DMA_STS), + ast_ep_read(ep, AST_UDC_EP_DMA_CTRL)); +} + +static void ast_udc_ep0_queue(struct ast_udc_ep *ep, + struct ast_udc_request *req) +{ + struct ast_udc_dev *udc = ep->udc; + u32 tx_len; + u32 last; + + last = req->req.length - req->req.actual; + tx_len = last > ep->ep.maxpacket ? ep->ep.maxpacket : last; + + ast_udc_write(udc, req->req.dma + req->req.actual, + AST_UDC_EP0_DATA_BUFF); + + if (ep->dir_in) { + /* IN requests, send data */ + SETUP_DBG(udc, "IN: %s:0x%x, %s:0x%x, %s:%d (%d/%d), %s:%d\n", + "buf", (u32)req->req.buf, + "dma", req->req.dma + req->req.actual, + "tx_len", tx_len, + req->req.actual, req->req.length, + "dir_in", ep->dir_in); + + req->req.actual += tx_len; + ast_udc_write(udc, EP0_TX_LEN(tx_len), AST_UDC_EP0_CTRL); + ast_udc_write(udc, EP0_TX_LEN(tx_len) | EP0_TX_BUFF_RDY, + AST_UDC_EP0_CTRL); + + } else { + /* OUT requests, receive data */ + SETUP_DBG(udc, "OUT: %s:%x, %s:%x, %s:(%d/%d), %s:%d\n", + "buf", (u32)req->req.buf, + "dma", req->req.dma + req->req.actual, + "len", req->req.actual, req->req.length, + "dir_in", ep->dir_in); + + if (!req->req.length) { + /* 0 len request, send tx as completion */ + ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); + ep->dir_in = 0x1; + } else + ast_udc_write(udc, EP0_RX_BUFF_RDY, AST_UDC_EP0_CTRL); + } +} + +static int ast_udc_ep_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t gfp_flags) +{ + struct ast_udc_request *req = to_ast_req(_req); + struct ast_udc_ep *ep = to_ast_ep(_ep); + struct ast_udc_dev *udc = ep->udc; + struct device *dev = &udc->pdev->dev; + unsigned long flags; + int rc; + + if (unlikely(!_req || !_req->complete || !_req->buf || !_ep)) { + dev_warn(dev, "Invalid EP request !\n"); + return -EINVAL; + } + + if (ep->stopped) { + dev_warn(dev, "%s is already stopped !\n", _ep->name); + return -ESHUTDOWN; + } + + spin_lock_irqsave(&udc->lock, flags); + + list_add_tail(&req->queue, &ep->queue); + + req->req.actual = 0; + req->req.status = -EINPROGRESS; + req->actual_dma_length = 0; + + rc = usb_gadget_map_request(&udc->gadget, &req->req, ep->dir_in); + if (rc) { + EP_DBG(ep, "Request mapping failure %d\n", rc); + dev_warn(dev, "Request mapping failure %d\n", rc); + goto end; + } + + EP_DBG(ep, "enqueue req @%p\n", req); + EP_DBG(ep, "l=%d, dma:0x%x, zero:%d, is_in:%d\n", + _req->length, _req->dma, _req->zero, ep->dir_in); + + /* EP0 request enqueue */ + if (ep->ep.desc == NULL) { + if ((req->req.dma % 4) != 0) { + dev_warn(dev, "EP0 req dma alignment error\n"); + return -ESHUTDOWN; + } + + ast_udc_ep0_queue(ep, req); + goto end; + } + + /* EPn request enqueue */ + if (list_is_singular(&ep->queue)) { + if (ep->desc_mode) + ast_udc_epn_kick_desc(ep, req); + else + ast_udc_epn_kick(ep, req); + } + +end: + spin_unlock_irqrestore(&udc->lock, flags); + + return rc; +} + +static int ast_udc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct ast_udc_ep *ep = to_ast_ep(_ep); + struct ast_udc_dev *udc = ep->udc; + struct ast_udc_request *req; + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&udc->lock, flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) { + list_del_init(&req->queue); + ast_udc_done(ep, req, -ESHUTDOWN); + _req->status = -ECONNRESET; + break; + } + } + + /* dequeue request not found */ + if (&req->req != _req) + rc = -EINVAL; + + spin_unlock_irqrestore(&udc->lock, flags); + + return rc; +} + +static int ast_udc_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct ast_udc_ep *ep = to_ast_ep(_ep); + struct ast_udc_dev *udc = ep->udc; + unsigned long flags; + int epnum; + u32 ctrl; + + EP_DBG(ep, "val:%d\n", value); + + spin_lock_irqsave(&udc->lock, flags); + + epnum = usb_endpoint_num(ep->desc); + + /* EP0 */ + if (epnum == 0) { + ctrl = ast_udc_read(udc, AST_UDC_EP0_CTRL); + if (value) + ctrl |= EP0_STALL; + else + ctrl &= ~EP0_STALL; + + ast_udc_write(udc, ctrl, AST_UDC_EP0_CTRL); + + } else { + /* EPn */ + ctrl = ast_udc_read(udc, AST_UDC_EP_CONFIG); + if (value) + ctrl |= EP_SET_EP_STALL; + else + ctrl &= ~EP_SET_EP_STALL; + + ast_ep_write(ep, ctrl, AST_UDC_EP_CONFIG); + + /* only epn is stopped and waits for clear */ + ep->stopped = value ? 1 : 0; + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static const struct usb_ep_ops ast_udc_ep_ops = { + .enable = ast_udc_ep_enable, + .disable = ast_udc_ep_disable, + .alloc_request = ast_udc_ep_alloc_request, + .free_request = ast_udc_ep_free_request, + .queue = ast_udc_ep_queue, + .dequeue = ast_udc_ep_dequeue, + .set_halt = ast_udc_ep_set_halt, + /* there's only imprecise fifo status reporting */ +}; + +static void ast_udc_ep0_rx(struct ast_udc_dev *udc) +{ + ast_udc_write(udc, udc->ep0_buf_dma, AST_UDC_EP0_DATA_BUFF); + ast_udc_write(udc, EP0_RX_BUFF_RDY, AST_UDC_EP0_CTRL); +} + +static void ast_udc_ep0_tx(struct ast_udc_dev *udc) +{ + ast_udc_write(udc, udc->ep0_buf_dma, AST_UDC_EP0_DATA_BUFF); + ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); +} + +static void ast_udc_ep0_out(struct ast_udc_dev *udc) +{ + struct device *dev = &udc->pdev->dev; + struct ast_udc_ep *ep = &udc->ep[0]; + struct ast_udc_request *req; + u16 rx_len; + + if (list_empty(&ep->queue)) + return; + + req = list_entry(ep->queue.next, struct ast_udc_request, queue); + + rx_len = EP0_GET_RX_LEN(ast_udc_read(udc, AST_UDC_EP0_CTRL)); + req->req.actual += rx_len; + + SETUP_DBG(udc, "req %p (%d/%d)\n", req, + req->req.actual, req->req.length); + + if ((rx_len < ep->ep.maxpacket) || + (req->req.actual == req->req.length)) { + ast_udc_ep0_tx(udc); + if (!ep->dir_in) + ast_udc_done(ep, req, 0); + + } else { + if (rx_len > req->req.length) { + // Issue Fix + dev_warn(dev, "Something wrong (%d/%d)\n", + req->req.actual, req->req.length); + ast_udc_ep0_tx(udc); + ast_udc_done(ep, req, 0); + return; + } + + ep->dir_in = 0; + + /* More works */ + ast_udc_ep0_queue(ep, req); + } +} + +static void ast_udc_ep0_in(struct ast_udc_dev *udc) +{ + struct ast_udc_ep *ep = &udc->ep[0]; + struct ast_udc_request *req; + + if (list_empty(&ep->queue)) { + if (udc->is_control_tx) { + ast_udc_ep0_rx(udc); + udc->is_control_tx = 0; + } + + return; + } + + req = list_entry(ep->queue.next, struct ast_udc_request, queue); + + SETUP_DBG(udc, "req %p (%d/%d)\n", req, + req->req.actual, req->req.length); + + if (req->req.length == req->req.actual) { + if (req->req.length) + ast_udc_ep0_rx(udc); + + if (ep->dir_in) + ast_udc_done(ep, req, 0); + + } else { + /* More works */ + ast_udc_ep0_queue(ep, req); + } +} + +static void ast_udc_epn_handle(struct ast_udc_dev *udc, u16 ep_num) +{ + struct ast_udc_ep *ep = &udc->ep[ep_num]; + struct ast_udc_request *req; + u16 len = 0; + + if (list_empty(&ep->queue)) + return; + + req = list_first_entry(&ep->queue, struct ast_udc_request, queue); + + len = EP_DMA_GET_TX_SIZE(ast_ep_read(ep, AST_UDC_EP_DMA_STS)); + req->req.actual += len; + + EP_DBG(ep, "req @%p, length:(%d/%d), %s:0x%x\n", req, + req->req.actual, req->req.length, "len", len); + + /* Done this request */ + if (req->req.length == req->req.actual) { + ast_udc_done(ep, req, 0); + req = list_first_entry_or_null(&ep->queue, + struct ast_udc_request, + queue); + + } else { + /* Check for short packet */ + if (len < ep->ep.maxpacket) { + ast_udc_done(ep, req, 0); + req = list_first_entry_or_null(&ep->queue, + struct ast_udc_request, + queue); + } + } + + /* More requests */ + if (req) + ast_udc_epn_kick(ep, req); +} + +static void ast_udc_epn_handle_desc(struct ast_udc_dev *udc, u16 ep_num) +{ + struct ast_udc_ep *ep = &udc->ep[ep_num]; + struct device *dev = &udc->pdev->dev; + struct ast_udc_request *req; + u32 proc_sts, wr_ptr, rd_ptr; + u32 len_in_desc, ctrl; + u16 total_len = 0; + int i; + + if (list_empty(&ep->queue)) { + dev_warn(dev, "%s reqest queue empty !\n", ep->ep.name); + return; + } + + req = list_first_entry(&ep->queue, struct ast_udc_request, queue); + + ctrl = ast_ep_read(ep, AST_UDC_EP_DMA_CTRL); + proc_sts = EP_DMA_CTRL_GET_PROC_STS(ctrl); + + /* Check processing status is idle */ + if (proc_sts != EP_DMA_CTRL_STS_RX_IDLE && + proc_sts != EP_DMA_CTRL_STS_TX_IDLE) { + dev_warn(dev, "EP DMA CTRL: 0x%x, PS:0x%x\n", + ast_ep_read(ep, AST_UDC_EP_DMA_CTRL), + proc_sts); + return; + } + + ctrl = ast_ep_read(ep, AST_UDC_EP_DMA_STS); + rd_ptr = EP_DMA_GET_RPTR(ctrl); + wr_ptr = EP_DMA_GET_WPTR(ctrl); + + if (rd_ptr != wr_ptr) { + dev_warn(dev, "desc list is not empty ! %s:%d, %s:%d\n", + "rptr", rd_ptr, "wptr", wr_ptr); + return; + } + + EP_DBG(ep, "rd_ptr:%d, wr_ptr:%d\n", rd_ptr, wr_ptr); + i = req->saved_dma_wptr; + + do { + len_in_desc = EP_DESC1_IN_LEN(ep->descs[i].des_1); + EP_DBG(ep, "desc[%d] len: %d\n", i, len_in_desc); + total_len += len_in_desc; + i++; + if (i >= AST_UDC_DESCS_COUNT) + i = 0; + + } while (i != wr_ptr); + + req->req.actual += total_len; + + EP_DBG(ep, "req @%p, length:(%d/%d), %s:0x%x\n", req, + req->req.actual, req->req.length, "len", total_len); + + /* Done this request */ + if (req->req.length == req->req.actual) { + ast_udc_done(ep, req, 0); + req = list_first_entry_or_null(&ep->queue, + struct ast_udc_request, + queue); + + } else { + /* Check for short packet */ + if (total_len < ep->ep.maxpacket) { + ast_udc_done(ep, req, 0); + req = list_first_entry_or_null(&ep->queue, + struct ast_udc_request, + queue); + } + } + + /* More requests & dma descs not setup yet */ + if (req && (req->actual_dma_length == req->req.actual)) { + EP_DBG(ep, "More requests\n"); + ast_udc_epn_kick_desc(ep, req); + } +} + +static void ast_udc_ep0_data_tx(struct ast_udc_dev *udc, u8 *tx_data, u32 len) +{ + if (len) { + memcpy(udc->ep0_buf, tx_data, len); + + ast_udc_write(udc, udc->ep0_buf_dma, AST_UDC_EP0_DATA_BUFF); + ast_udc_write(udc, EP0_TX_LEN(len), AST_UDC_EP0_CTRL); + ast_udc_write(udc, EP0_TX_LEN(len) | EP0_TX_BUFF_RDY, + AST_UDC_EP0_CTRL); + udc->is_control_tx = 1; + + } else + ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); +} + +static void ast_udc_getstatus(struct ast_udc_dev *udc) +{ + struct usb_ctrlrequest crq; + struct ast_udc_ep *ep; + u16 status = 0; + u16 epnum = 0; + + memcpy_fromio(&crq, udc->creq, sizeof(crq)); + + switch (crq.bRequestType & USB_RECIP_MASK) { + case USB_RECIP_DEVICE: + /* Get device status */ + status = 1 << USB_DEVICE_SELF_POWERED; + break; + case USB_RECIP_INTERFACE: + break; + case USB_RECIP_ENDPOINT: + epnum = crq.wIndex & USB_ENDPOINT_NUMBER_MASK; + status = udc->ep[epnum].stopped; + break; + default: + goto stall; + } + + ep = &udc->ep[epnum]; + EP_DBG(ep, "status: 0x%x\n", status); + ast_udc_ep0_data_tx(udc, (u8 *)&status, sizeof(status)); + + return; + +stall: + EP_DBG(ep, "Can't respond request\n"); + ast_udc_write(udc, ast_udc_read(udc, AST_UDC_EP0_CTRL) | EP0_STALL, + AST_UDC_EP0_CTRL); +} + +static void ast_udc_ep0_handle_setup(struct ast_udc_dev *udc) +{ + struct ast_udc_ep *ep = &udc->ep[0]; + struct ast_udc_request *req; + struct usb_ctrlrequest crq; + int req_num = 0; + int rc = 0; + u32 reg; + + memcpy_fromio(&crq, udc->creq, sizeof(crq)); + + SETUP_DBG(udc, "SETEUP packet: %02x/%02x/%04x/%04x/%04x\n", + crq.bRequestType, crq.bRequest, le16_to_cpu(crq.wValue), + le16_to_cpu(crq.wIndex), le16_to_cpu(crq.wLength)); + + /* + * Cleanup ep0 request(s) in queue because + * there is a new control setup comes. + */ + list_for_each_entry(req, &udc->ep[0].queue, queue) { + req_num++; + EP_DBG(ep, "there is req %p in ep0 queue !\n", req); + } + + if (req_num) + ast_udc_nuke(&udc->ep[0], -ETIMEDOUT); + + udc->ep[0].dir_in = crq.bRequestType & USB_DIR_IN; + + if ((crq.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { + switch (crq.bRequest) { + case USB_REQ_SET_ADDRESS: + if (ast_udc_read(udc, AST_UDC_STS) & UDC_STS_HIGHSPEED) + udc->gadget.speed = USB_SPEED_HIGH; + else + udc->gadget.speed = USB_SPEED_FULL; + + SETUP_DBG(udc, "set addr: 0x%x\n", crq.wValue); + reg = ast_udc_read(udc, AST_UDC_CONFIG); + reg &= ~UDC_CFG_ADDR_MASK; + reg |= UDC_CFG_SET_ADDR(crq.wValue); + ast_udc_write(udc, reg, AST_UDC_CONFIG); + goto req_complete; + + case USB_REQ_CLEAR_FEATURE: + SETUP_DBG(udc, "ep0: CLEAR FEATURE\n"); + goto req_driver; + + case USB_REQ_SET_FEATURE: + SETUP_DBG(udc, "ep0: SET FEATURE\n"); + goto req_driver; + + case USB_REQ_GET_STATUS: + ast_udc_getstatus(udc); + return; + + default: + goto req_driver; + } + + } + +req_driver: + if (udc->driver) { + SETUP_DBG(udc, "Forwarding %s to gadget...\n", + udc->gadget.name); + + spin_unlock(&udc->lock); + rc = udc->driver->setup(&udc->gadget, &crq); + spin_lock(&udc->lock); + + } else { + SETUP_DBG(udc, "No gadget for request !\n"); + } + + if (rc >= 0) + return; + + /* Stall if gadget failed */ + SETUP_DBG(udc, "Stalling, rc:0x%x\n", rc); + ast_udc_write(udc, ast_udc_read(udc, AST_UDC_EP0_CTRL) | EP0_STALL, + AST_UDC_EP0_CTRL); + return; + +req_complete: + SETUP_DBG(udc, "ep0: Sending IN status without data\n"); + ast_udc_write(udc, EP0_TX_BUFF_RDY, AST_UDC_EP0_CTRL); +} + +static irqreturn_t ast_udc_isr(int irq, void *data) +{ + struct ast_udc_dev *udc = (struct ast_udc_dev *)data; + struct ast_udc_ep *ep; + u32 isr, ep_isr; + int i; + + spin_lock(&udc->lock); + + isr = ast_udc_read(udc, AST_UDC_ISR); + if (!isr) + goto done; + + /* Ack interrupts */ + ast_udc_write(udc, isr, AST_UDC_ISR); + + if (isr & UDC_IRQ_BUS_RESET) { + ISR_DBG(udc, "UDC_IRQ_BUS_RESET\n"); + udc->gadget.speed = USB_SPEED_UNKNOWN; + + ep = &udc->ep[1]; + EP_DBG(ep, "dctrl:0x%x\n", + ast_ep_read(ep, AST_UDC_EP_DMA_CTRL)); + + if (udc->driver && udc->driver->reset) { + spin_unlock(&udc->lock); + udc->driver->reset(&udc->gadget); + spin_lock(&udc->lock); + } + } + + if (isr & UDC_IRQ_BUS_SUSPEND) { + ISR_DBG(udc, "UDC_IRQ_BUS_SUSPEND\n"); + udc->suspended_from = udc->gadget.state; + usb_gadget_set_state(&udc->gadget, USB_STATE_SUSPENDED); + + if (udc->driver && udc->driver->suspend) { + spin_unlock(&udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } + } + + if (isr & UDC_IRQ_BUS_RESUME) { + ISR_DBG(udc, "UDC_IRQ_BUS_RESUME\n"); + usb_gadget_set_state(&udc->gadget, udc->suspended_from); + + if (udc->driver && udc->driver->resume) { + spin_unlock(&udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + } + } + + if (isr & UDC_IRQ_EP0_IN_ACK_STALL) { + ISR_DBG(udc, "UDC_IRQ_EP0_IN_ACK_STALL\n"); + ast_udc_ep0_in(udc); + } + + if (isr & UDC_IRQ_EP0_OUT_ACK_STALL) { + ISR_DBG(udc, "UDC_IRQ_EP0_OUT_ACK_STALL\n"); + ast_udc_ep0_out(udc); + } + + if (isr & UDC_IRQ_EP0_SETUP) { + ISR_DBG(udc, "UDC_IRQ_EP0_SETUP\n"); + ast_udc_ep0_handle_setup(udc); + } + + if (isr & UDC_IRQ_EP_POOL_ACK_STALL) { + ISR_DBG(udc, "UDC_IRQ_EP_POOL_ACK_STALL\n"); + ep_isr = ast_udc_read(udc, AST_UDC_EP_ACK_ISR); + + /* Ack EP interrupts */ + ast_udc_write(udc, ep_isr, AST_UDC_EP_ACK_ISR); + + /* Handle each EP */ + for (i = 0; i < AST_UDC_NUM_ENDPOINTS - 1; i++) { + if (ep_isr & (0x1 << i)) { + ep = &udc->ep[i + 1]; + if (ep->desc_mode) + ast_udc_epn_handle_desc(udc, i + 1); + else + ast_udc_epn_handle(udc, i + 1); + } + } + } + +done: + spin_unlock(&udc->lock); + return IRQ_HANDLED; +} + +static int ast_udc_gadget_getframe(struct usb_gadget *gadget) +{ + struct ast_udc_dev *udc = to_ast_dev(gadget); + + return (ast_udc_read(udc, AST_UDC_STS) >> 16) & 0x7ff; +} + +static void ast_udc_wake_work(struct work_struct *work) +{ + struct ast_udc_dev *udc = container_of(work, struct ast_udc_dev, + wake_work); + unsigned long flags; + u32 ctrl; + + spin_lock_irqsave(&udc->lock, flags); + + UDC_DBG(udc, "Wakeup Host !\n"); + ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL); + ast_udc_write(udc, ctrl | USB_REMOTE_WAKEUP_EN, AST_UDC_FUNC_CTRL); + + spin_unlock_irqrestore(&udc->lock, flags); +} + +static void ast_udc_wakeup_all(struct ast_udc_dev *udc) +{ + /* + * A device is trying to wake the world, because this + * can recurse into the device, we break the call chain + * using a work queue + */ + schedule_work(&udc->wake_work); +} + +static int ast_udc_wakeup(struct usb_gadget *gadget) +{ + struct ast_udc_dev *udc = to_ast_dev(gadget); + unsigned long flags; + int rc = 0; + + spin_lock_irqsave(&udc->lock, flags); + + if (!udc->wakeup_en) { + UDC_DBG(udc, "Remote Wakeup is disabled\n"); + rc = -EINVAL; + goto err; + } + + UDC_DBG(udc, "Device initiated wakeup\n"); + ast_udc_wakeup_all(udc); + +err: + spin_unlock_irqrestore(&udc->lock, flags); + return rc; +} + +/* + * Activate/Deactivate link with host + */ +static int ast_udc_pullup(struct usb_gadget *gadget, int is_on) +{ + struct ast_udc_dev *udc = to_ast_dev(gadget); + unsigned long flags; + u32 ctrl; + + spin_lock_irqsave(&udc->lock, flags); + + UDC_DBG(udc, "is_on: %d\n", is_on); + if (is_on) + ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) | USB_UPSTREAM_EN; + else + ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) & ~USB_UPSTREAM_EN; + + ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int ast_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct ast_udc_dev *udc = to_ast_dev(gadget); + struct ast_udc_ep *ep; + unsigned long flags; + int i; + + spin_lock_irqsave(&udc->lock, flags); + + UDC_DBG(udc, "\n"); + udc->driver = driver; + udc->gadget.dev.of_node = udc->pdev->dev.of_node; + + for (i = 0; i < AST_UDC_NUM_ENDPOINTS; i++) { + ep = &udc->ep[i]; + ep->stopped = 0; + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int ast_udc_stop(struct usb_gadget *gadget) +{ + struct ast_udc_dev *udc = to_ast_dev(gadget); + unsigned long flags; + u32 ctrl; + + spin_lock_irqsave(&udc->lock, flags); + + UDC_DBG(udc, "\n"); + ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) & ~USB_UPSTREAM_EN; + ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); + + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->driver = NULL; + + ast_udc_stop_activity(udc); + usb_gadget_set_state(&udc->gadget, USB_STATE_NOTATTACHED); + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static const struct usb_gadget_ops ast_udc_ops = { + .get_frame = ast_udc_gadget_getframe, + .wakeup = ast_udc_wakeup, + .pullup = ast_udc_pullup, + .udc_start = ast_udc_start, + .udc_stop = ast_udc_stop, +}; + +/* + * Support 1 Control Endpoint. + * Support multiple programmable endpoints that can be configured to + * Bulk IN/OUT, Interrupt IN/OUT, and Isochronous IN/OUT type endpoint. + */ +static void ast_udc_init_ep(struct ast_udc_dev *udc) +{ + struct ast_udc_ep *ep; + int i; + + for (i = 0; i < AST_UDC_NUM_ENDPOINTS; i++) { + ep = &udc->ep[i]; + ep->ep.name = ast_ep_name[i]; + if (i == 0) { + ep->ep.caps.type_control = true; + } else { + ep->ep.caps.type_iso = true; + ep->ep.caps.type_bulk = true; + ep->ep.caps.type_int = true; + } + ep->ep.caps.dir_in = true; + ep->ep.caps.dir_out = true; + + ep->ep.ops = &ast_udc_ep_ops; + ep->udc = udc; + + INIT_LIST_HEAD(&ep->queue); + + if (i == 0) { + usb_ep_set_maxpacket_limit(&ep->ep, + AST_UDC_EP0_MAX_PACKET); + continue; + } + + ep->ep_reg = udc->reg + AST_UDC_EP_BASE + + (AST_UDC_EP_OFFSET * (i - 1)); + + ep->epn_buf = udc->ep0_buf + (i * AST_UDC_EP_DMA_SIZE); + ep->epn_buf_dma = udc->ep0_buf_dma + (i * AST_UDC_EP_DMA_SIZE); + usb_ep_set_maxpacket_limit(&ep->ep, AST_UDC_EPn_MAX_PACKET); + + ep->descs = ep->epn_buf + AST_UDC_EPn_MAX_PACKET; + ep->descs_dma = ep->epn_buf_dma + AST_UDC_EPn_MAX_PACKET; + ep->descs_wptr = 0; + + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + } +} + +static void ast_udc_init_dev(struct ast_udc_dev *udc) +{ + INIT_WORK(&udc->wake_work, ast_udc_wake_work); +} + +static void ast_udc_init_hw(struct ast_udc_dev *udc) +{ + u32 ctrl; + + /* Enable PHY */ + ctrl = USB_PHY_CLK_EN | USB_PHY_RESET_DIS; + ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); + + udelay(1); + ast_udc_write(udc, 0, AST_UDC_DEV_RESET); + + /* Set descriptor ring size */ + if (AST_UDC_DESCS_COUNT == 256) { + ctrl |= USB_EP_LONG_DESC; + ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); + } + + /* Mask & ack all interrupts before installing the handler */ + ast_udc_write(udc, 0, AST_UDC_IER); + ast_udc_write(udc, UDC_IRQ_ACK_ALL, AST_UDC_ISR); + + /* Enable some interrupts */ + ctrl = UDC_IRQ_EP_POOL_ACK_STALL | UDC_IRQ_BUS_RESUME | + UDC_IRQ_BUS_SUSPEND | UDC_IRQ_BUS_RESET | + UDC_IRQ_EP0_IN_ACK_STALL | UDC_IRQ_EP0_OUT_ACK_STALL | + UDC_IRQ_EP0_SETUP; + ast_udc_write(udc, ctrl, AST_UDC_IER); + + /* Cleanup and enable ep ACK interrupts */ + ast_udc_write(udc, UDC_IRQ_EP_ACK_ALL, AST_UDC_EP_ACK_IER); + ast_udc_write(udc, UDC_IRQ_EP_ACK_ALL, AST_UDC_EP_ACK_ISR); + + ast_udc_write(udc, 0, AST_UDC_EP0_CTRL); +} + +static int ast_udc_remove(struct platform_device *pdev) +{ + struct ast_udc_dev *udc = platform_get_drvdata(pdev); + unsigned long flags; + u32 ctrl; + + usb_del_gadget_udc(&udc->gadget); + if (udc->driver) + return -EBUSY; + + spin_lock_irqsave(&udc->lock, flags); + + /* Disable upstream port connection */ + ctrl = ast_udc_read(udc, AST_UDC_FUNC_CTRL) & ~USB_UPSTREAM_EN; + ast_udc_write(udc, ctrl, AST_UDC_FUNC_CTRL); + + clk_disable_unprepare(udc->clk); + + spin_unlock_irqrestore(&udc->lock, flags); + + if (udc->ep0_buf) + dma_free_coherent(&pdev->dev, + AST_UDC_EP_DMA_SIZE * AST_UDC_NUM_ENDPOINTS, + udc->ep0_buf, + udc->ep0_buf_dma); + + udc->ep0_buf = NULL; + + return 0; +} + +static int ast_udc_probe(struct platform_device *pdev) +{ + enum usb_device_speed max_speed; + struct device *dev = &pdev->dev; + struct ast_udc_dev *udc; + struct resource *res; + int rc; + + udc = devm_kzalloc(&pdev->dev, sizeof(struct ast_udc_dev), GFP_KERNEL); + if (!udc) + return -ENOMEM; + + udc->gadget.dev.parent = dev; + udc->pdev = pdev; + spin_lock_init(&udc->lock); + + udc->gadget.ops = &ast_udc_ops; + udc->gadget.ep0 = &udc->ep[0].ep; + udc->gadget.name = "aspeed-udc"; + udc->gadget.dev.init_name = "gadget"; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + udc->reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(udc->reg)) { + dev_err(&pdev->dev, "Failed to map resources\n"); + return PTR_ERR(udc->reg); + } + + platform_set_drvdata(pdev, udc); + + udc->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(udc->clk)) { + rc = PTR_ERR(udc->clk); + goto err; + } + rc = clk_prepare_enable(udc->clk); + if (rc) { + dev_err(&pdev->dev, "Failed to enable clock (0x%x)\n", rc); + goto err; + } + + /* Check if we need to limit the HW to USB1 */ + max_speed = usb_get_maximum_speed(&pdev->dev); + if (max_speed != USB_SPEED_UNKNOWN && max_speed < USB_SPEED_HIGH) + udc->force_usb1 = true; + + /* + * Allocate DMA buffers for all EPs in one chunk + */ + udc->ep0_buf = dma_alloc_coherent(&pdev->dev, + AST_UDC_EP_DMA_SIZE * + AST_UDC_NUM_ENDPOINTS, + &udc->ep0_buf_dma, GFP_KERNEL); + + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.max_speed = USB_SPEED_HIGH; + udc->creq = udc->reg + AST_UDC_SETUP0; + + /* + * Support single stage mode or 32/256 stages descriptor mode. + * Set default as Descriptor Mode. + */ + udc->desc_mode = AST_UDC_DESC_MODE; + + dev_info(&pdev->dev, "DMA %s\n", udc->desc_mode ? + "descriptor mode" : "single mode"); + + INIT_LIST_HEAD(&udc->gadget.ep_list); + INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); + + /* Initialized udc ep */ + ast_udc_init_ep(udc); + + /* Initialized udc device */ + ast_udc_init_dev(udc); + + /* Initialized udc hardware */ + ast_udc_init_hw(udc); + + /* Find interrupt and install handler */ + udc->irq = platform_get_irq(pdev, 0); + if (udc->irq < 0) { + dev_err(&pdev->dev, "Failed to get interrupt\n"); + rc = udc->irq; + goto err; + } + + rc = devm_request_irq(&pdev->dev, udc->irq, ast_udc_isr, 0, + KBUILD_MODNAME, udc); + if (rc) { + dev_err(&pdev->dev, "Failed to request interrupt\n"); + goto err; + } + + rc = usb_add_gadget_udc(&pdev->dev, &udc->gadget); + if (rc) { + dev_err(&pdev->dev, "Failed to add gadget udc\n"); + goto err; + } + + dev_info(&pdev->dev, "Initialized udc in USB%s mode\n", + udc->force_usb1 ? "1" : "2"); + + return 0; + +err: + dev_err(&pdev->dev, "Failed to udc probe, rc:0x%x\n", rc); + ast_udc_remove(pdev); + + return rc; +} + +static const struct of_device_id ast_udc_of_dt_ids[] = { + { .compatible = "aspeed,ast2600-udc", }, + {} +}; + +MODULE_DEVICE_TABLE(of, ast_udc_of_dt_ids); + +static struct platform_driver ast_udc_driver = { + .probe = ast_udc_probe, + .remove = ast_udc_remove, + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = ast_udc_of_dt_ids, + }, +}; + +module_platform_driver(ast_udc_driver); + +MODULE_DESCRIPTION("ASPEED UDC driver"); +MODULE_AUTHOR("Neal Liu "); +MODULE_LICENSE("GPL"); From 2cee50bf459051d1b41d0deee25e930a788cb94e Mon Sep 17 00:00:00 2001 From: Neal Liu Date: Mon, 23 May 2022 11:01:33 +0800 Subject: [PATCH 0463/1436] ARM: dts: aspeed: Add USB2.0 device controller node Add USB2.0 device controller(udc) node to device tree for AST2600. Acked-by: Krzysztof Kozlowski Signed-off-by: Neal Liu Link: https://lore.kernel.org/r/20220523030134.2977116-3-neal_liu@aspeedtech.com Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/aspeed-g6.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi index 6660564855ff..1ccd7bb6fe3c 100644 --- a/arch/arm/boot/dts/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed-g6.dtsi @@ -317,6 +317,16 @@ status = "disabled"; }; + udc: usb@1e6a2000 { + compatible = "aspeed,ast2600-udc"; + reg = <0x1e6a2000 0x300>; + interrupts = ; + clocks = <&syscon ASPEED_CLK_GATE_USBPORT2CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb2bd_default>; + status = "disabled"; + }; + apb { compatible = "simple-bus"; #address-cells = <1>; From 0dde9a46a2cfa58c69b5667272c1a6edc8144505 Mon Sep 17 00:00:00 2001 From: Neal Liu Date: Mon, 23 May 2022 11:01:34 +0800 Subject: [PATCH 0464/1436] dt-bindings: usb: add documentation for aspeed udc Add device tree binding documentation for the Aspeed USB2.0 Device Controller. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Neal Liu Link: https://lore.kernel.org/r/20220523030134.2977116-4-neal_liu@aspeedtech.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/aspeed,ast2600-udc.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/aspeed,ast2600-udc.yaml diff --git a/Documentation/devicetree/bindings/usb/aspeed,ast2600-udc.yaml b/Documentation/devicetree/bindings/usb/aspeed,ast2600-udc.yaml new file mode 100644 index 000000000000..c3b6be3d8002 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/aspeed,ast2600-udc.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2020 Facebook Inc. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/aspeed,ast2600-udc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ASPEED USB 2.0 Device Controller + +maintainers: + - Neal Liu + +description: |+ + The ASPEED USB 2.0 Device Controller implements 1 control endpoint and + 4 generic endpoints for AST260x. + + Supports independent DMA channel for each generic endpoint. + Supports 32/256 stages descriptor mode for all generic endpoints. + +properties: + compatible: + enum: + - aspeed,ast2600-udc + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - interrupts + +additionalProperties: false + +examples: + - | + #include + udc: usb@1e6a2000 { + compatible = "aspeed,ast2600-udc"; + reg = <0x1e6a2000 0x300>; + interrupts = <9>; + clocks = <&syscon ASPEED_CLK_GATE_USBPORT2CLK>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb2bd_default>; + }; From ac663ae22f0277cfb52563594931160bbbb6ad60 Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Sun, 12 Jun 2022 03:05:14 +0200 Subject: [PATCH 0465/1436] staging: r8188eu: replace FIELD_OFFSET with offsetof This driver defines FIELD_OFFSET which does the same as offsetof. Replace this macro with offsetof. Signed-off-by: Nam Cao Link: https://lore.kernel.org/r/9443ef83f565eafe1e4f348412772d4ab966093a.1654994517.git.namcaov@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 4 ++-- drivers/staging/r8188eu/include/basic_types.h | 2 -- drivers/staging/r8188eu/os_dep/ioctl_linux.c | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 37b1608ed2d1..cce0575e93b7 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -7110,7 +7110,7 @@ u8 createbss_hdl(struct adapter *padapter, u8 *pbuf) /* clear CAM */ flush_all_cam_entry(padapter); - memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength)); + memcpy(pnetwork, pbuf, offsetof(struct wlan_bssid_ex, IELength)); pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength; if (pnetwork->IELength > MAX_IE_SZ)/* Check pbuf->IELength */ @@ -7167,7 +7167,7 @@ u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf) pmlmeinfo->candidate_tid_bitmap = 0; pmlmeinfo->bwmode_updated = false; - memcpy(pnetwork, pbuf, FIELD_OFFSET(struct wlan_bssid_ex, IELength)); + memcpy(pnetwork, pbuf, offsetof(struct wlan_bssid_ex, IELength)); pnetwork->IELength = ((struct wlan_bssid_ex *)pbuf)->IELength; if (pnetwork->IELength > MAX_IE_SZ)/* Check pbuf->IELength */ diff --git a/drivers/staging/r8188eu/include/basic_types.h b/drivers/staging/r8188eu/include/basic_types.h index ffb21170e898..cfd15ac1d9c0 100644 --- a/drivers/staging/r8188eu/include/basic_types.h +++ b/drivers/staging/r8188eu/include/basic_types.h @@ -9,8 +9,6 @@ typedef void (*proc_t)(void *); -#define FIELD_OFFSET(s, field) ((ssize_t)&((s *)(0))->field) - /* port from fw */ /* TODO: Macros Below are Sync from SD7-Driver. It is necessary * to check correctness */ diff --git a/drivers/staging/r8188eu/os_dep/ioctl_linux.c b/drivers/staging/r8188eu/os_dep/ioctl_linux.c index e95cf35949d0..d02af841f599 100644 --- a/drivers/staging/r8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/r8188eu/os_dep/ioctl_linux.c @@ -403,7 +403,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, if (wep_key_len > 0) { wep_key_len = wep_key_len <= 5 ? 5 : 13; - wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); + wep_total_len = wep_key_len + offsetof(struct ndis_802_11_wep, KeyMaterial); pwep = kzalloc(wep_total_len, GFP_KERNEL); if (!pwep) goto exit; @@ -1593,7 +1593,7 @@ static int rtw_wx_set_enc(struct net_device *dev, if (erq->length > 0) { wep.KeyLength = erq->length <= 5 ? 5 : 13; - wep.Length = wep.KeyLength + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); + wep.Length = wep.KeyLength + offsetof(struct ndis_802_11_wep, KeyMaterial); } else { wep.KeyLength = 0; From de9257ae1d3b0d8856955045d194e3ff4f278394 Mon Sep 17 00:00:00 2001 From: Daniel Watson Date: Sat, 11 Jun 2022 20:07:34 -0700 Subject: [PATCH 0466/1436] staging: rtl8723bs: uninitialize static variable ensure static variable is not initialized, per checkpatch Signed-off-by: Daniel Watson Link: https://lore.kernel.org/r/20220612030734.31469-1-ozzloy@challenge-bot.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 7240220cf6ae..eed4be37d392 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -1256,7 +1256,7 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy } if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) { - static unsigned long lastscantime = 0; + static unsigned long lastscantime; unsigned long passtime; passtime = jiffies_to_msecs(jiffies - lastscantime); From 3cd8cc98d63492f6f69edd4486c9bd1fe29f91c3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 3 May 2022 16:02:07 +0200 Subject: [PATCH 0467/1436] platform/x86: Drop the PMC_ATOM Kconfig option The def_bool y PMC_ATOM Kconfig option provides a couple of symbols used by the code enabled by the X86_INTEL_LPSS option and it registers some clocks. These clocks are only registered on Bay Trail, Cherry Trail and Brasswell Intel SoCs and kernels targeting these SoCs must always have the X86_INTEL_LPSS option enabled otherwise many things will not work. Building the PMC_ATOM code on kernels which are not targeting the mentioned SoCs and which do not have the X86_INTEL_LPSS enabled is not useful. This means that we can simplify things by replacing the PMC_ATOM Kconfig option in Makefiles with X86_INTEL_LPSS and then drop the option. Cc: Paul Gortmaker Signed-off-by: Hans de Goede Acked-by: Andy Shevchenko Acked-by: Stephen Boyd Link: https://lore.kernel.org/r/20220503140207.101218-2-hdegoede@redhat.com --- drivers/clk/x86/Makefile | 4 +--- drivers/platform/x86/Kconfig | 5 ----- drivers/platform/x86/Makefile | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/clk/x86/Makefile b/drivers/clk/x86/Makefile index 1244c4e568ff..c2088b3c4081 100644 --- a/drivers/clk/x86/Makefile +++ b/drivers/clk/x86/Makefile @@ -1,6 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_PMC_ATOM) += clk-pmc-atom.o obj-$(CONFIG_X86_AMD_PLATFORM_DEVICE) += clk-fch.o -clk-x86-lpss-y := clk-lpss-atom.o -obj-$(CONFIG_X86_INTEL_LPSS) += clk-x86-lpss.o +obj-$(CONFIG_X86_INTEL_LPSS) += clk-lpss-atom.o clk-pmc-atom.o obj-$(CONFIG_CLK_LGM_CGU) += clk-cgu.o clk-cgu-pll.o clk-lgm.o diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f08ad85683cb..85c396a43048 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1161,8 +1161,3 @@ config WINMATE_FM07_KEYS that delivers key events when these buttons are pressed. endif # X86_PLATFORM_DEVICES - -config PMC_ATOM - def_bool y - depends on PCI - select COMMON_CLK diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 4a59f47a46e2..cc2a74713313 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -126,7 +126,7 @@ obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o obj-$(CONFIG_INTEL_SCU_PLATFORM) += intel_scu_pltdrv.o obj-$(CONFIG_INTEL_SCU_WDT) += intel_scu_wdt.o obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o -obj-$(CONFIG_PMC_ATOM) += pmc_atom.o +obj-$(CONFIG_X86_INTEL_LPSS) += pmc_atom.o # Siemens Simatic Industrial PCs obj-$(CONFIG_SIEMENS_SIMATIC_IPC) += simatic-ipc.o From 50d88b1d1e7970ed900080bab4fe3f1477908d46 Mon Sep 17 00:00:00 2001 From: Haowen Bai Date: Tue, 31 May 2022 17:24:23 +0800 Subject: [PATCH 0468/1436] platform/x86: system76_acpi: Use dev_get_drvdata Eliminate direct accesses to the driver_data field. Signed-off-by: Haowen Bai Link: https://lore.kernel.org/r/1653989063-20180-1-git-send-email-baihaowen@meizu.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/system76_acpi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c index 7299ad08c838..958df41ad509 100644 --- a/drivers/platform/x86/system76_acpi.c +++ b/drivers/platform/x86/system76_acpi.c @@ -339,7 +339,7 @@ static ssize_t kb_led_color_show( struct led_classdev *led; struct system76_data *data; - led = (struct led_classdev *)dev->driver_data; + led = dev_get_drvdata(dev); data = container_of(led, struct system76_data, kb_led); return sysfs_emit(buf, "%06X\n", data->kb_color); } @@ -356,7 +356,7 @@ static ssize_t kb_led_color_store( unsigned int val; int ret; - led = (struct led_classdev *)dev->driver_data; + led = dev_get_drvdata(dev); data = container_of(led, struct system76_data, kb_led); ret = kstrtouint(buf, 16, &val); if (ret) From de0130355306ec54d6c4d0d2ae0485dfb5dd7f26 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jun 2022 09:38:23 +0200 Subject: [PATCH 0469/1436] x86/crypto: Remove stray comment terminator It seems the SPDX patch script managed to confuse itself. Fixes: 2eb72d6696c6 ("treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_179.RULE") Reported-by: kernel test robot Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/x86/crypto/crc32-pclmul_asm.S | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/crypto/crc32-pclmul_asm.S b/arch/x86/crypto/crc32-pclmul_asm.S index c4bd1b47a600..ca53e96996ac 100644 --- a/arch/x86/crypto/crc32-pclmul_asm.S +++ b/arch/x86/crypto/crc32-pclmul_asm.S @@ -1,6 +1,4 @@ /* SPDX-License-Identifier: GPL-2.0-only */ - */ - /* * Copyright 2012 Xyratex Technology Limited * From 0eb6584068642767baab17c2e4385a6b9c029caa Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:36 +0200 Subject: [PATCH 0470/1436] platform/surface: aggregator: Allow is_ssam_device() to be used when CONFIG_SURFACE_AGGREGATOR_BUS is disabled In SSAM subsystem drivers that handle both ACPI and SSAM-native client devices, we may want to check whether we have a SSAM (native) client device. Further, we may want to do this even when instantiation thereof cannot happen due to CONFIG_SURFACE_AGGREGATOR_BUS=n. Currently, doing so causes an error due to an undefined reference error due to ssam_device_type being placed in the bus source unit. Therefore, if CONFIG_SURFACE_AGGREGATOR_BUS is not defined, simply let is_ssam_device() return false to prevent this error. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-2-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- include/linux/surface_aggregator/device.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index cc257097eb05..62b38b4487eb 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -177,6 +177,8 @@ struct ssam_device_driver { void (*remove)(struct ssam_device *sdev); }; +#ifdef CONFIG_SURFACE_AGGREGATOR_BUS + extern struct bus_type ssam_bus_type; extern const struct device_type ssam_device_type; @@ -193,6 +195,15 @@ static inline bool is_ssam_device(struct device *d) return d->type == &ssam_device_type; } +#else /* CONFIG_SURFACE_AGGREGATOR_BUS */ + +static inline bool is_ssam_device(struct device *d) +{ + return false; +} + +#endif /* CONFIG_SURFACE_AGGREGATOR_BUS */ + /** * to_ssam_device() - Casts the given device to a SSAM client device. * @d: The device to cast. From dc0393c76f378f68961587fd4f32de29fb8f0c79 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:37 +0200 Subject: [PATCH 0471/1436] platform/surface: aggregator: Allow devices to be marked as hot-removed Some SSAM devices, notably the keyboard cover (keyboard and touchpad) on the Surface Pro 8, can be hot-removed. When this occurs, communication with the device may fail and time out. This timeout can unnecessarily block and slow down device removal and even cause issues when the devices are detached and re-attached quickly. Thus, communication should generally be avoided once hot-removal is detected. While we already remove a device as soon as we detect its (hot-)removal, the corresponding device driver may still attempt to communicate with the device during teardown. This is especially critical as communication failure may also extend to disabling of events, which is typically done at that stage. Add a flag to allow marking devices as hot-removed. This can then be used during client driver teardown to check if any communication attempts should be avoided. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-3-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- include/linux/surface_aggregator/device.h | 48 +++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index 62b38b4487eb..6df7c8d4e50e 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -148,17 +148,30 @@ struct ssam_device_uid { #define SSAM_SDEV(cat, tid, iid, fun) \ SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, tid, iid, fun) +/* + * enum ssam_device_flags - Flags for SSAM client devices. + * @SSAM_DEVICE_HOT_REMOVED_BIT: + * The device has been hot-removed. Further communication with it may time + * out and should be avoided. + */ +enum ssam_device_flags { + SSAM_DEVICE_HOT_REMOVED_BIT = 0, +}; + /** * struct ssam_device - SSAM client device. - * @dev: Driver model representation of the device. - * @ctrl: SSAM controller managing this device. - * @uid: UID identifying the device. + * @dev: Driver model representation of the device. + * @ctrl: SSAM controller managing this device. + * @uid: UID identifying the device. + * @flags: Device state flags, see &enum ssam_device_flags. */ struct ssam_device { struct device dev; struct ssam_controller *ctrl; struct ssam_device_uid uid; + + unsigned long flags; }; /** @@ -251,6 +264,35 @@ struct ssam_device *ssam_device_alloc(struct ssam_controller *ctrl, int ssam_device_add(struct ssam_device *sdev); void ssam_device_remove(struct ssam_device *sdev); +/** + * ssam_device_mark_hot_removed() - Mark the given device as hot-removed. + * @sdev: The device to mark as hot-removed. + * + * Mark the device as having been hot-removed. This signals drivers using the + * device that communication with the device should be avoided and may lead to + * timeouts. + */ +static inline void ssam_device_mark_hot_removed(struct ssam_device *sdev) +{ + dev_dbg(&sdev->dev, "marking device as hot-removed\n"); + set_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags); +} + +/** + * ssam_device_is_hot_removed() - Check if the given device has been + * hot-removed. + * @sdev: The device to check. + * + * Checks if the given device has been marked as hot-removed. See + * ssam_device_mark_hot_removed() for more details. + * + * Return: Returns ``true`` if the device has been marked as hot-removed. + */ +static inline bool ssam_device_is_hot_removed(struct ssam_device *sdev) +{ + return test_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags); +} + /** * ssam_device_get() - Increment reference count of SSAM client device. * @sdev: The device to increment the reference count of. From 5c1e88b98c60e4074796e9a05d3c674479ab1919 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:38 +0200 Subject: [PATCH 0472/1436] platform/surface: aggregator: Allow notifiers to avoid communication on unregistering When SSAM client devices have been (physically) hot-removed, communication attempts with those devices may fail and time out. This can even extend to event notifiers, due to which timeouts may occur during device removal, slowing down that process. Add a parameter to the notifier unregister function that allows skipping communication with the EC to prevent this. Furthermore, add wrappers for registering and unregistering notifiers belonging to SSAM client devices that automatically check if the device has been marked as hot-removed and communication should be avoided. Note that non-SSAM client devices can generally not be hot-removed, so also add a convenience wrapper for those, defaulting to allow communication. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-4-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../driver-api/surface_aggregator/client.rst | 6 +- .../platform/surface/aggregator/controller.c | 53 ++++++++++----- include/linux/surface_aggregator/controller.h | 24 ++++++- include/linux/surface_aggregator/device.h | 66 +++++++++++++++++++ 4 files changed, 128 insertions(+), 21 deletions(-) diff --git a/Documentation/driver-api/surface_aggregator/client.rst b/Documentation/driver-api/surface_aggregator/client.rst index e519d374c378..27f95abdbe99 100644 --- a/Documentation/driver-api/surface_aggregator/client.rst +++ b/Documentation/driver-api/surface_aggregator/client.rst @@ -17,6 +17,8 @@ .. |SSAM_DEVICE| replace:: :c:func:`SSAM_DEVICE` .. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register` .. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister` +.. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register` +.. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister` .. |ssam_request_sync| replace:: :c:func:`ssam_request_sync` .. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask ` @@ -312,7 +314,9 @@ Handling Events To receive events from the SAM EC, an event notifier must be registered for the desired event via |ssam_notifier_register|. The notifier must be unregistered via |ssam_notifier_unregister| once it is not required any -more. +more. For |ssam_device| type clients, the |ssam_device_notifier_register| and +|ssam_device_notifier_unregister| wrappers should be preferred as they properly +handle hot-removal of client devices. Event notifiers are registered by providing (at minimum) a callback to call in case an event has been received, the registry specifying how the event diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c index b8c377b3f932..6de834b52b63 100644 --- a/drivers/platform/surface/aggregator/controller.c +++ b/drivers/platform/surface/aggregator/controller.c @@ -2199,16 +2199,26 @@ static int ssam_nf_refcount_enable(struct ssam_controller *ctrl, } /** - * ssam_nf_refcount_disable_free() - Disable event for reference count entry if it is - * no longer in use and free the corresponding entry. + * ssam_nf_refcount_disable_free() - Disable event for reference count entry if + * it is no longer in use and free the corresponding entry. * @ctrl: The controller to disable the event on. * @entry: The reference count entry for the event to be disabled. * @flags: The flags used for enabling the event on the EC. + * @ec: Flag specifying if the event should actually be disabled on the EC. * - * If the reference count equals zero, i.e. the event is no longer requested by - * any client, the event will be disabled and the corresponding reference count - * entry freed. The reference count entry must not be used any more after a - * call to this function. + * If ``ec`` equals ``true`` and the reference count equals zero (i.e. the + * event is no longer requested by any client), the specified event will be + * disabled on the EC via the corresponding request. + * + * If ``ec`` equals ``false``, no request will be sent to the EC and the event + * can be considered in a detached state (i.e. no longer used but still + * enabled). Disabling an event via this method may be required for + * hot-removable devices, where event disable requests may time out after the + * device has been physically removed. + * + * In both cases, if the reference count equals zero, the corresponding + * reference count entry will be freed. The reference count entry must not be + * used any more after a call to this function. * * Also checks if the flags used for disabling the event match the flags used * for enabling the event and warns if they do not (regardless of reference @@ -2223,7 +2233,7 @@ static int ssam_nf_refcount_enable(struct ssam_controller *ctrl, * returns the status of the event-enable EC command. */ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl, - struct ssam_nf_refcount_entry *entry, u8 flags) + struct ssam_nf_refcount_entry *entry, u8 flags, bool ec) { const struct ssam_event_registry reg = entry->key.reg; const struct ssam_event_id id = entry->key.id; @@ -2232,8 +2242,9 @@ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl, lockdep_assert_held(&nf->lock); - ssam_dbg(ctrl, "disabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", - reg.target_category, id.target_category, id.instance, entry->refcount); + ssam_dbg(ctrl, "%s event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", + ec ? "disabling" : "detaching", reg.target_category, id.target_category, + id.instance, entry->refcount); if (entry->flags != flags) { ssam_warn(ctrl, @@ -2242,7 +2253,7 @@ static int ssam_nf_refcount_disable_free(struct ssam_controller *ctrl, id.instance); } - if (entry->refcount == 0) { + if (ec && entry->refcount == 0) { status = ssam_ssh_event_disable(ctrl, reg, id, flags); kfree(entry); } @@ -2322,20 +2333,26 @@ int ssam_notifier_register(struct ssam_controller *ctrl, struct ssam_event_notif EXPORT_SYMBOL_GPL(ssam_notifier_register); /** - * ssam_notifier_unregister() - Unregister an event notifier. - * @ctrl: The controller the notifier has been registered on. - * @n: The event notifier to unregister. + * __ssam_notifier_unregister() - Unregister an event notifier. + * @ctrl: The controller the notifier has been registered on. + * @n: The event notifier to unregister. + * @disable: Whether to disable the corresponding event on the EC. * * Unregister an event notifier. Decrement the usage counter of the associated * SAM event if the notifier is not marked as an observer. If the usage counter - * reaches zero, the event will be disabled. + * reaches zero and ``disable`` equals ``true``, the event will be disabled. + * + * Useful for hot-removable devices, where communication may fail once the + * device has been physically removed. In that case, specifying ``disable`` as + * ``false`` avoids communication with the EC. * * Return: Returns zero on success, %-ENOENT if the given notifier block has * not been registered on the controller. If the given notifier block was the * last one associated with its specific event, returns the status of the * event-disable EC-command. */ -int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n) +int __ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n, + bool disable) { u16 rqid = ssh_tc_to_rqid(n->event.id.target_category); struct ssam_nf_refcount_entry *entry; @@ -2373,7 +2390,7 @@ int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_not goto remove; } - status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags); + status = ssam_nf_refcount_disable_free(ctrl, entry, n->event.flags, disable); } remove: @@ -2383,7 +2400,7 @@ remove: return status; } -EXPORT_SYMBOL_GPL(ssam_notifier_unregister); +EXPORT_SYMBOL_GPL(__ssam_notifier_unregister); /** * ssam_controller_event_enable() - Enable the specified event. @@ -2477,7 +2494,7 @@ int ssam_controller_event_disable(struct ssam_controller *ctrl, return -ENOENT; } - status = ssam_nf_refcount_disable_free(ctrl, entry, flags); + status = ssam_nf_refcount_disable_free(ctrl, entry, flags, true); mutex_unlock(&nf->lock); return status; diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h index 74bfdffaf7b0..50a2b4926c06 100644 --- a/include/linux/surface_aggregator/controller.h +++ b/include/linux/surface_aggregator/controller.h @@ -835,8 +835,28 @@ struct ssam_event_notifier { int ssam_notifier_register(struct ssam_controller *ctrl, struct ssam_event_notifier *n); -int ssam_notifier_unregister(struct ssam_controller *ctrl, - struct ssam_event_notifier *n); +int __ssam_notifier_unregister(struct ssam_controller *ctrl, + struct ssam_event_notifier *n, bool disable); + +/** + * ssam_notifier_unregister() - Unregister an event notifier. + * @ctrl: The controller the notifier has been registered on. + * @n: The event notifier to unregister. + * + * Unregister an event notifier. Decrement the usage counter of the associated + * SAM event if the notifier is not marked as an observer. If the usage counter + * reaches zero, the event will be disabled. + * + * Return: Returns zero on success, %-ENOENT if the given notifier block has + * not been registered on the controller. If the given notifier block was the + * last one associated with its specific event, returns the status of the + * event-disable EC-command. + */ +static inline int ssam_notifier_unregister(struct ssam_controller *ctrl, + struct ssam_event_notifier *n) +{ + return __ssam_notifier_unregister(ctrl, n, true); +} int ssam_controller_event_enable(struct ssam_controller *ctrl, struct ssam_event_registry reg, diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index 6df7c8d4e50e..c418f7f2732d 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -483,4 +483,70 @@ static inline void ssam_remove_clients(struct device *dev) {} sdev->uid.instance, ret); \ } + +/* -- Helpers for client-device notifiers. ---------------------------------- */ + +/** + * ssam_device_notifier_register() - Register an event notifier for the + * specified client device. + * @sdev: The device the notifier should be registered on. + * @n: The event notifier to register. + * + * Register an event notifier. Increment the usage counter of the associated + * SAM event if the notifier is not marked as an observer. If the event is not + * marked as an observer and is currently not enabled, it will be enabled + * during this call. If the notifier is marked as an observer, no attempt will + * be made at enabling any event and no reference count will be modified. + * + * Notifiers marked as observers do not need to be associated with one specific + * event, i.e. as long as no event matching is performed, only the event target + * category needs to be set. + * + * Return: Returns zero on success, %-ENOSPC if there have already been + * %INT_MAX notifiers for the event ID/type associated with the notifier block + * registered, %-ENOMEM if the corresponding event entry could not be + * allocated, %-ENODEV if the device is marked as hot-removed. If this is the + * first time that a notifier block is registered for the specific associated + * event, returns the status of the event-enable EC-command. + */ +static inline int ssam_device_notifier_register(struct ssam_device *sdev, + struct ssam_event_notifier *n) +{ + /* + * Note that this check does not provide any guarantees whatsoever as + * hot-removal could happen at any point and we can't protect against + * it. Nevertheless, if we can detect hot-removal, bail early to avoid + * communication timeouts. + */ + if (ssam_device_is_hot_removed(sdev)) + return -ENODEV; + + return ssam_notifier_register(sdev->ctrl, n); +} + +/** + * ssam_device_notifier_unregister() - Unregister an event notifier for the + * specified client device. + * @sdev: The device the notifier has been registered on. + * @n: The event notifier to unregister. + * + * Unregister an event notifier. Decrement the usage counter of the associated + * SAM event if the notifier is not marked as an observer. If the usage counter + * reaches zero, the event will be disabled. + * + * In case the device has been marked as hot-removed, the event will not be + * disabled on the EC, as in those cases any attempt at doing so may time out. + * + * Return: Returns zero on success, %-ENOENT if the given notifier block has + * not been registered on the controller. If the given notifier block was the + * last one associated with its specific event, returns the status of the + * event-disable EC-command. + */ +static inline int ssam_device_notifier_unregister(struct ssam_device *sdev, + struct ssam_event_notifier *n) +{ + return __ssam_notifier_unregister(sdev->ctrl, n, + !ssam_device_is_hot_removed(sdev)); +} + #endif /* _LINUX_SURFACE_AGGREGATOR_DEVICE_H */ From 74bb2d0bc57a1123ef39206051b03d4003673d8c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:39 +0200 Subject: [PATCH 0473/1436] platform/surface: aggregator_registry: Use client device wrappers for notifier registration Use newly introduced client device wrapper functions for notifier registration and unregistration. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-5-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_registry.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index ce2bd88feeaa..9f630e890ff7 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -468,7 +468,7 @@ static int ssam_base_hub_probe(struct ssam_device *sdev) ssam_device_set_drvdata(sdev, hub); - status = ssam_notifier_register(sdev->ctrl, &hub->notif); + status = ssam_device_notifier_register(sdev, &hub->notif); if (status) return status; @@ -480,7 +480,7 @@ static int ssam_base_hub_probe(struct ssam_device *sdev) return 0; err: - ssam_notifier_unregister(sdev->ctrl, &hub->notif); + ssam_device_notifier_unregister(sdev, &hub->notif); cancel_delayed_work_sync(&hub->update_work); ssam_remove_clients(&sdev->dev); return status; @@ -492,7 +492,7 @@ static void ssam_base_hub_remove(struct ssam_device *sdev) sysfs_remove_group(&sdev->dev.kobj, &ssam_base_hub_group); - ssam_notifier_unregister(sdev->ctrl, &hub->notif); + ssam_device_notifier_unregister(sdev, &hub->notif); cancel_delayed_work_sync(&hub->update_work); ssam_remove_clients(&sdev->dev); } From f80345b89cc5cb61c6c586e6800a66c45261fd74 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:40 +0200 Subject: [PATCH 0474/1436] power/supply: surface_charger: Use client device wrappers for notifier registration Use newly introduced client device wrapper functions for notifier registration and unregistration. Signed-off-by: Maximilian Luz Acked-by: Sebastian Reichel Link: https://lore.kernel.org/r/20220527023447.2460025-6-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/power/supply/surface_charger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/surface_charger.c b/drivers/power/supply/surface_charger.c index a060c36c7766..59182d55742d 100644 --- a/drivers/power/supply/surface_charger.c +++ b/drivers/power/supply/surface_charger.c @@ -216,7 +216,7 @@ static int spwr_ac_register(struct spwr_ac_device *ac) if (IS_ERR(ac->psy)) return PTR_ERR(ac->psy); - return ssam_notifier_register(ac->sdev->ctrl, &ac->notif); + return ssam_device_notifier_register(ac->sdev, &ac->notif); } @@ -251,7 +251,7 @@ static void surface_ac_remove(struct ssam_device *sdev) { struct spwr_ac_device *ac = ssam_device_get_drvdata(sdev); - ssam_notifier_unregister(sdev->ctrl, &ac->notif); + ssam_device_notifier_unregister(sdev, &ac->notif); } static const struct spwr_psy_properties spwr_psy_props_adp1 = { From b49ba26bec452d3065e09327fbda79d7120a9f9d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:41 +0200 Subject: [PATCH 0475/1436] power/supply: surface_battery: Use client device wrappers for notifier registration Use newly introduced client device wrapper functions for notifier registration and unregistration. Signed-off-by: Maximilian Luz Acked-by: Sebastian Reichel Link: https://lore.kernel.org/r/20220527023447.2460025-7-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/power/supply/surface_battery.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/surface_battery.c b/drivers/power/supply/surface_battery.c index 5ec2e6bb2465..540707882bb0 100644 --- a/drivers/power/supply/surface_battery.c +++ b/drivers/power/supply/surface_battery.c @@ -802,7 +802,7 @@ static int spwr_battery_register(struct spwr_battery_device *bat) if (IS_ERR(bat->psy)) return PTR_ERR(bat->psy); - return ssam_notifier_register(bat->sdev->ctrl, &bat->notif); + return ssam_device_notifier_register(bat->sdev, &bat->notif); } @@ -837,7 +837,7 @@ static void surface_battery_remove(struct ssam_device *sdev) { struct spwr_battery_device *bat = ssam_device_get_drvdata(sdev); - ssam_notifier_unregister(sdev->ctrl, &bat->notif); + ssam_device_notifier_unregister(sdev, &bat->notif); cancel_delayed_work_sync(&bat->update_work); } From 2c2c3a07086c910719dc7135f1d871d2c6c022fc Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:42 +0200 Subject: [PATCH 0476/1436] HID: surface-hid: Add support for hot-removal Add support for hot-removal of SSAM HID client devices. Once a device has been hot-removed, further communication with it should be avoided as it may fail and time out. While the device will be removed as soon as we detect hot-removal, communication may still occur during teardown, especially when unregistering notifiers. While hot-removal is a surprise event that can happen at any time, try to avoid communication as much as possible once it has been detected to prevent timeouts that can slow down device removal and cause issues, e.g. when quickly re-attaching the device. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-8-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/hid/surface-hid/surface_hid_core.c | 38 +++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/hid/surface-hid/surface_hid_core.c b/drivers/hid/surface-hid/surface_hid_core.c index e46330b2e561..87637f813de2 100644 --- a/drivers/hid/surface-hid/surface_hid_core.c +++ b/drivers/hid/surface-hid/surface_hid_core.c @@ -19,12 +19,30 @@ #include "surface_hid_core.h" +/* -- Utility functions. ---------------------------------------------------- */ + +static bool surface_hid_is_hot_removed(struct surface_hid_device *shid) +{ + /* + * Non-ssam client devices, i.e. platform client devices, cannot be + * hot-removed. + */ + if (!is_ssam_device(shid->dev)) + return false; + + return ssam_device_is_hot_removed(to_ssam_device(shid->dev)); +} + + /* -- Device descriptor access. --------------------------------------------- */ static int surface_hid_load_hid_descriptor(struct surface_hid_device *shid) { int status; + if (surface_hid_is_hot_removed(shid)) + return -ENODEV; + status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_HID, (u8 *)&shid->hid_desc, sizeof(shid->hid_desc)); if (status) @@ -61,6 +79,9 @@ static int surface_hid_load_device_attributes(struct surface_hid_device *shid) { int status; + if (surface_hid_is_hot_removed(shid)) + return -ENODEV; + status = shid->ops.get_descriptor(shid, SURFACE_HID_DESC_ATTRS, (u8 *)&shid->attrs, sizeof(shid->attrs)); if (status) @@ -88,9 +109,18 @@ static int surface_hid_start(struct hid_device *hid) static void surface_hid_stop(struct hid_device *hid) { struct surface_hid_device *shid = hid->driver_data; + bool hot_removed; + + /* + * Communication may fail for devices that have been hot-removed. This + * also includes unregistration of HID events, so we need to check this + * here. Only if the device has not been marked as hot-removed, we can + * safely disable events. + */ + hot_removed = surface_hid_is_hot_removed(shid); /* Note: This call will log errors for us, so ignore them here. */ - ssam_notifier_unregister(shid->ctrl, &shid->notif); + __ssam_notifier_unregister(shid->ctrl, &shid->notif, !hot_removed); } static int surface_hid_open(struct hid_device *hid) @@ -109,6 +139,9 @@ static int surface_hid_parse(struct hid_device *hid) u8 *buf; int status; + if (surface_hid_is_hot_removed(shid)) + return -ENODEV; + buf = kzalloc(len, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -126,6 +159,9 @@ static int surface_hid_raw_request(struct hid_device *hid, unsigned char reportn { struct surface_hid_device *shid = hid->driver_data; + if (surface_hid_is_hot_removed(shid)) + return -ENODEV; + if (rtype == HID_OUTPUT_REPORT && reqtype == HID_REQ_SET_REPORT) return shid->ops.output_report(shid, reportnum, buf, len); From 25e2ca7301bd3ca5a63a6be41d729eb42202bc21 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:43 +0200 Subject: [PATCH 0477/1436] platform/surface: aggregator: Add comment for KIP subsystem category The KIP subsystem (full name unknown, abbreviation has been obtained through reverse engineering) handles detachable peripherals such as the keyboard cover on the Surface Pro X and Surface Pro 8. It is currently not entirely clear what this subsystem entails, but at the very least it provides event notifications for when the keyboard cover on the Surface Pro X and Surface Pro 8 have been detached or re-attached, as well as the state that the keyboard cover is currently in (e.g. folded-back, folded laptop-like, closed, etc.). Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-9-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- include/linux/surface_aggregator/serial_hub.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/surface_aggregator/serial_hub.h b/include/linux/surface_aggregator/serial_hub.h index c3de43edcffa..26b95ec12733 100644 --- a/include/linux/surface_aggregator/serial_hub.h +++ b/include/linux/surface_aggregator/serial_hub.h @@ -306,7 +306,7 @@ enum ssam_ssh_tc { SSAM_SSH_TC_LPC = 0x0b, SSAM_SSH_TC_TCL = 0x0c, SSAM_SSH_TC_SFL = 0x0d, - SSAM_SSH_TC_KIP = 0x0e, + SSAM_SSH_TC_KIP = 0x0e, /* Manages detachable peripherals (Pro X/8 keyboard cover) */ SSAM_SSH_TC_EXT = 0x0f, SSAM_SSH_TC_BLD = 0x10, SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */ From 1aa4c85bab7623469271d5a9cde3e3005b56fb7c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:44 +0200 Subject: [PATCH 0478/1436] platform/surface: aggregator_registry: Generify subsystem hub functionality The Surface System Aggregator Module (SSAM) has multiple subsystems that can manage detachable devices. At the moment, we only support the "base" (BAS/0x11) subsystem, which is used on the Surface Book 3 to manage devices (including keyboard, touchpad, and secondary battery) connected to the base of the device. The Surface Pro 8 has a new type-cover with keyboard and touchpad, which is managed via the KIP/0x0e subsystem. The general procedure is the same, but with slightly different events and setup. To make implementation of the KIP hub easier and prevent duplication, generify the parts of the base hub that we can use for the KIP hub (or any potential future subsystem hubs). This also switches over to use the newly introduced "hot-remove" functionality, which should prevent communication issues when devices have been detached. Lastly, also drop the undocumented and unused sysfs "state" attribute of the base hub. It has at best been useful for debugging. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-10-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../surface/surface_aggregator_registry.c | 273 ++++++++++-------- 1 file changed, 155 insertions(+), 118 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 9f630e890ff7..09cbeee2428b 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -308,6 +308,150 @@ err: } +/* -- SSAM generic subsystem hub driver framework. -------------------------- */ + +enum ssam_hub_state { + SSAM_HUB_UNINITIALIZED, /* Only set during initialization. */ + SSAM_HUB_CONNECTED, + SSAM_HUB_DISCONNECTED, +}; + +enum ssam_hub_flags { + SSAM_HUB_HOT_REMOVED, +}; + +struct ssam_hub { + struct ssam_device *sdev; + + enum ssam_hub_state state; + unsigned long flags; + + struct delayed_work update_work; + unsigned long connect_delay; + + struct ssam_event_notifier notif; + + int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state); +}; + +static void ssam_hub_update_workfn(struct work_struct *work) +{ + struct ssam_hub *hub = container_of(work, struct ssam_hub, update_work.work); + struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev); + enum ssam_hub_state state; + int status = 0; + + status = hub->get_state(hub, &state); + if (status) + return; + + /* + * There is a small possibility that hub devices were hot-removed and + * re-added before we were able to remove them here. In that case, both + * the state returned by get_state() and the state of the hub will + * equal SSAM_HUB_CONNECTED and we would bail early below, which would + * leave child devices without proper (re-)initialization and the + * hot-remove flag set. + * + * Therefore, we check whether devices have been hot-removed via an + * additional flag on the hub and, in this case, override the returned + * hub state. In case of a missed disconnect (i.e. get_state returned + * "connected"), we further need to re-schedule this work (with the + * appropriate delay) as the actual connect work submission might have + * been merged with this one. + * + * This then leads to one of two cases: Either we submit an unnecessary + * work item (which will get ignored via either the queue or the state + * checks) or, in the unlikely case that the work is actually required, + * double the normal connect delay. + */ + if (test_and_clear_bit(SSAM_HUB_HOT_REMOVED, &hub->flags)) { + if (state == SSAM_HUB_CONNECTED) + schedule_delayed_work(&hub->update_work, hub->connect_delay); + + state = SSAM_HUB_DISCONNECTED; + } + + if (hub->state == state) + return; + hub->state = state; + + if (hub->state == SSAM_HUB_CONNECTED) + status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node); + else + ssam_remove_clients(&hub->sdev->dev); + + if (status) + dev_err(&hub->sdev->dev, "failed to update hub child devices: %d\n", status); +} + +static int ssam_hub_mark_hot_removed(struct device *dev, void *_data) +{ + struct ssam_device *sdev = to_ssam_device(dev); + + if (is_ssam_device(dev)) + ssam_device_mark_hot_removed(sdev); + + return 0; +} + +static void ssam_hub_update(struct ssam_hub *hub, bool connected) +{ + unsigned long delay; + + /* Mark devices as hot-removed before we remove any. */ + if (!connected) { + set_bit(SSAM_HUB_HOT_REMOVED, &hub->flags); + device_for_each_child_reverse(&hub->sdev->dev, NULL, ssam_hub_mark_hot_removed); + } + + /* + * Delay update when the base/keyboard cover is being connected to give + * devices/EC some time to set up. + */ + delay = connected ? hub->connect_delay : 0; + + schedule_delayed_work(&hub->update_work, delay); +} + +static int __maybe_unused ssam_hub_resume(struct device *dev) +{ + struct ssam_hub *hub = dev_get_drvdata(dev); + + schedule_delayed_work(&hub->update_work, 0); + return 0; +} +static SIMPLE_DEV_PM_OPS(ssam_hub_pm_ops, NULL, ssam_hub_resume); + +static int ssam_hub_setup(struct ssam_device *sdev, struct ssam_hub *hub) +{ + int status; + + hub->sdev = sdev; + hub->state = SSAM_HUB_UNINITIALIZED; + + INIT_DELAYED_WORK(&hub->update_work, ssam_hub_update_workfn); + + ssam_device_set_drvdata(sdev, hub); + + status = ssam_device_notifier_register(sdev, &hub->notif); + if (status) + return status; + + schedule_delayed_work(&hub->update_work, 0); + return 0; +} + +static void ssam_hub_remove(struct ssam_device *sdev) +{ + struct ssam_hub *hub = ssam_device_get_drvdata(sdev); + + ssam_device_notifier_unregister(sdev, &hub->notif); + cancel_delayed_work_sync(&hub->update_work); + ssam_remove_clients(&sdev->dev); +} + + /* -- SSAM base-hub driver. ------------------------------------------------- */ /* @@ -317,21 +461,6 @@ err: */ #define SSAM_BASE_UPDATE_CONNECT_DELAY msecs_to_jiffies(2500) -enum ssam_base_hub_state { - SSAM_BASE_HUB_UNINITIALIZED, - SSAM_BASE_HUB_CONNECTED, - SSAM_BASE_HUB_DISCONNECTED, -}; - -struct ssam_base_hub { - struct ssam_device *sdev; - - enum ssam_base_hub_state state; - struct delayed_work update_work; - - struct ssam_event_notifier notif; -}; - SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, { .target_category = SSAM_SSH_TC_BAS, .target_id = 0x01, @@ -342,7 +471,7 @@ SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, { #define SSAM_BAS_OPMODE_TABLET 0x00 #define SSAM_EVENT_BAS_CID_CONNECTION 0x0c -static int ssam_base_hub_query_state(struct ssam_base_hub *hub, enum ssam_base_hub_state *state) +static int ssam_base_hub_query_state(struct ssam_hub *hub, enum ssam_hub_state *state) { u8 opmode; int status; @@ -354,62 +483,16 @@ static int ssam_base_hub_query_state(struct ssam_base_hub *hub, enum ssam_base_h } if (opmode != SSAM_BAS_OPMODE_TABLET) - *state = SSAM_BASE_HUB_CONNECTED; + *state = SSAM_HUB_CONNECTED; else - *state = SSAM_BASE_HUB_DISCONNECTED; + *state = SSAM_HUB_DISCONNECTED; return 0; } -static ssize_t ssam_base_hub_state_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ssam_base_hub *hub = dev_get_drvdata(dev); - bool connected = hub->state == SSAM_BASE_HUB_CONNECTED; - - return sysfs_emit(buf, "%d\n", connected); -} - -static struct device_attribute ssam_base_hub_attr_state = - __ATTR(state, 0444, ssam_base_hub_state_show, NULL); - -static struct attribute *ssam_base_hub_attrs[] = { - &ssam_base_hub_attr_state.attr, - NULL, -}; - -static const struct attribute_group ssam_base_hub_group = { - .attrs = ssam_base_hub_attrs, -}; - -static void ssam_base_hub_update_workfn(struct work_struct *work) -{ - struct ssam_base_hub *hub = container_of(work, struct ssam_base_hub, update_work.work); - struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev); - enum ssam_base_hub_state state; - int status = 0; - - status = ssam_base_hub_query_state(hub, &state); - if (status) - return; - - if (hub->state == state) - return; - hub->state = state; - - if (hub->state == SSAM_BASE_HUB_CONNECTED) - status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node); - else - ssam_remove_clients(&hub->sdev->dev); - - if (status) - dev_err(&hub->sdev->dev, "failed to update base-hub devices: %d\n", status); -} - static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) { - struct ssam_base_hub *hub = container_of(nf, struct ssam_base_hub, notif); - unsigned long delay; + struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif); if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION) return 0; @@ -419,13 +502,7 @@ static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam return 0; } - /* - * Delay update when the base is being connected to give devices/EC - * some time to set up. - */ - delay = event->data[0] ? SSAM_BASE_UPDATE_CONNECT_DELAY : 0; - - schedule_delayed_work(&hub->update_work, delay); + ssam_hub_update(hub, event->data[0]); /* * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and @@ -435,27 +512,14 @@ static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam return 0; } -static int __maybe_unused ssam_base_hub_resume(struct device *dev) -{ - struct ssam_base_hub *hub = dev_get_drvdata(dev); - - schedule_delayed_work(&hub->update_work, 0); - return 0; -} -static SIMPLE_DEV_PM_OPS(ssam_base_hub_pm_ops, NULL, ssam_base_hub_resume); - static int ssam_base_hub_probe(struct ssam_device *sdev) { - struct ssam_base_hub *hub; - int status; + struct ssam_hub *hub; hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL); if (!hub) return -ENOMEM; - hub->sdev = sdev; - hub->state = SSAM_BASE_HUB_UNINITIALIZED; - hub->notif.base.priority = INT_MAX; /* This notifier should run first. */ hub->notif.base.fn = ssam_base_hub_notif; hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM; @@ -464,37 +528,10 @@ static int ssam_base_hub_probe(struct ssam_device *sdev) hub->notif.event.mask = SSAM_EVENT_MASK_NONE; hub->notif.event.flags = SSAM_EVENT_SEQUENCED; - INIT_DELAYED_WORK(&hub->update_work, ssam_base_hub_update_workfn); + hub->connect_delay = SSAM_BASE_UPDATE_CONNECT_DELAY; + hub->get_state = ssam_base_hub_query_state; - ssam_device_set_drvdata(sdev, hub); - - status = ssam_device_notifier_register(sdev, &hub->notif); - if (status) - return status; - - status = sysfs_create_group(&sdev->dev.kobj, &ssam_base_hub_group); - if (status) - goto err; - - schedule_delayed_work(&hub->update_work, 0); - return 0; - -err: - ssam_device_notifier_unregister(sdev, &hub->notif); - cancel_delayed_work_sync(&hub->update_work); - ssam_remove_clients(&sdev->dev); - return status; -} - -static void ssam_base_hub_remove(struct ssam_device *sdev) -{ - struct ssam_base_hub *hub = ssam_device_get_drvdata(sdev); - - sysfs_remove_group(&sdev->dev.kobj, &ssam_base_hub_group); - - ssam_device_notifier_unregister(sdev, &hub->notif); - cancel_delayed_work_sync(&hub->update_work); - ssam_remove_clients(&sdev->dev); + return ssam_hub_setup(sdev, hub); } static const struct ssam_device_id ssam_base_hub_match[] = { @@ -504,12 +541,12 @@ static const struct ssam_device_id ssam_base_hub_match[] = { static struct ssam_device_driver ssam_base_hub_driver = { .probe = ssam_base_hub_probe, - .remove = ssam_base_hub_remove, + .remove = ssam_hub_remove, .match_table = ssam_base_hub_match, .driver = { .name = "surface_aggregator_base_hub", .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .pm = &ssam_base_hub_pm_ops, + .pm = &ssam_hub_pm_ops, }, }; From 58a4d884b50947c0ffb494f690b2d7a1422a45c7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:45 +0200 Subject: [PATCH 0479/1436] platform/surface: aggregator_registry: Change device ID for base hub Use the target category of the (base) hub as instance id in the (virtual) hub device UID. This makes association of the hub with the respective subsystem easier. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-11-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_registry.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 09cbeee2428b..b11ce87c7184 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -43,7 +43,7 @@ static const struct software_node ssam_node_root = { /* Base device hub (devices attached to Surface Book 3 base). */ static const struct software_node ssam_node_hub_base = { - .name = "ssam:00:00:02:00:00", + .name = "ssam:00:00:02:11:00", .parent = &ssam_node_root, }; @@ -535,7 +535,7 @@ static int ssam_base_hub_probe(struct ssam_device *sdev) } static const struct ssam_device_id ssam_base_hub_match[] = { - { SSAM_VDEV(HUB, 0x02, SSAM_ANY_IID, 0x00) }, + { SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00) }, { }, }; From d420185489e52f414b18cef10487279a9a005b27 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:46 +0200 Subject: [PATCH 0480/1436] platform/surface: aggregator_registry: Add KIP device hub Add a Surface System Aggregator Module (SSAM) client device hub for hot-removable devices managed via the KIP subsystem. The KIP subsystem (full name unknown, abbreviation has been obtained through reverse engineering) is a subsystem that manages hot-removable SSAM client devices. Specifically, it manages HID input devices contained in the detachable keyboard cover of the Surface Pro 8 and Surface Pro X. The KIP subsystem handles a single group of devices (e.g. all devices contained in the keyboard cover) and cannot handle devices individually. Thus we model it as a client device hub, which (hot-)removes all devices contained under it once removal of the hub (e.g. keyboard cover) has been detected and (re-)adds all devices once the physical hub device has been (re-)attached. To do this, use the previously generified SSAM subsystem hub framework. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-12-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../surface/surface_aggregator_registry.c | 103 +++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index b11ce87c7184..f15cef60630f 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -551,6 +551,93 @@ static struct ssam_device_driver ssam_base_hub_driver = { }; +/* -- SSAM KIP-subsystem hub driver. ---------------------------------------- */ + +/* + * Some devices may need a bit of time to be fully usable after being + * (re-)connected. This delay has been determined via experimentation. + */ +#define SSAM_KIP_UPDATE_CONNECT_DELAY msecs_to_jiffies(250) + +#define SSAM_EVENT_KIP_CID_CONNECTION 0x2c + +SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_connection_state, u8, { + .target_category = SSAM_SSH_TC_KIP, + .target_id = 0x01, + .command_id = 0x2c, + .instance_id = 0x00, +}); + +static int ssam_kip_get_connection_state(struct ssam_hub *hub, enum ssam_hub_state *state) +{ + int status; + u8 connected; + + status = ssam_retry(__ssam_kip_get_connection_state, hub->sdev->ctrl, &connected); + if (status < 0) { + dev_err(&hub->sdev->dev, "failed to query KIP connection state: %d\n", status); + return status; + } + + *state = connected ? SSAM_HUB_CONNECTED : SSAM_HUB_DISCONNECTED; + return 0; +} + +static u32 ssam_kip_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) +{ + struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif); + + if (event->command_id != SSAM_EVENT_KIP_CID_CONNECTION) + return 0; /* Return "unhandled". */ + + if (event->length < 1) { + dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length); + return 0; + } + + ssam_hub_update(hub, event->data[0]); + return SSAM_NOTIF_HANDLED; +} + +static int ssam_kip_hub_probe(struct ssam_device *sdev) +{ + struct ssam_hub *hub; + + hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + hub->notif.base.priority = INT_MAX; /* This notifier should run first. */ + hub->notif.base.fn = ssam_kip_hub_notif; + hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM; + hub->notif.event.id.target_category = SSAM_SSH_TC_KIP, + hub->notif.event.id.instance = 0, + hub->notif.event.mask = SSAM_EVENT_MASK_TARGET; + hub->notif.event.flags = SSAM_EVENT_SEQUENCED; + + hub->connect_delay = SSAM_KIP_UPDATE_CONNECT_DELAY; + hub->get_state = ssam_kip_get_connection_state; + + return ssam_hub_setup(sdev, hub); +} + +static const struct ssam_device_id ssam_kip_hub_match[] = { + { SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00) }, + { }, +}; + +static struct ssam_device_driver ssam_kip_hub_driver = { + .probe = ssam_kip_hub_probe, + .remove = ssam_hub_remove, + .match_table = ssam_kip_hub_match, + .driver = { + .name = "surface_kip_hub", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &ssam_hub_pm_ops, + }, +}; + + /* -- SSAM platform/meta-hub driver. ---------------------------------------- */ static const struct acpi_device_id ssam_platform_hub_match[] = { @@ -673,18 +760,30 @@ static int __init ssam_device_hub_init(void) status = platform_driver_register(&ssam_platform_hub_driver); if (status) - return status; + goto err_platform; status = ssam_device_driver_register(&ssam_base_hub_driver); if (status) - platform_driver_unregister(&ssam_platform_hub_driver); + goto err_base; + status = ssam_device_driver_register(&ssam_kip_hub_driver); + if (status) + goto err_kip; + + return 0; + +err_kip: + ssam_device_driver_unregister(&ssam_base_hub_driver); +err_base: + platform_driver_unregister(&ssam_platform_hub_driver); +err_platform: return status; } module_init(ssam_device_hub_init); static void __exit ssam_device_hub_exit(void) { + ssam_device_driver_unregister(&ssam_kip_hub_driver); ssam_device_driver_unregister(&ssam_base_hub_driver); platform_driver_unregister(&ssam_platform_hub_driver); } From 7518eefeb7ad55ca2126ebdd6369490b9dc5e7a8 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 27 May 2022 04:34:47 +0200 Subject: [PATCH 0481/1436] platform/surface: aggregator_registry: Add support for keyboard cover on Surface Pro 8 Add support for the detachable keyboard cover on the Surface Pro 8. The keyboard cover on the Surface Pro 8 is, unlike the keyboard covers of earlier Surface Pro generations, handled via the Surface System Aggregator Module (SSAM). The keyboard and touchpad (as well as other HID input devices) of this cover are standard SSAM HID client devices (just like keyboard and touchpad on e.g. the Surface Laptop 3 and 4), however, some care needs to be taken as they can be physically detached (similarly to the Surface Book 3). Specifically, the respective SSAM client devices need to be removed when the keyboard cover has been detached and (re-)initialized when the keyboard cover has been (re-)attached. On the Surface Pro 8, detachment of the keyboard cover (and by extension its devices) is managed via the KIP subsystem. Therefore, said devices need to be registered under the KIP device hub, which in turn will remove and re-create/re-initialize those devices as needed. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220527023447.2460025-13-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../surface/surface_aggregator_registry.c | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index f15cef60630f..bf3303f1aa71 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -41,6 +41,12 @@ static const struct software_node ssam_node_root = { .name = "ssam_platform_hub", }; +/* KIP device hub (connects keyboard cover devices on Surface Pro 8). */ +static const struct software_node ssam_node_hub_kip = { + .name = "ssam:00:00:01:0e:00", + .parent = &ssam_node_root, +}; + /* Base device hub (devices attached to Surface Book 3 base). */ static const struct software_node ssam_node_hub_base = { .name = "ssam:00:00:02:11:00", @@ -155,6 +161,30 @@ static const struct software_node ssam_node_hid_base_iid6 = { .parent = &ssam_node_hub_base, }; +/* HID keyboard (KIP hub). */ +static const struct software_node ssam_node_hid_kip_keyboard = { + .name = "ssam:01:15:02:01:00", + .parent = &ssam_node_hub_kip, +}; + +/* HID pen stash (KIP hub; pen taken / stashed away evens). */ +static const struct software_node ssam_node_hid_kip_penstash = { + .name = "ssam:01:15:02:02:00", + .parent = &ssam_node_hub_kip, +}; + +/* HID touchpad (KIP hub). */ +static const struct software_node ssam_node_hid_kip_touchpad = { + .name = "ssam:01:15:02:03:00", + .parent = &ssam_node_hub_kip, +}; + +/* HID device instance 5 (KIP hub, unknown HID device). */ +static const struct software_node ssam_node_hid_kip_iid5 = { + .name = "ssam:01:15:02:05:00", + .parent = &ssam_node_hub_kip, +}; + /* * Devices for 5th- and 6th-generations models: * - Surface Book 2, @@ -230,10 +260,15 @@ static const struct software_node *ssam_node_group_sp7[] = { static const struct software_node *ssam_node_group_sp8[] = { &ssam_node_root, + &ssam_node_hub_kip, &ssam_node_bat_ac, &ssam_node_bat_main, &ssam_node_tmp_pprof, - /* TODO: Add support for keyboard cover. */ + &ssam_node_hid_kip_keyboard, + &ssam_node_hid_kip_penstash, + &ssam_node_hid_kip_touchpad, + &ssam_node_hid_kip_iid5, + /* TODO: Add support for tablet mode switch. */ NULL, }; From 203b2aff4786d16ef0cd1a6a9405043a99a5b3fb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 14 Jun 2022 07:49:09 +0100 Subject: [PATCH 0482/1436] platform/chrome: cros_ec_proto: Fix spelling mistake "unknwon" -> "unknown" There is a spelling mistake in a dev_dbg message. Fix it. Signed-off-by: Colin Ian King Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220614064909.47804-1-colin.i.king@gmail.com --- drivers/platform/chrome/cros_ec_proto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 1bd567244f8e..6923ea4401e5 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -346,7 +346,7 @@ static int cros_ec_get_proto_info(struct cros_ec_device *ec_dev, int devidx) dev_dbg(ec_dev->dev, "found PD chip\n"); break; default: - dev_dbg(ec_dev->dev, "unknwon passthru index: %d\n", devidx); + dev_dbg(ec_dev->dev, "unknown passthru index: %d\n", devidx); break; } From 74bb746407bf0d7c7d126c7731dbcd66d467619b Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 14 Jun 2022 00:57:26 -0700 Subject: [PATCH 0483/1436] platform/chrome: cros_ec: Always expose last resume result The last resume result exposing logic in cros_ec_sleep_event() incorrectly requires S0ix support, which doesn't work on ARM based systems where S0ix doesn't exist. That's because cros_ec_sleep_event() only reports the last resume result when the EC indicates the last sleep event was an S0ix resume. On ARM systems, the last sleep event is always S3 resume, but the EC can still detect sleep hang events in case some other part of the AP is blocking sleep. Always expose the last resume result if the EC supports it so that this works on all devices regardless of S0ix support. This fixes sleep hang detection on ARM based chromebooks like Trogdor. Cc: Rajat Jain Cc: Matthias Kaehlcke Cc: Hsin-Yi Wang Cc: Tzung-Bi Shih Reviewed-by: Guenter Roeck Reviewed-by: Evan Green Fixes: 7235560ac77a ("platform/chrome: Add support for v1 of host sleep event") Signed-off-by: Stephen Boyd Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220614075726.2729987-1-swboyd@chromium.org --- drivers/platform/chrome/cros_ec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c index e51a3f2176c7..8aace50d446d 100644 --- a/drivers/platform/chrome/cros_ec.c +++ b/drivers/platform/chrome/cros_ec.c @@ -132,16 +132,16 @@ static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event) buf.msg.command = EC_CMD_HOST_SLEEP_EVENT; ret = cros_ec_cmd_xfer_status(ec_dev, &buf.msg); - - /* For now, report failure to transition to S0ix with a warning. */ + /* Report failure to transition to system wide suspend with a warning. */ if (ret >= 0 && ec_dev->host_sleep_v1 && - (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) { + (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME || + sleep_event == HOST_SLEEP_EVENT_S3_RESUME)) { ec_dev->last_resume_result = buf.u.resp1.resume_response.sleep_transitions; WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions & EC_HOST_RESUME_SLEEP_TIMEOUT, - "EC detected sleep transition timeout. Total slp_s0 transitions: %d", + "EC detected sleep transition timeout. Total sleep transitions: %d", buf.u.resp1.resume_response.sleep_transitions & EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK); } From 235a6d80f021d9c3bb5652fb6b19d092a7339248 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 14 Jun 2022 11:27:16 +0200 Subject: [PATCH 0484/1436] Revert "ARM: dts: aspeed: Add USB2.0 device controller node" This reverts commit 2cee50bf459051d1b41d0deee25e930a788cb94e. It was already applied, and with this duplicate there is now build problems. Reported-by: Stephen Rothwell Reported-by: Bagas Sanjaya Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/aspeed-g6.dtsi | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi index 1ccd7bb6fe3c..6660564855ff 100644 --- a/arch/arm/boot/dts/aspeed-g6.dtsi +++ b/arch/arm/boot/dts/aspeed-g6.dtsi @@ -317,16 +317,6 @@ status = "disabled"; }; - udc: usb@1e6a2000 { - compatible = "aspeed,ast2600-udc"; - reg = <0x1e6a2000 0x300>; - interrupts = ; - clocks = <&syscon ASPEED_CLK_GATE_USBPORT2CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_usb2bd_default>; - status = "disabled"; - }; - apb { compatible = "simple-bus"; #address-cells = <1>; From b3b7c6a6e80d8347a4a5a13a25fa314800f2cbbe Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Tue, 14 Jun 2022 10:10:41 +0200 Subject: [PATCH 0485/1436] KVM: selftests: kvm_binary_stats_test: Fix index expressions kvm_binary_stats_test accepts two arguments, the number of vms and number of vcpus. If these inputs are not equal then the test would likely crash for one reason or another due to using miscalculated indices for the vcpus array. Fix the index expressions by swapping the use of i and j. Signed-off-by: Andrew Jones Message-Id: <20220614081041.2571511-1-drjones@redhat.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/kvm_binary_stats_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 1baabf955d63..3c2d06b61442 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -225,14 +225,14 @@ int main(int argc, char *argv[]) for (i = 0; i < max_vm; ++i) { vms[i] = vm_create_barebones(); for (j = 0; j < max_vcpu; ++j) - vcpus[j * max_vcpu + i] = __vm_vcpu_add(vms[i], j); + vcpus[i * max_vcpu + j] = __vm_vcpu_add(vms[i], j); } /* Check stats read for every VM and VCPU */ for (i = 0; i < max_vm; ++i) { vm_stats_test(vms[i]); for (j = 0; j < max_vcpu; ++j) - vcpu_stats_test(vcpus[j * max_vcpu + i]); + vcpu_stats_test(vcpus[i * max_vcpu + j]); } for (i = 0; i < max_vm; ++i) From 4f48e2e737451365bc81c3b6283036a9079bcc24 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 13 Jun 2022 16:19:39 +0000 Subject: [PATCH 0486/1436] KVM: selftests: Add a missing apostrophe in comment to show ownership Add an apostrophe in a comment about it being the caller's, not callers, responsibility to free an object. Reported-by: Andrew Jones Fixes: 768e9a61856b ("KVM: selftests: Purge vm+vcpu_id == vcpu silliness") Signed-off-by: Sean Christopherson Message-Id: <20220613161942.1586791-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/kvm_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 39f2f5f1338f..0c550fb0dab2 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1434,7 +1434,7 @@ void vcpu_run_complete_io(struct kvm_vcpu *vcpu) /* * Get the list of guest registers which are supported for * KVM_GET_ONE_REG/KVM_SET_ONE_REG ioctls. Returns a kvm_reg_list pointer, - * it is the callers responsibility to free the list. + * it is the caller's responsibility to free the list. */ struct kvm_reg_list *vcpu_get_reg_list(struct kvm_vcpu *vcpu) { From ad125f309850b9cf2ba4f39729c5cc827595fac4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 13 Jun 2022 16:19:40 +0000 Subject: [PATCH 0487/1436] KVM: selftests: Call a dummy helper in VM/vCPU ioctls() to enforce type Replace the goofy static_assert on the size of the @vm/@vcpu parameters with a call to a dummy helper, i.e. let the compiler naturally complain about an incompatible type instead of homebrewing a poor replacement. Reported-by: Andrew Jones Fixes: fcba483e8246 ("KVM: selftests: Sanity check input to ioctls() at build time") Signed-off-by: Sean Christopherson Message-Id: <20220613161942.1586791-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index cdaea2383543..7ebfc8c7de17 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -186,50 +186,55 @@ static inline bool kvm_has_cap(long cap) ioctl(fd, cmd, arg); \ }) -#define __kvm_ioctl(kvm_fd, cmd, arg) \ +#define __kvm_ioctl(kvm_fd, cmd, arg) \ kvm_do_ioctl(kvm_fd, cmd, arg) -#define _kvm_ioctl(kvm_fd, cmd, name, arg) \ -({ \ - int ret = __kvm_ioctl(kvm_fd, cmd, arg); \ - \ - TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \ +#define _kvm_ioctl(kvm_fd, cmd, name, arg) \ +({ \ + int ret = __kvm_ioctl(kvm_fd, cmd, arg); \ + \ + TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \ }) #define kvm_ioctl(kvm_fd, cmd, arg) \ _kvm_ioctl(kvm_fd, cmd, #cmd, arg) -#define __vm_ioctl(vm, cmd, arg) \ -({ \ - static_assert(sizeof(*(vm)) == sizeof(struct kvm_vm), ""); \ - kvm_do_ioctl((vm)->fd, cmd, arg); \ +static __always_inline void static_assert_is_vm(struct kvm_vm *vm) { } + +#define __vm_ioctl(vm, cmd, arg) \ +({ \ + static_assert_is_vm(vm); \ + kvm_do_ioctl((vm)->fd, cmd, arg); \ }) -#define _vm_ioctl(vm, cmd, name, arg) \ -({ \ - int ret = __vm_ioctl(vm, cmd, arg); \ - \ - TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \ +#define _vm_ioctl(vm, cmd, name, arg) \ +({ \ + int ret = __vm_ioctl(vm, cmd, arg); \ + \ + TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \ }) -#define vm_ioctl(vm, cmd, arg) \ +#define vm_ioctl(vm, cmd, arg) \ _vm_ioctl(vm, cmd, #cmd, arg) -#define __vcpu_ioctl(vcpu, cmd, arg) \ -({ \ - static_assert(sizeof(*(vcpu)) == sizeof(struct kvm_vcpu), ""); \ - kvm_do_ioctl((vcpu)->fd, cmd, arg); \ + +static __always_inline void static_assert_is_vcpu(struct kvm_vcpu *vcpu) { } + +#define __vcpu_ioctl(vcpu, cmd, arg) \ +({ \ + static_assert_is_vcpu(vcpu); \ + kvm_do_ioctl((vcpu)->fd, cmd, arg); \ }) -#define _vcpu_ioctl(vcpu, cmd, name, arg) \ -({ \ - int ret = __vcpu_ioctl(vcpu, cmd, arg); \ - \ - TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \ +#define _vcpu_ioctl(vcpu, cmd, name, arg) \ +({ \ + int ret = __vcpu_ioctl(vcpu, cmd, arg); \ + \ + TEST_ASSERT(!ret, __KVM_IOCTL_ERROR(name, ret)); \ }) -#define vcpu_ioctl(vcpu, cmd, arg) \ +#define vcpu_ioctl(vcpu, cmd, arg) \ _vcpu_ioctl(vcpu, cmd, #cmd, arg) /* From 96f113c40d2882ac9b5e4fcac9e48c32eb030aa3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 13 Jun 2022 16:19:41 +0000 Subject: [PATCH 0488/1436] KVM: selftests: Drop a duplicate TEST_ASSERT() in vm_nr_pages_required() Remove a duplicate TEST_ASSERT() on the number of runnable vCPUs in vm_nr_pages_required() that snuck in during a rebase gone bad. Reported-by: Andrew Jones Fixes: 6e1d13bf3815 ("KVM: selftests: Move per-VM/per-vCPU nr pages calculation to __vm_create()") Signed-off-by: Sean Christopherson Message-Id: <20220613161942.1586791-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/kvm_util.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 0c550fb0dab2..bceb668f2627 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -284,10 +284,6 @@ static uint64_t vm_nr_pages_required(enum vm_guest_mode mode, */ nr_pages += (nr_pages + extra_mem_pages) / PTES_PER_MIN_PAGE * 2; - TEST_ASSERT(nr_runnable_vcpus <= kvm_check_cap(KVM_CAP_MAX_VCPUS), - "Host doesn't support %d vCPUs, max-vcpus = %d", - nr_runnable_vcpus, kvm_check_cap(KVM_CAP_MAX_VCPUS)); - return vm_adjust_num_guest_pages(mode, nr_pages); } From 9393cb13fa5d4c1ef2f1c3086af1c2cc03389bad Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 13 Jun 2022 16:19:42 +0000 Subject: [PATCH 0489/1436] KVM: selftests: Use kvm_has_cap(), not kvm_check_cap(), where possible Replace calls to kvm_check_cap() that treat its return as a boolean with calls to kvm_has_cap(). Several instances of kvm_check_cap() were missed when kvm_has_cap() was introduced. Reported-by: Andrew Jones Fixes: 3ea9b809650b ("KVM: selftests: Add kvm_has_cap() to provide syntactic sugar") Signed-off-by: Sean Christopherson Message-Id: <20220613161942.1586791-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/aarch64/psci_test.c | 2 +- tools/testing/selftests/kvm/lib/x86_64/processor.c | 4 ++-- tools/testing/selftests/kvm/s390x/sync_regs_test.c | 2 +- tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c | 2 +- tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c | 6 +++--- tools/testing/selftests/kvm/x86_64/smm_test.c | 2 +- tools/testing/selftests/kvm/x86_64/state_test.c | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index a889e1cf5e4d..b665b534cb78 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -192,7 +192,7 @@ static void host_test_system_suspend(void) int main(void) { - TEST_REQUIRE(kvm_check_cap(KVM_CAP_ARM_SYSTEM_SUSPEND)); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SYSTEM_SUSPEND)); host_test_cpu_on(); host_test_system_suspend(); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 4a7de11d6f37..906132e70fa4 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -991,7 +991,7 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vcpu *vcpu) vcpu_regs_get(vcpu, &state->regs); vcpu_save_xsave_state(vcpu, state); - if (kvm_check_cap(KVM_CAP_XCRS)) + if (kvm_has_cap(KVM_CAP_XCRS)) vcpu_xcrs_get(vcpu, &state->xcrs); vcpu_sregs_get(vcpu, &state->sregs); @@ -1022,7 +1022,7 @@ void vcpu_load_state(struct kvm_vcpu *vcpu, struct kvm_x86_state *state) vcpu_sregs_set(vcpu, &state->sregs); vcpu_msrs_set(vcpu, &state->msrs); - if (kvm_check_cap(KVM_CAP_XCRS)) + if (kvm_has_cap(KVM_CAP_XCRS)) vcpu_xcrs_set(vcpu, &state->xcrs); vcpu_xsave_set(vcpu, state->xsave); diff --git a/tools/testing/selftests/kvm/s390x/sync_regs_test.c b/tools/testing/selftests/kvm/s390x/sync_regs_test.c index b69710822c47..3fdb6e2598eb 100644 --- a/tools/testing/selftests/kvm/s390x/sync_regs_test.c +++ b/tools/testing/selftests/kvm/s390x/sync_regs_test.c @@ -229,7 +229,7 @@ int main(int argc, char *argv[]) struct kvm_vm *vm; int idx; - TEST_REQUIRE(kvm_check_cap(KVM_CAP_SYNC_REGS)); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_SYNC_REGS)); /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 786b3a794f84..530a75fee92c 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -450,7 +450,7 @@ int main(int argc, char *argv[]) /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - TEST_REQUIRE(kvm_check_cap(KVM_CAP_PMU_EVENT_FILTER)); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_PMU_EVENT_FILTER)); TEST_REQUIRE(use_intel_pmu() || use_amd_pmu()); guest_code = use_intel_pmu() ? intel_guest_code : amd_guest_code; diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index 76ba6fc80e37..46018b247a04 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -411,16 +411,16 @@ int main(int argc, char *argv[]) have_sev_es = !!(cpuid->eax & X86_FEATURE_SEV_ES); - if (kvm_check_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM)) { + if (kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM)) { test_sev_migrate_from(/* es= */ false); if (have_sev_es) test_sev_migrate_from(/* es= */ true); test_sev_migrate_locking(); test_sev_migrate_parameters(); - if (kvm_check_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) + if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) test_sev_move_copy(); } - if (kvm_check_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) { + if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) { test_sev_mirror(/* es= */ false); if (have_sev_es) test_sev_mirror(/* es= */ true); diff --git a/tools/testing/selftests/kvm/x86_64/smm_test.c b/tools/testing/selftests/kvm/x86_64/smm_test.c index 3cd1da388b52..921cbf117329 100644 --- a/tools/testing/selftests/kvm/x86_64/smm_test.c +++ b/tools/testing/selftests/kvm/x86_64/smm_test.c @@ -153,7 +153,7 @@ int main(int argc, char *argv[]) vcpu_set_msr(vcpu, MSR_IA32_SMBASE, SMRAM_GPA); - if (kvm_check_cap(KVM_CAP_NESTED_STATE)) { + if (kvm_has_cap(KVM_CAP_NESTED_STATE)) { if (nested_svm_supported()) vcpu_alloc_svm(vm, &nested_gva); else if (nested_vmx_supported()) diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index 0bcd78cf7c79..e2f1f35e51ff 100644 --- a/tools/testing/selftests/kvm/x86_64/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -169,7 +169,7 @@ int main(int argc, char *argv[]) vcpu_regs_get(vcpu, ®s1); - if (kvm_check_cap(KVM_CAP_NESTED_STATE)) { + if (kvm_has_cap(KVM_CAP_NESTED_STATE)) { if (nested_svm_supported()) vcpu_alloc_svm(vm, &nested_gva); else if (nested_vmx_supported()) From 1cb67e25f9a844425f85e592c7ffb8428800a796 Mon Sep 17 00:00:00 2001 From: Shaoqin Huang Date: Tue, 14 Jun 2022 16:41:19 -0600 Subject: [PATCH 0490/1436] KVM: selftests: Remove the mismatched parameter comments There are some parameter being removed in function but the parameter comments still exist, so remove them. Signed-off-by: Shaoqin Huang Message-Id: <20220614224126.211054-1-shaoqin.huang@intel.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/kvm_util.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index bceb668f2627..f8c104dba258 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1163,8 +1163,6 @@ va_found: * vm - Virtual Machine * sz - Size in bytes * vaddr_min - Minimum starting virtual address - * data_memslot - Memory region slot for data pages - * pgd_memslot - Memory region slot for new virtual translation tables * * Output Args: None * @@ -1250,7 +1248,6 @@ vm_vaddr_t vm_vaddr_alloc_page(struct kvm_vm *vm) * vaddr - Virtuall address to map * paddr - VM Physical Address * npages - The number of pages to map - * pgd_memslot - Memory region slot for new virtual translation tables * * Output Args: None * From 5bdae49fc2f689b5f896b54bd9230425d3643dab Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 15 Jun 2022 08:03:53 -0400 Subject: [PATCH 0491/1436] KVM: SEV: fix misplaced closing parenthesis This caused a warning on 32-bit systems, but undoubtedly would have acted funny on 64-bit as well. The fix was applied directly on merge in 5.19, see commit 24625f7d91fb ("Merge tag for-linus of git://git.kernel.org/pub/scm/virt/kvm/kvm"). Fixes: 3743c2f02517 ("KVM: x86: inhibit APICv/AVIC on changes to APIC ID or APIC base") Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/avic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 5542d8959e11..d1bc5820ea46 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -908,9 +908,9 @@ bool avic_check_apicv_inhibit_reasons(enum kvm_apicv_inhibit reason) BIT(APICV_INHIBIT_REASON_PIT_REINJ) | BIT(APICV_INHIBIT_REASON_X2APIC) | BIT(APICV_INHIBIT_REASON_BLOCKIRQ) | - BIT(APICV_INHIBIT_REASON_SEV | + BIT(APICV_INHIBIT_REASON_SEV) | BIT(APICV_INHIBIT_REASON_APIC_ID_MODIFIED) | - BIT(APICV_INHIBIT_REASON_APIC_BASE_MODIFIED)); + BIT(APICV_INHIBIT_REASON_APIC_BASE_MODIFIED); return supported & BIT(reason); } From e5380f6d7586ea3ef3a55d8cf19ceffacea31392 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 13 Jun 2022 21:42:37 +0000 Subject: [PATCH 0492/1436] KVM: SVM: Hide SEV migration lockdep goo behind CONFIG_PROVE_LOCKING Wrap the manipulation of @role and the manual mutex_{release,acquire}() invocations in CONFIG_PROVE_LOCKING=y to squash a clang-15 warning. When building with -Wunused-but-set-parameter and CONFIG_DEBUG_LOCK_ALLOC=n, clang-15 seees there's no usage of @role in mutex_lock_killable_nested() and yells. PROVE_LOCKING selects DEBUG_LOCK_ALLOC, and the only reason KVM manipulates @role is to make PROVE_LOCKING happy. To avoid true ugliness, use "i" and "j" to detect the first pass in the loops; the "idx" field that's used by kvm_for_each_vcpu() is guaranteed to be '0' on the first pass as it's simply the first entry in the vCPUs XArray, which is fully KVM controlled. kvm_for_each_vcpu() passes '0' for xa_for_each_range()'s "start", and xa_for_each_range() will not enter the loop if there's no entry at '0'. Fixes: 0c2c7c069285 ("KVM: SEV: Mark nested locking of vcpu->lock") Reported-by: kernel test robot Cc: Peter Gonda Signed-off-by: Sean Christopherson Message-Id: <20220613214237.2538266-1-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/sev.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 51fd985cf21d..309bcdb2f929 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1606,38 +1606,35 @@ static int sev_lock_vcpus_for_migration(struct kvm *kvm, { struct kvm_vcpu *vcpu; unsigned long i, j; - bool first = true; kvm_for_each_vcpu(i, vcpu, kvm) { if (mutex_lock_killable_nested(&vcpu->mutex, role)) goto out_unlock; - if (first) { +#ifdef CONFIG_PROVE_LOCKING + if (!i) /* * Reset the role to one that avoids colliding with * the role used for the first vcpu mutex. */ role = SEV_NR_MIGRATION_ROLES; - first = false; - } else { + else mutex_release(&vcpu->mutex.dep_map, _THIS_IP_); - } +#endif } return 0; out_unlock: - first = true; kvm_for_each_vcpu(j, vcpu, kvm) { if (i == j) break; - if (first) - first = false; - else +#ifdef CONFIG_PROVE_LOCKING + if (j) mutex_acquire(&vcpu->mutex.dep_map, role, 0, _THIS_IP_); - +#endif mutex_unlock(&vcpu->mutex); } From 37f80a7c9987ff5f0a1e023dbbda2ad6b47431f7 Mon Sep 17 00:00:00 2001 From: Janis Schoetterl-Glausch Date: Tue, 14 Jun 2022 18:26:35 +0200 Subject: [PATCH 0493/1436] KVM: s390: selftests: Fix memop extension capability check Fix the inverted logic of the memop extension capability check. Fixes: 97da92c0ff92 ("KVM: s390: selftests: Use TAP interface in the memop test") Signed-off-by: Janis Schoetterl-Glausch Message-Id: <20220614162635.3445019-1-scgl@linux.ibm.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/s390x/memop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/s390x/memop.c b/tools/testing/selftests/kvm/s390x/memop.c index a8f9b74b9144..9113696d5178 100644 --- a/tools/testing/selftests/kvm/s390x/memop.c +++ b/tools/testing/selftests/kvm/s390x/memop.c @@ -768,7 +768,7 @@ int main(int argc, char *argv[]) extension_cap = kvm_check_cap(KVM_CAP_S390_MEM_OP_EXTENSION); for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) { - if (testlist[idx].extension >= extension_cap) { + if (extension_cap >= testlist[idx].extension) { testlist[idx].test(); ksft_test_result_pass("%s\n", testlist[idx].name); } else { From fc10020ac9ece7aacea87753beafc0fbd49e8c58 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Sun, 5 Jun 2022 14:34:13 +0800 Subject: [PATCH 0494/1436] KVM: X86/MMU: Remove unused PT32_DIR_BASE_ADDR_MASK from mmu.c It is unused. Signed-off-by: Lai Jiangshan Message-Id: <20220605063417.308311-3-jiangshanlai@gmail.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 17252f39bd7c..f168693695bd 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -125,8 +125,6 @@ module_param(dbg, bool, 0644); #define PT32_BASE_ADDR_MASK PAGE_MASK -#define PT32_DIR_BASE_ADDR_MASK \ - (PAGE_MASK & ~((1ULL << (PAGE_SHIFT + PT32_LEVEL_BITS)) - 1)) #define PT32_LVL_ADDR_MASK(level) \ (PAGE_MASK & ~((1ULL << (PAGE_SHIFT + (((level) - 1) \ * PT32_LEVEL_BITS))) - 1)) From f24b44e48d267092dd79dba1288dc73ac414447e Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Sun, 5 Jun 2022 14:34:15 +0800 Subject: [PATCH 0495/1436] KVM: Rename ack_flush() to ack_kick() Make it use the same verb as in kvm_kick_many_cpus(). Signed-off-by: Lai Jiangshan Message-Id: <20220605063417.308311-5-jiangshanlai@gmail.com> Signed-off-by: Paolo Bonzini --- virt/kvm/kvm_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index a67e996cbf7f..b13acbaa6d2a 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -239,7 +239,7 @@ static bool kvm_request_needs_ipi(struct kvm_vcpu *vcpu, unsigned req) return mode == IN_GUEST_MODE; } -static void ack_flush(void *_completed) +static void ack_kick(void *_completed) { } @@ -248,7 +248,7 @@ static inline bool kvm_kick_many_cpus(struct cpumask *cpus, bool wait) if (cpumask_empty(cpus)) return false; - smp_call_function_many(cpus, ack_flush, NULL, wait); + smp_call_function_many(cpus, ack_kick, NULL, wait); return true; } From 024c3c3304ca36c23ee400b507fb59ae2e2db7fa Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Sun, 5 Jun 2022 14:34:16 +0800 Subject: [PATCH 0496/1436] KVM: X86/MMU: Remove useless mmu_topup_memory_caches() in kvm_mmu_pte_write() Since the commit c5e2184d1544("KVM: x86/mmu: Remove the defunct update_pte() paging hook"), kvm_mmu_pte_write() no longer uses the rmap cache. So remove mmu_topup_memory_caches() in it. Cc: Sean Christopherson Signed-off-by: Lai Jiangshan Message-Id: <20220605063417.308311-6-jiangshanlai@gmail.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index f168693695bd..0a4438544c0d 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -5326,13 +5326,6 @@ static void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa, pgprintk("%s: gpa %llx bytes %d\n", __func__, gpa, bytes); - /* - * No need to care whether allocation memory is successful - * or not since pte prefetch is skipped if it does not have - * enough objects in the cache. - */ - mmu_topup_memory_caches(vcpu, true); - write_lock(&vcpu->kvm->mmu_lock); gentry = mmu_pte_write_fetch_gpte(vcpu, &gpa, &bytes); From 78c7d9001be704b7d13083333354c6ddf6e32fce Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Sun, 5 Jun 2022 14:34:17 +0800 Subject: [PATCH 0497/1436] KVM: X86/SVM: Use root_level in svm_load_mmu_pgd() Use root_level in svm_load_mmu_pg() rather that looking up the root level in vcpu->arch.mmu->root_role.level. svm_load_mmu_pgd() has only one caller, kvm_mmu_load_pgd(), which always passes vcpu->arch.mmu->root_role.level as root_level. Signed-off-by: Lai Jiangshan Message-Id: <20220605063417.308311-7-jiangshanlai@gmail.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/svm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index c6cca0ce127b..2ba0c62df8fb 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4049,7 +4049,7 @@ static void svm_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa, hv_track_root_tdp(vcpu, root_hpa); cr3 = vcpu->arch.cr3; - } else if (vcpu->arch.mmu->root_role.level >= PT64_ROOT_4LEVEL) { + } else if (root_level >= PT64_ROOT_4LEVEL) { cr3 = __sme_set(root_hpa) | kvm_get_active_pcid(vcpu); } else { /* PCID in the guest should be impossible with a 32-bit MMU. */ From 007a369fba3c120d9a343bb2e8f04cf64c988183 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 13 Jun 2022 22:57:16 +0000 Subject: [PATCH 0498/1436] KVM: x86/mmu: Drop unused CMPXCHG macro from paging_tmpl.h Drop the CMPXCHG macro from paging_tmpl.h, it's no longer used now that KVM uses a common uaccess helper to do 8-byte CMPXCHG. Fixes: f122dfe44768 ("KVM: x86: Use __try_cmpxchg_user() to update guest PTE A/D bits") Signed-off-by: Sean Christopherson Message-Id: <20220613225723.2734132-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/paging_tmpl.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index fe35d8fd3276..f595c4b8657f 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -34,7 +34,6 @@ #define PT_HAVE_ACCESSED_DIRTY(mmu) true #ifdef CONFIG_X86_64 #define PT_MAX_FULL_LEVELS PT64_ROOT_MAX_LEVEL - #define CMPXCHG "cmpxchgq" #else #define PT_MAX_FULL_LEVELS 2 #endif @@ -51,7 +50,6 @@ #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT #define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT #define PT_HAVE_ACCESSED_DIRTY(mmu) true - #define CMPXCHG "cmpxchgl" #elif PTTYPE == PTTYPE_EPT #define pt_element_t u64 #define guest_walker guest_walkerEPT @@ -64,9 +62,6 @@ #define PT_GUEST_DIRTY_SHIFT 9 #define PT_GUEST_ACCESSED_SHIFT 8 #define PT_HAVE_ACCESSED_DIRTY(mmu) (!(mmu)->cpu_role.base.ad_disabled) - #ifdef CONFIG_X86_64 - #define CMPXCHG "cmpxchgq" - #endif #define PT_MAX_FULL_LEVELS PT64_ROOT_MAX_LEVEL #else #error Invalid PTTYPE value @@ -1100,7 +1095,6 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) #undef PT_MAX_FULL_LEVELS #undef gpte_to_gfn #undef gpte_to_gfn_lvl -#undef CMPXCHG #undef PT_GUEST_ACCESSED_MASK #undef PT_GUEST_DIRTY_MASK #undef PT_GUEST_DIRTY_SHIFT From d895f28ed6da96d7b922bd79977e2b732b103a99 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 10 Jun 2022 21:41:40 +0000 Subject: [PATCH 0499/1436] KVM: VMX: Skip filter updates for MSRs that KVM is already intercepting When handling userspace MSR filter updates, recompute interception for possible passthrough MSRs if and only if KVM wants to disabled interception. If KVM wants to intercept accesses, i.e. the associated bit is set in vmx->shadow_msr_intercept, then there's no need to set the intercept again as KVM will intercept the MSR regardless of userspace's wants. No functional change intended, the call to vmx_enable_intercept_for_msr() really is just a gigantic nop. Suggested-by: Aaron Lewis Signed-off-by: Sean Christopherson Message-Id: <20220610214140.612025-1-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 5e14e4c40007..61962f3c4b28 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -3981,17 +3981,21 @@ static void vmx_msr_filter_changed(struct kvm_vcpu *vcpu) u32 i; /* - * Set intercept permissions for all potentially passed through MSRs - * again. They will automatically get filtered through the MSR filter, - * so we are back in sync after this. + * Redo intercept permissions for MSRs that KVM is passing through to + * the guest. Disabling interception will check the new MSR filter and + * ensure that KVM enables interception if usersepace wants to filter + * the MSR. MSRs that KVM is already intercepting don't need to be + * refreshed since KVM is going to intercept them regardless of what + * userspace wants. */ for (i = 0; i < ARRAY_SIZE(vmx_possible_passthrough_msrs); i++) { u32 msr = vmx_possible_passthrough_msrs[i]; - bool read = test_bit(i, vmx->shadow_msr_intercept.read); - bool write = test_bit(i, vmx->shadow_msr_intercept.write); - vmx_set_intercept_for_msr(vcpu, msr, MSR_TYPE_R, read); - vmx_set_intercept_for_msr(vcpu, msr, MSR_TYPE_W, write); + if (!test_bit(i, vmx->shadow_msr_intercept.read)) + vmx_disable_intercept_for_msr(vcpu, msr, MSR_TYPE_R); + + if (!test_bit(i, vmx->shadow_msr_intercept.write)) + vmx_disable_intercept_for_msr(vcpu, msr, MSR_TYPE_W); } pt_update_intercept_for_msr(vcpu); From aee98a6838d52d5cca14610d228893e9208f4ed1 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Wed, 18 May 2022 15:51:11 +0200 Subject: [PATCH 0500/1436] KVM: x86/mmu: Use try_cmpxchg64 in tdp_mmu_set_spte_atomic Use try_cmpxchg64 instead of cmpxchg64 (*ptr, old, new) != old in tdp_mmu_set_spte_atomic. cmpxchg returns success in ZF flag, so this change saves a compare after cmpxchg (and related move instruction in front of cmpxchg). Also, remove explicit assignment to iter->old_spte when cmpxchg fails, this is what try_cmpxchg does implicitly. Cc: Paolo Bonzini Cc: Sean Christopherson Signed-off-by: Uros Bizjak Reviewed-by: David Matlack Message-Id: <20220518135111.3535-1-ubizjak@gmail.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/tdp_mmu.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 7b9265d67131..2cd060eb34a4 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -633,7 +633,6 @@ static inline int tdp_mmu_set_spte_atomic(struct kvm *kvm, u64 new_spte) { u64 *sptep = rcu_dereference(iter->sptep); - u64 old_spte; /* * The caller is responsible for ensuring the old SPTE is not a REMOVED @@ -649,17 +648,8 @@ static inline int tdp_mmu_set_spte_atomic(struct kvm *kvm, * Note, fast_pf_fix_direct_spte() can also modify TDP MMU SPTEs and * does not hold the mmu_lock. */ - old_spte = cmpxchg64(sptep, iter->old_spte, new_spte); - if (old_spte != iter->old_spte) { - /* - * The page table entry was modified by a different logical - * CPU. Refresh iter->old_spte with the current value so the - * caller operates on fresh data, e.g. if it retries - * tdp_mmu_set_spte_atomic(). - */ - iter->old_spte = old_spte; + if (!try_cmpxchg64(sptep, &iter->old_spte, new_spte)) return -EBUSY; - } __handle_changed_spte(kvm, iter->as_id, iter->gfn, iter->old_spte, new_spte, iter->level, true); From 0ac304de73b37b66793d6cc1ad3a03886aa79791 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Fri, 20 May 2022 16:37:37 +0200 Subject: [PATCH 0501/1436] KVM: VMX: Use try_cmpxchg64 in pi_try_set_control Use try_cmpxchg64 instead of cmpxchg64 (*ptr, old, new) != old in pi_try_set_control. cmpxchg returns success in ZF flag, so this change saves a compare after cmpxchg (and related move instruction in front of cmpxchg): b9: 88 44 24 60 mov %al,0x60(%rsp) bd: 48 89 c8 mov %rcx,%rax c0: c6 44 24 62 f2 movb $0xf2,0x62(%rsp) c5: 48 8b 74 24 60 mov 0x60(%rsp),%rsi ca: f0 49 0f b1 34 24 lock cmpxchg %rsi,(%r12) d0: 48 39 c1 cmp %rax,%rcx d3: 75 cf jne a4 patched: c1: 88 54 24 60 mov %dl,0x60(%rsp) c5: c6 44 24 62 f2 movb $0xf2,0x62(%rsp) ca: 48 8b 54 24 60 mov 0x60(%rsp),%rdx cf: f0 48 0f b1 13 lock cmpxchg %rdx,(%rbx) d4: 75 d5 jne ab Signed-off-by: Uros Bizjak Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vitaly Kuznetsov Cc: Wanpeng Li Cc: Jim Mattson Cc: Joerg Roedel Reported-by: kernel test robot Message-Id: <20220520143737.62513-1-ubizjak@gmail.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/posted_intr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/posted_intr.c b/arch/x86/kvm/vmx/posted_intr.c index 237a1f40f939..73f60aa480fe 100644 --- a/arch/x86/kvm/vmx/posted_intr.c +++ b/arch/x86/kvm/vmx/posted_intr.c @@ -42,7 +42,7 @@ static int pi_try_set_control(struct pi_desc *pi_desc, u64 old, u64 new) * update must be retried with a fresh snapshot an ON change causes * the cmpxchg to fail. */ - if (cmpxchg64(&pi_desc->control, old, new) != old) + if (!try_cmpxchg64(&pi_desc->control, &old, new)) return -EBUSY; return 0; From 2db2f46fdfc25691f3e90224e78bc5b2fc23dcd7 Mon Sep 17 00:00:00 2001 From: Uros Bizjak Date: Fri, 20 May 2022 16:46:35 +0200 Subject: [PATCH 0502/1436] KVM: x86/mmu: Use try_cmpxchg64 in fast_pf_fix_direct_spte Use try_cmpxchg64 instead of cmpxchg64 (*ptr, old, new) != old in fast_pf_fix_direct_spte. cmpxchg returns success in ZF flag, so this change saves a compare after cmpxchg (and related move instruction in front of cmpxchg). Signed-off-by: Uros Bizjak Cc: Paolo Bonzini Cc: Sean Christopherson Cc: Vitaly Kuznetsov Cc: Wanpeng Li Cc: Jim Mattson Cc: Joerg Roedel Message-Id: <20220520144635.63134-1-ubizjak@gmail.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 0a4438544c0d..34785bc3077d 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3093,7 +3093,7 @@ fast_pf_fix_direct_spte(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, * * Compare with set_spte where instead shadow_dirty_mask is set. */ - if (cmpxchg64(sptep, old_spte, new_spte) != old_spte) + if (!try_cmpxchg64(sptep, &old_spte, new_spte)) return false; if (is_writable_pte(new_spte) && !is_writable_pte(old_spte)) From 76e645be7ebecbf39ab2edd949ea7f1757f58900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Sat, 11 Jun 2022 13:39:11 +0200 Subject: [PATCH 0503/1436] HID: uclogic: Make template placeholder IDs generic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Up until now, the report descriptor template parameter IDs were only used with pen report descriptors and they were named accordingly. Rename the enum and the total number of IDs to make them interface agnostic. Refactor, no functional changes. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-params.c | 4 ++-- drivers/hid/hid-uclogic-rdesc.c | 14 +++++++------- drivers/hid/hid-uclogic-rdesc.h | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index db838f16282d..b43142f98a8b 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -234,7 +234,7 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen, const int len = 12; s32 resolution; /* Pen report descriptor template parameters */ - s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM]; + s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; __u8 *desc_ptr = NULL; /* Check arguments */ @@ -379,7 +379,7 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen, size_t i; s32 resolution; /* Pen report descriptor template parameters */ - s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM]; + s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; __u8 *desc_ptr = NULL; /* Check arguments */ diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index 13f9ce73f1b1..7126fba80968 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -979,7 +979,7 @@ const size_t uclogic_rdesc_xppen_deco01_frame_size = * uclogic_rdesc_template_apply() - apply report descriptor parameters to a * report descriptor template, creating a report descriptor. Copies the * template over to the new report descriptor and replaces every occurrence of - * UCLOGIC_RDESC_PH_HEAD, followed by an index byte, with the value from the + * UCLOGIC_RDESC_PEN_PH_HEAD, followed by an index byte, with the value from the * parameter list at that index. * * @template_ptr: Pointer to the template buffer. @@ -996,7 +996,7 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, const s32 *param_list, size_t param_num) { - static const __u8 head[] = {UCLOGIC_RDESC_PH_HEAD}; + static const __u8 pen_head[] = {UCLOGIC_RDESC_PEN_PH_HEAD}; __u8 *rdesc_ptr; __u8 *p; s32 v; @@ -1005,12 +1005,12 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, if (rdesc_ptr == NULL) return NULL; - for (p = rdesc_ptr; p + sizeof(head) < rdesc_ptr + template_size;) { - if (memcmp(p, head, sizeof(head)) == 0 && - p[sizeof(head)] < param_num) { - v = param_list[p[sizeof(head)]]; + for (p = rdesc_ptr; p + sizeof(pen_head) < rdesc_ptr + template_size;) { + if (memcmp(p, pen_head, sizeof(pen_head)) == 0 && + p[sizeof(pen_head)] < param_num) { + v = param_list[p[sizeof(pen_head)]]; put_unaligned(cpu_to_le32(v), (s32 *)p); - p += sizeof(head) + 1; + p += sizeof(pen_head) + 1; } else { p++; } diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h index 0c6e95e8bde7..9d37090c39d1 100644 --- a/drivers/hid/hid-uclogic-rdesc.h +++ b/drivers/hid/hid-uclogic-rdesc.h @@ -81,7 +81,7 @@ extern __u8 uclogic_rdesc_twha60_fixed1_arr[]; extern const size_t uclogic_rdesc_twha60_fixed1_size; /* Report descriptor template placeholder head */ -#define UCLOGIC_RDESC_PH_HEAD 0xFE, 0xED, 0x1D +#define UCLOGIC_RDESC_PEN_PH_HEAD 0xFE, 0xED, 0x1D /* Apply report descriptor parameters to a report descriptor template */ extern __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, @@ -89,19 +89,19 @@ extern __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, const s32 *param_list, size_t param_num); -/* Pen report descriptor template placeholder IDs */ -enum uclogic_rdesc_pen_ph_id { +/* Report descriptor template placeholder IDs */ +enum uclogic_rdesc_ph_id { UCLOGIC_RDESC_PEN_PH_ID_X_LM, UCLOGIC_RDESC_PEN_PH_ID_X_PM, UCLOGIC_RDESC_PEN_PH_ID_Y_LM, UCLOGIC_RDESC_PEN_PH_ID_Y_PM, UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM, - UCLOGIC_RDESC_PEN_PH_ID_NUM + UCLOGIC_RDESC_PH_ID_NUM }; /* Report descriptor pen template placeholder */ #define UCLOGIC_RDESC_PEN_PH(_ID) \ - UCLOGIC_RDESC_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID + UCLOGIC_RDESC_PEN_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID /* Report ID for v1 pen reports */ #define UCLOGIC_RDESC_V1_PEN_ID 0x07 From 2d167aaba3864cf8f46b8364aa33e780de1da8f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Sat, 11 Jun 2022 13:39:12 +0200 Subject: [PATCH 0504/1436] HID: uclogic: Add KUnit tests for uclogic_rdesc_template_apply() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The uclogic_rdesc_template_apply() function is used by the driver to generate HID descriptors from templates. In order to avoid regressions in future patches, add KUnit tests to test the function. To run the tests: $ ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/hid \ --kconfig_add CONFIG_VIRTIO_UML=y \ --kconfig_add CONFIG_UML_PCI_OVER_VIRTIO=y Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/.kunitconfig | 5 + drivers/hid/Kconfig | 16 +++ drivers/hid/Makefile | 3 + drivers/hid/hid-uclogic-rdesc-test.c | 183 +++++++++++++++++++++++++++ 4 files changed, 207 insertions(+) create mode 100644 drivers/hid/.kunitconfig create mode 100644 drivers/hid/hid-uclogic-rdesc-test.c diff --git a/drivers/hid/.kunitconfig b/drivers/hid/.kunitconfig new file mode 100644 index 000000000000..04daeff5c970 --- /dev/null +++ b/drivers/hid/.kunitconfig @@ -0,0 +1,5 @@ +CONFIG_KUNIT=y +CONFIG_USB=y +CONFIG_USB_HID=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_KUNIT_TEST=y diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 70da5931082f..6ce92830b5d1 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1306,6 +1306,22 @@ config HID_MCP2221 To compile this driver as a module, choose M here: the module will be called hid-mcp2221.ko. +config HID_KUNIT_TEST + bool "KUnit tests for HID" if !KUNIT_ALL_TESTS + depends on KUNIT=y + depends on HID_UCLOGIC + default KUNIT_ALL_TESTS + help + This builds unit tests for HID. This option is not useful for + distributions or general kernels, but only for kernel + developers working on HID and associated drivers. + + For more information on KUnit and unit tests in general, + please refer to the KUnit documentation in + Documentation/dev-tools/kunit/. + + If in doubt, say "N". + endmenu endif # HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index cac2cbe26d11..b0bef8098139 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -144,6 +144,9 @@ obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o +obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-rdesc.o \ + hid-uclogic-rdesc-test.o + obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ obj-$(CONFIG_USB_KBD) += usbhid/ diff --git a/drivers/hid/hid-uclogic-rdesc-test.c b/drivers/hid/hid-uclogic-rdesc-test.c new file mode 100644 index 000000000000..ded59e226230 --- /dev/null +++ b/drivers/hid/hid-uclogic-rdesc-test.c @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * HID driver for UC-Logic devices not fully compliant with HID standard + * + * Copyright (c) 2022 José Expósito + */ + +#include +#include "./hid-uclogic-rdesc.h" + +struct uclogic_template_case { + const char *name; + const __u8 *template; + size_t template_size; + const s32 *param_list; + size_t param_num; + const __u8 *expected; +}; + +static const s32 params_pen_all[UCLOGIC_RDESC_PH_ID_NUM] = { + [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xAA, + [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB, + [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0xCC, + [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0xDD, + [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0xEE, +}; + +static const s32 params_pen_some[] = { + [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xAA, + [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB, +}; + +static const __u8 template_empty[] = { }; +static const __u8 template_small[] = { 0x00 }; +static const __u8 template_no_ph[] = { 0xAA, 0xFE, 0xAA, 0xED, 0x1D }; + +static const __u8 template_pen_ph_end[] = { + 0xAA, 0xBB, UCLOGIC_RDESC_PEN_PH_HEAD +}; + +static const __u8 template_pen_all_params[] = { + UCLOGIC_RDESC_PEN_PH(X_LM), + 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), + UCLOGIC_RDESC_PEN_PH(Y_PM), + 0x00, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), +}; + +static const __u8 expected_pen_all_params[] = { + 0xAA, 0x00, 0x00, 0x00, + 0x47, 0xBB, 0x00, 0x00, 0x00, + 0x27, 0xCC, 0x00, 0x00, 0x00, + 0xDD, 0x00, 0x00, 0x00, + 0x00, 0xEE, 0x00, 0x00, 0x00, +}; + +static const __u8 template_pen_some_params[] = { + 0x01, 0x02, + UCLOGIC_RDESC_PEN_PH(X_LM), + 0x03, UCLOGIC_RDESC_PEN_PH(X_PM), + 0x04, 0x05, +}; + +static const __u8 expected_pen_some_params[] = { + 0x01, 0x02, + 0xAA, 0x00, 0x00, 0x00, + 0x03, 0xBB, 0x00, 0x00, 0x00, + 0x04, 0x05, +}; + +static const __u8 template_params_none[] = { + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), + UCLOGIC_RDESC_PEN_PH(Y_PM), + 0x00, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), +}; + +static struct uclogic_template_case uclogic_template_cases[] = { + { + .name = "Empty template", + .template = template_empty, + .template_size = sizeof(template_empty), + .param_list = params_pen_all, + .param_num = ARRAY_SIZE(params_pen_all), + .expected = template_empty, + }, + { + .name = "Template smaller than the placeholder", + .template = template_small, + .template_size = sizeof(template_small), + .param_list = params_pen_all, + .param_num = ARRAY_SIZE(params_pen_all), + .expected = template_small, + }, + { + .name = "No placeholder", + .template = template_no_ph, + .template_size = sizeof(template_no_ph), + .param_list = params_pen_all, + .param_num = ARRAY_SIZE(params_pen_all), + .expected = template_no_ph, + }, + { + .name = "Pen placeholder at the end, without ID", + .template = template_pen_ph_end, + .template_size = sizeof(template_pen_ph_end), + .param_list = params_pen_all, + .param_num = ARRAY_SIZE(params_pen_all), + .expected = template_pen_ph_end, + }, + { + .name = "All params present in the pen template", + .template = template_pen_all_params, + .template_size = sizeof(template_pen_all_params), + .param_list = params_pen_all, + .param_num = ARRAY_SIZE(params_pen_all), + .expected = expected_pen_all_params, + }, + { + .name = "Some params present in the pen template (complete param list)", + .template = template_pen_some_params, + .template_size = sizeof(template_pen_some_params), + .param_list = params_pen_all, + .param_num = ARRAY_SIZE(params_pen_all), + .expected = expected_pen_some_params, + }, + { + .name = "Some params present in the pen template (incomplete param list)", + .template = template_pen_some_params, + .template_size = sizeof(template_pen_some_params), + .param_list = params_pen_some, + .param_num = ARRAY_SIZE(params_pen_some), + .expected = expected_pen_some_params, + }, + { + .name = "No params present in the template", + .template = template_params_none, + .template_size = sizeof(template_params_none), + .param_list = params_pen_some, + .param_num = ARRAY_SIZE(params_pen_some), + .expected = template_params_none, + }, +}; + +static void uclogic_template_case_desc(struct uclogic_template_case *t, + char *desc) +{ + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(uclogic_template, uclogic_template_cases, + uclogic_template_case_desc); + +static void uclogic_template_test(struct kunit *test) +{ + __u8 *res; + const struct uclogic_template_case *params = test->param_value; + + res = uclogic_rdesc_template_apply(params->template, + params->template_size, + params->param_list, + params->param_num); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res); + KUNIT_EXPECT_EQ(test, 0, + memcmp(res, params->expected, params->template_size)); + kfree(res); +} + +static struct kunit_case hid_uclogic_rdesc_test_cases[] = { + KUNIT_CASE_PARAM(uclogic_template_test, uclogic_template_gen_params), + {} +}; + +static struct kunit_suite hid_uclogic_rdesc_test_suite = { + .name = "hid-uclogic-rdesc-test", + .test_cases = hid_uclogic_rdesc_test_cases, +}; + +kunit_test_suite(hid_uclogic_rdesc_test_suite); + +MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("José Expósito "); From 867c8925442579f7c4a8901f02a54fb07e99c2be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Sat, 11 Jun 2022 13:39:13 +0200 Subject: [PATCH 0505/1436] HID: uclogic: Allow to generate frame templates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new template placeholder to allow configuring the number of buttons in the drawing tablet frame and update the KUnit tests to cover the new case. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-uclogic-rdesc-test.c | 36 ++++++++++++++++++++++++++++ drivers/hid/hid-uclogic-rdesc.c | 14 ++++++++--- drivers/hid/hid-uclogic-rdesc.h | 6 +++++ 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-uclogic-rdesc-test.c b/drivers/hid/hid-uclogic-rdesc-test.c index ded59e226230..ebebffef5f8a 100644 --- a/drivers/hid/hid-uclogic-rdesc-test.c +++ b/drivers/hid/hid-uclogic-rdesc-test.c @@ -31,6 +31,10 @@ static const s32 params_pen_some[] = { [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB, }; +static const s32 params_frame_all[UCLOGIC_RDESC_PH_ID_NUM] = { + [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0xFF, +}; + static const __u8 template_empty[] = { }; static const __u8 template_small[] = { 0x00 }; static const __u8 template_no_ph[] = { 0xAA, 0xFE, 0xAA, 0xED, 0x1D }; @@ -39,6 +43,10 @@ static const __u8 template_pen_ph_end[] = { 0xAA, 0xBB, UCLOGIC_RDESC_PEN_PH_HEAD }; +static const __u8 template_btn_ph_end[] = { + 0xAA, 0xBB, UCLOGIC_RDESC_FRAME_PH_BTN_HEAD +}; + static const __u8 template_pen_all_params[] = { UCLOGIC_RDESC_PEN_PH(X_LM), 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), @@ -55,6 +63,18 @@ static const __u8 expected_pen_all_params[] = { 0x00, 0xEE, 0x00, 0x00, 0x00, }; +static const __u8 template_frame_all_params[] = { + 0x01, 0x02, + UCLOGIC_RDESC_FRAME_PH_BTN, + 0x99, +}; + +static const __u8 expected_frame_all_params[] = { + 0x01, 0x02, + 0x2A, 0xFF, 0x00, + 0x99, +}; + static const __u8 template_pen_some_params[] = { 0x01, 0x02, UCLOGIC_RDESC_PEN_PH(X_LM), @@ -108,6 +128,14 @@ static struct uclogic_template_case uclogic_template_cases[] = { .param_num = ARRAY_SIZE(params_pen_all), .expected = template_pen_ph_end, }, + { + .name = "Frame button placeholder at the end, without ID", + .template = template_btn_ph_end, + .template_size = sizeof(template_btn_ph_end), + .param_list = params_frame_all, + .param_num = ARRAY_SIZE(params_frame_all), + .expected = template_btn_ph_end, + }, { .name = "All params present in the pen template", .template = template_pen_all_params, @@ -116,6 +144,14 @@ static struct uclogic_template_case uclogic_template_cases[] = { .param_num = ARRAY_SIZE(params_pen_all), .expected = expected_pen_all_params, }, + { + .name = "All params present in the frame template", + .template = template_frame_all_params, + .template_size = sizeof(template_frame_all_params), + .param_list = params_frame_all, + .param_num = ARRAY_SIZE(params_frame_all), + .expected = expected_frame_all_params, + }, { .name = "Some params present in the pen template (complete param list)", .template = template_pen_some_params, diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index 7126fba80968..3fb84ac492b4 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -979,7 +979,7 @@ const size_t uclogic_rdesc_xppen_deco01_frame_size = * uclogic_rdesc_template_apply() - apply report descriptor parameters to a * report descriptor template, creating a report descriptor. Copies the * template over to the new report descriptor and replaces every occurrence of - * UCLOGIC_RDESC_PEN_PH_HEAD, followed by an index byte, with the value from the + * the template placeholders, followed by an index byte, with the value from the * parameter list at that index. * * @template_ptr: Pointer to the template buffer. @@ -996,6 +996,7 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, const s32 *param_list, size_t param_num) { + static const __u8 btn_head[] = {UCLOGIC_RDESC_FRAME_PH_BTN_HEAD}; static const __u8 pen_head[] = {UCLOGIC_RDESC_PEN_PH_HEAD}; __u8 *rdesc_ptr; __u8 *p; @@ -1005,12 +1006,19 @@ __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, if (rdesc_ptr == NULL) return NULL; - for (p = rdesc_ptr; p + sizeof(pen_head) < rdesc_ptr + template_size;) { - if (memcmp(p, pen_head, sizeof(pen_head)) == 0 && + for (p = rdesc_ptr; p + sizeof(btn_head) < rdesc_ptr + template_size;) { + if (p + sizeof(pen_head) < rdesc_ptr + template_size && + memcmp(p, pen_head, sizeof(pen_head)) == 0 && p[sizeof(pen_head)] < param_num) { v = param_list[p[sizeof(pen_head)]]; put_unaligned(cpu_to_le32(v), (s32 *)p); p += sizeof(pen_head) + 1; + } else if (memcmp(p, btn_head, sizeof(btn_head)) == 0 && + p[sizeof(btn_head)] < param_num) { + v = param_list[p[sizeof(btn_head)]]; + put_unaligned((__u8)0x2A, p); /* Usage Maximum */ + put_unaligned_le16((__force u16)cpu_to_le16(v), p + 1); + p += sizeof(btn_head) + 1; } else { p++; } diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h index 9d37090c39d1..3d78299f082d 100644 --- a/drivers/hid/hid-uclogic-rdesc.h +++ b/drivers/hid/hid-uclogic-rdesc.h @@ -82,6 +82,7 @@ extern const size_t uclogic_rdesc_twha60_fixed1_size; /* Report descriptor template placeholder head */ #define UCLOGIC_RDESC_PEN_PH_HEAD 0xFE, 0xED, 0x1D +#define UCLOGIC_RDESC_FRAME_PH_BTN_HEAD 0xFE, 0xED /* Apply report descriptor parameters to a report descriptor template */ extern __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, @@ -96,6 +97,7 @@ enum uclogic_rdesc_ph_id { UCLOGIC_RDESC_PEN_PH_ID_Y_LM, UCLOGIC_RDESC_PEN_PH_ID_Y_PM, UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM, + UCLOGIC_RDESC_FRAME_PH_ID_UM, UCLOGIC_RDESC_PH_ID_NUM }; @@ -103,6 +105,10 @@ enum uclogic_rdesc_ph_id { #define UCLOGIC_RDESC_PEN_PH(_ID) \ UCLOGIC_RDESC_PEN_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID +/* Report descriptor frame buttons template placeholder */ +#define UCLOGIC_RDESC_FRAME_PH_BTN \ + UCLOGIC_RDESC_FRAME_PH_BTN_HEAD, UCLOGIC_RDESC_FRAME_PH_ID_UM + /* Report ID for v1 pen reports */ #define UCLOGIC_RDESC_V1_PEN_ID 0x07 From 0cb1fc0988e32bda84c2b7218e0c761af1430baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Exp=C3=B3sito?= Date: Sat, 11 Jun 2022 13:39:14 +0200 Subject: [PATCH 0506/1436] HID: uclogic: Add support for XP-PEN Deco L MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The XP-PEN Deco L (UGEE) needs to be initialized by sending a buffer of magic data, discovered by sniffing the Windows driver traffic. In order to differentiate UGEE tablets that need this kind of initialization from the previous ones, name them v2 internally and create an entry point for them. After initialization, the template report descriptors can be discovered by parsing a string descriptor, similar to the one exposed by HUION v1 devices. Add all the required elements to support the device. Signed-off-by: José Expósito Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-uclogic-core.c | 2 + drivers/hid/hid-uclogic-params.c | 197 +++++++++++++++++++++++++++++++ drivers/hid/hid-uclogic-rdesc.c | 102 ++++++++++++++++ drivers/hid/hid-uclogic-rdesc.h | 8 ++ 5 files changed, 310 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d9eb676abe96..139910034c17 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1278,6 +1278,7 @@ #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042 +#define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 #define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074 #define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071 diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index c0fe66e50c58..47a17375c7fc 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -521,6 +521,8 @@ static const struct hid_device_id uclogic_devices[] = { USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) }, { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) }, { } diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c index b43142f98a8b..f24a4aca7920 100644 --- a/drivers/hid/hid-uclogic-params.c +++ b/drivers/hid/hid-uclogic-params.c @@ -1002,6 +1002,197 @@ cleanup: return rc; } +/** + * uclogic_probe_interface() - some tablets, like the Parblo A610 PLUS V2 or + * the XP-PEN Deco Mini 7, need to be initialized by sending them magic data. + * + * @hdev: The HID device of the tablet interface to initialize and get + * parameters from. Cannot be NULL. + * @magic_arr: The magic data that should be sent to probe the interface. + * Cannot be NULL. + * @magic_size: Size of the magic data. + * @endpoint: Endpoint where the magic data should be sent. + * + * Returns: + * Zero, if successful. A negative errno code on error. + */ +static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr, + int magic_size, int endpoint) +{ + struct usb_device *udev; + unsigned int pipe = 0; + int sent; + u8 *buf = NULL; + int rc = 0; + + if (!hdev || !magic_arr) { + rc = -EINVAL; + goto cleanup; + } + + buf = kmemdup(magic_arr, magic_size, GFP_KERNEL); + if (!buf) { + rc = -ENOMEM; + goto cleanup; + } + + udev = hid_to_usb_dev(hdev); + pipe = usb_sndintpipe(udev, endpoint); + + rc = usb_interrupt_msg(udev, pipe, buf, magic_size, &sent, 1000); + if (rc || sent != magic_size) { + hid_err(hdev, "Interface probing failed: %d\n", rc); + rc = -1; + goto cleanup; + } + + rc = 0; +cleanup: + kfree(buf); + return rc; +} + +/** + * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by + * discovering their parameters. + * + * These tables, internally designed as v2 to differentiate them from older + * models, expect a payload of magic data in orther to be switched to the fully + * functional mode and expose their parameters in a similar way to the + * information present in uclogic_params_pen_init_v1() but with some + * differences. + * + * @params: Parameters to fill in (to be cleaned with + * uclogic_params_cleanup()). Not modified in case of error. + * Cannot be NULL. + * @hdev: The HID device of the tablet interface to initialize and get + * parameters from. Cannot be NULL. + * + * Returns: + * Zero, if successful. A negative errno code on error. + */ +static int uclogic_params_ugee_v2_init(struct uclogic_params *params, + struct hid_device *hdev) +{ + int rc = 0; + struct usb_interface *iface; + __u8 bInterfaceNumber; + const int str_desc_len = 12; + __u8 *str_desc = NULL; + __u8 *rdesc_pen = NULL; + __u8 *rdesc_frame = NULL; + s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; + s32 resolution; + __u8 magic_arr[] = { + 0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + /* The resulting parameters (noop) */ + struct uclogic_params p = {0, }; + + if (!params || !hdev) { + rc = -EINVAL; + goto cleanup; + } + + iface = to_usb_interface(hdev->dev.parent); + bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; + if (bInterfaceNumber != 2) { + uclogic_params_init_invalid(&p); + goto output; + } + + /* + * Initialize the interface by sending magic data. + * The specific data was discovered by sniffing the Windows driver + * traffic. + */ + rc = uclogic_probe_interface(hdev, magic_arr, sizeof(magic_arr), 0x03); + if (rc) { + uclogic_params_init_invalid(&p); + goto output; + } + + /* + * Read the string descriptor containing pen and frame parameters. + * The specific string descriptor and data were discovered by sniffing + * the Windows driver traffic. + */ + rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len); + if (rc != str_desc_len) { + hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc); + uclogic_params_init_invalid(&p); + goto output; + } + + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = + get_unaligned_le16(str_desc + 2); + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = + get_unaligned_le16(str_desc + 4); + desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = str_desc[6]; + desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = + get_unaligned_le16(str_desc + 8); + resolution = get_unaligned_le16(str_desc + 10); + if (resolution == 0) { + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0; + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0; + } else { + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / + resolution; + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / + resolution; + } + kfree(str_desc); + str_desc = NULL; + + /* Initialize the pen interface */ + rdesc_pen = uclogic_rdesc_template_apply( + uclogic_rdesc_ugee_v2_pen_template_arr, + uclogic_rdesc_ugee_v2_pen_template_size, + desc_params, ARRAY_SIZE(desc_params)); + if (!rdesc_pen) { + rc = -ENOMEM; + goto cleanup; + } + + p.pen.desc_ptr = rdesc_pen; + p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size; + p.pen.id = 0x02; + p.pen.subreport_list[0].value = 0xf0; + p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID; + + /* Initialize the frame interface */ + rdesc_frame = uclogic_rdesc_template_apply( + uclogic_rdesc_ugee_v2_frame_btn_template_arr, + uclogic_rdesc_ugee_v2_frame_btn_template_size, + desc_params, ARRAY_SIZE(desc_params)); + if (!rdesc_frame) { + rc = -ENOMEM; + goto cleanup; + } + + rc = uclogic_params_frame_init_with_desc(&p.frame_list[0], + rdesc_frame, + uclogic_rdesc_ugee_v2_frame_btn_template_size, + UCLOGIC_RDESC_V1_FRAME_ID); + kfree(rdesc_frame); + if (rc) { + uclogic_params_init_invalid(&p); + goto output; + } + +output: + /* Output parameters */ + memcpy(params, &p, sizeof(*params)); + memset(&p, 0, sizeof(p)); + rc = 0; +cleanup: + kfree(str_desc); + uclogic_params_cleanup(&p); + return rc; +} + /** * uclogic_params_init() - initialize a tablet interface and discover its * parameters. @@ -1237,6 +1428,12 @@ int uclogic_params_init(struct uclogic_params *params, uclogic_params_init_invalid(&p); } break; + case VID_PID(USB_VENDOR_ID_UGEE, + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L): + rc = uclogic_params_ugee_v2_init(&p, hdev); + if (rc != 0) + goto cleanup; + break; case VID_PID(USB_VENDOR_ID_TRUST, USB_DEVICE_ID_TRUST_PANORA_TABLET): case VID_PID(USB_VENDOR_ID_UGEE, diff --git a/drivers/hid/hid-uclogic-rdesc.c b/drivers/hid/hid-uclogic-rdesc.c index 3fb84ac492b4..3d68e8b0784d 100644 --- a/drivers/hid/hid-uclogic-rdesc.c +++ b/drivers/hid/hid-uclogic-rdesc.c @@ -859,6 +859,108 @@ const __u8 uclogic_rdesc_v2_frame_dial_arr[] = { const size_t uclogic_rdesc_v2_frame_dial_size = sizeof(uclogic_rdesc_v2_frame_dial_arr); +/* Fixed report descriptor template for UGEE v2 pen reports */ +const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[] = { + 0x05, 0x0d, /* Usage Page (Digitizers), */ + 0x09, 0x01, /* Usage (Digitizer), */ + 0xa1, 0x01, /* Collection (Application), */ + 0x85, 0x02, /* Report ID (2), */ + 0x09, 0x20, /* Usage (Stylus), */ + 0xa1, 0x00, /* Collection (Physical), */ + 0x09, 0x42, /* Usage (Tip Switch), */ + 0x09, 0x44, /* Usage (Barrel Switch), */ + 0x09, 0x46, /* Usage (Tablet Pick), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x14, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x09, 0x32, /* Usage (In Range), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x75, 0x10, /* Report Size (16), */ + 0x95, 0x01, /* Report Count (1), */ + 0x35, 0x00, /* Physical Minimum (0), */ + 0xa4, /* Push, */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x30, /* Usage (X), */ + 0x65, 0x13, /* Unit (Inch), */ + 0x55, 0x0d, /* Unit Exponent (-3), */ + 0x27, UCLOGIC_RDESC_PEN_PH(X_LM), + /* Logical Maximum (PLACEHOLDER), */ + 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), + /* Physical Maximum (PLACEHOLDER), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0x31, /* Usage (Y), */ + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), + /* Logical Maximum (PLACEHOLDER), */ + 0x47, UCLOGIC_RDESC_PEN_PH(Y_PM), + /* Physical Maximum (PLACEHOLDER), */ + 0x81, 0x02, /* Input (Variable), */ + 0xb4, /* Pop, */ + 0x09, 0x30, /* Usage (Tip Pressure), */ + 0x45, 0x00, /* Physical Maximum (0), */ + 0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), + /* Logical Maximum (PLACEHOLDER), */ + 0x75, 0x0D, /* Report Size (13), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x01, /* Input (Constant), */ + 0x09, 0x3d, /* Usage (X Tilt), */ + 0x35, 0xC3, /* Physical Minimum (-61), */ + 0x45, 0x3C, /* Physical Maximum (60), */ + 0x15, 0xC3, /* Logical Minimum (-61), */ + 0x25, 0x3C, /* Logical Maximum (60), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0x3e, /* Usage (Y Tilt), */ + 0x35, 0xC3, /* Physical Minimum (-61), */ + 0x45, 0x3C, /* Physical Maximum (60), */ + 0x15, 0xC3, /* Logical Minimum (-61), */ + 0x25, 0x3C, /* Logical Maximum (60), */ + 0x81, 0x02, /* Input (Variable), */ + 0xc0, /* End Collection, */ + 0xc0, /* End Collection */ +}; +const size_t uclogic_rdesc_ugee_v2_pen_template_size = + sizeof(uclogic_rdesc_ugee_v2_pen_template_arr); + +/* Fixed report descriptor template for UGEE v2 frame reports (buttons only) */ +const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x07, /* Usage (Keypad), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, UCLOGIC_RDESC_V1_FRAME_ID, + /* Report ID, */ + 0x05, 0x0D, /* Usage Page (Digitizer), */ + 0x09, 0x39, /* Usage (Tablet Function Keys), */ + 0xA0, /* Collection (Physical), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x08, /* Report Count (8), */ + 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + UCLOGIC_RDESC_FRAME_PH_BTN, + /* Usage Maximum (PLACEHOLDER), */ + 0x95, 0x0A, /* Report Count (10), */ + 0x14, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x46, /* Report Count (70), */ + 0x81, 0x01, /* Input (Constant), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; +const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size = + sizeof(uclogic_rdesc_ugee_v2_frame_btn_template_arr); + /* Fixed report descriptor for Ugee EX07 frame */ const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = { 0x05, 0x01, /* Usage Page (Desktop), */ diff --git a/drivers/hid/hid-uclogic-rdesc.h b/drivers/hid/hid-uclogic-rdesc.h index 3d78299f082d..86e64a9ee6bd 100644 --- a/drivers/hid/hid-uclogic-rdesc.h +++ b/drivers/hid/hid-uclogic-rdesc.h @@ -161,6 +161,14 @@ extern const size_t uclogic_rdesc_v2_frame_dial_size; /* Device ID byte offset in v2 frame dial reports */ #define UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE 0x4 +/* Fixed report descriptor template for UGEE v2 pen reports */ +extern const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[]; +extern const size_t uclogic_rdesc_ugee_v2_pen_template_size; + +/* Fixed report descriptor template for UGEE v2 frame reports (buttons only) */ +extern const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[]; +extern const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size; + /* Fixed report descriptor for Ugee EX07 frame */ extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[]; extern const size_t uclogic_rdesc_ugee_ex07_frame_size; From 842fec058171db8f58a6073502a625372dddd96a Mon Sep 17 00:00:00 2001 From: Thomas Schneider Date: Sat, 11 Jun 2022 03:03:59 +0200 Subject: [PATCH 0507/1436] HID: nintendo: Set phys property of input device based on HID phys While the MAC address the uniq identifier is set to (cf. commit 1425247383c5 ("HID: nintendo: set controller uniq to MAC")) is certainly unique, the physical location can be more helpful in user interfaces. The underlying hid_device already provides a suitable value, so we can simply reuse this here. Signed-off-by: Thomas Schneider Signed-off-by: Jiri Kosina --- drivers/hid/hid-nintendo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index 2204de889739..df9cd5d883c0 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -1634,6 +1634,7 @@ static int joycon_input_create(struct joycon_ctlr *ctlr) ctlr->input->id.version = hdev->version; ctlr->input->uniq = ctlr->mac_addr_str; ctlr->input->name = name; + ctlr->input->phys = hdev->phys; input_set_drvdata(ctlr->input, ctlr); /* set up sticks and buttons */ @@ -1713,6 +1714,7 @@ static int joycon_input_create(struct joycon_ctlr *ctlr) ctlr->imu_input->id.version = hdev->version; ctlr->imu_input->uniq = ctlr->mac_addr_str; ctlr->imu_input->name = imu_name; + ctlr->imu_input->phys = hdev->phys; input_set_drvdata(ctlr->imu_input, ctlr); /* configure imu axes */ From 668c01baa7106bffec8d9ebc076609fc86bb208d Mon Sep 17 00:00:00 2001 From: Stanislav Jakubek Date: Sat, 11 Jun 2022 20:07:03 +0200 Subject: [PATCH 0508/1436] dt-bindings: interrupt-controller: Convert rda,8810pl-intc to YAML Convert RDA Micro interrupt controller bindings to DT schema format. Signed-off-by: Stanislav Jakubek Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220611180703.GA24988@standask-GA-A55M-S2HP --- .../interrupt-controller/rda,8810pl-intc.txt | 61 ------------------- .../interrupt-controller/rda,8810pl-intc.yaml | 43 +++++++++++++ MAINTAINERS | 2 +- 3 files changed, 44 insertions(+), 62 deletions(-) delete mode 100644 Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt create mode 100644 Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.yaml diff --git a/Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt deleted file mode 100644 index e0062aebf025..000000000000 --- a/Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt +++ /dev/null @@ -1,61 +0,0 @@ -RDA Micro RDA8810PL Interrupt Controller - -The interrupt controller in RDA8810PL SoC is a custom interrupt controller -which supports up to 32 interrupts. - -Required properties: - -- compatible: Should be "rda,8810pl-intc". -- reg: Specifies base physical address of the registers set. -- interrupt-controller: Identifies the node as an interrupt controller. -- #interrupt-cells: Specifies the number of cells needed to encode an - interrupt source. The value shall be 2. - -The interrupt sources are as follows: - -ID Name ------------- -0: PULSE_DUMMY -1: I2C -2: NAND_NFSC -3: SDMMC1 -4: SDMMC2 -5: SDMMC3 -6: SPI1 -7: SPI2 -8: SPI3 -9: UART1 -10: UART2 -11: UART3 -12: GPIO1 -13: GPIO2 -14: GPIO3 -15: KEYPAD -16: TIMER -17: TIMEROS -18: COMREG0 -19: COMREG1 -20: USB -21: DMC -22: DMA -23: CAMERA -24: GOUDA -25: GPU -26: VPU_JPG -27: VPU_HOST -28: VOC -29: AUIFC0 -30: AUIFC1 -31: L2CC - -Example: - apb@20800000 { - compatible = "simple-bus"; - ... - intc: interrupt-controller@0 { - compatible = "rda,8810pl-intc"; - reg = <0x0 0x1000>; - interrupt-controller; - #interrupt-cells = <2>; - }; - }; diff --git a/Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.yaml new file mode 100644 index 000000000000..96d6285d0087 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.yaml @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/interrupt-controller/rda,8810pl-intc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: RDA Micro RDA8810PL interrupt controller + +maintainers: + - Manivannan Sadhasivam + +allOf: + - $ref: /schemas/interrupt-controller.yaml# + +properties: + compatible: + const: rda,8810pl-intc + + reg: + maxItems: 1 + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + +required: + - compatible + - reg + - interrupt-controller + - '#interrupt-cells' + +additionalProperties: false + +examples: + - | + intc: interrupt-controller@0 { + compatible = "rda,8810pl-intc"; + reg = <0x0 0x1000>; + interrupt-controller; + #interrupt-cells = <2>; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index a6d3bd9d2a8d..adc518ff1474 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2587,7 +2587,7 @@ L: linux-unisoc@lists.infradead.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/arm/rda.yaml F: Documentation/devicetree/bindings/gpio/gpio-rda.yaml -F: Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt +F: Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.yaml F: Documentation/devicetree/bindings/serial/rda,8810pl-uart.yaml F: Documentation/devicetree/bindings/timer/rda,8810pl-timer.yaml F: arch/arm/boot/dts/rda8810pl-* From b624c4d03760084988f4814b879b08c8c4d8169e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 15 Jun 2022 23:16:19 +0200 Subject: [PATCH 0509/1436] dt-bindings: hwmon: move ibm,p8-occ bindings to proper folder It accidently ended up in i2c, but it should be in the hwmon folder. Signed-off-by: Wolfram Sang Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220615211619.6742-1-wsa@kernel.org --- .../devicetree/bindings/{i2c => hwmon}/ibm,p8-occ-hwmon.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Documentation/devicetree/bindings/{i2c => hwmon}/ibm,p8-occ-hwmon.txt (100%) diff --git a/Documentation/devicetree/bindings/i2c/ibm,p8-occ-hwmon.txt b/Documentation/devicetree/bindings/hwmon/ibm,p8-occ-hwmon.txt similarity index 100% rename from Documentation/devicetree/bindings/i2c/ibm,p8-occ-hwmon.txt rename to Documentation/devicetree/bindings/hwmon/ibm,p8-occ-hwmon.txt From ee774c40fa32e3b2642bb2533bc54662ea8445c2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 15 Jun 2022 23:07:19 +0200 Subject: [PATCH 0510/1436] dt-bindings: efm32: remove bindings for deleted platform Commit cc6111375cec ("ARM: drop efm32 platform") removed the platform, so no need to still carry the bindings. Signed-off-by: Wolfram Sang Acked-by: Mark Brown Acked-by: Stephen Boyd Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220615210720.6363-1-wsa@kernel.org --- .../devicetree/bindings/clock/efm32-clock.txt | 11 ----- .../devicetree/bindings/i2c/i2c-efm32.txt | 33 -------------- .../devicetree/bindings/serial/efm32-uart.txt | 20 --------- .../devicetree/bindings/spi/efm32-spi.txt | 39 ----------------- include/dt-bindings/clock/efm32-cmu.h | 43 ------------------- 5 files changed, 146 deletions(-) delete mode 100644 Documentation/devicetree/bindings/clock/efm32-clock.txt delete mode 100644 Documentation/devicetree/bindings/i2c/i2c-efm32.txt delete mode 100644 Documentation/devicetree/bindings/serial/efm32-uart.txt delete mode 100644 Documentation/devicetree/bindings/spi/efm32-spi.txt delete mode 100644 include/dt-bindings/clock/efm32-cmu.h diff --git a/Documentation/devicetree/bindings/clock/efm32-clock.txt b/Documentation/devicetree/bindings/clock/efm32-clock.txt deleted file mode 100644 index 263d293f6a10..000000000000 --- a/Documentation/devicetree/bindings/clock/efm32-clock.txt +++ /dev/null @@ -1,11 +0,0 @@ -* Clock bindings for Energy Micro efm32 Giant Gecko's Clock Management Unit - -Required properties: -- compatible: Should be "efm32gg,cmu" -- reg: Base address and length of the register set -- interrupts: Interrupt used by the CMU -- #clock-cells: Should be <1> - -The clock consumer should specify the desired clock by having the clock ID in -its "clocks" phandle cell. The header efm32-clk.h contains a list of available -IDs. diff --git a/Documentation/devicetree/bindings/i2c/i2c-efm32.txt b/Documentation/devicetree/bindings/i2c/i2c-efm32.txt deleted file mode 100644 index 3b30e54ae3c7..000000000000 --- a/Documentation/devicetree/bindings/i2c/i2c-efm32.txt +++ /dev/null @@ -1,33 +0,0 @@ -* Energymicro efm32 i2c controller - -Required properties : - - - reg : Offset and length of the register set for the device - - compatible : should be "energymicro,efm32-i2c" - - interrupts : the interrupt number - - clocks : reference to the module clock - -Recommended properties : - - - clock-frequency : maximal I2C bus clock frequency in Hz. - - energymicro,location : Decides the location of the USART I/O pins. - Allowed range : [0 .. 6] - -Example: - i2c0: i2c@4000a000 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "energymicro,efm32-i2c"; - reg = <0x4000a000 0x400>; - interrupts = <9>; - clocks = <&cmu clk_HFPERCLKI2C0>; - clock-frequency = <100000>; - energymicro,location = <3>; - - eeprom@50 { - compatible = "microchip,24c02"; - reg = <0x50>; - pagesize = <16>; - }; - }; - diff --git a/Documentation/devicetree/bindings/serial/efm32-uart.txt b/Documentation/devicetree/bindings/serial/efm32-uart.txt deleted file mode 100644 index 4f8d8fde0c1c..000000000000 --- a/Documentation/devicetree/bindings/serial/efm32-uart.txt +++ /dev/null @@ -1,20 +0,0 @@ -* Energymicro efm32 UART - -Required properties: -- compatible : Should be "energymicro,efm32-uart" -- reg : Address and length of the register set -- interrupts : Should contain uart interrupt - -Optional properties: -- energymicro,location : Decides the location of the USART I/O pins. - Allowed range : [0 .. 5] - Default: 0 - -Example: - -uart@4000c400 { - compatible = "energymicro,efm32-uart"; - reg = <0x4000c400 0x400>; - interrupts = <15>; - energymicro,location = <0>; -}; diff --git a/Documentation/devicetree/bindings/spi/efm32-spi.txt b/Documentation/devicetree/bindings/spi/efm32-spi.txt deleted file mode 100644 index e0fa61a1be0c..000000000000 --- a/Documentation/devicetree/bindings/spi/efm32-spi.txt +++ /dev/null @@ -1,39 +0,0 @@ -* Energy Micro EFM32 SPI - -Required properties: -- #address-cells: see spi-bus.txt -- #size-cells: see spi-bus.txt -- compatible: should be "energymicro,efm32-spi" -- reg: Offset and length of the register set for the controller -- interrupts: pair specifying rx and tx irq -- clocks: phandle to the spi clock -- cs-gpios: see spi-bus.txt - -Recommended properties : -- energymicro,location: Value to write to the ROUTE register's LOCATION - bitfield to configure the pinmux for the device, see - datasheet for values. - If this property is not provided, keeping what is - already configured in the hardware, so its either the - reset default 0 or whatever the bootloader did. - -Example: - -spi1: spi@4000c400 { /* USART1 */ - #address-cells = <1>; - #size-cells = <0>; - compatible = "energymicro,efm32-spi"; - reg = <0x4000c400 0x400>; - interrupts = <15 16>; - clocks = <&cmu 20>; - cs-gpios = <&gpio 51 1>; // D3 - energymicro,location = <1>; - - ks8851@0 { - compatible = "ks8851"; - spi-max-frequency = <6000000>; - reg = <0>; - interrupt-parent = <&boardfpga>; - interrupts = <4>; - }; -}; diff --git a/include/dt-bindings/clock/efm32-cmu.h b/include/dt-bindings/clock/efm32-cmu.h deleted file mode 100644 index 4b48d15fe194..000000000000 --- a/include/dt-bindings/clock/efm32-cmu.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __DT_BINDINGS_CLOCK_EFM32_CMU_H -#define __DT_BINDINGS_CLOCK_EFM32_CMU_H - -#define clk_HFXO 0 -#define clk_HFRCO 1 -#define clk_LFXO 2 -#define clk_LFRCO 3 -#define clk_ULFRCO 4 -#define clk_AUXHFRCO 5 -#define clk_HFCLKNODIV 6 -#define clk_HFCLK 7 -#define clk_HFPERCLK 8 -#define clk_HFCORECLK 9 -#define clk_LFACLK 10 -#define clk_LFBCLK 11 -#define clk_WDOGCLK 12 -#define clk_HFCORECLKDMA 13 -#define clk_HFCORECLKAES 14 -#define clk_HFCORECLKUSBC 15 -#define clk_HFCORECLKUSB 16 -#define clk_HFCORECLKLE 17 -#define clk_HFCORECLKEBI 18 -#define clk_HFPERCLKUSART0 19 -#define clk_HFPERCLKUSART1 20 -#define clk_HFPERCLKUSART2 21 -#define clk_HFPERCLKUART0 22 -#define clk_HFPERCLKUART1 23 -#define clk_HFPERCLKTIMER0 24 -#define clk_HFPERCLKTIMER1 25 -#define clk_HFPERCLKTIMER2 26 -#define clk_HFPERCLKTIMER3 27 -#define clk_HFPERCLKACMP0 28 -#define clk_HFPERCLKACMP1 29 -#define clk_HFPERCLKI2C0 30 -#define clk_HFPERCLKI2C1 31 -#define clk_HFPERCLKGPIO 32 -#define clk_HFPERCLKVCMP 33 -#define clk_HFPERCLKPRS 34 -#define clk_HFPERCLKADC0 35 -#define clk_HFPERCLKDAC0 36 - -#endif /* __DT_BINDINGS_CLOCK_EFM32_CMU_H */ From 34b9715b7caee2e2b7d74bb4230f2be2c2765c0a Mon Sep 17 00:00:00 2001 From: Xiang Wangx Date: Fri, 17 Jun 2022 00:38:30 +0800 Subject: [PATCH 0511/1436] thunderbolt: Fix typo in comment Delete the redundant word 'the'. Signed-off-by: Xiang Wangx Signed-off-by: Mika Westerberg --- drivers/thunderbolt/ctl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thunderbolt/ctl.h b/drivers/thunderbolt/ctl.h index e8c64898dfce..7c7d80f96c0c 100644 --- a/drivers/thunderbolt/ctl.h +++ b/drivers/thunderbolt/ctl.h @@ -35,7 +35,7 @@ struct tb_cfg_result { * If err = 1 then this is the port that send the * error. * If err = 0 and if this was a cfg_read/write then - * this is the the upstream port of the responding + * this is the upstream port of the responding * switch. * Otherwise the field is set to zero. */ From e291506242b134ce81817865ecb15955fd1e5d0e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 13 Jun 2022 08:57:09 -0600 Subject: [PATCH 0512/1436] dt-bindings: display: Add Arm virtual platforms display 'arm,rtsm-display' is a panel for Arm, Ltd. virtual platforms (e.g. FVP). The binding has been in use for a long time, but was never documented. Some users and an example have a 'panel-dpi' compatible, but that's not needed without a 'panel-timing' node which none of the users have since commit 928faf5e3e8d ("arm64: dts: fvp: Remove panel timings"). The example does have a 'panel-timing' node, but it should not for the same reasons the node was removed in the dts files. So update the example in arm,pl11x.yaml to match the schema. Cc: Linus Walleij Cc: Robin Murphy Cc: Andre Przywara Signed-off-by: Rob Herring Acked-by: Sam Ravnborg Reviewed-by: Linus Walleij Link: https://lore.kernel.org/r/20220613145709.3729053-1-robh@kernel.org --- .../bindings/display/arm,pl11x.yaml | 15 +---------- .../display/panel/arm,rtsm-display.yaml | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 Documentation/devicetree/bindings/display/panel/arm,rtsm-display.yaml diff --git a/Documentation/devicetree/bindings/display/arm,pl11x.yaml b/Documentation/devicetree/bindings/display/arm,pl11x.yaml index b545c6d20325..6cc9045e5c68 100644 --- a/Documentation/devicetree/bindings/display/arm,pl11x.yaml +++ b/Documentation/devicetree/bindings/display/arm,pl11x.yaml @@ -159,25 +159,12 @@ examples: }; panel { - compatible = "arm,rtsm-display", "panel-dpi"; - power-supply = <&vcc_supply>; + compatible = "arm,rtsm-display"; port { clcd_panel: endpoint { remote-endpoint = <&clcd_pads>; }; }; - - panel-timing { - clock-frequency = <25175000>; - hactive = <640>; - hback-porch = <40>; - hfront-porch = <24>; - hsync-len = <96>; - vactive = <480>; - vback-porch = <32>; - vfront-porch = <11>; - vsync-len = <2>; - }; }; ... diff --git a/Documentation/devicetree/bindings/display/panel/arm,rtsm-display.yaml b/Documentation/devicetree/bindings/display/panel/arm,rtsm-display.yaml new file mode 100644 index 000000000000..4ad484f09ba3 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/arm,rtsm-display.yaml @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/arm,rtsm-display.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Arm RTSM Virtual Platforms Display + +maintainers: + - Linus Walleij + +allOf: + - $ref: panel-common.yaml# + +properties: + compatible: + const: arm,rtsm-display + + port: true + +required: + - compatible + - port + +additionalProperties: false + +... From bb9a3cc77aa153650d2c431c5be27ec78fadf401 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 13 Jun 2022 08:55:54 -0600 Subject: [PATCH 0513/1436] dt-bindings: perf: Convert Arm CCN to DT schema Convert the Arm CCN performance monitors binding to DT schema format. Signed-off-by: Rob Herring Acked-by: Robin Murphy Link: https://lore.kernel.org/r/20220613145554.3727354-1-robh@kernel.org --- .../devicetree/bindings/perf/arm,ccn.yaml | 40 +++++++++++++++++++ .../devicetree/bindings/perf/arm-ccn.txt | 23 ----------- 2 files changed, 40 insertions(+), 23 deletions(-) create mode 100644 Documentation/devicetree/bindings/perf/arm,ccn.yaml delete mode 100644 Documentation/devicetree/bindings/perf/arm-ccn.txt diff --git a/Documentation/devicetree/bindings/perf/arm,ccn.yaml b/Documentation/devicetree/bindings/perf/arm,ccn.yaml new file mode 100644 index 000000000000..0b0bb2091016 --- /dev/null +++ b/Documentation/devicetree/bindings/perf/arm,ccn.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/perf/arm,ccn.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM CCN (Cache Coherent Network) Performance Monitors + +maintainers: + - Robin Murphy + +properties: + compatible: + enum: + - arm,ccn-502 + - arm,ccn-504 + - arm,ccn-508 + - arm,ccn-512 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +additionalProperties: false + +examples: + - | + ccn@20000000 { + compatible = "arm,ccn-504"; + reg = <0x20000000 0x1000000>; + interrupts = <0 181 4>; + }; +... diff --git a/Documentation/devicetree/bindings/perf/arm-ccn.txt b/Documentation/devicetree/bindings/perf/arm-ccn.txt deleted file mode 100644 index 1c53b5aa3317..000000000000 --- a/Documentation/devicetree/bindings/perf/arm-ccn.txt +++ /dev/null @@ -1,23 +0,0 @@ -* ARM CCN (Cache Coherent Network) - -Required properties: - -- compatible: (standard compatible string) should be one of: - "arm,ccn-502" - "arm,ccn-504" - "arm,ccn-508" - "arm,ccn-512" - -- reg: (standard registers property) physical address and size - (16MB) of the configuration registers block - -- interrupts: (standard interrupt property) single interrupt - generated by the control block - -Example: - - ccn@2000000000 { - compatible = "arm,ccn-504"; - reg = <0x20 0x00000000 0 0x1000000>; - interrupts = <0 181 4>; - }; From 67fcaf28772027350e7aa60006b620c1d4b0be6e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 13 Jun 2022 11:18:07 -0600 Subject: [PATCH 0514/1436] dt-bindings: vexpress-sysreg: Add deprecated GPIO provider properties While the current binding expects a child GPIO node, the old style binding with GPIO provider properties in the parent vexpress-sysreg node is still in use. Add the GPIO provider properties as deprecated. Cc: Andre Przywara Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220613171809.3928949-1-robh@kernel.org --- Documentation/devicetree/bindings/arm/vexpress-sysreg.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/vexpress-sysreg.yaml b/Documentation/devicetree/bindings/arm/vexpress-sysreg.yaml index b5e26e41f88c..2d2afada5ad1 100644 --- a/Documentation/devicetree/bindings/arm/vexpress-sysreg.yaml +++ b/Documentation/devicetree/bindings/arm/vexpress-sysreg.yaml @@ -29,6 +29,13 @@ properties: ranges: true + gpio-controller: + deprecated: true + + "#gpio-cells": + deprecated: true + const: 2 + additionalProperties: false patternProperties: From cfda05c1ddb8b375562b54dc86276cdc42d48297 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 13 Jun 2022 11:18:08 -0600 Subject: [PATCH 0515/1436] dt-bindings: vexpress-sysreg: Allow for no child nodes It is valid for arm,vexpress-sysreg to have no child nodes when either the deprecated binding without child nodes is used or a platform has no GPIOs. If there are no child nodes, then "#address-cells" and "#size-cells" should not be required. However, "reg" should be present in all cases, so let's add it now. Cc: Andre Przywara Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220613171809.3928949-2-robh@kernel.org --- Documentation/devicetree/bindings/arm/vexpress-sysreg.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/vexpress-sysreg.yaml b/Documentation/devicetree/bindings/arm/vexpress-sysreg.yaml index 2d2afada5ad1..f04db802a732 100644 --- a/Documentation/devicetree/bindings/arm/vexpress-sysreg.yaml +++ b/Documentation/devicetree/bindings/arm/vexpress-sysreg.yaml @@ -74,8 +74,7 @@ patternProperties: required: - compatible - - "#address-cells" - - "#size-cells" + - reg examples: - | From 488ca2cb93453e4ef27162fc61c1b525ef04bc47 Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Tue, 14 Jun 2022 21:32:29 +0800 Subject: [PATCH 0516/1436] staging: r8188eu: remove NULL check before vfree vfree can handle NULL pointer as its argument. According to coccinelle isnullfree check, remove NULL check before vfree operation. Signed-off-by: Dongliang Mu Link: https://lore.kernel.org/r/20220614133239.147076-1-dzm91@hust.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/os_dep/usb_intf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/os_dep/usb_intf.c b/drivers/staging/r8188eu/os_dep/usb_intf.c index 68869c5daeff..cc2b44f60c46 100644 --- a/drivers/staging/r8188eu/os_dep/usb_intf.c +++ b/drivers/staging/r8188eu/os_dep/usb_intf.c @@ -372,7 +372,7 @@ handle_dualmac: free_adapter: if (pnetdev) rtw_free_netdev(pnetdev); - else if (padapter) + else vfree(padapter); return NULL; From d3bf108493f20a803b04fd7620f56dabeed47089 Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Tue, 14 Jun 2022 17:58:44 +0200 Subject: [PATCH 0517/1436] staging: r8188eu: replace confusing macros The macro GET_TX_REPORT_TYPE1_RERTY_0 and similar macros are not obvious on what they are doing. Replace them with clearer codes. Reviewed-by: Dan Carpenter Signed-off-by: Nam Cao Link: https://lore.kernel.org/r/e697e47aad21362f68d148d2351e6d49f4fa9eaf.1655220367.git.namcaov@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c | 12 ++++++------ .../staging/r8188eu/include/Hal8188ERateAdaptive.h | 13 ------------- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c b/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c index 3cefdf90d6e0..1e04de3a6622 100644 --- a/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c +++ b/drivers/staging/r8188eu/hal/Hal8188ERateAdaptive.c @@ -614,12 +614,12 @@ void ODM_RA_TxRPT2Handle_8188E(struct odm_dm_struct *dm_odm, u8 *TxRPT_Buf, u16 pRAInfo = &dm_odm->RAInfo[MacId]; if (valid) { - pRAInfo->RTY[0] = (u16)GET_TX_REPORT_TYPE1_RERTY_0(pBuffer); - pRAInfo->RTY[1] = (u16)GET_TX_REPORT_TYPE1_RERTY_1(pBuffer); - pRAInfo->RTY[2] = (u16)GET_TX_REPORT_TYPE1_RERTY_2((u8 *)pBuffer); - pRAInfo->RTY[3] = (u16)GET_TX_REPORT_TYPE1_RERTY_3(pBuffer); - pRAInfo->RTY[4] = (u16)GET_TX_REPORT_TYPE1_RERTY_4(pBuffer); - pRAInfo->DROP = (u16)GET_TX_REPORT_TYPE1_DROP_0(pBuffer); + pRAInfo->RTY[0] = le16_to_cpup((__le16 *)pBuffer); + pRAInfo->RTY[1] = pBuffer[2]; + pRAInfo->RTY[2] = pBuffer[3]; + pRAInfo->RTY[3] = pBuffer[4]; + pRAInfo->RTY[4] = pBuffer[5]; + pRAInfo->DROP = pBuffer[6]; pRAInfo->TOTAL = pRAInfo->RTY[0] + pRAInfo->RTY[1] + pRAInfo->RTY[2] + pRAInfo->RTY[3] + pRAInfo->RTY[4] + pRAInfo->DROP; diff --git a/drivers/staging/r8188eu/include/Hal8188ERateAdaptive.h b/drivers/staging/r8188eu/include/Hal8188ERateAdaptive.h index 20d73ca781e8..c571ad9478ea 100644 --- a/drivers/staging/r8188eu/include/Hal8188ERateAdaptive.h +++ b/drivers/staging/r8188eu/include/Hal8188ERateAdaptive.h @@ -22,19 +22,6 @@ le32_to_cpu((*(__le32 *)(__rxstatusdesc + 16)) #define GET_TX_RPT2_DESC_MACID_VALID_2_88E(__rxstatusdesc) \ le32_to_cpu((*(__le32 *)(__rxstatusdesc + 20)) - -#define GET_TX_REPORT_TYPE1_RERTY_0(__paddr) \ - le16_get_bits(*(__le16 *)__paddr, GENMASK(15, 0)) -#define GET_TX_REPORT_TYPE1_RERTY_1(__paddr) \ - LE_BITS_TO_1BYTE(__paddr + 2, 0, 8) -#define GET_TX_REPORT_TYPE1_RERTY_2(__paddr) \ - LE_BITS_TO_1BYTE(__paddr + 3, 0, 8) -#define GET_TX_REPORT_TYPE1_RERTY_3(__paddr) \ - LE_BITS_TO_1BYTE(__paddr + 4, 0, 8) -#define GET_TX_REPORT_TYPE1_RERTY_4(__paddr) \ - LE_BITS_TO_1BYTE(__paddr + 5, 0, 8) -#define GET_TX_REPORT_TYPE1_DROP_0(__paddr) \ - LE_BITS_TO_1BYTE(__paddr + 6, 0, 8) /* End rate adaptive define */ int ODM_RAInfo_Init_all(struct odm_dm_struct *dm_odm); From 97319bf5ca2af392b5719a614ca4dbf28dcfd150 Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Tue, 14 Jun 2022 17:58:45 +0200 Subject: [PATCH 0518/1436] staging: r8188eu: remove unused macros Remove LE_BITS_TO_1BYTE and relevant macros because they are not used anywhere. Reviewed-by: Dan Carpenter Signed-off-by: Nam Cao Link: https://lore.kernel.org/r/a7f700c0688a16bb697fb693894f4c16594fd483.1655220367.git.namcaov@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/include/basic_types.h | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/drivers/staging/r8188eu/include/basic_types.h b/drivers/staging/r8188eu/include/basic_types.h index cfd15ac1d9c0..0b71e2c6e41a 100644 --- a/drivers/staging/r8188eu/include/basic_types.h +++ b/drivers/staging/r8188eu/include/basic_types.h @@ -13,37 +13,6 @@ typedef void (*proc_t)(void *); /* TODO: Macros Below are Sync from SD7-Driver. It is necessary * to check correctness */ -/* - * Call endian free function when - * 1. Read/write packet content. - * 2. Before write integer to IO. - * 3. After read integer from IO. -*/ - -/* Convert little data endian to host ordering */ -#define EF1BYTE(_val) \ - ((u8)(_val)) - -/* Create a bit mask */ -#define BIT_LEN_MASK_8(__bitlen) \ - (0xFF >> (8 - (__bitlen))) - -/*Description: - * Return 4-byte value in host byte ordering from - * 4-byte pointer in little-endian system. - */ -#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \ - (EF1BYTE(*((u8 *)(__pstart)))) - -/*Description: -Translate subfield (continuous bits in little-endian) of 4-byte -value to host byte ordering.*/ -#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \ - ( \ - (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \ - BIT_LEN_MASK_8(__bitlen) \ - ) - #define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \ (__value) : (((__value + __aligment - 1) / __aligment) * __aligment)) From 43bf6b646d0a3f1419468a22e12d1fd46b47441e Mon Sep 17 00:00:00 2001 From: Daniel Watson Date: Wed, 15 Jun 2022 10:17:00 -0700 Subject: [PATCH 0519/1436] staging: r8188eu: call rtw_IOL_append_WB_cmd directly Call rtw_IOL_append_WB_cmd directly, instead of using wrapper macro. Delete wrapper macro, which is not needed. Signed-off-by: Daniel Watson Link: https://lore.kernel.org/r/e0002dcce35e78a4c7308515f68e473cad2f290b.1655312169.git.ozzloy@challenge-bot.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_iol.c | 2 +- drivers/staging/r8188eu/include/rtw_iol.h | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_iol.c b/drivers/staging/r8188eu/core/rtw_iol.c index af8e84a41b85..8c990b1af5a7 100644 --- a/drivers/staging/r8188eu/core/rtw_iol.c +++ b/drivers/staging/r8188eu/core/rtw_iol.c @@ -67,7 +67,7 @@ bool rtw_IOL_applied(struct adapter *adapter) return false; } -int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask) +int rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask) { struct ioreg_cfg cmd = {8, IOREG_CMD_WB_REG, 0x0, 0x0, 0x0}; diff --git a/drivers/staging/r8188eu/include/rtw_iol.h b/drivers/staging/r8188eu/include/rtw_iol.h index fb88ebc1dabb..a648f9ba50a6 100644 --- a/drivers/staging/r8188eu/include/rtw_iol.h +++ b/drivers/staging/r8188eu/include/rtw_iol.h @@ -41,16 +41,14 @@ int rtw_IOL_append_END_cmd(struct xmit_frame *xmit_frame); void read_efuse_from_txpktbuf(struct adapter *adapter, int bcnhead, u8 *content, u16 *size); -int _rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, - u8 value, u8 mask); +int rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, + u8 value, u8 mask); int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask); int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask); int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask); -#define rtw_IOL_append_WB_cmd(xmit_frame, addr, value, mask) \ - _rtw_IOL_append_WB_cmd((xmit_frame), (addr), (value) ,(mask)) #define rtw_IOL_append_WW_cmd(xmit_frame, addr, value, mask) \ _rtw_IOL_append_WW_cmd((xmit_frame), (addr), (value),(mask)) #define rtw_IOL_append_WD_cmd(xmit_frame, addr, value, mask) \ From 75997163e013779ca616642b01bc44de313d067a Mon Sep 17 00:00:00 2001 From: Daniel Watson Date: Wed, 15 Jun 2022 10:17:01 -0700 Subject: [PATCH 0520/1436] staging: r8188eu: call rtw_IOL_append_WW_cmd directly Call rtw_IOL_append_WW_cmd directly, instead of using wrapper macro. Delete wrapper macro, which is not needed. Signed-off-by: Daniel Watson Link: https://lore.kernel.org/r/ca53fca1d5557684a4f6430ecd88aef481238ada.1655312169.git.ozzloy@challenge-bot.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_iol.c | 2 +- drivers/staging/r8188eu/include/rtw_iol.h | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_iol.c b/drivers/staging/r8188eu/core/rtw_iol.c index 8c990b1af5a7..7292bab12607 100644 --- a/drivers/staging/r8188eu/core/rtw_iol.c +++ b/drivers/staging/r8188eu/core/rtw_iol.c @@ -81,7 +81,7 @@ int rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); } -int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask) +int rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask) { struct ioreg_cfg cmd = {8, IOREG_CMD_WW_REG, 0x0, 0x0, 0x0}; diff --git a/drivers/staging/r8188eu/include/rtw_iol.h b/drivers/staging/r8188eu/include/rtw_iol.h index a648f9ba50a6..c99d7d515109 100644 --- a/drivers/staging/r8188eu/include/rtw_iol.h +++ b/drivers/staging/r8188eu/include/rtw_iol.h @@ -43,14 +43,12 @@ void read_efuse_from_txpktbuf(struct adapter *adapter, int bcnhead, int rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask); -int _rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, - u16 value, u16 mask); +int rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, + u16 value, u16 mask); int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask); int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask); -#define rtw_IOL_append_WW_cmd(xmit_frame, addr, value, mask) \ - _rtw_IOL_append_WW_cmd((xmit_frame), (addr), (value),(mask)) #define rtw_IOL_append_WD_cmd(xmit_frame, addr, value, mask) \ _rtw_IOL_append_WD_cmd((xmit_frame), (addr), (value), (mask)) #define rtw_IOL_append_WRF_cmd(xmit_frame, rf_path, addr, value, mask) \ From 892ba0393f5ae295e1a8c36f9fb5ca157f95cc28 Mon Sep 17 00:00:00 2001 From: Daniel Watson Date: Wed, 15 Jun 2022 10:17:02 -0700 Subject: [PATCH 0521/1436] staging: r8188eu: call rtw_IOL_append_WD_cmd directly Call rtw_IOL_append_WD_cmd directly, instead of using wrapper macro. Delete wrapper macro, which is not needed. Signed-off-by: Daniel Watson Link: https://lore.kernel.org/r/005bbee3575555135be26be9b80a9ceb35d6069f.1655312169.git.ozzloy@challenge-bot.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_iol.c | 2 +- drivers/staging/r8188eu/include/rtw_iol.h | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_iol.c b/drivers/staging/r8188eu/core/rtw_iol.c index 7292bab12607..b7ee3833c908 100644 --- a/drivers/staging/r8188eu/core/rtw_iol.c +++ b/drivers/staging/r8188eu/core/rtw_iol.c @@ -95,7 +95,7 @@ int rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u1 return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); } -int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask) +int rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask) { struct ioreg_cfg cmd = {8, IOREG_CMD_WD_REG, 0x0, 0x0, 0x0}; diff --git a/drivers/staging/r8188eu/include/rtw_iol.h b/drivers/staging/r8188eu/include/rtw_iol.h index c99d7d515109..9ad467759ef1 100644 --- a/drivers/staging/r8188eu/include/rtw_iol.h +++ b/drivers/staging/r8188eu/include/rtw_iol.h @@ -45,12 +45,10 @@ int rtw_IOL_append_WB_cmd(struct xmit_frame *xmit_frame, u16 addr, u8 value, u8 mask); int rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask); -int _rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, - u32 value, u32 mask); +int rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, + u32 value, u32 mask); int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask); -#define rtw_IOL_append_WD_cmd(xmit_frame, addr, value, mask) \ - _rtw_IOL_append_WD_cmd((xmit_frame), (addr), (value), (mask)) #define rtw_IOL_append_WRF_cmd(xmit_frame, rf_path, addr, value, mask) \ _rtw_IOL_append_WRF_cmd((xmit_frame),(rf_path), (addr), (value), (mask)) From 012e6068801ced67856ffa867e9093733f56b2f4 Mon Sep 17 00:00:00 2001 From: Daniel Watson Date: Wed, 15 Jun 2022 10:17:03 -0700 Subject: [PATCH 0522/1436] staging: r8188eu: call rtw_IOL_append_WRF_cmd directly Call rtw_IOL_append_WRF_cmd directly, instead of using wrapper macro. Delete wrapper macro, which is not needed. Signed-off-by: Daniel Watson Link: https://lore.kernel.org/r/4f26e0dd99e32738d7019ebcf680e7c73ed8ac8a.1655312169.git.ozzloy@challenge-bot.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_iol.c | 2 +- drivers/staging/r8188eu/include/rtw_iol.h | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_iol.c b/drivers/staging/r8188eu/core/rtw_iol.c index b7ee3833c908..31e196ccd899 100644 --- a/drivers/staging/r8188eu/core/rtw_iol.c +++ b/drivers/staging/r8188eu/core/rtw_iol.c @@ -109,7 +109,7 @@ int rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u3 return rtw_IOL_append_cmds(xmit_frame, (u8 *)&cmd, cmd.length); } -int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask) +int rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, u16 addr, u32 value, u32 mask) { struct ioreg_cfg cmd = {8, IOREG_CMD_W_RF, 0x0, 0x0, 0x0}; diff --git a/drivers/staging/r8188eu/include/rtw_iol.h b/drivers/staging/r8188eu/include/rtw_iol.h index 9ad467759ef1..099f5a075274 100644 --- a/drivers/staging/r8188eu/include/rtw_iol.h +++ b/drivers/staging/r8188eu/include/rtw_iol.h @@ -47,10 +47,8 @@ int rtw_IOL_append_WW_cmd(struct xmit_frame *xmit_frame, u16 addr, u16 value, u16 mask); int rtw_IOL_append_WD_cmd(struct xmit_frame *xmit_frame, u16 addr, u32 value, u32 mask); -int _rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, - u16 addr, u32 value, u32 mask); -#define rtw_IOL_append_WRF_cmd(xmit_frame, rf_path, addr, value, mask) \ - _rtw_IOL_append_WRF_cmd((xmit_frame),(rf_path), (addr), (value), (mask)) +int rtw_IOL_append_WRF_cmd(struct xmit_frame *xmit_frame, u8 rf_path, + u16 addr, u32 value, u32 mask); u8 rtw_IOL_cmd_boundary_handle(struct xmit_frame *pxmit_frame); From 6e9e4acd8a0611193fa9fabf4dd53c48c0122b2a Mon Sep 17 00:00:00 2001 From: Arne Petersen Date: Sat, 18 Jun 2022 10:32:57 +0200 Subject: [PATCH 0523/1436] staging: sm750fb: fix CamelCase function parameter Change function parameter in header file from powerMode to mode, now identical to c file function declaration. Issue found by checkpatch. Signed-off-by: Arne Petersen Link: https://lore.kernel.org/r/Yq2NufHtWbuXCjWE@ubuntu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/sm750fb/ddk750_power.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/sm750fb/ddk750_power.h b/drivers/staging/sm750fb/ddk750_power.h index 7002567a47d2..63c9e8b6ffb3 100644 --- a/drivers/staging/sm750fb/ddk750_power.h +++ b/drivers/staging/sm750fb/ddk750_power.h @@ -15,7 +15,7 @@ enum dpms { } void ddk750_set_dpms(enum dpms state); -void sm750_set_power_mode(unsigned int powerMode); +void sm750_set_power_mode(unsigned int mode); void sm750_set_current_gate(unsigned int gate); /* From e0c718411cbb259d47d9d824d173b6770e7a3ee5 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 18 Jun 2022 11:00:02 +0200 Subject: [PATCH 0524/1436] staging: vchiq: provide testing instructions This small document should to help kernel developer to test their changes on the VCHIQ driver. Signed-off-by: Stefan Wahren Link: https://lore.kernel.org/r/20220618090002.20663-1-stefan.wahren@i2se.com Signed-off-by: Greg Kroah-Hartman --- .../staging/vc04_services/interface/TESTING | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 drivers/staging/vc04_services/interface/TESTING diff --git a/drivers/staging/vc04_services/interface/TESTING b/drivers/staging/vc04_services/interface/TESTING new file mode 100644 index 000000000000..a6d63efcbcb9 --- /dev/null +++ b/drivers/staging/vc04_services/interface/TESTING @@ -0,0 +1,82 @@ +This document contains some hints to test the function of the VCHIQ driver +without having additional hardware to the Raspberry Pi. + +* Requirements & limitations + +Testing the VCHIQ driver requires a Raspberry Pi with one of the following SoC: + - BCM2835 ( e.g. Raspberry Pi Zero W ) + - BCM2836 ( e.g. Raspberry Pi 2 ) + - BCM2837 ( e.g. Raspberry Pi 3 B+ ) + +The BCM2711 used in the Raspberry Pi 4 is currently not supported in the +mainline kernel. + +There are no specific requirements to the VideoCore firmware to get VCHIQ +working. + +The test scenarios described in this document based on the tool vchiq_test. +Its source code is available here: https://github.com/raspberrypi/userland + +* Configuration + +Here are the most common kernel configurations: + + 1. BCM2835 target SoC (ARM 32 bit) + + Just use bcm2835_defconfig which already has VCHIQ enabled. + + 2. BCM2836/7 target SoC (ARM 32 bit) + + Use the multi_v7_defconfig as a base and then enable all VCHIQ options. + + 3. BCM2837 target SoC (ARM 64 bit) + + Use the defconfig as a base and then enable all VCHIQ options. + +* Scenarios + + * Initial test + + Check the driver is probed and /dev/vchiq is created + + * Functional test + + Command: vchiq_test -f 10 + + Expected output: + Functional test - iters:10 + ======== iteration 1 ======== + Testing bulk transfer for alignment. + Testing bulk transfer at PAGE_SIZE. + ... + + * Ping test + + Command: vchiq_test -p 1 + + Expected output: + Ping test - service:echo, iters:1, version 3 + vchi ping (size 0) -> 57.000000us + vchi ping (size 0, 0 async, 0 oneway) -> 122.000000us + vchi bulk (size 0, 0 async, 0 oneway) -> 546.000000us + vchi bulk (size 0, 0 oneway) -> 230.000000us + vchi ping (size 0) -> 49.000000us + vchi ping (size 0, 0 async, 0 oneway) -> 70.000000us + vchi bulk (size 0, 0 async, 0 oneway) -> 296.000000us + vchi bulk (size 0, 0 oneway) -> 266.000000us + vchi ping (size 0, 1 async, 0 oneway) -> 65.000000us + vchi bulk (size 0, 0 oneway) -> 456.000000us + vchi ping (size 0, 2 async, 0 oneway) -> 74.000000us + vchi bulk (size 0, 0 oneway) -> 640.000000us + vchi ping (size 0, 10 async, 0 oneway) -> 125.000000us + vchi bulk (size 0, 0 oneway) -> 2309.000000us + vchi ping (size 0, 0 async, 1 oneway) -> 70.000000us + vchi ping (size 0, 0 async, 2 oneway) -> 76.000000us + vchi ping (size 0, 0 async, 10 oneway) -> 105.000000us + vchi ping (size 0, 10 async, 10 oneway) -> 165.000000us + vchi ping (size 0, 100 async, 0 oneway) -> nanus + vchi bulk (size 0, 0 oneway) -> nanus + vchi ping (size 0, 0 async, 100 oneway) -> nanus + vchi ping (size 0, 100 async, 100 oneway) -> infus + vchi ping (size 0, 200 async, 0 oneway) -> infus + ... From aa64e956f4bde5f41c8302d990f8b4222e035c8d Mon Sep 17 00:00:00 2001 From: Daniel Watson Date: Sun, 19 Jun 2022 22:45:29 -0700 Subject: [PATCH 0525/1436] staging: rtl8723bs: remove trailing whitespace remove trailing whitespace found by checkpatch Signed-off-by: Daniel Watson Link: https://lore.kernel.org/r/20220620054529.4019-1-ozzloy@challenge-bot.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index 1bdbd0971f73..f878b04076d8 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -960,7 +960,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) return _FAIL; frame_type = GetFrameSubType(pframe); - if (frame_type == WIFI_ASSOCREQ) + if (frame_type == WIFI_ASSOCREQ) ie_offset = _ASOCREQ_IE_OFFSET_; else /* WIFI_REASSOCREQ */ ie_offset = _REASOCREQ_IE_OFFSET_; From 9832187bf9423ba2b3e3932e67cf7517a60c338f Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Sun, 19 Jun 2022 12:42:27 -0700 Subject: [PATCH 0526/1436] Staging: r8188eu: core: rtw_xmit: Fixed some whitespace coding style issues Removed superfluous blank lines and added blank lines after variable declarations as per checkpath.pl Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/841716cec5032ad706fbee8677e1b67aec8ad736.1655666628.git.marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_xmit.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_xmit.c b/drivers/staging/r8188eu/core/rtw_xmit.c index 7135d89caac1..da1a10735d48 100644 --- a/drivers/staging/r8188eu/core/rtw_xmit.c +++ b/drivers/staging/r8188eu/core/rtw_xmit.c @@ -16,16 +16,13 @@ static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; static void _init_txservq(struct tx_servq *ptxservq) { - INIT_LIST_HEAD(&ptxservq->tx_pending); rtw_init_queue(&ptxservq->sta_pending); ptxservq->qcnt = 0; - } void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) { - memset((unsigned char *)psta_xmitpriv, 0, sizeof(struct sta_xmit_priv)); spin_lock_init(&psta_xmitpriv->lock); _init_txservq(&psta_xmitpriv->be_q); @@ -34,7 +31,6 @@ void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv) _init_txservq(&psta_xmitpriv->vo_q); INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz); INIT_LIST_HEAD(&psta_xmitpriv->apsd); - } s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) @@ -299,6 +295,7 @@ static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame * /* check HT op mode */ if (pattrib->ht_en) { u8 htopmode = pmlmeinfo->HT_protection; + if ((pmlmeext->cur_bwmode && (htopmode == 2 || htopmode == 3)) || (!pmlmeext->cur_bwmode && htopmode == 3)) { pattrib->vcs_mode = RTS_CTS; @@ -449,6 +446,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p /* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */ /* to prevent DHCP protocol fail */ u8 tmp[24]; + _rtw_pktfile_read(&pktfile, &tmp[0], 24); pattrib->dhcp_pkt = 0; if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */ @@ -1068,7 +1066,6 @@ void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len) } break; } - } void rtw_count_tx_stats(struct adapter *padapter, struct xmit_frame *pxmitframe, int sz) @@ -1315,7 +1312,6 @@ void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pfram rtw_free_xmitframe(pxmitpriv, pxmitframe); } spin_unlock_bh(&pframequeue->lock); - } s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) @@ -1505,7 +1501,6 @@ void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry) for (i = 0; i < entry; i++, phwxmit++) phwxmit->accnt = 0; - } static int rtw_br_client_tx(struct adapter *padapter, struct sk_buff **pskb) From 4c813e791b149c785f03180c161d14eb800527bd Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Sun, 19 Jun 2022 12:42:28 -0700 Subject: [PATCH 0527/1436] Staging: r8188eu: core: rtw_xmit: Fixed two indentation coding style issues. Fixed two indentation issues. Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/6b0e3efe83bf06ea60cdbe27f31f6f3aa1058f01.1655666628.git.marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_xmit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_xmit.c b/drivers/staging/r8188eu/core/rtw_xmit.c index da1a10735d48..edb224a39f70 100644 --- a/drivers/staging/r8188eu/core/rtw_xmit.c +++ b/drivers/staging/r8188eu/core/rtw_xmit.c @@ -625,7 +625,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr if (pframe[1] & 2) /* From Ds == 1 */ rtw_secmicappend(&micdata, &pframe[24], 6); else - rtw_secmicappend(&micdata, &pframe[10], 6); + rtw_secmicappend(&micdata, &pframe[10], 6); } else { /* ToDS == 0 */ rtw_secmicappend(&micdata, &pframe[4], 6); /* DA */ if (pframe[1] & 2) /* From Ds == 1 */ @@ -1727,7 +1727,7 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra bool bmcst = is_multicast_ether_addr(pattrib->ra); if (!check_fwstate(pmlmepriv, WIFI_AP_STATE)) - return ret; + return ret; if (pattrib->psta) psta = pattrib->psta; From afc0eba8b3e5668f891f9fcd835ddb47281033bd Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Sun, 19 Jun 2022 12:42:29 -0700 Subject: [PATCH 0528/1436] Staging: r8188eu: core: rtw_xmit: Fixed some spelling errors in the comments Fixed the spelling of "broadcast" and "update" in the comments. Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/8d2f49631551b53ad970c9165cceb845c4d60b75.1655666628.git.marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_xmit.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_xmit.c b/drivers/staging/r8188eu/core/rtw_xmit.c index edb224a39f70..0f9cbfa6ea50 100644 --- a/drivers/staging/r8188eu/core/rtw_xmit.c +++ b/drivers/staging/r8188eu/core/rtw_xmit.c @@ -956,7 +956,7 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct } if (bmcst) { - /* don't do fragment to broadcat/multicast packets */ + /* don't do fragment to broadcast/multicast packets */ mem_sz = _rtw_pktfile_read(&pktfile, pframe, pattrib->pktlen); } else { mem_sz = _rtw_pktfile_read(&pktfile, pframe, mpdu_len); @@ -1755,8 +1755,8 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra pstapriv->tim_bitmap |= BIT(0);/* */ pstapriv->sta_dz_bitmap |= BIT(0); - - update_beacon(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after upate bcn */ + /* tx bc/mc packets after update bcn */ + update_beacon(padapter, _TIM_IE_, NULL, false); ret = true; } @@ -1806,7 +1806,7 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra pstapriv->tim_bitmap |= BIT(psta->aid); if (psta->sleepq_len == 1) { - /* upate BCN for TIM IE */ + /* update BCN for TIM IE */ update_beacon(padapter, _TIM_IE_, NULL, false); } } @@ -2075,7 +2075,7 @@ void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *pst if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) { pstapriv->tim_bitmap &= ~BIT(psta->aid); - /* upate BCN for TIM IE */ + /* update BCN for TIM IE */ update_beacon(padapter, _TIM_IE_, NULL, false); } } From 34a033fe34766920c36bae15ff7e154ac234abc6 Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Sun, 19 Jun 2022 12:42:30 -0700 Subject: [PATCH 0529/1436] Staging: r8188eu: core: rtw_xmit: Fixed a brace coding style issue Removed superfluous brackets around a if clause as per checkpatch.pl Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/ff6f2ecb22c3d295ceae0dab593bedfc6eac9e32.1655666628.git.marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_xmit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_xmit.c b/drivers/staging/r8188eu/core/rtw_xmit.c index 0f9cbfa6ea50..06fda7d8383d 100644 --- a/drivers/staging/r8188eu/core/rtw_xmit.c +++ b/drivers/staging/r8188eu/core/rtw_xmit.c @@ -951,9 +951,8 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, struct sk_buff *pkt, struct mpdu_len -= llc_sz; } - if ((pattrib->icv_len > 0) && (pattrib->bswenc)) { + if ((pattrib->icv_len > 0) && (pattrib->bswenc)) mpdu_len -= pattrib->icv_len; - } if (bmcst) { /* don't do fragment to broadcast/multicast packets */ From 4175971d0effb00f01c48a2990f51c1f1503be98 Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Sun, 19 Jun 2022 12:42:31 -0700 Subject: [PATCH 0530/1436] Staging: r8188eu: core: rtw_xmit: Fixed a coding style issue Moved the constant ETH_P_IP to the right hand side of the comparison as per checkpatch.pl Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/e938a8ac0ff3a9d777754a081c7a08026aaae253.1655666628.git.marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_xmit.c b/drivers/staging/r8188eu/core/rtw_xmit.c index 06fda7d8383d..647c38134d2a 100644 --- a/drivers/staging/r8188eu/core/rtw_xmit.c +++ b/drivers/staging/r8188eu/core/rtw_xmit.c @@ -442,7 +442,7 @@ static s32 update_attrib(struct adapter *padapter, struct sk_buff *pkt, struct p pattrib->pktlen = pktfile.pkt_len; - if (ETH_P_IP == pattrib->ether_type) { + if (pattrib->ether_type == ETH_P_IP) { /* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */ /* to prevent DHCP protocol fail */ u8 tmp[24]; From fa578398a0ba2c079fa1170da21fa5baae0cedb2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 21:58:27 +0000 Subject: [PATCH 0531/1436] KVM: nVMX: Snapshot pre-VM-Enter BNDCFGS for !nested_run_pending case If a nested run isn't pending, snapshot vmcs01.GUEST_BNDCFGS irrespective of whether or not VM_ENTRY_LOAD_BNDCFGS is set in vmcs12. When restoring nested state, e.g. after migration, without a nested run pending, prepare_vmcs02() will propagate nested.vmcs01_guest_bndcfgs to vmcs02, i.e. will load garbage/zeros into vmcs02.GUEST_BNDCFGS. If userspace restores nested state before MSRs, then loading garbage is a non-issue as loading BNDCFGS will also update vmcs02. But if usersepace restores MSRs first, then KVM is responsible for propagating L2's value, which is actually thrown into vmcs01, into vmcs02. Restoring L2 MSRs into vmcs01, i.e. loading all MSRs before nested state is all kinds of bizarre and ideally would not be supported. Sadly, some VMMs do exactly that and rely on KVM to make things work. Note, there's still a lurking SMM bug, as propagating vmcs01.GUEST_BNDFGS to vmcs02 across RSM may corrupt L2's BNDCFGS. But KVM's entire VMX+SMM emulation is flawed as SMI+RSM should not toouch _any_ VMCS when use the "default treatment of SMIs", i.e. when not using an SMI Transfer Monitor. Link: https://lore.kernel.org/all/Yobt1XwOfb5M6Dfa@google.com Fixes: 62cf9bd8118c ("KVM: nVMX: Fix emulation of VM_ENTRY_LOAD_BNDCFGS") Cc: stable@vger.kernel.org Cc: Lei Wang Signed-off-by: Sean Christopherson Message-Id: <20220614215831.3762138-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 7d8cd0ebcc75..66c25bb56938 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -3382,7 +3382,8 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS)) vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL); if (kvm_mpx_supported() && - !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS)) + (!vmx->nested.nested_run_pending || + !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS))) vmx->nested.vmcs01_guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS); /* From 764643a6be07445308e492a528197044c801b3ba Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 21:58:28 +0000 Subject: [PATCH 0532/1436] KVM: nVMX: Snapshot pre-VM-Enter DEBUGCTL for !nested_run_pending case If a nested run isn't pending, snapshot vmcs01.GUEST_IA32_DEBUGCTL irrespective of whether or not VM_ENTRY_LOAD_DEBUG_CONTROLS is set in vmcs12. When restoring nested state, e.g. after migration, without a nested run pending, prepare_vmcs02() will propagate nested.vmcs01_debugctl to vmcs02, i.e. will load garbage/zeros into vmcs02.GUEST_IA32_DEBUGCTL. If userspace restores nested state before MSRs, then loading garbage is a non-issue as loading DEBUGCTL will also update vmcs02. But if usersepace restores MSRs first, then KVM is responsible for propagating L2's value, which is actually thrown into vmcs01, into vmcs02. Restoring L2 MSRs into vmcs01, i.e. loading all MSRs before nested state is all kinds of bizarre and ideally would not be supported. Sadly, some VMMs do exactly that and rely on KVM to make things work. Note, there's still a lurking SMM bug, as propagating vmcs01's DEBUGCTL to vmcs02 across RSM may corrupt L2's DEBUGCTL. But KVM's entire VMX+SMM emulation is flawed as SMI+RSM should not toouch _any_ VMCS when use the "default treatment of SMIs", i.e. when not using an SMI Transfer Monitor. Link: https://lore.kernel.org/all/Yobt1XwOfb5M6Dfa@google.com Fixes: 8fcc4b5923af ("kvm: nVMX: Introduce KVM_CAP_NESTED_STATE") Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Message-Id: <20220614215831.3762138-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 66c25bb56938..4a53e0c73445 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -3379,7 +3379,8 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, if (likely(!evaluate_pending_interrupts) && kvm_vcpu_apicv_active(vcpu)) evaluate_pending_interrupts |= vmx_has_apicv_interrupt(vcpu); - if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS)) + if (!vmx->nested.nested_run_pending || + !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS)) vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL); if (kvm_mpx_supported() && (!vmx->nested.nested_run_pending || From 5d76b1f8c79309c0b60c8db5f16774f1691945a7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 21:58:29 +0000 Subject: [PATCH 0533/1436] KVM: nVMX: Rename nested.vmcs01_* fields to nested.pre_vmenter_* Rename the fields in struct nested_vmx used to snapshot pre-VM-Enter values to reflect that they can hold L2's values when restoring nested state, e.g. if userspace restores MSRs before nested state. As crazy as it seems, restoring MSRs before nested state actually works (because KVM goes out if it's way to make it work), even though the initial MSR writes will hit vmcs01 despite holding L2 values. Add a related comment to vmx_enter_smm() to call out that using the common VM-Exit and VM-Enter helpers to emulate SMI and RSM is wrong and broken. The few MSRs that have snapshots _could_ be fixed by taking a snapshot prior to the forced VM-Exit instead of at forced VM-Enter, but that's just the tip of the iceberg as the rather long list of MSRs that aren't snapshotted (hello, VM-Exit MSR load list) can't be handled this way. Signed-off-by: Sean Christopherson Message-Id: <20220614215831.3762138-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 8 ++++---- arch/x86/kvm/vmx/vmx.c | 7 +++++++ arch/x86/kvm/vmx/vmx.h | 15 ++++++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 4a53e0c73445..38015f4ecc54 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -2520,11 +2520,11 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, vmcs_write64(GUEST_IA32_DEBUGCTL, vmcs12->guest_ia32_debugctl); } else { kvm_set_dr(vcpu, 7, vcpu->arch.dr7); - vmcs_write64(GUEST_IA32_DEBUGCTL, vmx->nested.vmcs01_debugctl); + vmcs_write64(GUEST_IA32_DEBUGCTL, vmx->nested.pre_vmenter_debugctl); } if (kvm_mpx_supported() && (!vmx->nested.nested_run_pending || !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS))) - vmcs_write64(GUEST_BNDCFGS, vmx->nested.vmcs01_guest_bndcfgs); + vmcs_write64(GUEST_BNDCFGS, vmx->nested.pre_vmenter_bndcfgs); vmx_set_rflags(vcpu, vmcs12->guest_rflags); /* EXCEPTION_BITMAP and CR0_GUEST_HOST_MASK should basically be the @@ -3381,11 +3381,11 @@ enum nvmx_vmentry_status nested_vmx_enter_non_root_mode(struct kvm_vcpu *vcpu, if (!vmx->nested.nested_run_pending || !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS)) - vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL); + vmx->nested.pre_vmenter_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL); if (kvm_mpx_supported() && (!vmx->nested.nested_run_pending || !(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_BNDCFGS))) - vmx->nested.vmcs01_guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS); + vmx->nested.pre_vmenter_bndcfgs = vmcs_read64(GUEST_BNDCFGS); /* * Overwrite vmcs01.GUEST_CR3 with L1's CR3 if EPT is disabled *and* diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 61962f3c4b28..b4d3820e9800 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7847,6 +7847,13 @@ static int vmx_enter_smm(struct kvm_vcpu *vcpu, char *smstate) { struct vcpu_vmx *vmx = to_vmx(vcpu); + /* + * TODO: Implement custom flows for forcing the vCPU out/in of L2 on + * SMI and RSM. Using the common VM-Exit + VM-Enter routines is wrong + * SMI and RSM only modify state that is saved and restored via SMRAM. + * E.g. most MSRs are left untouched, but many are modified by VM-Exit + * and VM-Enter, and thus L2's values may be corrupted on SMI+RSM. + */ vmx->nested.smm.guest_mode = is_guest_mode(vcpu); if (vmx->nested.smm.guest_mode) nested_vmx_vmexit(vcpu, -1, 0, 0); diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 71bcb486e73f..a84c91ee2a48 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -219,9 +219,18 @@ struct nested_vmx { bool has_preemption_timer_deadline; bool preemption_timer_expired; - /* to migrate it to L2 if VM_ENTRY_LOAD_DEBUG_CONTROLS is off */ - u64 vmcs01_debugctl; - u64 vmcs01_guest_bndcfgs; + /* + * Used to snapshot MSRs that are conditionally loaded on VM-Enter in + * order to propagate the guest's pre-VM-Enter value into vmcs02. For + * emulation of VMLAUNCH/VMRESUME, the snapshot will be of L1's value. + * For KVM_SET_NESTED_STATE, the snapshot is of L2's value, _if_ + * userspace restores MSRs before nested state. If userspace restores + * MSRs after nested state, the snapshot holds garbage, but KVM can't + * detect that, and the garbage value in vmcs02 will be overwritten by + * MSR restoration in any case. + */ + u64 pre_vmenter_debugctl; + u64 pre_vmenter_bndcfgs; /* to migrate it to L1 if L2 writes to L1's CR8 directly */ int l1_tpr_threshold; From 308a4fffeb361af90f17837c1bcace3139d1f677 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 21:58:30 +0000 Subject: [PATCH 0534/1436] KVM: nVMX: Save BNDCFGS to vmcs12 iff relevant controls are exposed to L1 Save BNDCFGS to vmcs12 (from vmcs02) if and only if at least of one of the load-on-entry or clear-on-exit fields for BNDCFGS is enumerated as an allowed-1 bit in vmcs12. Skipping the field avoids an unnecessary VMREAD when MPX is supported but not exposed to L1. Per Intel's SDM: If the processor supports either the 1-setting of the "load IA32_BNDCFGS" VM-entry control or that of the "clear IA32_BNDCFGS" VM-exit control, the contents of the IA32_BNDCFGS MSR are saved into the corresponding field. Signed-off-by: Sean Christopherson Message-Id: <20220614215831.3762138-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 38015f4ecc54..496981b86f94 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4104,7 +4104,8 @@ static void sync_vmcs02_to_vmcs12_rare(struct kvm_vcpu *vcpu, vmcs12->guest_idtr_base = vmcs_readl(GUEST_IDTR_BASE); vmcs12->guest_pending_dbg_exceptions = vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS); - if (kvm_mpx_supported()) + if ((vmx->nested.msrs.entry_ctls_high & VM_ENTRY_LOAD_BNDCFGS) || + (vmx->nested.msrs.exit_ctls_high & VM_EXIT_CLEAR_BNDCFGS)) vmcs12->guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS); vmx->nested.need_sync_vmcs02_to_vmcs12_rare = false; From 913d6c9b8fe48f0836c00e359fb1ea39089d25e9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 21:58:31 +0000 Subject: [PATCH 0535/1436] KVM: nVMX: Update vmcs12 on BNDCFGS write, not at vmcs02=>vmcs12 sync Update vmcs12->guest_bndcfgs on intercepted writes to BNDCFGS from L2 instead of waiting until vmcs02 is synchronized to vmcs12. KVM always intercepts BNDCFGS accesses, so the only way the value in vmcs02 can change is via KVM's explicit VMWRITE during emulation. Signed-off-by: Sean Christopherson Message-Id: <20220614215831.3762138-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 3 --- arch/x86/kvm/vmx/vmx.c | 6 ++++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 496981b86f94..aad938e1e51d 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4104,9 +4104,6 @@ static void sync_vmcs02_to_vmcs12_rare(struct kvm_vcpu *vcpu, vmcs12->guest_idtr_base = vmcs_readl(GUEST_IDTR_BASE); vmcs12->guest_pending_dbg_exceptions = vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS); - if ((vmx->nested.msrs.entry_ctls_high & VM_ENTRY_LOAD_BNDCFGS) || - (vmx->nested.msrs.exit_ctls_high & VM_EXIT_CLEAR_BNDCFGS)) - vmcs12->guest_bndcfgs = vmcs_read64(GUEST_BNDCFGS); vmx->nested.need_sync_vmcs02_to_vmcs12_rare = false; } diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index b4d3820e9800..e4c16ee879d5 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2044,6 +2044,12 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (is_noncanonical_address(data & PAGE_MASK, vcpu) || (data & MSR_IA32_BNDCFGS_RSVD)) return 1; + + if (is_guest_mode(vcpu) && + ((vmx->nested.msrs.entry_ctls_high & VM_ENTRY_LOAD_BNDCFGS) || + (vmx->nested.msrs.exit_ctls_high & VM_EXIT_CLEAR_BNDCFGS))) + get_vmcs12(vcpu)->guest_bndcfgs = data; + vmcs_write64(GUEST_BNDCFGS, data); break; case MSR_IA32_UMWAIT_CONTROL: From ec1d7e6ab9ff15d9ff7b3628a4320907544675e1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:05:44 +0000 Subject: [PATCH 0536/1436] KVM: SVM: Drop unused AVIC / kvm_x86_ops declarations Drop a handful of unused AVIC function declarations whose implementations were removed during the conversion to optional static calls. No functional change intended. Fixes: abb6d479e226 ("KVM: x86: make several APIC virtualization callbacks optional") Signed-off-by: Sean Christopherson Message-Id: <20220614230548.3852141-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/svm.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 128993feb4c6..d51de3c9264a 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -617,12 +617,8 @@ int avic_init_vcpu(struct vcpu_svm *svm); void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu); void avic_vcpu_put(struct kvm_vcpu *vcpu); void avic_apicv_post_state_restore(struct kvm_vcpu *vcpu); -void avic_set_virtual_apic_mode(struct kvm_vcpu *vcpu); void avic_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu); bool avic_check_apicv_inhibit_reasons(enum kvm_apicv_inhibit reason); -void avic_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr); -void avic_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr); -bool avic_dy_apicv_has_pending_interrupt(struct kvm_vcpu *vcpu); int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq, uint32_t guest_irq, bool set); void avic_vcpu_blocking(struct kvm_vcpu *vcpu); From d39850f57d2102c6b46feb21237bc23bc42de4f7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:05:45 +0000 Subject: [PATCH 0537/1436] KVM: x86: Drop @vcpu parameter from kvm_x86_ops.hwapic_isr_update() Drop the unused @vcpu parameter from hwapic_isr_update(). AMD/AVIC is unlikely to implement the helper, and VMX/APICv doesn't need the vCPU as it operates on the current VMCS. The result is somewhat odd, but allows for a decent amount of (future) cleanup in the APIC code. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220614230548.3852141-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/lapic.c | 8 ++++---- arch/x86/kvm/vmx/vmx.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 7e98b2876380..16acc54d49a7 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1517,7 +1517,7 @@ struct kvm_x86_ops { bool (*check_apicv_inhibit_reasons)(enum kvm_apicv_inhibit reason); void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu); void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr); - void (*hwapic_isr_update)(struct kvm_vcpu *vcpu, int isr); + void (*hwapic_isr_update)(int isr); bool (*guest_apic_has_interrupt)(struct kvm_vcpu *vcpu); void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap); void (*set_virtual_apic_mode)(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index a413a1d8df4c..cc0da5671eb9 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -556,7 +556,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic) * just set SVI. */ if (unlikely(vcpu->arch.apicv_active)) - static_call_cond(kvm_x86_hwapic_isr_update)(vcpu, vec); + static_call_cond(kvm_x86_hwapic_isr_update)(vec); else { ++apic->isr_count; BUG_ON(apic->isr_count > MAX_APIC_VECTOR); @@ -604,7 +604,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic) * and must be left alone. */ if (unlikely(vcpu->arch.apicv_active)) - static_call_cond(kvm_x86_hwapic_isr_update)(vcpu, apic_find_highest_isr(apic)); + static_call_cond(kvm_x86_hwapic_isr_update)(apic_find_highest_isr(apic)); else { --apic->isr_count; BUG_ON(apic->isr_count < 0); @@ -2457,7 +2457,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) if (vcpu->arch.apicv_active) { static_call_cond(kvm_x86_apicv_post_state_restore)(vcpu); static_call_cond(kvm_x86_hwapic_irr_update)(vcpu, -1); - static_call_cond(kvm_x86_hwapic_isr_update)(vcpu, -1); + static_call_cond(kvm_x86_hwapic_isr_update)(-1); } vcpu->arch.apic_arb_prio = 0; @@ -2737,7 +2737,7 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s) if (vcpu->arch.apicv_active) { static_call_cond(kvm_x86_apicv_post_state_restore)(vcpu); static_call_cond(kvm_x86_hwapic_irr_update)(vcpu, apic_find_highest_irr(apic)); - static_call_cond(kvm_x86_hwapic_isr_update)(vcpu, apic_find_highest_isr(apic)); + static_call_cond(kvm_x86_hwapic_isr_update)(apic_find_highest_isr(apic)); } kvm_make_request(KVM_REQ_EVENT, vcpu); if (ioapic_in_kernel(vcpu->kvm)) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index e4c16ee879d5..380c8e7c1fb8 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -6566,7 +6566,7 @@ static void vmx_set_apic_access_page_addr(struct kvm_vcpu *vcpu) put_page(page); } -static void vmx_hwapic_isr_update(struct kvm_vcpu *vcpu, int max_isr) +static void vmx_hwapic_isr_update(int max_isr) { u16 status; u8 old; From ae801e1303e939ad5ebd9f390bdcc57275ada33b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:05:46 +0000 Subject: [PATCH 0538/1436] KVM: x86: Check for in-kernel xAPIC when querying APICv for directed yield Use kvm_vcpu_apicv_active() to check if APICv is active when seeing if a vCPU is a candidate for directed yield due to a pending ACPIv interrupt. This will allow moving apicv_active into kvm_lapic without introducing a potential NULL pointer deref (kvm_vcpu_apicv_active() effectively adds a pre-check on the vCPU having an in-kernel APIC). No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220614230548.3852141-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a0baf49bb00d..db35d40bf996 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -12395,7 +12395,8 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) bool kvm_arch_dy_has_pending_interrupt(struct kvm_vcpu *vcpu) { - if (vcpu->arch.apicv_active && static_call(kvm_x86_dy_apicv_has_pending_interrupt)(vcpu)) + if (kvm_vcpu_apicv_active(vcpu) && + static_call(kvm_x86_dy_apicv_has_pending_interrupt)(vcpu)) return true; return false; From ce0a58f4756c14d7646cfdf279dbaada9d7712a0 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:05:47 +0000 Subject: [PATCH 0539/1436] KVM: x86: Move "apicv_active" into "struct kvm_lapic" Move the per-vCPU apicv_active flag into KVM's local APIC instance. APICv is fully dependent on an in-kernel local APIC, but that's not at all clear when reading the current code due to the flag being stored in the generic kvm_vcpu_arch struct. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220614230548.3852141-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 1 - arch/x86/kvm/lapic.c | 30 ++++++++++-------------------- arch/x86/kvm/lapic.h | 3 ++- arch/x86/kvm/svm/svm.c | 5 +++-- arch/x86/kvm/vmx/vmx.c | 3 ++- arch/x86/kvm/x86.c | 11 ++++++----- 6 files changed, 23 insertions(+), 30 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 16acc54d49a7..1038ccb7056a 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -663,7 +663,6 @@ struct kvm_vcpu_arch { u64 efer; u64 apic_base; struct kvm_lapic *apic; /* kernel irqchip context */ - bool apicv_active; bool load_eoi_exitmap_pending; DECLARE_BITMAP(ioapic_handled_vectors, 256); unsigned long apic_attention; diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index cc0da5671eb9..43c42a580295 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -519,14 +519,11 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic) static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) { - struct kvm_vcpu *vcpu; - - vcpu = apic->vcpu; - - if (unlikely(vcpu->arch.apicv_active)) { + if (unlikely(apic->apicv_active)) { /* need to update RVI */ kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR); - static_call_cond(kvm_x86_hwapic_irr_update)(vcpu, apic_find_highest_irr(apic)); + static_call_cond(kvm_x86_hwapic_irr_update)(apic->vcpu, + apic_find_highest_irr(apic)); } else { apic->irr_pending = false; kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR); @@ -543,19 +540,15 @@ EXPORT_SYMBOL_GPL(kvm_apic_clear_irr); static inline void apic_set_isr(int vec, struct kvm_lapic *apic) { - struct kvm_vcpu *vcpu; - if (__apic_test_and_set_vector(vec, apic->regs + APIC_ISR)) return; - vcpu = apic->vcpu; - /* * With APIC virtualization enabled, all caching is disabled * because the processor can modify ISR under the hood. Instead * just set SVI. */ - if (unlikely(vcpu->arch.apicv_active)) + if (unlikely(apic->apicv_active)) static_call_cond(kvm_x86_hwapic_isr_update)(vec); else { ++apic->isr_count; @@ -590,12 +583,9 @@ static inline int apic_find_highest_isr(struct kvm_lapic *apic) static inline void apic_clear_isr(int vec, struct kvm_lapic *apic) { - struct kvm_vcpu *vcpu; if (!__apic_test_and_clear_vector(vec, apic->regs + APIC_ISR)) return; - vcpu = apic->vcpu; - /* * We do get here for APIC virtualization enabled if the guest * uses the Hyper-V APIC enlightenment. In this case we may need @@ -603,7 +593,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic) * on the other hand isr_count and highest_isr_cache are unused * and must be left alone. */ - if (unlikely(vcpu->arch.apicv_active)) + if (unlikely(apic->apicv_active)) static_call_cond(kvm_x86_hwapic_isr_update)(apic_find_highest_isr(apic)); else { --apic->isr_count; @@ -1584,7 +1574,7 @@ static bool lapic_timer_int_injected(struct kvm_vcpu *vcpu) int vec = reg & APIC_VECTOR_MASK; void *bitmap = apic->regs + APIC_ISR; - if (vcpu->arch.apicv_active) + if (apic->apicv_active) bitmap = apic->regs + APIC_IRR; if (apic_test_vector(vec, bitmap)) @@ -1701,7 +1691,7 @@ static void apic_timer_expired(struct kvm_lapic *apic, bool from_timer_fn) if (apic_lvtt_tscdeadline(apic) || ktimer->hv_timer_in_use) ktimer->expired_tscdeadline = ktimer->tscdeadline; - if (!from_timer_fn && vcpu->arch.apicv_active) { + if (!from_timer_fn && apic->apicv_active) { WARN_ON(kvm_get_running_vcpu() != vcpu); kvm_apic_inject_pending_timer_irqs(apic); return; @@ -2379,7 +2369,7 @@ void kvm_apic_update_apicv(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - if (vcpu->arch.apicv_active) { + if (apic->apicv_active) { /* irr_pending is always true when apicv is activated. */ apic->irr_pending = true; apic->isr_count = 1; @@ -2454,7 +2444,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) vcpu->arch.pv_eoi.msr_val = 0; apic_update_ppr(apic); - if (vcpu->arch.apicv_active) { + if (apic->apicv_active) { static_call_cond(kvm_x86_apicv_post_state_restore)(vcpu); static_call_cond(kvm_x86_hwapic_irr_update)(vcpu, -1); static_call_cond(kvm_x86_hwapic_isr_update)(-1); @@ -2734,7 +2724,7 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s) kvm_lapic_set_reg(apic, APIC_TMCCT, 0); kvm_apic_update_apicv(vcpu); apic->highest_isr_cache = -1; - if (vcpu->arch.apicv_active) { + if (apic->apicv_active) { static_call_cond(kvm_x86_apicv_post_state_restore)(vcpu); static_call_cond(kvm_x86_hwapic_irr_update)(vcpu, apic_find_highest_irr(apic)); static_call_cond(kvm_x86_hwapic_isr_update)(apic_find_highest_isr(apic)); diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 65bb2a8cf145..e09ad97f3250 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -48,6 +48,7 @@ struct kvm_lapic { struct kvm_timer lapic_timer; u32 divide_count; struct kvm_vcpu *vcpu; + bool apicv_active; bool sw_enabled; bool irr_pending; bool lvt0_in_nmi_mode; @@ -204,7 +205,7 @@ static inline int apic_x2apic_mode(struct kvm_lapic *apic) static inline bool kvm_vcpu_apicv_active(struct kvm_vcpu *vcpu) { - return vcpu->arch.apic && vcpu->arch.apicv_active; + return vcpu->arch.apic && vcpu->arch.apic->apicv_active; } static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 2ba0c62df8fb..136298cfb3fb 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3465,12 +3465,13 @@ void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode, int trig_mode, int vector) { /* - * vcpu->arch.apicv_active must be read after vcpu->mode. + * apic->apicv_active must be read after vcpu->mode. * Pairs with smp_store_release in vcpu_enter_guest. */ bool in_guest_mode = (smp_load_acquire(&vcpu->mode) == IN_GUEST_MODE); - if (!READ_ONCE(vcpu->arch.apicv_active)) { + /* Note, this is called iff the local APIC is in-kernel. */ + if (!READ_ONCE(vcpu->arch.apic->apicv_active)) { /* Process the interrupt via inject_pending_event */ kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 380c8e7c1fb8..2609bcc8c130 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4099,7 +4099,8 @@ static int vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, int vector) if (!r) return 0; - if (!vcpu->arch.apicv_active) + /* Note, this is called iff the local APIC is in-kernel. */ + if (!vcpu->arch.apic->apicv_active) return -1; if (pi_test_and_set_pir(vector, &vmx->pi_desc)) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index db35d40bf996..00e23dc518e0 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9460,7 +9460,7 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu) if (!lapic_in_kernel(vcpu)) return; - if (vcpu->arch.apicv_active) + if (vcpu->arch.apic->apicv_active) return; if (!vcpu->arch.apic->vapic_addr) @@ -9913,6 +9913,7 @@ void kvm_make_scan_ioapic_request(struct kvm *kvm) void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu) { + struct kvm_lapic *apic = vcpu->arch.apic; bool activate; if (!lapic_in_kernel(vcpu)) @@ -9923,10 +9924,10 @@ void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu) activate = kvm_vcpu_apicv_activated(vcpu); - if (vcpu->arch.apicv_active == activate) + if (apic->apicv_active == activate) goto out; - vcpu->arch.apicv_active = activate; + apic->apicv_active = activate; kvm_apic_update_apicv(vcpu); static_call(kvm_x86_refresh_apicv_exec_ctrl)(vcpu); @@ -9936,7 +9937,7 @@ void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu) * still active when the interrupt got accepted. Make sure * inject_pending_event() is called to check for that. */ - if (!vcpu->arch.apicv_active) + if (!apic->apicv_active) kvm_make_request(KVM_REQ_EVENT, vcpu); out: @@ -11379,7 +11380,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) * will ensure the vCPU gets the correct state before VM-Entry. */ if (enable_apicv) { - vcpu->arch.apicv_active = true; + vcpu->arch.apic->apicv_active = true; kvm_make_request(KVM_REQ_APICV_UPDATE, vcpu); } } else From b8e1b9626746209c980ce3fbf9ec3fc86910873d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:05:48 +0000 Subject: [PATCH 0540/1436] KVM: x86: Use lapic_in_kernel() to query in-kernel APIC in APICv helper Use lapic_in_kernel() in kvm_vcpu_apicv_active() to take advantage of the kvm_has_noapic_vcpu static branch. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220614230548.3852141-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index e09ad97f3250..6207b64b1281 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -205,7 +205,7 @@ static inline int apic_x2apic_mode(struct kvm_lapic *apic) static inline bool kvm_vcpu_apicv_active(struct kvm_vcpu *vcpu) { - return vcpu->arch.apic && vcpu->arch.apic->apicv_active; + return lapic_in_kernel(vcpu) && vcpu->arch.apic->apicv_active; } static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu) From 1ae20e0b975caf8ff51511a89cce5e28ec3e4d70 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:33:22 +0000 Subject: [PATCH 0541/1436] KVM: VMX: Refactor 32-bit PSE PT creation to avoid using MMU macro Compute the number of PTEs to be filled for the 32-bit PSE page tables using the page size and the size of each entry. While using the MMU's PT32_ENT_PER_PAGE macro is arguably better in isolation, removing VMX's usage will allow a future namespacing cleanup to move the guest page table macros into paging_tmpl.h, out of the reach of code that isn't directly related to shadow paging. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220614233328.3896033-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 2609bcc8c130..4002f6cc179d 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -3710,7 +3710,7 @@ static int init_rmode_identity_map(struct kvm *kvm) } /* Set up identity-mapping pagetable for EPT in real mode */ - for (i = 0; i < PT32_ENT_PER_PAGE; i++) { + for (i = 0; i < (PAGE_SIZE / sizeof(tmp)); i++) { tmp = (i << 22) + (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE); if (__copy_to_user(uaddr + i * sizeof(tmp), &tmp, sizeof(tmp))) { From b3fcdb04a98035f55f7ba9e3c87d3c4eb2f95b4b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:33:23 +0000 Subject: [PATCH 0542/1436] KVM: x86/mmu: Bury 32-bit PSE paging helpers in paging_tmpl.h Move a handful of one-off macros and helpers for 32-bit PSE paging into paging_tmpl.h and hide them behind "PTTYPE == 32". Under no circumstance should anything but 32-bit shadow paging care about PSE paging. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220614233328.3896033-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu.h | 5 ----- arch/x86/kvm/mmu/mmu.c | 7 ------- arch/x86/kvm/mmu/paging_tmpl.h | 18 +++++++++++++++++- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index f8192864b496..d1021e34ac15 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -34,11 +34,6 @@ #define PT_DIR_PAT_SHIFT 12 #define PT_DIR_PAT_MASK (1ULL << PT_DIR_PAT_SHIFT) -#define PT32_DIR_PSE36_SIZE 4 -#define PT32_DIR_PSE36_SHIFT 13 -#define PT32_DIR_PSE36_MASK \ - (((1ULL << PT32_DIR_PSE36_SIZE) - 1) << PT32_DIR_PSE36_SHIFT) - #define PT64_ROOT_5LEVEL 5 #define PT64_ROOT_4LEVEL 4 #define PT32_ROOT_LEVEL 2 diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 34785bc3077d..1a49b50d152e 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -324,13 +324,6 @@ static int is_cpuid_PSE36(void) return 1; } -static gfn_t pse36_gfn_delta(u32 gpte) -{ - int shift = 32 - PT32_DIR_PSE36_SHIFT - PAGE_SHIFT; - - return (gpte & PT32_DIR_PSE36_MASK) << shift; -} - #ifdef CONFIG_X86_64 static void __set_spte(u64 *sptep, u64 spte) { diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index f595c4b8657f..55fd35b1b227 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -50,6 +50,11 @@ #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT #define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT #define PT_HAVE_ACCESSED_DIRTY(mmu) true + + #define PT32_DIR_PSE36_SIZE 4 + #define PT32_DIR_PSE36_SHIFT 13 + #define PT32_DIR_PSE36_MASK \ + (((1ULL << PT32_DIR_PSE36_SIZE) - 1) << PT32_DIR_PSE36_SHIFT) #elif PTTYPE == PTTYPE_EPT #define pt_element_t u64 #define guest_walker guest_walkerEPT @@ -92,6 +97,15 @@ struct guest_walker { struct x86_exception fault; }; +#if PTTYPE == 32 +static inline gfn_t pse36_gfn_delta(u32 gpte) +{ + int shift = 32 - PT32_DIR_PSE36_SHIFT - PAGE_SHIFT; + + return (gpte & PT32_DIR_PSE36_MASK) << shift; +} +#endif + static gfn_t gpte_to_gfn_lvl(pt_element_t gpte, int lvl) { return (gpte & PT_LVL_ADDR_MASK(lvl)) >> PAGE_SHIFT; @@ -416,8 +430,10 @@ retry_walk: gfn = gpte_to_gfn_lvl(pte, walker->level); gfn += (addr & PT_LVL_OFFSET_MASK(walker->level)) >> PAGE_SHIFT; - if (PTTYPE == 32 && walker->level > PG_LEVEL_4K && is_cpuid_PSE36()) +#if PTTYPE == 32 + if (walker->level > PG_LEVEL_4K && is_cpuid_PSE36()) gfn += pse36_gfn_delta(pte); +#endif real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(gfn), access, &walker->fault); if (real_gpa == UNMAPPED_GVA) From 42c88ff893f06b6ab4eaeb2c37e513edf8c1943b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:33:24 +0000 Subject: [PATCH 0543/1436] KVM: x86/mmu: Dedup macros for computing various page table masks Provide common helper macros to generate various masks, shifts, etc... for 32-bit vs. 64-bit page tables. Only the inputs differ, the actual calculations are identical. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220614233328.3896033-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu.h | 4 ++-- arch/x86/kvm/mmu/mmu.c | 14 +++++--------- arch/x86/kvm/mmu/mmu_internal.h | 14 ++++++++++++++ arch/x86/kvm/mmu/paging.h | 9 +++++---- arch/x86/kvm/mmu/spte.h | 7 +++---- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index d1021e34ac15..6efe6bd7fb6e 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -7,9 +7,9 @@ #include "cpuid.h" #define PT64_PT_BITS 9 -#define PT64_ENT_PER_PAGE (1 << PT64_PT_BITS) +#define PT64_ENT_PER_PAGE __PT_ENT_PER_PAGE(PT64_PT_BITS) #define PT32_PT_BITS 10 -#define PT32_ENT_PER_PAGE (1 << PT32_PT_BITS) +#define PT32_ENT_PER_PAGE __PT_ENT_PER_PAGE(PT32_PT_BITS) #define PT_WRITABLE_SHIFT 1 #define PT_USER_SHIFT 2 diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 1a49b50d152e..2c5470953579 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -113,21 +113,17 @@ module_param(dbg, bool, 0644); #define PT32_LEVEL_BITS 10 -#define PT32_LEVEL_SHIFT(level) \ - (PAGE_SHIFT + (level - 1) * PT32_LEVEL_BITS) +#define PT32_LEVEL_SHIFT(level) __PT_LEVEL_SHIFT(level, PT32_LEVEL_BITS) #define PT32_LVL_OFFSET_MASK(level) \ - (PT32_BASE_ADDR_MASK & ((1ULL << (PAGE_SHIFT + (((level) - 1) \ - * PT32_LEVEL_BITS))) - 1)) - -#define PT32_INDEX(address, level)\ - (((address) >> PT32_LEVEL_SHIFT(level)) & ((1 << PT32_LEVEL_BITS) - 1)) + __PT_LVL_OFFSET_MASK(PT32_BASE_ADDR_MASK, level, PT32_LEVEL_BITS) +#define PT32_INDEX(address, level) __PT_INDEX(address, level, PT32_LEVEL_BITS) #define PT32_BASE_ADDR_MASK PAGE_MASK + #define PT32_LVL_ADDR_MASK(level) \ - (PAGE_MASK & ~((1ULL << (PAGE_SHIFT + (((level) - 1) \ - * PT32_LEVEL_BITS))) - 1)) + __PT_LVL_ADDR_MASK(PT32_BASE_ADDR_MASK, level, PT32_LEVEL_BITS) #include diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index bd2a26897b97..5e1e3c8f8aaa 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -20,6 +20,20 @@ extern bool dbg; #define MMU_WARN_ON(x) do { } while (0) #endif +/* Page table builder macros common to shadow (host) PTEs and guest PTEs. */ +#define __PT_LEVEL_SHIFT(level, bits_per_level) \ + (PAGE_SHIFT + ((level) - 1) * (bits_per_level)) +#define __PT_INDEX(address, level, bits_per_level) \ + (((address) >> __PT_LEVEL_SHIFT(level, bits_per_level)) & ((1 << (bits_per_level)) - 1)) + +#define __PT_LVL_ADDR_MASK(base_addr_mask, level, bits_per_level) \ + ((base_addr_mask) & ~((1ULL << (PAGE_SHIFT + (((level) - 1) * (bits_per_level)))) - 1)) + +#define __PT_LVL_OFFSET_MASK(base_addr_mask, level, bits_per_level) \ + ((base_addr_mask) & ((1ULL << (PAGE_SHIFT + (((level) - 1) * (bits_per_level)))) - 1)) + +#define __PT_ENT_PER_PAGE(bits_per_level) (1 << (bits_per_level)) + /* * Unlike regular MMU roots, PAE "roots", a.k.a. PDPTEs/PDPTRs, have a PRESENT * bit, and thus are guaranteed to be non-zero when valid. And, when a guest diff --git a/arch/x86/kvm/mmu/paging.h b/arch/x86/kvm/mmu/paging.h index de8ab323bb70..23f3f64b8092 100644 --- a/arch/x86/kvm/mmu/paging.h +++ b/arch/x86/kvm/mmu/paging.h @@ -4,11 +4,12 @@ #define __KVM_X86_PAGING_H #define GUEST_PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1)) + #define PT64_LVL_ADDR_MASK(level) \ - (GUEST_PT64_BASE_ADDR_MASK & ~((1ULL << (PAGE_SHIFT + (((level) - 1) \ - * PT64_LEVEL_BITS))) - 1)) + __PT_LVL_ADDR_MASK(GUEST_PT64_BASE_ADDR_MASK, level, PT64_LEVEL_BITS) + #define PT64_LVL_OFFSET_MASK(level) \ - (GUEST_PT64_BASE_ADDR_MASK & ((1ULL << (PAGE_SHIFT + (((level) - 1) \ - * PT64_LEVEL_BITS))) - 1)) + __PT_LVL_OFFSET_MASK(GUEST_PT64_BASE_ADDR_MASK, level, PT64_LEVEL_BITS) + #endif /* __KVM_X86_PAGING_H */ diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h index 0127bb6e3c7d..d5a8183b7232 100644 --- a/arch/x86/kvm/mmu/spte.h +++ b/arch/x86/kvm/mmu/spte.h @@ -55,11 +55,10 @@ static_assert(SPTE_TDP_AD_ENABLED_MASK == 0); #define PT64_LEVEL_BITS 9 -#define PT64_LEVEL_SHIFT(level) \ - (PAGE_SHIFT + (level - 1) * PT64_LEVEL_BITS) +#define PT64_LEVEL_SHIFT(level) __PT_LEVEL_SHIFT(level, PT64_LEVEL_BITS) + +#define PT64_INDEX(address, level) __PT_INDEX(address, level, PT64_LEVEL_BITS) -#define PT64_INDEX(address, level)\ - (((address) >> PT64_LEVEL_SHIFT(level)) & ((1 << PT64_LEVEL_BITS) - 1)) #define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) /* From 2ca3129e8045b18eb15431b485d40c028fe8fb00 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:33:25 +0000 Subject: [PATCH 0544/1436] KVM: x86/mmu: Use separate namespaces for guest PTEs and shadow PTEs Separate the macros for KVM's shadow PTEs (SPTE) from guest 64-bit PTEs (PT64). SPTE and PT64 are _mostly_ the same, but the few differences are quite critical, e.g. *_BASE_ADDR_MASK must differentiate between host and guest physical address spaces, and SPTE_PERM_MASK (was PT64_PERM_MASK) is very much specific to SPTEs. Opportunistically (and temporarily) move most guest macros into paging.h to clearly associate them with shadow paging, and to ensure that they're not used as of this commit. A future patch will eliminate them entirely. Sadly, PT32_LEVEL_BITS is left behind in mmu_internal.h because it's needed for the quadrant calculation in kvm_mmu_get_page(). The quadrant calculation is hot enough (when using shadow paging with 32-bit guests) that adding a per-context helper is undesirable, and burying the computation in paging_tmpl.h with a forward declaration isn't exactly an improvement. Signed-off-by: Sean Christopherson Message-Id: <20220614233328.3896033-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu.h | 5 --- arch/x86/kvm/mmu/mmu.c | 60 ++++++++++++++++++---------------- arch/x86/kvm/mmu/paging.h | 17 ++++++++++ arch/x86/kvm/mmu/paging_tmpl.h | 6 ++-- arch/x86/kvm/mmu/spte.c | 2 +- arch/x86/kvm/mmu/spte.h | 27 +++++++-------- arch/x86/kvm/mmu/tdp_iter.c | 6 ++-- arch/x86/kvm/mmu/tdp_mmu.c | 6 ++-- 8 files changed, 70 insertions(+), 59 deletions(-) diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h index 6efe6bd7fb6e..a99acec925eb 100644 --- a/arch/x86/kvm/mmu.h +++ b/arch/x86/kvm/mmu.h @@ -6,11 +6,6 @@ #include "kvm_cache_regs.h" #include "cpuid.h" -#define PT64_PT_BITS 9 -#define PT64_ENT_PER_PAGE __PT_ENT_PER_PAGE(PT64_PT_BITS) -#define PT32_PT_BITS 10 -#define PT32_ENT_PER_PAGE __PT_ENT_PER_PAGE(PT32_PT_BITS) - #define PT_WRITABLE_SHIFT 1 #define PT_USER_SHIFT 2 diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 2c5470953579..75f9e344812e 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -111,20 +111,6 @@ module_param(dbg, bool, 0644); #define PTE_PREFETCH_NUM 8 -#define PT32_LEVEL_BITS 10 - -#define PT32_LEVEL_SHIFT(level) __PT_LEVEL_SHIFT(level, PT32_LEVEL_BITS) - -#define PT32_LVL_OFFSET_MASK(level) \ - __PT_LVL_OFFSET_MASK(PT32_BASE_ADDR_MASK, level, PT32_LEVEL_BITS) - -#define PT32_INDEX(address, level) __PT_INDEX(address, level, PT32_LEVEL_BITS) - -#define PT32_BASE_ADDR_MASK PAGE_MASK - -#define PT32_LVL_ADDR_MASK(level) \ - __PT_LVL_ADDR_MASK(PT32_BASE_ADDR_MASK, level, PT32_LEVEL_BITS) - #include /* make pte_list_desc fit well in cache lines */ @@ -704,7 +690,7 @@ static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index) if (!sp->role.direct) return sp->gfns[index]; - return sp->gfn + (index << ((sp->role.level - 1) * PT64_LEVEL_BITS)); + return sp->gfn + (index << ((sp->role.level - 1) * SPTE_LEVEL_BITS)); } static void kvm_mmu_page_set_gfn(struct kvm_mmu_page *sp, int index, gfn_t gfn) @@ -1776,7 +1762,7 @@ static int __mmu_unsync_walk(struct kvm_mmu_page *sp, continue; } - child = to_shadow_page(ent & PT64_BASE_ADDR_MASK); + child = to_shadow_page(ent & SPTE_BASE_ADDR_MASK); if (child->unsync_children) { if (mmu_pages_add(pvec, child, i)) @@ -2027,8 +2013,24 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, role.direct = direct; role.access = access; if (role.has_4_byte_gpte) { - quadrant = gaddr >> (PAGE_SHIFT + (PT64_PT_BITS * level)); - quadrant &= (1 << ((PT32_PT_BITS - PT64_PT_BITS) * level)) - 1; + /* + * If the guest has 4-byte PTEs then that means it's using 32-bit, + * 2-level, non-PAE paging. KVM shadows such guests with PAE paging + * (i.e. 8-byte PTEs). The difference in PTE size means that KVM must + * shadow each guest page table with multiple shadow page tables, which + * requires extra bookkeeping in the role. + * + * Specifically, to shadow the guest's page directory (which covers a + * 4GiB address space), KVM uses 4 PAE page directories, each mapping + * 1GiB of the address space. @role.quadrant encodes which quarter of + * the address space each maps. + * + * To shadow the guest's page tables (which each map a 4MiB region), KVM + * uses 2 PAE page tables, each mapping a 2MiB region. For these, + * @role.quadrant encodes which half of the region they map. + */ + quadrant = gaddr >> (PAGE_SHIFT + (SPTE_LEVEL_BITS * level)); + quadrant &= (1 << level) - 1; role.quadrant = quadrant; } if (level <= vcpu->arch.mmu->cpu_role.base.level) @@ -2132,7 +2134,7 @@ static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterato iterator->shadow_addr = vcpu->arch.mmu->pae_root[(addr >> 30) & 3]; - iterator->shadow_addr &= PT64_BASE_ADDR_MASK; + iterator->shadow_addr &= SPTE_BASE_ADDR_MASK; --iterator->level; if (!iterator->shadow_addr) iterator->level = 0; @@ -2151,7 +2153,7 @@ static bool shadow_walk_okay(struct kvm_shadow_walk_iterator *iterator) if (iterator->level < PG_LEVEL_4K) return false; - iterator->index = SHADOW_PT_INDEX(iterator->addr, iterator->level); + iterator->index = SPTE_INDEX(iterator->addr, iterator->level); iterator->sptep = ((u64 *)__va(iterator->shadow_addr)) + iterator->index; return true; } @@ -2164,7 +2166,7 @@ static void __shadow_walk_next(struct kvm_shadow_walk_iterator *iterator, return; } - iterator->shadow_addr = spte & PT64_BASE_ADDR_MASK; + iterator->shadow_addr = spte & SPTE_BASE_ADDR_MASK; --iterator->level; } @@ -2203,7 +2205,7 @@ static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep, * so we should update the spte at this point to get * a new sp with the correct access. */ - child = to_shadow_page(*sptep & PT64_BASE_ADDR_MASK); + child = to_shadow_page(*sptep & SPTE_BASE_ADDR_MASK); if (child->role.access == direct_access) return; @@ -2224,7 +2226,7 @@ static int mmu_page_zap_pte(struct kvm *kvm, struct kvm_mmu_page *sp, if (is_last_spte(pte, sp->role.level)) { drop_spte(kvm, spte); } else { - child = to_shadow_page(pte & PT64_BASE_ADDR_MASK); + child = to_shadow_page(pte & SPTE_BASE_ADDR_MASK); drop_parent_pte(child, spte); /* @@ -2250,7 +2252,7 @@ static int kvm_mmu_page_unlink_children(struct kvm *kvm, int zapped = 0; unsigned i; - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) + for (i = 0; i < SPTE_ENT_PER_PAGE; ++i) zapped += mmu_page_zap_pte(kvm, sp, sp->spt + i, invalid_list); return zapped; @@ -2663,7 +2665,7 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot, struct kvm_mmu_page *child; u64 pte = *sptep; - child = to_shadow_page(pte & PT64_BASE_ADDR_MASK); + child = to_shadow_page(pte & SPTE_BASE_ADDR_MASK); drop_parent_pte(child, sptep); flush = true; } else if (pfn != spte_to_pfn(*sptep)) { @@ -3252,7 +3254,7 @@ static void mmu_free_root_page(struct kvm *kvm, hpa_t *root_hpa, if (!VALID_PAGE(*root_hpa)) return; - sp = to_shadow_page(*root_hpa & PT64_BASE_ADDR_MASK); + sp = to_shadow_page(*root_hpa & SPTE_BASE_ADDR_MASK); if (WARN_ON(!sp)) return; @@ -3724,7 +3726,7 @@ void kvm_mmu_sync_roots(struct kvm_vcpu *vcpu) hpa_t root = vcpu->arch.mmu->pae_root[i]; if (IS_VALID_PAE_ROOT(root)) { - root &= PT64_BASE_ADDR_MASK; + root &= SPTE_BASE_ADDR_MASK; sp = to_shadow_page(root); mmu_sync_children(vcpu, sp, true); } @@ -5186,11 +5188,11 @@ static bool need_remote_flush(u64 old, u64 new) return false; if (!is_shadow_present_pte(new)) return true; - if ((old ^ new) & PT64_BASE_ADDR_MASK) + if ((old ^ new) & SPTE_BASE_ADDR_MASK) return true; old ^= shadow_nx_mask; new ^= shadow_nx_mask; - return (old & ~new & PT64_PERM_MASK) != 0; + return (old & ~new & SPTE_PERM_MASK) != 0; } static u64 mmu_pte_write_fetch_gpte(struct kvm_vcpu *vcpu, gpa_t *gpa, diff --git a/arch/x86/kvm/mmu/paging.h b/arch/x86/kvm/mmu/paging.h index 23f3f64b8092..6a63727cc7e8 100644 --- a/arch/x86/kvm/mmu/paging.h +++ b/arch/x86/kvm/mmu/paging.h @@ -5,11 +5,28 @@ #define GUEST_PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1)) +#define PT64_LEVEL_BITS 9 + +#define PT64_INDEX(address, level) __PT_INDEX(address, level, PT64_LEVEL_BITS) + #define PT64_LVL_ADDR_MASK(level) \ __PT_LVL_ADDR_MASK(GUEST_PT64_BASE_ADDR_MASK, level, PT64_LEVEL_BITS) #define PT64_LVL_OFFSET_MASK(level) \ __PT_LVL_OFFSET_MASK(GUEST_PT64_BASE_ADDR_MASK, level, PT64_LEVEL_BITS) + +#define PT32_LEVEL_SHIFT(level) __PT_LEVEL_SHIFT(level, PT32_LEVEL_BITS) + +#define PT32_LVL_OFFSET_MASK(level) \ + __PT_LVL_OFFSET_MASK(PT32_BASE_ADDR_MASK, level, PT32_LEVEL_BITS) + +#define PT32_INDEX(address, level) __PT_INDEX(address, level, PT32_LEVEL_BITS) + +#define PT32_BASE_ADDR_MASK PAGE_MASK + +#define PT32_LVL_ADDR_MASK(level) \ + __PT_LVL_ADDR_MASK(PT32_BASE_ADDR_MASK, level, PT32_LEVEL_BITS) + #endif /* __KVM_X86_PAGING_H */ diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 55fd35b1b227..3ec90303e2f5 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -45,7 +45,7 @@ #define PT_LVL_ADDR_MASK(lvl) PT32_LVL_ADDR_MASK(lvl) #define PT_LVL_OFFSET_MASK(lvl) PT32_LVL_OFFSET_MASK(lvl) #define PT_INDEX(addr, level) PT32_INDEX(addr, level) - #define PT_LEVEL_BITS PT32_LEVEL_BITS + #define PT_LEVEL_BITS 10 #define PT_MAX_FULL_LEVELS 2 #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT #define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT @@ -899,7 +899,7 @@ static gpa_t FNAME(get_level1_sp_gpa)(struct kvm_mmu_page *sp) WARN_ON(sp->role.level != PG_LEVEL_4K); if (PTTYPE == 32) - offset = sp->role.quadrant << PT64_LEVEL_BITS; + offset = sp->role.quadrant << SPTE_LEVEL_BITS; return gfn_to_gpa(sp->gfn) + offset * sizeof(pt_element_t); } @@ -1034,7 +1034,7 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) first_pte_gpa = FNAME(get_level1_sp_gpa)(sp); - for (i = 0; i < PT64_ENT_PER_PAGE; i++) { + for (i = 0; i < SPTE_ENT_PER_PAGE; i++) { u64 *sptep, spte; struct kvm_memory_slot *slot; unsigned pte_access; diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index cda1851ec155..242e4828d7df 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -301,7 +301,7 @@ u64 kvm_mmu_changed_pte_notifier_make_spte(u64 old_spte, kvm_pfn_t new_pfn) { u64 new_spte; - new_spte = old_spte & ~PT64_BASE_ADDR_MASK; + new_spte = old_spte & ~SPTE_BASE_ADDR_MASK; new_spte |= (u64)new_pfn << PAGE_SHIFT; new_spte &= ~PT_WRITABLE_MASK; diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h index d5a8183b7232..121c5eaaec77 100644 --- a/arch/x86/kvm/mmu/spte.h +++ b/arch/x86/kvm/mmu/spte.h @@ -36,12 +36,12 @@ extern bool __read_mostly enable_mmio_caching; static_assert(SPTE_TDP_AD_ENABLED_MASK == 0); #ifdef CONFIG_DYNAMIC_PHYSICAL_MASK -#define PT64_BASE_ADDR_MASK (physical_mask & ~(u64)(PAGE_SIZE-1)) +#define SPTE_BASE_ADDR_MASK (physical_mask & ~(u64)(PAGE_SIZE-1)) #else -#define PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1)) +#define SPTE_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1)) #endif -#define PT64_PERM_MASK (PT_PRESENT_MASK | PT_WRITABLE_MASK | shadow_user_mask \ +#define SPTE_PERM_MASK (PT_PRESENT_MASK | PT_WRITABLE_MASK | shadow_user_mask \ | shadow_x_mask | shadow_nx_mask | shadow_me_mask) #define ACC_EXEC_MASK 1 @@ -50,16 +50,13 @@ static_assert(SPTE_TDP_AD_ENABLED_MASK == 0); #define ACC_ALL (ACC_EXEC_MASK | ACC_WRITE_MASK | ACC_USER_MASK) /* The mask for the R/X bits in EPT PTEs */ -#define PT64_EPT_READABLE_MASK 0x1ull -#define PT64_EPT_EXECUTABLE_MASK 0x4ull +#define SPTE_EPT_READABLE_MASK 0x1ull +#define SPTE_EPT_EXECUTABLE_MASK 0x4ull -#define PT64_LEVEL_BITS 9 - -#define PT64_LEVEL_SHIFT(level) __PT_LEVEL_SHIFT(level, PT64_LEVEL_BITS) - -#define PT64_INDEX(address, level) __PT_INDEX(address, level, PT64_LEVEL_BITS) - -#define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level) +#define SPTE_LEVEL_BITS 9 +#define SPTE_LEVEL_SHIFT(level) __PT_LEVEL_SHIFT(level, SPTE_LEVEL_BITS) +#define SPTE_INDEX(address, level) __PT_INDEX(address, level, SPTE_LEVEL_BITS) +#define SPTE_ENT_PER_PAGE __PT_ENT_PER_PAGE(SPTE_LEVEL_BITS) /* * The mask/shift to use for saving the original R/X bits when marking the PTE @@ -68,8 +65,8 @@ static_assert(SPTE_TDP_AD_ENABLED_MASK == 0); * restored only when a write is attempted to the page. This mask obviously * must not overlap the A/D type mask. */ -#define SHADOW_ACC_TRACK_SAVED_BITS_MASK (PT64_EPT_READABLE_MASK | \ - PT64_EPT_EXECUTABLE_MASK) +#define SHADOW_ACC_TRACK_SAVED_BITS_MASK (SPTE_EPT_READABLE_MASK | \ + SPTE_EPT_EXECUTABLE_MASK) #define SHADOW_ACC_TRACK_SAVED_BITS_SHIFT 54 #define SHADOW_ACC_TRACK_SAVED_MASK (SHADOW_ACC_TRACK_SAVED_BITS_MASK << \ SHADOW_ACC_TRACK_SAVED_BITS_SHIFT) @@ -281,7 +278,7 @@ static inline bool is_executable_pte(u64 spte) static inline kvm_pfn_t spte_to_pfn(u64 pte) { - return (pte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT; + return (pte & SPTE_BASE_ADDR_MASK) >> PAGE_SHIFT; } static inline bool is_accessed_spte(u64 spte) diff --git a/arch/x86/kvm/mmu/tdp_iter.c b/arch/x86/kvm/mmu/tdp_iter.c index ee4802d7b36c..9c65a64a56d9 100644 --- a/arch/x86/kvm/mmu/tdp_iter.c +++ b/arch/x86/kvm/mmu/tdp_iter.c @@ -11,7 +11,7 @@ static void tdp_iter_refresh_sptep(struct tdp_iter *iter) { iter->sptep = iter->pt_path[iter->level - 1] + - SHADOW_PT_INDEX(iter->gfn << PAGE_SHIFT, iter->level); + SPTE_INDEX(iter->gfn << PAGE_SHIFT, iter->level); iter->old_spte = kvm_tdp_mmu_read_spte(iter->sptep); } @@ -116,8 +116,8 @@ static bool try_step_side(struct tdp_iter *iter) * Check if the iterator is already at the end of the current page * table. */ - if (SHADOW_PT_INDEX(iter->gfn << PAGE_SHIFT, iter->level) == - (PT64_ENT_PER_PAGE - 1)) + if (SPTE_INDEX(iter->gfn << PAGE_SHIFT, iter->level) == + (SPTE_ENT_PER_PAGE - 1)) return false; iter->gfn += KVM_PAGES_PER_HPAGE(iter->level); diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 2cd060eb34a4..8e8d412fb65c 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -425,7 +425,7 @@ static void handle_removed_pt(struct kvm *kvm, tdp_ptep_t pt, bool shared) tdp_mmu_unlink_sp(kvm, sp, shared); - for (i = 0; i < PT64_ENT_PER_PAGE; i++) { + for (i = 0; i < SPTE_ENT_PER_PAGE; i++) { tdp_ptep_t sptep = pt + i; gfn_t gfn = base_gfn + i * KVM_PAGES_PER_HPAGE(level); u64 old_spte; @@ -1477,7 +1477,7 @@ static int tdp_mmu_split_huge_page(struct kvm *kvm, struct tdp_iter *iter, * No need for atomics when writing to sp->spt since the page table has * not been linked in yet and thus is not reachable from any other CPU. */ - for (i = 0; i < PT64_ENT_PER_PAGE; i++) + for (i = 0; i < SPTE_ENT_PER_PAGE; i++) sp->spt[i] = make_huge_page_split_spte(huge_spte, level, i); /* @@ -1497,7 +1497,7 @@ static int tdp_mmu_split_huge_page(struct kvm *kvm, struct tdp_iter *iter, * are overwriting from the page stats. But we have to manually update * the page stats with the new present child pages. */ - kvm_update_page_stats(kvm, level - 1, PT64_ENT_PER_PAGE); + kvm_update_page_stats(kvm, level - 1, SPTE_ENT_PER_PAGE); out: trace_kvm_mmu_split_huge_page(iter->gfn, huge_spte, level, ret); From f6b8ea6d43640ebfd1aeaa1faf1016d0bff7b8a0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 15 Jun 2022 10:15:56 -0400 Subject: [PATCH 0545/1436] KVM: x86/mmu: Use common macros to compute 32/64-bit paging masks Dedup the code for generating (most of) the per-type PT_* masks in paging_tmpl.h. The relevant macros only vary based on the number of bits per level, and that smidge of info is already provided in a common form as PT_LEVEL_BITS. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220614233328.3896033-7-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/paging.h | 23 ----------------------- arch/x86/kvm/mmu/paging_tmpl.h | 25 +++++++++++-------------- 2 files changed, 11 insertions(+), 37 deletions(-) diff --git a/arch/x86/kvm/mmu/paging.h b/arch/x86/kvm/mmu/paging.h index 6a63727cc7e8..9de4976b2d46 100644 --- a/arch/x86/kvm/mmu/paging.h +++ b/arch/x86/kvm/mmu/paging.h @@ -5,28 +5,5 @@ #define GUEST_PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1)) -#define PT64_LEVEL_BITS 9 - -#define PT64_INDEX(address, level) __PT_INDEX(address, level, PT64_LEVEL_BITS) - -#define PT64_LVL_ADDR_MASK(level) \ - __PT_LVL_ADDR_MASK(GUEST_PT64_BASE_ADDR_MASK, level, PT64_LEVEL_BITS) - -#define PT64_LVL_OFFSET_MASK(level) \ - __PT_LVL_OFFSET_MASK(GUEST_PT64_BASE_ADDR_MASK, level, PT64_LEVEL_BITS) - - -#define PT32_LEVEL_SHIFT(level) __PT_LEVEL_SHIFT(level, PT32_LEVEL_BITS) - -#define PT32_LVL_OFFSET_MASK(level) \ - __PT_LVL_OFFSET_MASK(PT32_BASE_ADDR_MASK, level, PT32_LEVEL_BITS) - -#define PT32_INDEX(address, level) __PT_INDEX(address, level, PT32_LEVEL_BITS) - -#define PT32_BASE_ADDR_MASK PAGE_MASK - -#define PT32_LVL_ADDR_MASK(level) \ - __PT_LVL_ADDR_MASK(PT32_BASE_ADDR_MASK, level, PT32_LEVEL_BITS) - #endif /* __KVM_X86_PAGING_H */ diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 3ec90303e2f5..61b328b0f2dc 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -16,8 +16,9 @@ */ /* - * We need the mmu code to access both 32-bit and 64-bit guest ptes, - * so the code in this file is compiled twice, once per pte size. + * The MMU needs to be able to access/walk 32-bit and 64-bit guest page tables, + * as well as guest EPT tables, so the code in this file is compiled thrice, + * once per guest PTE type. The per-type defines are #undef'd at the end. */ #if PTTYPE == 64 @@ -25,10 +26,7 @@ #define guest_walker guest_walker64 #define FNAME(name) paging##64_##name #define PT_BASE_ADDR_MASK GUEST_PT64_BASE_ADDR_MASK - #define PT_LVL_ADDR_MASK(lvl) PT64_LVL_ADDR_MASK(lvl) - #define PT_LVL_OFFSET_MASK(lvl) PT64_LVL_OFFSET_MASK(lvl) - #define PT_INDEX(addr, level) PT64_INDEX(addr, level) - #define PT_LEVEL_BITS PT64_LEVEL_BITS + #define PT_LEVEL_BITS 9 #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT #define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT #define PT_HAVE_ACCESSED_DIRTY(mmu) true @@ -41,10 +39,7 @@ #define pt_element_t u32 #define guest_walker guest_walker32 #define FNAME(name) paging##32_##name - #define PT_BASE_ADDR_MASK PT32_BASE_ADDR_MASK - #define PT_LVL_ADDR_MASK(lvl) PT32_LVL_ADDR_MASK(lvl) - #define PT_LVL_OFFSET_MASK(lvl) PT32_LVL_OFFSET_MASK(lvl) - #define PT_INDEX(addr, level) PT32_INDEX(addr, level) + #define PT_BASE_ADDR_MASK PAGE_MASK #define PT_LEVEL_BITS 10 #define PT_MAX_FULL_LEVELS 2 #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT @@ -60,10 +55,7 @@ #define guest_walker guest_walkerEPT #define FNAME(name) ept_##name #define PT_BASE_ADDR_MASK GUEST_PT64_BASE_ADDR_MASK - #define PT_LVL_ADDR_MASK(lvl) PT64_LVL_ADDR_MASK(lvl) - #define PT_LVL_OFFSET_MASK(lvl) PT64_LVL_OFFSET_MASK(lvl) - #define PT_INDEX(addr, level) PT64_INDEX(addr, level) - #define PT_LEVEL_BITS PT64_LEVEL_BITS + #define PT_LEVEL_BITS 9 #define PT_GUEST_DIRTY_SHIFT 9 #define PT_GUEST_ACCESSED_SHIFT 8 #define PT_HAVE_ACCESSED_DIRTY(mmu) (!(mmu)->cpu_role.base.ad_disabled) @@ -72,6 +64,11 @@ #error Invalid PTTYPE value #endif +/* Common logic, but per-type values. These also need to be undefined. */ +#define PT_LVL_ADDR_MASK(lvl) __PT_LVL_ADDR_MASK(PT_BASE_ADDR_MASK, lvl, PT_LEVEL_BITS) +#define PT_LVL_OFFSET_MASK(lvl) __PT_LVL_OFFSET_MASK(PT_BASE_ADDR_MASK, lvl, PT_LEVEL_BITS) +#define PT_INDEX(addr, lvl) __PT_INDEX(addr, lvl, PT_LEVEL_BITS) + #define PT_GUEST_DIRTY_MASK (1 << PT_GUEST_DIRTY_SHIFT) #define PT_GUEST_ACCESSED_MASK (1 << PT_GUEST_ACCESSED_SHIFT) From f7384b8866b0b07f249130aa8b63135687626c5c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:33:27 +0000 Subject: [PATCH 0546/1436] KVM: x86/mmu: Truncate paging32's PT_BASE_ADDR_MASK to 32 bits Truncate paging32's PT_BASE_ADDR_MASK to a pt_element_t, i.e. to 32 bits. Ignoring PSE huge pages, the mask is only used in conjunction with gPTEs, which are 32 bits, and so the address is limited to bits 31:12. PSE huge pages encoded PA bits 39:32 in PTE bits 20:13, i.e. need custom logic to handle their funky encoding regardless of PT_BASE_ADDR_MASK. Note, PT_LVL_OFFSET_MASK is somewhat confusing in that it computes the offset of the _gfn_, not of the gpa, i.e. not having bits 63:32 set in PT_BASE_ADDR_MASK is again correct. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220614233328.3896033-8-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/paging_tmpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 61b328b0f2dc..b7424d63c706 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -39,7 +39,7 @@ #define pt_element_t u32 #define guest_walker guest_walker32 #define FNAME(name) paging##32_##name - #define PT_BASE_ADDR_MASK PAGE_MASK + #define PT_BASE_ADDR_MASK ((pt_element_t)PAGE_MASK) #define PT_LEVEL_BITS 10 #define PT_MAX_FULL_LEVELS 2 #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT From 70e41c31bc7776b262cd9f524df3dfc2b5869a0a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 23:33:28 +0000 Subject: [PATCH 0547/1436] KVM: x86/mmu: Use common logic for computing the 32/64-bit base PA mask Use common logic for computing PT_BASE_ADDR_MASK for 32-bit, 64-bit, and EPT paging. Both PAGE_MASK and the new-common logic are supsersets of what is actually needed for 32-bit paging. PAGE_MASK sets bits 63:12 and the former GUEST_PT64_BASE_ADDR_MASK sets bits 51:12, so regardless of which value is used, the result will always be bits 31:12. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220614233328.3896033-9-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 2 -- arch/x86/kvm/mmu/paging.h | 9 --------- arch/x86/kvm/mmu/paging_tmpl.h | 4 +--- 3 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 arch/x86/kvm/mmu/paging.h diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 75f9e344812e..2dcedf04ef85 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -53,8 +53,6 @@ #include #include "trace.h" -#include "paging.h" - extern bool itlb_multihit_kvm_mitigation; int __read_mostly nx_huge_pages = -1; diff --git a/arch/x86/kvm/mmu/paging.h b/arch/x86/kvm/mmu/paging.h deleted file mode 100644 index 9de4976b2d46..000000000000 --- a/arch/x86/kvm/mmu/paging.h +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* Shadow paging constants/helpers that don't need to be #undef'd. */ -#ifndef __KVM_X86_PAGING_H -#define __KVM_X86_PAGING_H - -#define GUEST_PT64_BASE_ADDR_MASK (((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1)) - -#endif /* __KVM_X86_PAGING_H */ - diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index b7424d63c706..e4655056e651 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -25,7 +25,6 @@ #define pt_element_t u64 #define guest_walker guest_walker64 #define FNAME(name) paging##64_##name - #define PT_BASE_ADDR_MASK GUEST_PT64_BASE_ADDR_MASK #define PT_LEVEL_BITS 9 #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT #define PT_GUEST_ACCESSED_SHIFT PT_ACCESSED_SHIFT @@ -39,7 +38,6 @@ #define pt_element_t u32 #define guest_walker guest_walker32 #define FNAME(name) paging##32_##name - #define PT_BASE_ADDR_MASK ((pt_element_t)PAGE_MASK) #define PT_LEVEL_BITS 10 #define PT_MAX_FULL_LEVELS 2 #define PT_GUEST_DIRTY_SHIFT PT_DIRTY_SHIFT @@ -54,7 +52,6 @@ #define pt_element_t u64 #define guest_walker guest_walkerEPT #define FNAME(name) ept_##name - #define PT_BASE_ADDR_MASK GUEST_PT64_BASE_ADDR_MASK #define PT_LEVEL_BITS 9 #define PT_GUEST_DIRTY_SHIFT 9 #define PT_GUEST_ACCESSED_SHIFT 8 @@ -65,6 +62,7 @@ #endif /* Common logic, but per-type values. These also need to be undefined. */ +#define PT_BASE_ADDR_MASK ((pt_element_t)(((1ULL << 52) - 1) & ~(u64)(PAGE_SIZE-1))) #define PT_LVL_ADDR_MASK(lvl) __PT_LVL_ADDR_MASK(PT_BASE_ADDR_MASK, lvl, PT_LEVEL_BITS) #define PT_LVL_OFFSET_MASK(lvl) __PT_LVL_OFFSET_MASK(PT_BASE_ADDR_MASK, lvl, PT_LEVEL_BITS) #define PT_INDEX(addr, lvl) __PT_INDEX(addr, lvl, PT_LEVEL_BITS) From 28b85ae06f64bf1c1adea68a2fbb31dc40cc060e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:08 +0000 Subject: [PATCH 0548/1436] KVM: Drop bogus "pfn != 0" guard from kvm_release_pfn() Remove a check from kvm_release_pfn() to bail if the provided @pfn is zero. Zero is a perfectly valid pfn on most architectures, and should not be used to indicate an error or an invalid pfn. The bogus check was added by commit 917248144db5 ("x86/kvm: Cache gfn to pfn translation"), which also did the bad thing of zeroing the pfn and gfn to mark a cache invalid. Thankfully, that bad behavior was axed by commit 357a18ad230f ("KVM: Kill kvm_map_gfn() / kvm_unmap_gfn() and gfn_to_pfn_cache"). Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/kvm_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index b13acbaa6d2a..8f475d174e3d 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2745,9 +2745,6 @@ EXPORT_SYMBOL_GPL(gfn_to_page); void kvm_release_pfn(kvm_pfn_t pfn, bool dirty) { - if (pfn == 0) - return; - if (dirty) kvm_release_pfn_dirty(pfn); else From a1040b0d42acf69bb4f6dbdc54c2dcd78eea1de5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:09 +0000 Subject: [PATCH 0549/1436] KVM: Don't set Accessed/Dirty bits for ZERO_PAGE Don't set Accessed/Dirty bits for a struct page with PG_reserved set, i.e. don't set A/D bits for the ZERO_PAGE. The ZERO_PAGE (or pages depending on the architecture) should obviously never be written, and similarly there's no point in marking it accessed as the page will never be swapped out or reclaimed. The comment in page-flags.h is quite clear that PG_reserved pages should be managed only by their owner, and strictly following that mandate also simplifies KVM's logic. Fixes: 7df003c85218 ("KVM: fix overflow of zero page refcount with ksm running") Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/kvm_main.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 8f475d174e3d..351cbd121cf5 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2850,16 +2850,28 @@ void kvm_release_pfn_dirty(kvm_pfn_t pfn) } EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty); +static bool kvm_is_ad_tracked_pfn(kvm_pfn_t pfn) +{ + if (!pfn_valid(pfn)) + return false; + + /* + * Per page-flags.h, pages tagged PG_reserved "should in general not be + * touched (e.g. set dirty) except by its owner". + */ + return !PageReserved(pfn_to_page(pfn)); +} + void kvm_set_pfn_dirty(kvm_pfn_t pfn) { - if (!kvm_is_reserved_pfn(pfn) && !kvm_is_zone_device_pfn(pfn)) + if (kvm_is_ad_tracked_pfn(pfn)) SetPageDirty(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty); void kvm_set_pfn_accessed(kvm_pfn_t pfn) { - if (!kvm_is_reserved_pfn(pfn) && !kvm_is_zone_device_pfn(pfn)) + if (kvm_is_ad_tracked_pfn(pfn)) mark_page_accessed(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed); From 8e1c69149f27189cff93a0cfe9402e576d89ce29 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:10 +0000 Subject: [PATCH 0550/1436] KVM: Avoid pfn_to_page() and vice versa when releasing pages Invert the order of KVM's page/pfn release helpers so that the "inner" helper operates on a page instead of a pfn. As pointed out by Linus[*], converting between struct page and a pfn isn't necessarily cheap, and that's not even counting the overhead of is_error_noslot_pfn() and kvm_is_reserved_pfn(). Even if the checks were dirt cheap, there's no reason to convert from a page to a pfn and back to a page, just to mark the page dirty/accessed or to put a reference to the page. Opportunistically drop a stale declaration of kvm_set_page_accessed() from kvm_host.h (there was no implementation). No functional change intended. [*] https://lore.kernel.org/all/CAHk-=wifQimj2d6npq-wCi5onYPjzQg4vyO4tFcPJJZr268cRw@mail.gmail.com Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 1 - virt/kvm/kvm_main.c | 64 +++++++++++++++++++++++++++------------- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index c20f2d55840c..af4b5c0bf04e 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1139,7 +1139,6 @@ unsigned long gfn_to_hva_memslot_prot(struct kvm_memory_slot *slot, gfn_t gfn, bool *writable); void kvm_release_page_clean(struct page *page); void kvm_release_page_dirty(struct page *page); -void kvm_set_page_accessed(struct page *page); kvm_pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn); kvm_pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault, diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 351cbd121cf5..4732a99935f9 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2820,18 +2820,40 @@ struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn) } EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_page); +static bool kvm_is_ad_tracked_page(struct page *page) +{ + /* + * Per page-flags.h, pages tagged PG_reserved "should in general not be + * touched (e.g. set dirty) except by its owner". + */ + return !PageReserved(page); +} + +static void kvm_set_page_dirty(struct page *page) +{ + if (kvm_is_ad_tracked_page(page)) + SetPageDirty(page); +} + +static void kvm_set_page_accessed(struct page *page) +{ + if (kvm_is_ad_tracked_page(page)) + mark_page_accessed(page); +} + void kvm_release_page_clean(struct page *page) { WARN_ON(is_error_page(page)); - kvm_release_pfn_clean(page_to_pfn(page)); + kvm_set_page_accessed(page); + put_page(page); } EXPORT_SYMBOL_GPL(kvm_release_page_clean); void kvm_release_pfn_clean(kvm_pfn_t pfn) { if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn)) - put_page(pfn_to_page(pfn)); + kvm_release_page_clean(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); @@ -2839,40 +2861,40 @@ void kvm_release_page_dirty(struct page *page) { WARN_ON(is_error_page(page)); - kvm_release_pfn_dirty(page_to_pfn(page)); + kvm_set_page_dirty(page); + kvm_release_page_clean(page); } EXPORT_SYMBOL_GPL(kvm_release_page_dirty); void kvm_release_pfn_dirty(kvm_pfn_t pfn) { - kvm_set_pfn_dirty(pfn); - kvm_release_pfn_clean(pfn); + if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn)) + kvm_release_page_dirty(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty); -static bool kvm_is_ad_tracked_pfn(kvm_pfn_t pfn) -{ - if (!pfn_valid(pfn)) - return false; - - /* - * Per page-flags.h, pages tagged PG_reserved "should in general not be - * touched (e.g. set dirty) except by its owner". - */ - return !PageReserved(pfn_to_page(pfn)); -} - +/* + * Note, checking for an error/noslot pfn is the caller's responsibility when + * directly marking a page dirty/accessed. Unlike the "release" helpers, the + * "set" helpers are not to be used when the pfn might point at garbage. + */ void kvm_set_pfn_dirty(kvm_pfn_t pfn) { - if (kvm_is_ad_tracked_pfn(pfn)) - SetPageDirty(pfn_to_page(pfn)); + if (WARN_ON(is_error_noslot_pfn(pfn))) + return; + + if (pfn_valid(pfn)) + kvm_set_page_dirty(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty); void kvm_set_pfn_accessed(kvm_pfn_t pfn) { - if (kvm_is_ad_tracked_pfn(pfn)) - mark_page_accessed(pfn_to_page(pfn)); + if (WARN_ON(is_error_noslot_pfn(pfn))) + return; + + if (pfn_valid(pfn)) + kvm_set_page_accessed(pfn_to_page(pfn)); } EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed); From fe1911aa443ed774df46607970bed58d9769db41 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:11 +0000 Subject: [PATCH 0551/1436] KVM: nVMX: Use kvm_vcpu_map() to get/pin vmcs12's APIC-access page Use kvm_vcpu_map() to get/pin the backing for vmcs12's APIC-access page, there's no reason it has to be restricted to 'struct page' backing. The APIC-access page actually doesn't need to be backed by anything, which is ironically why it got left behind by the series which introduced kvm_vcpu_map()[1]; the plan was to shove a dummy pfn into vmcs02[2], but that code never got merged. Switching the APIC-access page to kvm_vcpu_map() doesn't preclude using a magic pfn in the future, and will allow a future patch to drop kvm_vcpu_gpa_to_page(). [1] https://lore.kernel.org/all/1547026933-31226-1-git-send-email-karahmed@amazon.de [2] https://lore.kernel.org/lkml/1543845551-4403-1-git-send-email-karahmed@amazon.de Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 39 ++++++++++++--------------------------- arch/x86/kvm/vmx/vmx.h | 2 +- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index aad938e1e51d..778f82015f03 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -311,11 +311,12 @@ static void free_nested(struct kvm_vcpu *vcpu) vmx->nested.cached_vmcs12 = NULL; kfree(vmx->nested.cached_shadow_vmcs12); vmx->nested.cached_shadow_vmcs12 = NULL; - /* Unpin physical memory we referred to in the vmcs02 */ - if (vmx->nested.apic_access_page) { - kvm_release_page_clean(vmx->nested.apic_access_page); - vmx->nested.apic_access_page = NULL; - } + /* + * Unpin physical memory we referred to in the vmcs02. The APIC access + * page's backing page (yeah, confusing) shouldn't actually be accessed, + * and if it is written, the contents are irrelevant. + */ + kvm_vcpu_unmap(vcpu, &vmx->nested.apic_access_page_map, false); kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map, true); kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map, true); vmx->nested.pi_desc = NULL; @@ -3164,8 +3165,6 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu) struct vmcs12 *vmcs12 = get_vmcs12(vcpu); struct vcpu_vmx *vmx = to_vmx(vcpu); struct kvm_host_map *map; - struct page *page; - u64 hpa; if (!vcpu->arch.pdptrs_from_userspace && !nested_cpu_has_ept(vmcs12) && is_pae_paging(vcpu)) { @@ -3180,23 +3179,12 @@ static bool nested_get_vmcs12_pages(struct kvm_vcpu *vcpu) if (nested_cpu_has2(vmcs12, SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) { - /* - * Translate L1 physical address to host physical - * address for vmcs02. Keep the page pinned, so this - * physical address remains valid. We keep a reference - * to it so we can release it later. - */ - if (vmx->nested.apic_access_page) { /* shouldn't happen */ - kvm_release_page_clean(vmx->nested.apic_access_page); - vmx->nested.apic_access_page = NULL; - } - page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->apic_access_addr); - if (!is_error_page(page)) { - vmx->nested.apic_access_page = page; - hpa = page_to_phys(vmx->nested.apic_access_page); - vmcs_write64(APIC_ACCESS_ADDR, hpa); + map = &vmx->nested.apic_access_page_map; + + if (!kvm_vcpu_map(vcpu, gpa_to_gfn(vmcs12->apic_access_addr), map)) { + vmcs_write64(APIC_ACCESS_ADDR, pfn_to_hpa(map->pfn)); } else { - pr_debug_ratelimited("%s: no backing 'struct page' for APIC-access address in vmcs12\n", + pr_debug_ratelimited("%s: no backing for APIC-access address in vmcs12\n", __func__); vcpu->run->exit_reason = KVM_EXIT_INTERNAL_ERROR; vcpu->run->internal.suberror = @@ -4632,10 +4620,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason, } /* Unpin physical memory we referred to in vmcs02 */ - if (vmx->nested.apic_access_page) { - kvm_release_page_clean(vmx->nested.apic_access_page); - vmx->nested.apic_access_page = NULL; - } + kvm_vcpu_unmap(vcpu, &vmx->nested.apic_access_page_map, false); kvm_vcpu_unmap(vcpu, &vmx->nested.virtual_apic_map, true); kvm_vcpu_unmap(vcpu, &vmx->nested.pi_desc_map, true); vmx->nested.pi_desc = NULL; diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index a84c91ee2a48..286c88e285ea 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -204,7 +204,7 @@ struct nested_vmx { * Guest pages referred to in the vmcs02 with host-physical * pointers, so we must keep them pinned while L2 runs. */ - struct page *apic_access_page; + struct kvm_host_map apic_access_page_map; struct kvm_host_map virtual_apic_map; struct kvm_host_map pi_desc_map; From 6573a6910ce46ece35c1aa4bd38b70884553cd21 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:12 +0000 Subject: [PATCH 0552/1436] KVM: Don't WARN if kvm_pfn_to_page() encounters a "reserved" pfn Drop a WARN_ON() if kvm_pfn_to_page() encounters a "reserved" pfn, which in this context means a struct page that has PG_reserved but is not a/the ZERO_PAGE and is not a ZONE_DEVICE page. The usage, via gfn_to_page(), in x86 is safe as gfn_to_page() is used only to retrieve a page from KVM-controlled memslot, but the usage in PPC and s390 operates on arbitrary gfns and thus memslots that can be backed by incompatible memory. Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-7-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/kvm_main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 4732a99935f9..78d280e119b3 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2725,10 +2725,8 @@ static struct page *kvm_pfn_to_page(kvm_pfn_t pfn) if (is_error_noslot_pfn(pfn)) return KVM_ERR_PTR_BAD_PAGE; - if (kvm_is_reserved_pfn(pfn)) { - WARN_ON(1); + if (kvm_is_reserved_pfn(pfn)) return KVM_ERR_PTR_BAD_PAGE; - } return pfn_to_page(pfn); } From b1624f99aa8fedafcabf1b92fa51ed88dde14acb Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:13 +0000 Subject: [PATCH 0553/1436] KVM: Remove kvm_vcpu_gfn_to_page() and kvm_vcpu_gpa_to_page() Drop helpers to convert a gfn/gpa to a 'struct page' in the context of a vCPU. KVM doesn't require that guests be backed by 'struct page' memory, thus any use of helpers that assume 'struct page' is bound to be flawed, as was the case for the recently removed last user in x86's nested VMX. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-8-seanjc@google.com> Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 7 ------- virt/kvm/kvm_main.c | 31 +++++++++++-------------------- 2 files changed, 11 insertions(+), 27 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index af4b5c0bf04e..4334789409c0 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1230,7 +1230,6 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn kvm_pfn_t kvm_vcpu_gfn_to_pfn_atomic(struct kvm_vcpu *vcpu, gfn_t gfn); kvm_pfn_t kvm_vcpu_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn); int kvm_vcpu_map(struct kvm_vcpu *vcpu, gpa_t gpa, struct kvm_host_map *map); -struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn); void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty); unsigned long kvm_vcpu_gfn_to_hva(struct kvm_vcpu *vcpu, gfn_t gfn); unsigned long kvm_vcpu_gfn_to_hva_prot(struct kvm_vcpu *vcpu, gfn_t gfn, bool *writable); @@ -1718,12 +1717,6 @@ static inline hpa_t pfn_to_hpa(kvm_pfn_t pfn) return (hpa_t)pfn << PAGE_SHIFT; } -static inline struct page *kvm_vcpu_gpa_to_page(struct kvm_vcpu *vcpu, - gpa_t gpa) -{ - return kvm_vcpu_gfn_to_page(vcpu, gpa_to_gfn(gpa)); -} - static inline bool kvm_is_error_gpa(struct kvm *kvm, gpa_t gpa) { unsigned long hva = gfn_to_hva(kvm, gpa_to_gfn(gpa)); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 78d280e119b3..7cd0e3d67f9f 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2720,8 +2720,18 @@ int gfn_to_page_many_atomic(struct kvm_memory_slot *slot, gfn_t gfn, } EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic); -static struct page *kvm_pfn_to_page(kvm_pfn_t pfn) +/* + * Do not use this helper unless you are absolutely certain the gfn _must_ be + * backed by 'struct page'. A valid example is if the backing memslot is + * controlled by KVM. Note, if the returned page is valid, it's refcount has + * been elevated by gfn_to_pfn(). + */ +struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) { + kvm_pfn_t pfn; + + pfn = gfn_to_pfn(kvm, gfn); + if (is_error_noslot_pfn(pfn)) return KVM_ERR_PTR_BAD_PAGE; @@ -2730,15 +2740,6 @@ static struct page *kvm_pfn_to_page(kvm_pfn_t pfn) return pfn_to_page(pfn); } - -struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) -{ - kvm_pfn_t pfn; - - pfn = gfn_to_pfn(kvm, gfn); - - return kvm_pfn_to_page(pfn); -} EXPORT_SYMBOL_GPL(gfn_to_page); void kvm_release_pfn(kvm_pfn_t pfn, bool dirty) @@ -2808,16 +2809,6 @@ void kvm_vcpu_unmap(struct kvm_vcpu *vcpu, struct kvm_host_map *map, bool dirty) } EXPORT_SYMBOL_GPL(kvm_vcpu_unmap); -struct page *kvm_vcpu_gfn_to_page(struct kvm_vcpu *vcpu, gfn_t gfn) -{ - kvm_pfn_t pfn; - - pfn = kvm_vcpu_gfn_to_pfn(vcpu, gfn); - - return kvm_pfn_to_page(pfn); -} -EXPORT_SYMBOL_GPL(kvm_vcpu_gfn_to_page); - static bool kvm_is_ad_tracked_page(struct page *page) { /* From 284dc49307738d2a897fd375431f741213cd0f27 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:14 +0000 Subject: [PATCH 0554/1436] KVM: Take a 'struct page', not a pfn in kvm_is_zone_device_page() Operate on a 'struct page' instead of a pfn when checking if a page is a ZONE_DEVICE page, and rename the helper accordingly. Generally speaking, KVM doesn't actually care about ZONE_DEVICE memory, i.e. shouldn't do anything special for ZONE_DEVICE memory. Rather, KVM wants to treat ZONE_DEVICE memory like regular memory, and the need to identify ZONE_DEVICE memory only arises as an exception to PG_reserved pages. In other words, KVM should only ever check for ZONE_DEVICE memory after KVM has already verified that there is a struct page associated with the pfn. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-9-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 5 +++-- include/linux/kvm_host.h | 2 +- virt/kvm/kvm_main.c | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 2dcedf04ef85..b209aaf096df 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2788,15 +2788,16 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep) static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, const struct kvm_memory_slot *slot) { + struct page *page = pfn_to_page(pfn); + int level = PG_LEVEL_4K; unsigned long hva; unsigned long flags; - int level = PG_LEVEL_4K; pgd_t pgd; p4d_t p4d; pud_t pud; pmd_t pmd; - if (!PageCompound(pfn_to_page(pfn)) && !kvm_is_zone_device_pfn(pfn)) + if (!PageCompound(page) && !kvm_is_zone_device_page(page)) return PG_LEVEL_4K; /* diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 4334789409c0..6fb433ac2ba1 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1571,7 +1571,7 @@ void kvm_arch_sync_events(struct kvm *kvm); int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); bool kvm_is_reserved_pfn(kvm_pfn_t pfn); -bool kvm_is_zone_device_pfn(kvm_pfn_t pfn); +bool kvm_is_zone_device_page(struct page *page); struct kvm_irq_ack_notifier { struct hlist_node link; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 7cd0e3d67f9f..aa1bcd5f140d 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -168,7 +168,7 @@ __weak void kvm_arch_guest_memory_reclaimed(struct kvm *kvm) { } -bool kvm_is_zone_device_pfn(kvm_pfn_t pfn) +bool kvm_is_zone_device_page(struct page *page) { /* * The metadata used by is_zone_device_page() to determine whether or @@ -176,10 +176,10 @@ bool kvm_is_zone_device_pfn(kvm_pfn_t pfn) * the device has been pinned, e.g. by get_user_pages(). WARN if the * page_count() is zero to help detect bad usage of this helper. */ - if (!pfn_valid(pfn) || WARN_ON_ONCE(!page_count(pfn_to_page(pfn)))) + if (WARN_ON_ONCE(!page_count(page))) return false; - return is_zone_device_page(pfn_to_page(pfn)); + return is_zone_device_page(page); } bool kvm_is_reserved_pfn(kvm_pfn_t pfn) @@ -192,7 +192,7 @@ bool kvm_is_reserved_pfn(kvm_pfn_t pfn) if (pfn_valid(pfn)) return PageReserved(pfn_to_page(pfn)) && !is_zero_pfn(pfn) && - !kvm_is_zone_device_pfn(pfn); + !kvm_is_zone_device_page(pfn_to_page(pfn)); return true; } From b14b2690c50e02145bb867dfcde8845eb17aa8a4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:15 +0000 Subject: [PATCH 0555/1436] KVM: Rename/refactor kvm_is_reserved_pfn() to kvm_pfn_to_refcounted_page() Rename and refactor kvm_is_reserved_pfn() to kvm_pfn_to_refcounted_page() to better reflect what KVM is actually checking, and to eliminate extra pfn_to_page() lookups. The kvm_release_pfn_*() an kvm_try_get_pfn() helpers in particular benefit from "refouncted" nomenclature, as it's not all that obvious why KVM needs to get/put refcounts for some PG_reserved pages (ZERO_PAGE and ZONE_DEVICE). Add a comment to call out that the list of exceptions to PG_reserved is all but guaranteed to be incomplete. The list has mostly been compiled by people throwing noodles at KVM and finding out they stick a little too well, e.g. the ZERO_PAGE's refcount overflowed and ZONE_DEVICE pages didn't get freed. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-10-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 15 +++++---- arch/x86/kvm/mmu/tdp_mmu.c | 2 +- include/linux/kvm_host.h | 2 +- virt/kvm/kvm_main.c | 66 ++++++++++++++++++++++++++++++-------- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index b209aaf096df..7ebb97c95da7 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -534,6 +534,7 @@ static int mmu_spte_clear_track_bits(struct kvm *kvm, u64 *sptep) kvm_pfn_t pfn; u64 old_spte = *sptep; int level = sptep_to_sp(sptep)->role.level; + struct page *page; if (!is_shadow_present_pte(old_spte) || !spte_has_volatile_bits(old_spte)) @@ -549,11 +550,13 @@ static int mmu_spte_clear_track_bits(struct kvm *kvm, u64 *sptep) pfn = spte_to_pfn(old_spte); /* - * KVM does not hold the refcount of the page used by - * kvm mmu, before reclaiming the page, we should - * unmap it from mmu first. + * KVM doesn't hold a reference to any pages mapped into the guest, and + * instead uses the mmu_notifier to ensure that KVM unmaps any pages + * before they are reclaimed. Sanity check that, if the pfn is backed + * by a refcounted page, the refcount is elevated. */ - WARN_ON(!kvm_is_reserved_pfn(pfn) && !page_count(pfn_to_page(pfn))); + page = kvm_pfn_to_refcounted_page(pfn); + WARN_ON(page && !page_count(page)); if (is_accessed_spte(old_spte)) kvm_set_pfn_accessed(pfn); @@ -2881,7 +2884,7 @@ void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault if (unlikely(fault->max_level == PG_LEVEL_4K)) return; - if (is_error_noslot_pfn(fault->pfn) || kvm_is_reserved_pfn(fault->pfn)) + if (is_error_noslot_pfn(fault->pfn) || !kvm_pfn_to_refcounted_page(fault->pfn)) return; if (kvm_slot_dirty_track_enabled(slot)) @@ -5993,7 +5996,7 @@ restart: * the guest, and the guest page table is using 4K page size * mapping if the indirect sp has level = 1. */ - if (sp->role.direct && !kvm_is_reserved_pfn(pfn) && + if (sp->role.direct && kvm_pfn_to_refcounted_page(pfn) && sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn, pfn, PG_LEVEL_NUM)) { pte_list_remove(kvm, rmap_head, sptep); diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 8e8d412fb65c..1e777b739ac4 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -1751,7 +1751,7 @@ static void zap_collapsible_spte_range(struct kvm *kvm, */ pfn = spte_to_pfn(iter.old_spte); - if (kvm_is_reserved_pfn(pfn)) + if (!kvm_pfn_to_refcounted_page(pfn)) continue; max_mapping_level = kvm_mmu_max_mapping_level(kvm, slot, diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 6fb433ac2ba1..a2bbdf3ab086 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1570,7 +1570,7 @@ void kvm_arch_sync_events(struct kvm *kvm); int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); -bool kvm_is_reserved_pfn(kvm_pfn_t pfn); +struct page *kvm_pfn_to_refcounted_page(kvm_pfn_t pfn); bool kvm_is_zone_device_page(struct page *page); struct kvm_irq_ack_notifier { diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index aa1bcd5f140d..04196096f9e4 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -182,19 +182,36 @@ bool kvm_is_zone_device_page(struct page *page) return is_zone_device_page(page); } -bool kvm_is_reserved_pfn(kvm_pfn_t pfn) +/* + * Returns a 'struct page' if the pfn is "valid" and backed by a refcounted + * page, NULL otherwise. Note, the list of refcounted PG_reserved page types + * is likely incomplete, it has been compiled purely through people wanting to + * back guest with a certain type of memory and encountering issues. + */ +struct page *kvm_pfn_to_refcounted_page(kvm_pfn_t pfn) { + struct page *page; + + if (!pfn_valid(pfn)) + return NULL; + + page = pfn_to_page(pfn); + if (!PageReserved(page)) + return page; + + /* The ZERO_PAGE(s) is marked PG_reserved, but is refcounted. */ + if (is_zero_pfn(pfn)) + return page; + /* * ZONE_DEVICE pages currently set PG_reserved, but from a refcounting * perspective they are "normal" pages, albeit with slightly different * usage rules. */ - if (pfn_valid(pfn)) - return PageReserved(pfn_to_page(pfn)) && - !is_zero_pfn(pfn) && - !kvm_is_zone_device_page(pfn_to_page(pfn)); + if (kvm_is_zone_device_page(page)) + return page; - return true; + return NULL; } /* @@ -2501,9 +2518,12 @@ static bool vma_is_valid(struct vm_area_struct *vma, bool write_fault) static int kvm_try_get_pfn(kvm_pfn_t pfn) { - if (kvm_is_reserved_pfn(pfn)) + struct page *page = kvm_pfn_to_refcounted_page(pfn); + + if (!page) return 1; - return get_page_unless_zero(pfn_to_page(pfn)); + + return get_page_unless_zero(page); } static int hva_to_pfn_remapped(struct vm_area_struct *vma, @@ -2728,6 +2748,7 @@ EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic); */ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) { + struct page *page; kvm_pfn_t pfn; pfn = gfn_to_pfn(kvm, gfn); @@ -2735,10 +2756,11 @@ struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn) if (is_error_noslot_pfn(pfn)) return KVM_ERR_PTR_BAD_PAGE; - if (kvm_is_reserved_pfn(pfn)) + page = kvm_pfn_to_refcounted_page(pfn); + if (!page) return KVM_ERR_PTR_BAD_PAGE; - return pfn_to_page(pfn); + return page; } EXPORT_SYMBOL_GPL(gfn_to_page); @@ -2841,8 +2863,16 @@ EXPORT_SYMBOL_GPL(kvm_release_page_clean); void kvm_release_pfn_clean(kvm_pfn_t pfn) { - if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn)) - kvm_release_page_clean(pfn_to_page(pfn)); + struct page *page; + + if (is_error_noslot_pfn(pfn)) + return; + + page = kvm_pfn_to_refcounted_page(pfn); + if (!page) + return; + + kvm_release_page_clean(page); } EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); @@ -2857,8 +2887,16 @@ EXPORT_SYMBOL_GPL(kvm_release_page_dirty); void kvm_release_pfn_dirty(kvm_pfn_t pfn) { - if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn)) - kvm_release_page_dirty(pfn_to_page(pfn)); + struct page *page; + + if (is_error_noslot_pfn(pfn)) + return; + + page = kvm_pfn_to_refcounted_page(pfn); + if (!page) + return; + + kvm_release_page_dirty(page); } EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty); From 5d49f08c2e08c1f0de1bb0f2e1307ec969451729 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:16 +0000 Subject: [PATCH 0556/1436] KVM: x86/mmu: Shove refcounted page dependency into host_pfn_mapping_level() Move the check that restricts mapping huge pages into the guest to pfns that are backed by refcounted 'struct page' memory into the helper that actually "requires" a 'struct page', host_pfn_mapping_level(). In addition to deduplicating code, moving the check to the helper eliminates the subtle requirement that the caller check that the incoming pfn is backed by a refcounted struct page, and as an added bonus avoids an extra pfn_to_page() lookup. Note, the is_error_noslot_pfn() check in kvm_mmu_hugepage_adjust() needs to stay where it is, as it guards against dereferencing a NULL memslot in the kvm_slot_dirty_track_enabled() that follows. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-11-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 14 +++++++++++--- arch/x86/kvm/mmu/tdp_mmu.c | 4 ---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 7ebb97c95da7..27b2a5603496 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2791,8 +2791,8 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep) static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, const struct kvm_memory_slot *slot) { - struct page *page = pfn_to_page(pfn); int level = PG_LEVEL_4K; + struct page *page; unsigned long hva; unsigned long flags; pgd_t pgd; @@ -2800,6 +2800,14 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, pud_t pud; pmd_t pmd; + /* + * Note, @slot must be non-NULL, i.e. the caller is responsible for + * ensuring @pfn isn't garbage and is backed by a memslot. + */ + page = kvm_pfn_to_refcounted_page(pfn); + if (!page) + return PG_LEVEL_4K; + if (!PageCompound(page) && !kvm_is_zone_device_page(page)) return PG_LEVEL_4K; @@ -2884,7 +2892,7 @@ void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault if (unlikely(fault->max_level == PG_LEVEL_4K)) return; - if (is_error_noslot_pfn(fault->pfn) || !kvm_pfn_to_refcounted_page(fault->pfn)) + if (is_error_noslot_pfn(fault->pfn)) return; if (kvm_slot_dirty_track_enabled(slot)) @@ -5996,7 +6004,7 @@ restart: * the guest, and the guest page table is using 4K page size * mapping if the indirect sp has level = 1. */ - if (sp->role.direct && kvm_pfn_to_refcounted_page(pfn) && + if (sp->role.direct && sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn, pfn, PG_LEVEL_NUM)) { pte_list_remove(kvm, rmap_head, sptep); diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 1e777b739ac4..1ea40809ef1f 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -1750,10 +1750,6 @@ static void zap_collapsible_spte_range(struct kvm *kvm, * be mapped at a higher level. */ pfn = spte_to_pfn(iter.old_spte); - - if (!kvm_pfn_to_refcounted_page(pfn)) - continue; - max_mapping_level = kvm_mmu_max_mapping_level(kvm, slot, iter.gfn, pfn, PG_LEVEL_NUM); From 943dfea8f166d62657057170dbe8667ec96247ca Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 29 Apr 2022 01:04:07 +0000 Subject: [PATCH 0557/1436] KVM: Do not zero initialize 'pfn' in hva_to_pfn() Drop the unnecessary initialization of the local 'pfn' variable in hva_to_pfn(). First and foremost, '0' is not an invalid pfn, it's a perfectly valid pfn on most architectures. I.e. if hva_to_pfn() were to return an "uninitializd" pfn, it would actually be interpeted as a legal pfn by most callers. Second, hva_to_pfn() can't return an uninitialized pfn as hva_to_pfn() explicitly sets pfn to an error value (or returns an error value directly) if a helper returns failure, and all helpers set the pfn on success. The zeroing of 'pfn' was introduced by commit 2fc843117d64 ("KVM: reorganize hva_to_pfn"), probably to avoid "uninitialized variable" warnings on statements that return pfn. However, no compiler seems to produce them, making the initialization unnecessary. Signed-off-by: Sean Christopherson Message-Id: <20220429010416.2788472-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- virt/kvm/kvm_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 04196096f9e4..5b8ae83e09d7 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -2609,7 +2609,7 @@ kvm_pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, bool write_fault, bool *writable) { struct vm_area_struct *vma; - kvm_pfn_t pfn = 0; + kvm_pfn_t pfn; int npages, r; /* we can do it either atomically or asynchronously, not both */ From e20918f6d11253d62b110e8d16b17cc9bf82d832 Mon Sep 17 00:00:00 2001 From: Dongliang Mu Date: Tue, 14 Jun 2022 21:34:58 +0800 Subject: [PATCH 0558/1436] x86: kvm: remove NULL check before kfree kfree can handle NULL pointer as its argument. According to coccinelle isnullfree check, remove NULL check before kfree operation. Signed-off-by: Dongliang Mu Message-Id: <20220614133458.147314-1-dzm91@hust.edu.cn> Signed-off-by: Paolo Bonzini --- arch/x86/kernel/kvm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 1a3658f7e6d9..d4e48b4a438b 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -236,8 +236,7 @@ again: raw_spin_unlock(&b->lock); /* A dummy token might be allocated and ultimately not used. */ - if (dummy) - kfree(dummy); + kfree(dummy); } EXPORT_SYMBOL_GPL(kvm_async_pf_task_wake); From 9fc222967a39d6be96dabb942cc94e4f07ca049c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Sat, 11 Jun 2022 00:57:49 +0000 Subject: [PATCH 0559/1436] KVM: x86: Give host userspace full control of MSR_IA32_MISC_ENABLES Give userspace full control of the read-only bits in MISC_ENABLES, i.e. do not modify bits on PMU refresh and do not preserve existing bits when userspace writes MISC_ENABLES. With a few exceptions where KVM doesn't expose the necessary controls to userspace _and_ there is a clear cut association with CPUID, e.g. reserved CR4 bits, KVM does not own the vCPU and should not manipulate the vCPU model on behalf of "dummy user space". The argument that KVM is doing userspace a favor because "the order of setting vPMU capabilities and MSR_IA32_MISC_ENABLE is not strictly guaranteed" is specious, as attempting to configure MSRs on behalf of userspace inevitably leads to edge cases precisely because KVM does not prescribe a specific order of initialization. Example #1: intel_pmu_refresh() consumes and modifies the vCPU's MSR_IA32_PERF_CAPABILITIES, and so assumes userspace initializes config MSRs before setting the guest CPUID model. If userspace sets CPUID first, then KVM will mark PEBS as available when arch.perf_capabilities is initialized with a non-zero PEBS format, thus creating a bad vCPU model if userspace later disables PEBS by writing PERF_CAPABILITIES. Example #2: intel_pmu_refresh() does not clear PERF_CAP_PEBS_MASK in MSR_IA32_PERF_CAPABILITIES if there is no vPMU, making KVM inconsistent in its desire to be consistent. Example #3: intel_pmu_refresh() does not clear MSR_IA32_MISC_ENABLE_EMON if KVM_SET_CPUID2 is called multiple times, first with a vPMU, then without a vPMU. While slightly contrived, it's plausible a VMM could reflect KVM's default vCPU and then operate on KVM's copy of CPUID to later clear the vPMU settings, e.g. see KVM's selftests. Example #4: Enumerating an Intel vCPU on an AMD host will not call into intel_pmu_refresh() at any point, and so the BTS and PEBS "unavailable" bits will be left clear, without any way for userspace to set them. Keep the "R" behavior of the bit 7, "EMON available", for the guest. Unlike the BTS and PEBS bits, which are fully "RO", the EMON bit can be written with a different value, but that new value is ignored. Cc: Like Xu Signed-off-by: Sean Christopherson Reported-by: kernel test robot Message-Id: <20220611005755.753273-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/pmu_intel.c | 5 ----- arch/x86/kvm/x86.c | 24 +++++++++++------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 422f0a6562ac..3b324ce0b142 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -536,8 +536,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->pebs_enable_mask = ~0ull; pmu->pebs_data_cfg_mask = ~0ull; - vcpu->arch.ia32_misc_enable_msr |= MSR_IA32_MISC_ENABLE_PMU_RO_MASK; - entry = kvm_find_cpuid_entry(vcpu, 0xa, 0); if (!entry || !vcpu->kvm->arch.enable_pmu) return; @@ -548,8 +546,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) if (!pmu->version) return; - vcpu->arch.ia32_misc_enable_msr |= MSR_IA32_MISC_ENABLE_EMON; - pmu->nr_arch_gp_counters = min_t(int, eax.split.num_counters, kvm_pmu_cap.num_counters_gp); eax.split.bit_width = min_t(int, eax.split.bit_width, @@ -611,7 +607,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) bitmap_set(pmu->all_valid_pmc_idx, INTEL_PMC_IDX_FIXED_VLBR, 1); if (vcpu->arch.perf_capabilities & PERF_CAP_PEBS_FORMAT) { - vcpu->arch.ia32_misc_enable_msr &= ~MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL; if (vcpu->arch.perf_capabilities & PERF_CAP_PEBS_BASELINE) { pmu->pebs_enable_mask = counter_mask; pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 00e23dc518e0..67bdd7e20534 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3550,21 +3550,17 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; case MSR_IA32_MISC_ENABLE: { u64 old_val = vcpu->arch.ia32_misc_enable_msr; - u64 pmu_mask = MSR_IA32_MISC_ENABLE_PMU_RO_MASK | - MSR_IA32_MISC_ENABLE_EMON; - /* RO bits */ - if (!msr_info->host_initiated && - ((old_val ^ data) & MSR_IA32_MISC_ENABLE_PMU_RO_MASK)) - return 1; + if (!msr_info->host_initiated) { + /* RO bits */ + if ((old_val ^ data) & MSR_IA32_MISC_ENABLE_PMU_RO_MASK) + return 1; + + /* R bits, i.e. writes are ignored, but don't fault. */ + data = data & ~MSR_IA32_MISC_ENABLE_EMON; + data |= old_val & MSR_IA32_MISC_ENABLE_EMON; + } - /* - * For a dummy user space, the order of setting vPMU capabilities and - * initialising MSR_IA32_MISC_ENABLE is not strictly guaranteed, so to - * avoid inconsistent functionality we keep the vPMU bits unchanged here. - */ - data &= ~pmu_mask; - data |= old_val & pmu_mask; if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT) && ((old_val ^ data) & MSR_IA32_MISC_ENABLE_MWAIT)) { if (!guest_cpuid_has(vcpu, X86_FEATURE_XMM3)) @@ -11573,6 +11569,8 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) vcpu->arch.smbase = 0x30000; vcpu->arch.msr_misc_features_enables = 0; + vcpu->arch.ia32_misc_enable_msr = MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL | + MSR_IA32_MISC_ENABLE_BTS_UNAVAIL; __kvm_set_xcr(vcpu, 0, XFEATURE_MASK_FP); __kvm_set_msr(vcpu, MSR_IA32_XSS, 0, true); From 0f4a7185270c4879fa40b33d7e07b6ac38353b34 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Sat, 11 Jun 2022 00:57:50 +0000 Subject: [PATCH 0560/1436] KVM: VMX: Give host userspace full control of MSR_IA32_PERF_CAPABILITIES Do not clear manipulate MSR_IA32_PERF_CAPABILITIES in intel_pmu_refresh(), i.e. give userspace full control over capability/read-only MSRs. KVM is not a babysitter, it is userspace's responsiblity to provide a valid and coherent vCPU model. Attempting to "help" the guest by forcing a consistent model creates edge cases, and ironicially leads to inconsistent behavior. Example #1: KVM doesn't do intel_pmu_refresh() when userspace writes the MSR. Example #2: KVM doesn't clear the bits when the PMU is disabled, or when there's no architectural PMU. Signed-off-by: Sean Christopherson Message-Id: <20220611005755.753273-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/pmu_intel.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 3b324ce0b142..b62012766226 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -619,8 +619,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->pebs_enable_mask = ~((1ull << pmu->nr_arch_gp_counters) - 1); } - } else { - vcpu->arch.perf_capabilities &= ~PERF_CAP_PEBS_MASK; } } From 5d4283df5a0fc8299fba9443c33d219939eccc2d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Sat, 11 Jun 2022 00:57:51 +0000 Subject: [PATCH 0561/1436] Revert "KVM: x86/pmu: Accept 0 for absent PMU MSRs when host-initiated if !enable_pmu" Eating reads and writes to all "PMU" MSRs when there is no PMU is wildly broken as it results in allowing accesses to _any_ MSR on Intel CPUs as intel_is_valid_msr() returns true for all host_initiated accesses. A revert of commit d1c88a402056 ("KVM: x86: always allow host-initiated writes to PMU MSRs") will soon follow. This reverts commit 8e6a58e28b34e8d247e772159b8fa8f6bae39192. Signed-off-by: Sean Christopherson Message-Id: <20220611005755.753273-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 8 -------- arch/x86/kvm/svm/pmu.c | 11 +---------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 6a32092460d3..87483e503c46 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -442,19 +442,11 @@ static void kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u32 msr) int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { - if (msr_info->host_initiated && !vcpu->kvm->arch.enable_pmu) { - msr_info->data = 0; - return 0; - } - return static_call(kvm_x86_pmu_get_msr)(vcpu, msr_info); } int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) { - if (msr_info->host_initiated && !vcpu->kvm->arch.enable_pmu) - return !!msr_info->data; - kvm_pmu_mark_pmc_in_use(vcpu, msr_info->index); return static_call(kvm_x86_pmu_set_msr)(vcpu, msr_info); } diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index fe520b2649b5..256244b8f89c 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -182,16 +182,7 @@ static struct kvm_pmc *amd_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated) { /* All MSRs refer to exactly one PMC, so msr_idx_to_pmc is enough. */ - if (!host_initiated) - return false; - - switch (msr) { - case MSR_K7_EVNTSEL0 ... MSR_K7_PERFCTR3: - case MSR_F15H_PERF_CTL0 ... MSR_F15H_PERF_CTR5: - return true; - default: - return false; - } + return false; } static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr) From 545feb96c052809dab5ec04b95f976acca9f9364 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Sat, 11 Jun 2022 00:57:52 +0000 Subject: [PATCH 0562/1436] Revert "KVM: x86: always allow host-initiated writes to PMU MSRs" Revert the hack to allow host-initiated accesses to all "PMU" MSRs, as intel_is_valid_msr() returns true for _all_ MSRs, regardless of whether or not it has a snowball's chance in hell of actually being a PMU MSR. That mostly gets papered over by the actual get/set helpers only handling MSRs that they knows about, except there's the minor detail that kvm_pmu_{g,s}et_msr() eat reads and writes when the PMU is disabled. I.e. KVM will happy allow reads and writes to _any_ MSR if the PMU is disabled, either via module param or capability. This reverts commit d1c88a4020567ba4da52f778bcd9619d87e4ea75. Fixes: d1c88a402056 ("KVM: x86: always allow host-initiated writes to PMU MSRs") Signed-off-by: Sean Christopherson Message-Id: <20220611005755.753273-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/pmu.c | 4 ++-- arch/x86/kvm/pmu.h | 4 ++-- arch/x86/kvm/svm/pmu.c | 2 +- arch/x86/kvm/vmx/pmu_intel.c | 27 ++++++++++----------------- arch/x86/kvm/x86.c | 10 +++++----- 5 files changed, 20 insertions(+), 27 deletions(-) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index 87483e503c46..02f9e4f245bd 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -425,10 +425,10 @@ void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu) } } -bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated) +bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) { return static_call(kvm_x86_pmu_msr_idx_to_pmc)(vcpu, msr) || - static_call(kvm_x86_pmu_is_valid_msr)(vcpu, msr, host_initiated); + static_call(kvm_x86_pmu_is_valid_msr)(vcpu, msr); } static void kvm_pmu_mark_pmc_in_use(struct kvm_vcpu *vcpu, u32 msr) diff --git a/arch/x86/kvm/pmu.h b/arch/x86/kvm/pmu.h index c1b61671ba1e..5cc5721f260b 100644 --- a/arch/x86/kvm/pmu.h +++ b/arch/x86/kvm/pmu.h @@ -32,7 +32,7 @@ struct kvm_pmu_ops { unsigned int idx, u64 *mask); struct kvm_pmc *(*msr_idx_to_pmc)(struct kvm_vcpu *vcpu, u32 msr); bool (*is_valid_rdpmc_ecx)(struct kvm_vcpu *vcpu, unsigned int idx); - bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated); + bool (*is_valid_msr)(struct kvm_vcpu *vcpu, u32 msr); int (*get_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info); int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr_info); void (*refresh)(struct kvm_vcpu *vcpu); @@ -189,7 +189,7 @@ void kvm_pmu_deliver_pmi(struct kvm_vcpu *vcpu); void kvm_pmu_handle_event(struct kvm_vcpu *vcpu); int kvm_pmu_rdpmc(struct kvm_vcpu *vcpu, unsigned pmc, u64 *data); bool kvm_pmu_is_valid_rdpmc_ecx(struct kvm_vcpu *vcpu, unsigned int idx); -bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated); +bool kvm_pmu_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr); int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info); void kvm_pmu_refresh(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c index 256244b8f89c..f24613a108c5 100644 --- a/arch/x86/kvm/svm/pmu.c +++ b/arch/x86/kvm/svm/pmu.c @@ -179,7 +179,7 @@ static struct kvm_pmc *amd_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu, return &counters[idx]; } -static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated) +static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) { /* All MSRs refer to exactly one PMC, so msr_idx_to_pmc is enough. */ return false; diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index b62012766226..b1aae60cf061 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -196,45 +196,38 @@ static bool intel_pmu_is_valid_lbr_msr(struct kvm_vcpu *vcpu, u32 index) return ret; } -static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr, bool host_initiated) +static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); u64 perf_capabilities = vcpu->arch.perf_capabilities; + int ret; switch (msr) { case MSR_CORE_PERF_FIXED_CTR_CTRL: case MSR_CORE_PERF_GLOBAL_STATUS: case MSR_CORE_PERF_GLOBAL_CTRL: case MSR_CORE_PERF_GLOBAL_OVF_CTRL: - if (host_initiated) - return true; - return pmu->version > 1; + ret = pmu->version > 1; break; case MSR_IA32_PEBS_ENABLE: - if (host_initiated) - return true; - return perf_capabilities & PERF_CAP_PEBS_FORMAT; + ret = perf_capabilities & PERF_CAP_PEBS_FORMAT; break; case MSR_IA32_DS_AREA: - if (host_initiated) - return true; - return guest_cpuid_has(vcpu, X86_FEATURE_DS); + ret = guest_cpuid_has(vcpu, X86_FEATURE_DS); break; case MSR_PEBS_DATA_CFG: - if (host_initiated) - return true; - return (perf_capabilities & PERF_CAP_PEBS_BASELINE) && + ret = (perf_capabilities & PERF_CAP_PEBS_BASELINE) && ((perf_capabilities & PERF_CAP_PEBS_FORMAT) > 3); break; default: - if (host_initiated) - return true; - return get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0) || + ret = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0) || get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0) || get_fixed_pmc(pmu, msr) || get_fw_gp_pmc(pmu, msr) || intel_pmu_is_valid_lbr_msr(vcpu, msr); break; } + + return ret; } static struct kvm_pmc *intel_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr) @@ -596,7 +589,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) INTEL_PMC_MAX_GENERIC, pmu->nr_arch_fixed_counters); nested_vmx_pmu_refresh(vcpu, - intel_is_valid_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL, false)); + intel_is_valid_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL)); if (cpuid_model_is_consistent(vcpu)) x86_perf_get_lbr(&lbr_desc->records); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 67bdd7e20534..46301b148f64 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3704,7 +3704,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) fallthrough; case MSR_K7_EVNTSEL0 ... MSR_K7_EVNTSEL3: case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL1: - if (kvm_pmu_is_valid_msr(vcpu, msr, msr_info->host_initiated)) + if (kvm_pmu_is_valid_msr(vcpu, msr)) return kvm_pmu_set_msr(vcpu, msr_info); if (pr || data != 0) @@ -3787,7 +3787,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; #endif default: - if (kvm_pmu_is_valid_msr(vcpu, msr, msr_info->host_initiated)) + if (kvm_pmu_is_valid_msr(vcpu, msr)) return kvm_pmu_set_msr(vcpu, msr_info); return KVM_MSR_RET_INVALID; } @@ -3867,7 +3867,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) msr_info->data = 0; break; case MSR_F15H_PERF_CTL0 ... MSR_F15H_PERF_CTR5: - if (kvm_pmu_is_valid_msr(vcpu, msr_info->index, msr_info->host_initiated)) + if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) return kvm_pmu_get_msr(vcpu, msr_info); if (!msr_info->host_initiated) return 1; @@ -3877,7 +3877,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3: case MSR_P6_PERFCTR0 ... MSR_P6_PERFCTR1: case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL1: - if (kvm_pmu_is_valid_msr(vcpu, msr_info->index, msr_info->host_initiated)) + if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) return kvm_pmu_get_msr(vcpu, msr_info); msr_info->data = 0; break; @@ -4123,7 +4123,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; #endif default: - if (kvm_pmu_is_valid_msr(vcpu, msr_info->index, msr_info->host_initiated)) + if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) return kvm_pmu_get_msr(vcpu, msr_info); return KVM_MSR_RET_INVALID; } From 3f7999b988bde6c50cb7b20d6c742d6512d1f0bd Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Sat, 11 Jun 2022 00:57:53 +0000 Subject: [PATCH 0563/1436] KVM: VMX: Use vcpu_get_perf_capabilities() to get guest-visible value Use vcpu_get_perf_capabilities() when querying MSR_IA32_PERF_CAPABILITIES from the guest's perspective, e.g. to update the vPMU and to determine which MSRs exist. If userspace ignores MSR_IA32_PERF_CAPABILITIES but clear X86_FEATURE_PDCM, the guest should see '0'. Fixes: 902caeb6841a ("KVM: x86/pmu: Add PEBS_DATA_CFG MSR emulation to support adaptive PEBS") Fixes: c59a1f106f5c ("KVM: x86/pmu: Add IA32_PEBS_ENABLE MSR emulation for extended PEBS") Signed-off-by: Sean Christopherson Message-Id: <20220611005755.753273-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/pmu_intel.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index b1aae60cf061..53ccba896e77 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -199,7 +199,7 @@ static bool intel_pmu_is_valid_lbr_msr(struct kvm_vcpu *vcpu, u32 index) static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) { struct kvm_pmu *pmu = vcpu_to_pmu(vcpu); - u64 perf_capabilities = vcpu->arch.perf_capabilities; + u64 perf_capabilities; int ret; switch (msr) { @@ -210,12 +210,13 @@ static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) ret = pmu->version > 1; break; case MSR_IA32_PEBS_ENABLE: - ret = perf_capabilities & PERF_CAP_PEBS_FORMAT; + ret = vcpu_get_perf_capabilities(vcpu) & PERF_CAP_PEBS_FORMAT; break; case MSR_IA32_DS_AREA: ret = guest_cpuid_has(vcpu, X86_FEATURE_DS); break; case MSR_PEBS_DATA_CFG: + perf_capabilities = vcpu_get_perf_capabilities(vcpu); ret = (perf_capabilities & PERF_CAP_PEBS_BASELINE) && ((perf_capabilities & PERF_CAP_PEBS_FORMAT) > 3); break; @@ -515,6 +516,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) struct kvm_cpuid_entry2 *entry; union cpuid10_eax eax; union cpuid10_edx edx; + u64 perf_capabilities; u64 counter_mask; int i; @@ -599,8 +601,9 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) if (lbr_desc->records.nr) bitmap_set(pmu->all_valid_pmc_idx, INTEL_PMC_IDX_FIXED_VLBR, 1); - if (vcpu->arch.perf_capabilities & PERF_CAP_PEBS_FORMAT) { - if (vcpu->arch.perf_capabilities & PERF_CAP_PEBS_BASELINE) { + perf_capabilities = vcpu_get_perf_capabilities(vcpu); + if (perf_capabilities & PERF_CAP_PEBS_FORMAT) { + if (perf_capabilities & PERF_CAP_PEBS_BASELINE) { pmu->pebs_enable_mask = counter_mask; pmu->reserved_bits &= ~ICL_EVENTSEL_ADAPTIVE; for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { From 157fc497b54fd1dfcdedbca6199adca4bf5ee6ff Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Sat, 11 Jun 2022 00:57:54 +0000 Subject: [PATCH 0564/1436] KVM: x86: Ignore benign host accesses to "unsupported" PEBS and BTS MSRs Ignore host userspace reads and writes of '0' to PEBS and BTS MSRs that KVM reports in the MSR-to-save list, but the MSRs are ultimately unsupported. All MSRs in said list must be writable by userspace, e.g. if userspace sends the list back at KVM without filtering out the MSRs it doesn't need. Fixes: 8183a538cd95 ("KVM: x86/pmu: Add IA32_DS_AREA MSR emulation to support guest DS") Fixes: 902caeb6841a ("KVM: x86/pmu: Add PEBS_DATA_CFG MSR emulation to support adaptive PEBS") Fixes: c59a1f106f5c ("KVM: x86/pmu: Add IA32_PEBS_ENABLE MSR emulation for extended PEBS") Signed-off-by: Sean Christopherson Message-Id: <20220611005755.753273-7-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 46301b148f64..e07c5765a551 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3786,6 +3786,16 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.guest_fpu.xfd_err = data; break; #endif + case MSR_IA32_PEBS_ENABLE: + case MSR_IA32_DS_AREA: + case MSR_PEBS_DATA_CFG: + if (kvm_pmu_is_valid_msr(vcpu, msr)) + return kvm_pmu_set_msr(vcpu, msr_info); + /* + * Userspace is allowed to write '0' to MSRs that KVM reports + * as to-be-saved, even if an MSRs isn't fully supported. + */ + return !msr_info->host_initiated || data; default: if (kvm_pmu_is_valid_msr(vcpu, msr)) return kvm_pmu_set_msr(vcpu, msr_info); @@ -3866,9 +3876,16 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_DRAM_ENERGY_STATUS: /* DRAM controller */ msr_info->data = 0; break; + case MSR_IA32_PEBS_ENABLE: + case MSR_IA32_DS_AREA: + case MSR_PEBS_DATA_CFG: case MSR_F15H_PERF_CTL0 ... MSR_F15H_PERF_CTR5: if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) return kvm_pmu_get_msr(vcpu, msr_info); + /* + * Userspace is allowed to read MSRs that KVM reports in + * KVM_GET_MSR_INDEX_LIST, even if an MSR isn't fully supported. + */ if (!msr_info->host_initiated) return 1; msr_info->data = 0; From ff81a90f45ce6b818167c590f7625b3b573defc9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Sat, 11 Jun 2022 00:57:55 +0000 Subject: [PATCH 0565/1436] KVM: x86: Ignore benign host writes to "unsupported" F15H_PERF_CTL MSRs Ignore host userspace writes of '0' to F15H_PERF_CTL MSRs KVM reports in the MSR-to-save list, but the MSRs are ultimately unsupported. All MSRs in said list must be writable by userspace, e.g. if userspace sends the list back at KVM without filtering out the MSRs it doesn't need. Note, reads of said MSRs already have the desired behavior. Signed-off-by: Sean Christopherson Message-Id: <20220611005755.753273-8-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e07c5765a551..b70fe8560881 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3789,6 +3789,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_IA32_PEBS_ENABLE: case MSR_IA32_DS_AREA: case MSR_PEBS_DATA_CFG: + case MSR_F15H_PERF_CTL0 ... MSR_F15H_PERF_CTR5: if (kvm_pmu_is_valid_msr(vcpu, msr)) return kvm_pmu_set_msr(vcpu, msr_info); /* From bfbcc81bb82cbbad8bf4e40cea274f42b50674e2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 8 Jun 2022 22:45:12 +0000 Subject: [PATCH 0566/1436] KVM: x86: Add a quirk for KVM's "MONITOR/MWAIT are NOPs!" behavior Add a quirk for KVM's behavior of emulating intercepted MONITOR/MWAIT instructions a NOPs regardless of whether or not they are supported in guest CPUID. KVM's current behavior was likely motiviated by a certain fruity operating system that expects MONITOR/MWAIT to be supported unconditionally and blindly executes MONITOR/MWAIT without first checking CPUID. And because KVM does NOT advertise MONITOR/MWAIT to userspace, that's effectively the default setup for any VMM that regurgitates KVM_GET_SUPPORTED_CPUID to KVM_SET_CPUID2. Note, this quirk interacts with KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT. The behavior is actually desirable, as userspace VMMs that want to unconditionally hide MONITOR/MWAIT from the guest can leave the MISC_ENABLE quirk enabled. Signed-off-by: Sean Christopherson Message-Id: <20220608224516.3788274-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 13 +++++++++++++ arch/x86/include/asm/kvm_host.h | 3 ++- arch/x86/include/uapi/asm/kvm.h | 1 + arch/x86/kvm/x86.c | 30 +++++++++++++++++++----------- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 84c486ce6279..320cb04f7bd9 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -7522,6 +7522,19 @@ The valid bits in cap.args[0] are: hypercall instructions. Executing the incorrect hypercall instruction will generate a #UD within the guest. + +KVM_X86_QUIRK_MWAIT_NEVER_FAULTS By default, KVM emulates MONITOR/MWAIT (if + they are intercepted) as NOPs regardless of + whether or not MONITOR/MWAIT are supported + according to guest CPUID. When this quirk + is disabled and KVM_X86_DISABLE_EXITS_MWAIT + is not set (MONITOR/MWAIT are intercepted), + KVM will inject a #UD on MONITOR/MWAIT if + they're unsupported per guest CPUID. Note, + KVM will modify MONITOR/MWAIT support in + guest CPUID on writes to MISC_ENABLE if + KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT is + disabled. =================================== ============================================ 7.32 KVM_CAP_MAX_VCPU_ID diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 1038ccb7056a..e37727a74d0a 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2076,6 +2076,7 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages); KVM_X86_QUIRK_LAPIC_MMIO_HOLE | \ KVM_X86_QUIRK_OUT_7E_INC_RIP | \ KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT | \ - KVM_X86_QUIRK_FIX_HYPERCALL_INSN) + KVM_X86_QUIRK_FIX_HYPERCALL_INSN | \ + KVM_X86_QUIRK_MWAIT_NEVER_FAULTS) #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index 50a4e787d5e6..ee3896416c68 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -439,6 +439,7 @@ struct kvm_sync_regs { #define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3) #define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4) #define KVM_X86_QUIRK_FIX_HYPERCALL_INSN (1 << 5) +#define KVM_X86_QUIRK_MWAIT_NEVER_FAULTS (1 << 6) #define KVM_STATE_NESTED_FORMAT_VMX 0 #define KVM_STATE_NESTED_FORMAT_SVM 1 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b70fe8560881..9b9f9f65c548 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2036,13 +2036,6 @@ int kvm_emulate_invd(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_emulate_invd); -int kvm_emulate_mwait(struct kvm_vcpu *vcpu) -{ - pr_warn_once("kvm: MWAIT instruction emulated as NOP!\n"); - return kvm_emulate_as_nop(vcpu); -} -EXPORT_SYMBOL_GPL(kvm_emulate_mwait); - int kvm_handle_invalid_op(struct kvm_vcpu *vcpu) { kvm_queue_exception(vcpu, UD_VECTOR); @@ -2050,10 +2043,25 @@ int kvm_handle_invalid_op(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_handle_invalid_op); + +static int kvm_emulate_monitor_mwait(struct kvm_vcpu *vcpu, const char *insn) +{ + if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MWAIT_NEVER_FAULTS) && + !guest_cpuid_has(vcpu, X86_FEATURE_MWAIT)) + return kvm_handle_invalid_op(vcpu); + + pr_warn_once("kvm: %s instruction emulated as NOP!\n", insn); + return kvm_emulate_as_nop(vcpu); +} +int kvm_emulate_mwait(struct kvm_vcpu *vcpu) +{ + return kvm_emulate_monitor_mwait(vcpu, "MWAIT"); +} +EXPORT_SYMBOL_GPL(kvm_emulate_mwait); + int kvm_emulate_monitor(struct kvm_vcpu *vcpu) { - pr_warn_once("kvm: MONITOR instruction emulated as NOP!\n"); - return kvm_emulate_as_nop(vcpu); + return kvm_emulate_monitor_mwait(vcpu, "MONITOR"); } EXPORT_SYMBOL_GPL(kvm_emulate_monitor); @@ -3884,8 +3892,8 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (kvm_pmu_is_valid_msr(vcpu, msr_info->index)) return kvm_pmu_get_msr(vcpu, msr_info); /* - * Userspace is allowed to read MSRs that KVM reports in - * KVM_GET_MSR_INDEX_LIST, even if an MSR isn't fully supported. + * Userspace is allowed to read MSRs that KVM reports as + * to-be-saved, even if an MSR isn't fully supported. */ if (!msr_info->host_initiated) return 1; From 3b23054cd3f5106aed31ccf71a7bc14518a768eb Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 8 Jun 2022 22:45:13 +0000 Subject: [PATCH 0567/1436] KVM: selftests: Add x86-64 support for exception fixup Add x86-64 support for exception fixup on single instructions, without forcing tests to install their own fault handlers. Use registers r9-r11 to flag the instruction as "safe" and pass fixup/vector information, i.e. introduce yet another flavor of fixup (versus the kernel's in-memory tables and KUT's per-CPU area) to take advantage of KVM sefltests being 64-bit only. Using only registers avoids the need to allocate fixup tables, ensure FS or GS base is valid for the guest, ensure memory is mapped into the guest, etc..., and also reduces the potential for recursive faults due to accessing memory. Providing exception fixup trivializes tests that just want to verify that an instruction faults, e.g. no need to track start/end using global labels, no need to install a dedicated handler, etc... Deliberately do not support #DE in exception fixup so that the fixup glue doesn't need to account for a fault with vector == 0, i.e. the vector can also indicate that a fault occurred. KVM injects #DE only for esoteric emulation scenarios, i.e. there's very, very little value in testing #DE. Force any test that wants to generate #DEs to install its own handler(s). Use kvm_pv_test as a guinea pig for the new fixup, as it has a very straightforward use case of wanting to verify that RDMSR and WRMSR fault. Signed-off-by: Sean Christopherson Message-Id: <20220608224516.3788274-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/x86_64/processor.h | 74 ++++++++++++++++++ .../selftests/kvm/lib/x86_64/processor.c | 17 +++++ .../selftests/kvm/x86_64/kvm_pv_test.c | 76 +++---------------- 3 files changed, 103 insertions(+), 64 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 32964d7b2218..79dcf6be1b47 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -15,6 +15,8 @@ #include #include +#include + #include "../kvm_util.h" #define NMI_VECTOR 0x02 @@ -541,6 +543,78 @@ void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu); void vm_install_exception_handler(struct kvm_vm *vm, int vector, void (*handler)(struct ex_regs *)); +/* If a toddler were to say "abracadabra". */ +#define KVM_EXCEPTION_MAGIC 0xabacadabaull + +/* + * KVM selftest exception fixup uses registers to coordinate with the exception + * handler, versus the kernel's in-memory tables and KVM-Unit-Tests's in-memory + * per-CPU data. Using only registers avoids having to map memory into the + * guest, doesn't require a valid, stable GS.base, and reduces the risk of + * for recursive faults when accessing memory in the handler. The downside to + * using registers is that it restricts what registers can be used by the actual + * instruction. But, selftests are 64-bit only, making register* pressure a + * minor concern. Use r9-r11 as they are volatile, i.e. don't need* to be saved + * by the callee, and except for r11 are not implicit parameters to any + * instructions. Ideally, fixup would use r8-r10 and thus avoid implicit + * parameters entirely, but Hyper-V's hypercall ABI uses r8 and testing Hyper-V + * is higher priority than testing non-faulting SYSCALL/SYSRET. + * + * Note, the fixup handler deliberately does not handle #DE, i.e. the vector + * is guaranteed to be non-zero on fault. + * + * REGISTER INPUTS: + * r9 = MAGIC + * r10 = RIP + * r11 = new RIP on fault + * + * REGISTER OUTPUTS: + * r9 = exception vector (non-zero) + */ +#define KVM_ASM_SAFE(insn) \ + "mov $" __stringify(KVM_EXCEPTION_MAGIC) ", %%r9\n\t" \ + "lea 1f(%%rip), %%r10\n\t" \ + "lea 2f(%%rip), %%r11\n\t" \ + "1: " insn "\n\t" \ + "mov $0, %[vector]\n\t" \ + "jmp 3f\n\t" \ + "2:\n\t" \ + "mov %%r9b, %[vector]\n\t" \ + "3:\n\t" + +#define KVM_ASM_SAFE_OUTPUTS(v) [vector] "=qm"(v) +#define KVM_ASM_SAFE_CLOBBERS "r9", "r10", "r11" + +#define kvm_asm_safe(insn, inputs...) \ +({ \ + uint8_t vector; \ + \ + asm volatile(KVM_ASM_SAFE(insn) \ + : KVM_ASM_SAFE_OUTPUTS(vector) \ + : inputs \ + : KVM_ASM_SAFE_CLOBBERS); \ + vector; \ +}) + +static inline uint8_t rdmsr_safe(uint32_t msr, uint64_t *val) +{ + uint8_t vector; + uint32_t a, d; + + asm volatile(KVM_ASM_SAFE("rdmsr") + : "=a"(a), "=d"(d), KVM_ASM_SAFE_OUTPUTS(vector) + : "c"(msr) + : KVM_ASM_SAFE_CLOBBERS); + + *val = (uint64_t)a | ((uint64_t)d << 32); + return vector; +} + +static inline uint8_t wrmsr_safe(uint32_t msr, uint64_t val) +{ + return kvm_asm_safe("wrmsr", "A"(val), "c"(msr)); +} + uint64_t vm_get_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, uint64_t vaddr); void vm_set_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 906132e70fa4..1a32b1c75e9a 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1127,6 +1127,20 @@ static void set_idt_entry(struct kvm_vm *vm, int vector, unsigned long addr, e->offset2 = addr >> 32; } + +static bool kvm_fixup_exception(struct ex_regs *regs) +{ + if (regs->r9 != KVM_EXCEPTION_MAGIC || regs->rip != regs->r10) + return false; + + if (regs->vector == DE_VECTOR) + return false; + + regs->rip = regs->r11; + regs->r9 = regs->vector; + return true; +} + void kvm_exit_unexpected_vector(uint32_t value) { ucall(UCALL_UNHANDLED, 1, value); @@ -1142,6 +1156,9 @@ void route_exception(struct ex_regs *regs) return; } + if (kvm_fixup_exception(regs)) + return; + kvm_exit_unexpected_vector(regs->vector); } diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index 5901ccec7079..feff85e43be3 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -12,55 +12,6 @@ #include "kvm_util.h" #include "processor.h" -extern unsigned char rdmsr_start; -extern unsigned char rdmsr_end; - -static u64 do_rdmsr(u32 idx) -{ - u32 lo, hi; - - asm volatile("rdmsr_start: rdmsr;" - "rdmsr_end:" - : "=a"(lo), "=c"(hi) - : "c"(idx)); - - return (((u64) hi) << 32) | lo; -} - -extern unsigned char wrmsr_start; -extern unsigned char wrmsr_end; - -static void do_wrmsr(u32 idx, u64 val) -{ - u32 lo, hi; - - lo = val; - hi = val >> 32; - - asm volatile("wrmsr_start: wrmsr;" - "wrmsr_end:" - : : "a"(lo), "c"(idx), "d"(hi)); -} - -static int nr_gp; - -static void guest_gp_handler(struct ex_regs *regs) -{ - unsigned char *rip = (unsigned char *)regs->rip; - bool r, w; - - r = rip == &rdmsr_start; - w = rip == &wrmsr_start; - GUEST_ASSERT(r || w); - - nr_gp++; - - if (r) - regs->rip = (uint64_t)&rdmsr_end; - else - regs->rip = (uint64_t)&wrmsr_end; -} - struct msr_data { uint32_t idx; const char *name; @@ -89,14 +40,16 @@ static struct msr_data msrs_to_test[] = { static void test_msr(struct msr_data *msr) { - PR_MSR(msr); - do_rdmsr(msr->idx); - GUEST_ASSERT(READ_ONCE(nr_gp) == 1); + uint64_t ignored; + uint8_t vector; - nr_gp = 0; - do_wrmsr(msr->idx, 0); - GUEST_ASSERT(READ_ONCE(nr_gp) == 1); - nr_gp = 0; + PR_MSR(msr); + + vector = rdmsr_safe(msr->idx, &ignored); + GUEST_ASSERT_1(vector == GP_VECTOR, vector); + + vector = wrmsr_safe(msr->idx, 0); + GUEST_ASSERT_1(vector == GP_VECTOR, vector); } struct hcall_data { @@ -165,12 +118,6 @@ static void pr_hcall(struct ucall *uc) pr_info("testing hcall: %s (%lu)\n", hc->name, hc->nr); } -static void handle_abort(struct ucall *uc) -{ - TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], - __FILE__, uc->args[1]); -} - static void enter_guest(struct kvm_vcpu *vcpu) { struct kvm_run *run = vcpu->run; @@ -190,7 +137,9 @@ static void enter_guest(struct kvm_vcpu *vcpu) pr_hcall(&uc); break; case UCALL_ABORT: - handle_abort(&uc); + TEST_FAIL("%s at %s:%ld, vector = %lu", + (const char *)uc.args[0], __FILE__, + uc.args[1], uc.args[2]); return; case UCALL_DONE: return; @@ -216,7 +165,6 @@ int main(void) vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); - vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); enter_guest(vcpu); kvm_vm_free(vm); From 9f88d062c3db13164a0d2007b88e1e430f523a06 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 8 Jun 2022 22:45:14 +0000 Subject: [PATCH 0568/1436] KVM: selftests: Mostly fix broken Hyper-V Features test Explicitly do all setup at every stage of the Hyper-V Features test, e.g. set the MSR/hypercall, enable capabilities, etc... Now that the VM is recreated for every stage, values that are written into the VM's address space, i.e. shared with the guest, are reset between sub-tests, as are any capabilities, etc... Fix the hypercall params as well, which were broken in the same rework. The "hcall" struct/pointer needs to point at the hcall_params object, not the set of hypercall pages. The goofs were hidden by the test's dubious behavior of using '0' to signal "done", i.e. the MSR test ran exactly one sub-test, and the hypercall test was a gigantic nop. Fixes: 6c1186430a80 ("KVM: selftests: Avoid KVM_SET_CPUID2 after KVM_RUN in hyperv_features test") Signed-off-by: Sean Christopherson Message-Id: <20220608224516.3788274-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/hyperv_features.c | 142 ++++++++++-------- 1 file changed, 81 insertions(+), 61 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index d5f37495ade8..1a2a06c3027a 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -101,52 +101,44 @@ struct hcall_data { static void guest_msr(struct msr_data *msr) { - int i = 0; + GUEST_ASSERT(msr->idx); - while (msr->idx) { - WRITE_ONCE(nr_gp, 0); - if (!msr->write) - do_rdmsr(msr->idx); - else - do_wrmsr(msr->idx, msr->write_val); - - if (msr->available) - GUEST_ASSERT(READ_ONCE(nr_gp) == 0); - else - GUEST_ASSERT(READ_ONCE(nr_gp) == 1); - - GUEST_SYNC(i++); - } + WRITE_ONCE(nr_gp, 0); + if (!msr->write) + do_rdmsr(msr->idx); + else + do_wrmsr(msr->idx, msr->write_val); + if (msr->available) + GUEST_ASSERT(READ_ONCE(nr_gp) == 0); + else + GUEST_ASSERT(READ_ONCE(nr_gp) == 1); GUEST_DONE(); } static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) { - int i = 0; u64 res, input, output; + GUEST_ASSERT(hcall->control); + wrmsr(HV_X64_MSR_GUEST_OS_ID, LINUX_OS_ID); wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa); - while (hcall->control) { - nr_ud = 0; - if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) { - input = pgs_gpa; - output = pgs_gpa + 4096; - } else { - input = output = 0; - } - - res = hypercall(hcall->control, input, output); - if (hcall->ud_expected) - GUEST_ASSERT(nr_ud == 1); - else - GUEST_ASSERT(res == hcall->expect); - - GUEST_SYNC(i++); + nr_ud = 0; + if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) { + input = pgs_gpa; + output = pgs_gpa + 4096; + } else { + input = output = 0; } + res = hypercall(hcall->control, input, output); + if (hcall->ud_expected) + GUEST_ASSERT(nr_ud == 1); + else + GUEST_ASSERT(res == hcall->expect); + GUEST_DONE(); } @@ -204,6 +196,10 @@ static void guest_test_msrs_access(void) run = vcpu->run; + /* TODO: Make this entire test easier to maintain. */ + if (stage >= 21) + vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_SYNIC2, 0); + switch (stage) { case 0: /* @@ -247,11 +243,13 @@ static void guest_test_msrs_access(void) break; case 6: feat.eax |= HV_MSR_VP_RUNTIME_AVAILABLE; + msr->idx = HV_X64_MSR_VP_RUNTIME; msr->write = 0; msr->available = 1; break; case 7: /* Read only */ + msr->idx = HV_X64_MSR_VP_RUNTIME; msr->write = 1; msr->write_val = 1; msr->available = 0; @@ -264,11 +262,13 @@ static void guest_test_msrs_access(void) break; case 9: feat.eax |= HV_MSR_TIME_REF_COUNT_AVAILABLE; + msr->idx = HV_X64_MSR_TIME_REF_COUNT; msr->write = 0; msr->available = 1; break; case 10: /* Read only */ + msr->idx = HV_X64_MSR_TIME_REF_COUNT; msr->write = 1; msr->write_val = 1; msr->available = 0; @@ -281,11 +281,13 @@ static void guest_test_msrs_access(void) break; case 12: feat.eax |= HV_MSR_VP_INDEX_AVAILABLE; + msr->idx = HV_X64_MSR_VP_INDEX; msr->write = 0; msr->available = 1; break; case 13: /* Read only */ + msr->idx = HV_X64_MSR_VP_INDEX; msr->write = 1; msr->write_val = 1; msr->available = 0; @@ -298,10 +300,12 @@ static void guest_test_msrs_access(void) break; case 15: feat.eax |= HV_MSR_RESET_AVAILABLE; + msr->idx = HV_X64_MSR_RESET; msr->write = 0; msr->available = 1; break; case 16: + msr->idx = HV_X64_MSR_RESET; msr->write = 1; msr->write_val = 0; msr->available = 1; @@ -314,10 +318,12 @@ static void guest_test_msrs_access(void) break; case 18: feat.eax |= HV_MSR_REFERENCE_TSC_AVAILABLE; + msr->idx = HV_X64_MSR_REFERENCE_TSC; msr->write = 0; msr->available = 1; break; case 19: + msr->idx = HV_X64_MSR_REFERENCE_TSC; msr->write = 1; msr->write_val = 0; msr->available = 1; @@ -333,14 +339,18 @@ static void guest_test_msrs_access(void) * Remains unavailable even with KVM_CAP_HYPERV_SYNIC2 * capability enabled and guest visible CPUID bit unset. */ - vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_SYNIC2, 0); + msr->idx = HV_X64_MSR_EOM; + msr->write = 0; + msr->available = 0; break; case 22: feat.eax |= HV_MSR_SYNIC_AVAILABLE; + msr->idx = HV_X64_MSR_EOM; msr->write = 0; msr->available = 1; break; case 23: + msr->idx = HV_X64_MSR_EOM; msr->write = 1; msr->write_val = 0; msr->available = 1; @@ -353,22 +363,28 @@ static void guest_test_msrs_access(void) break; case 25: feat.eax |= HV_MSR_SYNTIMER_AVAILABLE; + msr->idx = HV_X64_MSR_STIMER0_CONFIG; msr->write = 0; msr->available = 1; break; case 26: + msr->idx = HV_X64_MSR_STIMER0_CONFIG; msr->write = 1; msr->write_val = 0; msr->available = 1; break; case 27: /* Direct mode test */ + msr->idx = HV_X64_MSR_STIMER0_CONFIG; msr->write = 1; msr->write_val = 1 << 12; msr->available = 0; break; case 28: feat.edx |= HV_STIMER_DIRECT_MODE_AVAILABLE; + msr->idx = HV_X64_MSR_STIMER0_CONFIG; + msr->write = 1; + msr->write_val = 1 << 12; msr->available = 1; break; @@ -379,6 +395,7 @@ static void guest_test_msrs_access(void) break; case 30: feat.eax |= HV_MSR_APIC_ACCESS_AVAILABLE; + msr->idx = HV_X64_MSR_EOI; msr->write = 1; msr->write_val = 1; msr->available = 1; @@ -391,11 +408,13 @@ static void guest_test_msrs_access(void) break; case 32: feat.eax |= HV_ACCESS_FREQUENCY_MSRS; + msr->idx = HV_X64_MSR_TSC_FREQUENCY; msr->write = 0; msr->available = 1; break; case 33: /* Read only */ + msr->idx = HV_X64_MSR_TSC_FREQUENCY; msr->write = 1; msr->write_val = 1; msr->available = 0; @@ -408,10 +427,12 @@ static void guest_test_msrs_access(void) break; case 35: feat.eax |= HV_ACCESS_REENLIGHTENMENT; + msr->idx = HV_X64_MSR_REENLIGHTENMENT_CONTROL; msr->write = 0; msr->available = 1; break; case 36: + msr->idx = HV_X64_MSR_REENLIGHTENMENT_CONTROL; msr->write = 1; msr->write_val = 1; msr->available = 1; @@ -431,10 +452,12 @@ static void guest_test_msrs_access(void) break; case 39: feat.edx |= HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE; + msr->idx = HV_X64_MSR_CRASH_P0; msr->write = 0; msr->available = 1; break; case 40: + msr->idx = HV_X64_MSR_CRASH_P0; msr->write = 1; msr->write_val = 1; msr->available = 1; @@ -448,28 +471,26 @@ static void guest_test_msrs_access(void) case 42: feat.edx |= HV_FEATURE_DEBUG_MSRS_AVAILABLE; dbg.eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; + msr->idx = HV_X64_MSR_SYNDBG_STATUS; msr->write = 0; msr->available = 1; break; case 43: + msr->idx = HV_X64_MSR_SYNDBG_STATUS; msr->write = 1; msr->write_val = 0; msr->available = 1; break; case 44: - /* END */ - msr->idx = 0; - break; + kvm_vm_free(vm); + return; } hv_set_cpuid(vcpu, best, &feat, &recomm, &dbg); - if (msr->idx) - pr_debug("Stage %d: testing msr: 0x%x for %s\n", stage, - msr->idx, msr->write ? "write" : "read"); - else - pr_debug("Stage %d: finish\n", stage); + pr_debug("Stage %d: testing msr: 0x%x for %s\n", stage, + msr->idx, msr->write ? "write" : "read"); vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, @@ -477,16 +498,14 @@ static void guest_test_msrs_access(void) run->exit_reason, exit_reason_str(run->exit_reason)); switch (get_ucall(vcpu, &uc)) { - case UCALL_SYNC: - TEST_ASSERT(uc.args[1] == 0, - "Unexpected stage: %ld (0 expected)\n", - uc.args[1]); - break; case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); return; case UCALL_DONE: + break; + default: + TEST_FAIL("Unhandled ucall: %ld", uc.cmd); return; } @@ -525,11 +544,11 @@ static void guest_test_hcalls_access(void) /* Hypercall input/output */ hcall_page = vm_vaddr_alloc_pages(vm, 2); - hcall = addr_gva2hva(vm, hcall_page); memset(addr_gva2hva(vm, hcall_page), 0x0, 2 * getpagesize()); hcall_params = vm_vaddr_alloc_page(vm); memset(addr_gva2hva(vm, hcall_params), 0x0, getpagesize()); + hcall = addr_gva2hva(vm, hcall_params); vcpu_args_set(vcpu, 2, addr_gva2gpa(vm, hcall_page), hcall_params); vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); @@ -552,6 +571,7 @@ static void guest_test_hcalls_access(void) break; case 2: feat.ebx |= HV_POST_MESSAGES; + hcall->control = HVCALL_POST_MESSAGE; hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT; break; @@ -561,6 +581,7 @@ static void guest_test_hcalls_access(void) break; case 4: feat.ebx |= HV_SIGNAL_EVENTS; + hcall->control = HVCALL_SIGNAL_EVENT; hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT; break; @@ -570,10 +591,12 @@ static void guest_test_hcalls_access(void) break; case 6: dbg.eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; + hcall->control = HVCALL_RESET_DEBUG_SESSION; hcall->expect = HV_STATUS_ACCESS_DENIED; break; case 7: feat.ebx |= HV_DEBUGGING; + hcall->control = HVCALL_RESET_DEBUG_SESSION; hcall->expect = HV_STATUS_OPERATION_DENIED; break; @@ -583,6 +606,7 @@ static void guest_test_hcalls_access(void) break; case 9: recomm.eax |= HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED; + hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE; hcall->expect = HV_STATUS_SUCCESS; break; case 10: @@ -591,6 +615,7 @@ static void guest_test_hcalls_access(void) break; case 11: recomm.eax |= HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED; + hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX; hcall->expect = HV_STATUS_SUCCESS; break; @@ -600,6 +625,7 @@ static void guest_test_hcalls_access(void) break; case 13: recomm.eax |= HV_X64_CLUSTER_IPI_RECOMMENDED; + hcall->control = HVCALL_SEND_IPI; hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT; break; case 14: @@ -614,6 +640,7 @@ static void guest_test_hcalls_access(void) break; case 16: recomm.ebx = 0xfff; + hcall->control = HVCALL_NOTIFY_LONG_SPIN_WAIT; hcall->expect = HV_STATUS_SUCCESS; break; case 17: @@ -623,23 +650,18 @@ static void guest_test_hcalls_access(void) break; case 18: feat.edx |= HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE; + hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE | HV_HYPERCALL_FAST_BIT; hcall->ud_expected = false; hcall->expect = HV_STATUS_SUCCESS; break; - case 19: - /* END */ - hcall->control = 0; - break; + kvm_vm_free(vm); + return; } hv_set_cpuid(vcpu, best, &feat, &recomm, &dbg); - if (hcall->control) - pr_debug("Stage %d: testing hcall: 0x%lx\n", stage, - hcall->control); - else - pr_debug("Stage %d: finish\n", stage); + pr_debug("Stage %d: testing hcall: 0x%lx\n", stage, hcall->control); vcpu_run(vcpu); TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, @@ -647,16 +669,14 @@ static void guest_test_hcalls_access(void) run->exit_reason, exit_reason_str(run->exit_reason)); switch (get_ucall(vcpu, &uc)) { - case UCALL_SYNC: - TEST_ASSERT(uc.args[1] == 0, - "Unexpected stage: %ld (0 expected)\n", - uc.args[1]); - break; case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); return; case UCALL_DONE: + break; + default: + TEST_FAIL("Unhandled ucall: %ld", uc.cmd); return; } From cc5851c6be864c5772944e32df3da322fe3ad415 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 8 Jun 2022 22:45:15 +0000 Subject: [PATCH 0569/1436] KVM: selftests: Use exception fixup for #UD/#GP Hyper-V MSR/hcall tests Use exception fixup to verify VMCALL/RDMSR/WRMSR fault as expected in the Hyper-V Features test. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220608224516.3788274-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/hyperv_features.c | 113 +++++------------- 1 file changed, 31 insertions(+), 82 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index 1a2a06c3027a..c05acd78548f 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -15,75 +15,20 @@ #define LINUX_OS_ID ((u64)0x8100 << 48) -extern unsigned char rdmsr_start; -extern unsigned char rdmsr_end; - -static u64 do_rdmsr(u32 idx) +static inline uint8_t hypercall(u64 control, vm_vaddr_t input_address, + vm_vaddr_t output_address, uint64_t *hv_status) { - u32 lo, hi; + uint8_t vector; - asm volatile("rdmsr_start: rdmsr;" - "rdmsr_end:" - : "=a"(lo), "=c"(hi) - : "c"(idx)); - - return (((u64) hi) << 32) | lo; -} - -extern unsigned char wrmsr_start; -extern unsigned char wrmsr_end; - -static void do_wrmsr(u32 idx, u64 val) -{ - u32 lo, hi; - - lo = val; - hi = val >> 32; - - asm volatile("wrmsr_start: wrmsr;" - "wrmsr_end:" - : : "a"(lo), "c"(idx), "d"(hi)); -} - -static int nr_gp; -static int nr_ud; - -static inline u64 hypercall(u64 control, vm_vaddr_t input_address, - vm_vaddr_t output_address) -{ - u64 hv_status; - - asm volatile("mov %3, %%r8\n" - "vmcall" - : "=a" (hv_status), - "+c" (control), "+d" (input_address) - : "r" (output_address) - : "cc", "memory", "r8", "r9", "r10", "r11"); - - return hv_status; -} - -static void guest_gp_handler(struct ex_regs *regs) -{ - unsigned char *rip = (unsigned char *)regs->rip; - bool r, w; - - r = rip == &rdmsr_start; - w = rip == &wrmsr_start; - GUEST_ASSERT(r || w); - - nr_gp++; - - if (r) - regs->rip = (uint64_t)&rdmsr_end; - else - regs->rip = (uint64_t)&wrmsr_end; -} - -static void guest_ud_handler(struct ex_regs *regs) -{ - nr_ud++; - regs->rip += 3; + /* Note both the hypercall and the "asm safe" clobber r9-r11. */ + asm volatile("mov %[output_address], %%r8\n\t" + KVM_ASM_SAFE("vmcall") + : "=a" (*hv_status), + "+c" (control), "+d" (input_address), + KVM_ASM_SAFE_OUTPUTS(vector) + : [output_address] "r"(output_address) + : "cc", "memory", "r8", KVM_ASM_SAFE_CLOBBERS); + return vector; } struct msr_data { @@ -101,31 +46,33 @@ struct hcall_data { static void guest_msr(struct msr_data *msr) { + uint64_t ignored; + uint8_t vector; + GUEST_ASSERT(msr->idx); - WRITE_ONCE(nr_gp, 0); if (!msr->write) - do_rdmsr(msr->idx); + vector = rdmsr_safe(msr->idx, &ignored); else - do_wrmsr(msr->idx, msr->write_val); + vector = wrmsr_safe(msr->idx, msr->write_val); if (msr->available) - GUEST_ASSERT(READ_ONCE(nr_gp) == 0); + GUEST_ASSERT_2(!vector, msr->idx, vector); else - GUEST_ASSERT(READ_ONCE(nr_gp) == 1); + GUEST_ASSERT_2(vector == GP_VECTOR, msr->idx, vector); GUEST_DONE(); } static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) { u64 res, input, output; + uint8_t vector; GUEST_ASSERT(hcall->control); wrmsr(HV_X64_MSR_GUEST_OS_ID, LINUX_OS_ID); wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa); - nr_ud = 0; if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) { input = pgs_gpa; output = pgs_gpa + 4096; @@ -133,12 +80,14 @@ static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) input = output = 0; } - res = hypercall(hcall->control, input, output); + vector = hypercall(hcall->control, input, output, &res); if (hcall->ud_expected) - GUEST_ASSERT(nr_ud == 1); + GUEST_ASSERT_2(vector == UD_VECTOR, hcall->control, vector); else - GUEST_ASSERT(res == hcall->expect); + GUEST_ASSERT_2(!vector, hcall->control, vector); + GUEST_ASSERT_2(!hcall->ud_expected || res == hcall->expect, + hcall->expect, res); GUEST_DONE(); } @@ -192,7 +141,6 @@ static void guest_test_msrs_access(void) vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); - vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); run = vcpu->run; @@ -499,8 +447,9 @@ static void guest_test_msrs_access(void) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + TEST_FAIL("%s at %s:%ld, MSR = %lx, vector = %lx", + (const char *)uc.args[0], __FILE__, + uc.args[1], uc.args[2], uc.args[3]); return; case UCALL_DONE: break; @@ -540,7 +489,6 @@ static void guest_test_hcalls_access(void) vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); - vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); /* Hypercall input/output */ hcall_page = vm_vaddr_alloc_pages(vm, 2); @@ -670,8 +618,9 @@ static void guest_test_hcalls_access(void) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + TEST_FAIL("%s at %s:%ld, arg1 = %lx, arg2 = %lx", + (const char *)uc.args[0], __FILE__, + uc.args[1], uc.args[2], uc.args[3]); return; case UCALL_DONE: break; From 908b130df51e04f317d5413f5bf31ebbf1a9e205 Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Mon, 20 Jun 2022 19:19:33 +0200 Subject: [PATCH 0570/1436] staging: r8188eu: replace N_BYTE_ALIGMENT with ALIGN Replace the macro N_BYTE_ALIGMENT (defined in this driver) with ALIGN because they do the same thing. Acked-by: Larry Finger Signed-off-by: Nam Cao Link: https://lore.kernel.org/r/28087b76483f10dca1e1c3bdcba5e4b08eecd544.1655745123.git.namcaov@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 2 +- drivers/staging/r8188eu/core/rtw_xmit.c | 6 +++--- drivers/staging/r8188eu/hal/rtl8188eu_recv.c | 2 +- drivers/staging/r8188eu/os_dep/xmit_linux.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index fe3d597fea69..36ea79586992 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -62,7 +62,7 @@ int _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) goto exit; } - precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ); + precvpriv->precv_frame_buf = (u8 *)ALIGN((size_t)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ); precvframe = (struct recv_frame *)precvpriv->precv_frame_buf; diff --git a/drivers/staging/r8188eu/core/rtw_xmit.c b/drivers/staging/r8188eu/core/rtw_xmit.c index 647c38134d2a..24401f3ae2a0 100644 --- a/drivers/staging/r8188eu/core/rtw_xmit.c +++ b/drivers/staging/r8188eu/core/rtw_xmit.c @@ -74,7 +74,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) res = _FAIL; goto exit; } - pxmitpriv->pxmit_frame_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_frame_buf), 4); + pxmitpriv->pxmit_frame_buf = (u8 *)ALIGN((size_t)(pxmitpriv->pallocated_frame_buf), 4); /* pxmitpriv->pxmit_frame_buf = pxmitpriv->pallocated_frame_buf + 4 - */ /* ((size_t) (pxmitpriv->pallocated_frame_buf) &3); */ @@ -111,7 +111,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) goto exit; } - pxmitpriv->pxmitbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmitbuf), 4); + pxmitpriv->pxmitbuf = (u8 *)ALIGN((size_t)(pxmitpriv->pallocated_xmitbuf), 4); /* pxmitpriv->pxmitbuf = pxmitpriv->pallocated_xmitbuf + 4 - */ /* ((size_t) (pxmitpriv->pallocated_xmitbuf) &3); */ @@ -151,7 +151,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) goto exit; } - pxmitpriv->pxmit_extbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitpriv->pallocated_xmit_extbuf), 4); + pxmitpriv->pxmit_extbuf = (u8 *)ALIGN((size_t)(pxmitpriv->pallocated_xmit_extbuf), 4); pxmitbuf = (struct xmit_buf *)pxmitpriv->pxmit_extbuf; diff --git a/drivers/staging/r8188eu/hal/rtl8188eu_recv.c b/drivers/staging/r8188eu/hal/rtl8188eu_recv.c index 727e1adce1dc..def6d0d6e402 100644 --- a/drivers/staging/r8188eu/hal/rtl8188eu_recv.c +++ b/drivers/staging/r8188eu/hal/rtl8188eu_recv.c @@ -32,7 +32,7 @@ int rtl8188eu_init_recv_priv(struct adapter *padapter) goto exit; } - precvpriv->precv_buf = (u8 *)N_BYTE_ALIGMENT((size_t)(precvpriv->pallocated_recv_buf), 4); + precvpriv->precv_buf = (u8 *)ALIGN((size_t)(precvpriv->pallocated_recv_buf), 4); precvbuf = (struct recv_buf *)precvpriv->precv_buf; diff --git a/drivers/staging/r8188eu/os_dep/xmit_linux.c b/drivers/staging/r8188eu/os_dep/xmit_linux.c index e430c64e9068..91a1e4e3219a 100644 --- a/drivers/staging/r8188eu/os_dep/xmit_linux.c +++ b/drivers/staging/r8188eu/os_dep/xmit_linux.c @@ -71,7 +71,7 @@ int rtw_os_xmit_resource_alloc(struct adapter *padapter, struct xmit_buf *pxmitb if (!pxmitbuf->pallocated_buf) return _FAIL; - pxmitbuf->pbuf = (u8 *)N_BYTE_ALIGMENT((size_t)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ); + pxmitbuf->pbuf = (u8 *)ALIGN((size_t)(pxmitbuf->pallocated_buf), XMITBUF_ALIGN_SZ); pxmitbuf->dma_transfer_addr = 0; pxmitbuf->pxmit_urb = usb_alloc_urb(0, GFP_KERNEL); From 263929afa4d674b2f1ab92801ff29a133171f757 Mon Sep 17 00:00:00 2001 From: Nam Cao Date: Mon, 20 Jun 2022 19:19:34 +0200 Subject: [PATCH 0571/1436] staging: r8188eu: remove basic_types.h Remove file basic_types.h because the content of this file is not used anywhere. Acked-by: Larry Finger Signed-off-by: Nam Cao Link: https://lore.kernel.org/r/1b8200420a2a1b7276f49eb3c2768ef39d641713.1655745123.git.namcaov@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/include/basic_types.h | 19 ------------------- .../staging/r8188eu/include/osdep_service.h | 1 - 2 files changed, 20 deletions(-) delete mode 100644 drivers/staging/r8188eu/include/basic_types.h diff --git a/drivers/staging/r8188eu/include/basic_types.h b/drivers/staging/r8188eu/include/basic_types.h deleted file mode 100644 index 0b71e2c6e41a..000000000000 --- a/drivers/staging/r8188eu/include/basic_types.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* Copyright(c) 2007 - 2011 Realtek Corporation. */ - -#ifndef __BASIC_TYPES_H__ -#define __BASIC_TYPES_H__ - -#include -#define NDIS_OID uint - -typedef void (*proc_t)(void *); - -/* port from fw */ -/* TODO: Macros Below are Sync from SD7-Driver. It is necessary - * to check correctness */ - -#define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \ - (__value) : (((__value + __aligment - 1) / __aligment) * __aligment)) - -#endif /* __BASIC_TYPES_H__ */ diff --git a/drivers/staging/r8188eu/include/osdep_service.h b/drivers/staging/r8188eu/include/osdep_service.h index f1a703643e74..1d97d5be46d5 100644 --- a/drivers/staging/r8188eu/include/osdep_service.h +++ b/drivers/staging/r8188eu/include/osdep_service.h @@ -5,7 +5,6 @@ #define __OSDEP_SERVICE_H_ #include -#include "basic_types.h" #define _FAIL 0 #define _SUCCESS 1 From fb119dcb97f43cf2a6164094209a08e7e6cd6f08 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Tue, 14 Jun 2022 18:07:25 -0700 Subject: [PATCH 0572/1436] Revert "usb: dwc3: Remove the checks of -ENOSYS" This reverts commit df22ecc41b54def624735b83784857e708bd1502. If CONFIG_GENERIC_PHY is not enabled, then the devm_phy_get() returns -ENOSYS. Don't remove this check. Fixes: df22ecc41b54 ("usb: dwc3: Remove the checks of -ENOSYS") Cc: Kushagra Verma Signed-off-by: Thinh Nguyen Link: https://lore.kernel.org/r/eb1df7ef954b5af093c0528982db52a41df18615.1655255152.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 1bd87da0bda7..cb8742f2a4b0 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1318,7 +1318,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); if (IS_ERR(dwc->usb2_generic_phy)) { ret = PTR_ERR(dwc->usb2_generic_phy); - if (ret == -ENODEV) + if (ret == -ENOSYS || ret == -ENODEV) dwc->usb2_generic_phy = NULL; else return dev_err_probe(dev, ret, "no usb2 phy configured\n"); @@ -1327,7 +1327,7 @@ static int dwc3_core_get_phy(struct dwc3 *dwc) dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); if (IS_ERR(dwc->usb3_generic_phy)) { ret = PTR_ERR(dwc->usb3_generic_phy); - if (ret == -ENODEV) + if (ret == -ENOSYS || ret == -ENODEV) dwc->usb3_generic_phy = NULL; else return dev_err_probe(dev, ret, "no usb3 phy configured\n"); From 485394c63f47df18eb7498608d5fc9041c19ec13 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Wed, 15 Jun 2022 21:44:09 +0200 Subject: [PATCH 0573/1436] MAINTAINERS: Repair file entry in ASPEED USB UDC DRIVER Commit 055276c13205 ("usb: gadget: add Aspeed ast2600 udc driver") adds the section ASPEED USB UDC DRIVER with a file entry to aspeed,udc.yaml, but then, commit 0dde9a46a2cf ("dt-bindings: usb: add documentation for aspeed udc") actually adds a device tree binding aspeed,ast2600-udc.yaml. Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about a broken reference. Repair the reference to the actually added file in ASPEED USB UDC DRIVER. Acked-by: Neal Liu Signed-off-by: Lukas Bulwahn Link: https://lore.kernel.org/r/20220615194409.11875-1-lukas.bulwahn@gmail.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 74eb60645ba0..41bddd55c324 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3140,7 +3140,7 @@ ASPEED USB UDC DRIVER M: Neal Liu L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) S: Maintained -F: Documentation/devicetree/bindings/usb/aspeed,udc.yaml +F: Documentation/devicetree/bindings/usb/aspeed,ast2600-udc.yaml F: drivers/usb/gadget/udc/aspeed_udc.c ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS From 3d393f0303b5120aa8c98a8ee70535ea9604ef20 Mon Sep 17 00:00:00 2001 From: Zheng Bin Date: Thu, 16 Jun 2022 21:35:08 +0800 Subject: [PATCH 0574/1436] usb: gadget: aspeed_udc: fix missing spin_unlock_irqrestore in ast_udc_ep_queue ast_udc_ep_queue misses spin_unlock_irqrestore in an error path, this patch fixes that. Fixes: 055276c13205 ("usb: gadget: add Aspeed ast2600 udc driver") Reviewed-by: Neal Liu Signed-off-by: Zheng Bin Link: https://lore.kernel.org/r/20220616133508.3655864-1-zhengbin13@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/aspeed_udc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c index 1fc15228ff15..6c91f7f288a2 100644 --- a/drivers/usb/gadget/udc/aspeed_udc.c +++ b/drivers/usb/gadget/udc/aspeed_udc.c @@ -665,7 +665,8 @@ static int ast_udc_ep_queue(struct usb_ep *_ep, struct usb_request *_req, if (ep->ep.desc == NULL) { if ((req->req.dma % 4) != 0) { dev_warn(dev, "EP0 req dma alignment error\n"); - return -ESHUTDOWN; + rc = -ESHUTDOWN; + goto end; } ast_udc_ep0_queue(ep, req); From c09b1f372e746aeeb61ef8ffe0fea3970fd9273e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 18 Jun 2022 11:54:20 +0300 Subject: [PATCH 0575/1436] usb: gadget: aspeed_udc: cleanup loop in ast_dma_descriptor_setup() The "chunk >= 0" condition does not work because count is a u32. Also, really we shouldn't enter the loop when "chunk" is zero. Once that condition is fixed then there is no need for the "last" variable. I reversed the "if (chunk <= ep->chunk_max)" as well. The new loop is much simpler. Fixes: 055276c13205 ("usb: gadget: add Aspeed ast2600 udc driver") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/Yq2SvM2bbrtSd1H9@kili Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/aspeed_udc.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c index 6c91f7f288a2..4dead40895dd 100644 --- a/drivers/usb/gadget/udc/aspeed_udc.c +++ b/drivers/usb/gadget/udc/aspeed_udc.c @@ -476,8 +476,8 @@ static int ast_dma_descriptor_setup(struct ast_udc_ep *ep, u32 dma_buf, { struct ast_udc_dev *udc = ep->udc; struct device *dev = &udc->pdev->dev; - u32 offset, chunk; - int count, last; + int chunk, count; + u32 offset; if (!ep->descs) { dev_warn(dev, "%s: Empty DMA descs list failure\n", @@ -486,30 +486,28 @@ static int ast_dma_descriptor_setup(struct ast_udc_ep *ep, u32 dma_buf, } chunk = tx_len; - offset = count = last = 0; + offset = count = 0; EP_DBG(ep, "req @%p, %s:%d, %s:0x%x, %s:0x%x\n", req, "wptr", ep->descs_wptr, "dma_buf", dma_buf, "tx_len", tx_len); /* Create Descriptor Lists */ - while (chunk >= 0 && !last && count < AST_UDC_DESCS_COUNT) { + while (chunk > 0 && count < AST_UDC_DESCS_COUNT) { ep->descs[ep->descs_wptr].des_0 = dma_buf + offset; - if (chunk <= ep->chunk_max) { - ep->descs[ep->descs_wptr].des_1 = chunk; - last = 1; - } else { + if (chunk > ep->chunk_max) ep->descs[ep->descs_wptr].des_1 = ep->chunk_max; - chunk -= ep->chunk_max; - } + else + ep->descs[ep->descs_wptr].des_1 = chunk; - EP_DBG(ep, "descs[%d]: 0x%x 0x%x, last:%d\n", + chunk -= ep->chunk_max; + + EP_DBG(ep, "descs[%d]: 0x%x 0x%x\n", ep->descs_wptr, ep->descs[ep->descs_wptr].des_0, - ep->descs[ep->descs_wptr].des_1, - last); + ep->descs[ep->descs_wptr].des_1); if (count == 0) req->saved_dma_wptr = ep->descs_wptr; From e2900f7466ddf013686520f2d23c3a9d50a6a516 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 15 Jun 2022 08:35:18 +0100 Subject: [PATCH 0576/1436] usb: gadget: ast2600: Fix a couple of spelling mistakes There are a couple of spelling mistakes, one in a dev_warn message and another in a SETUP_DBG message. Fix these and remove an extraneous white space too. Acked-by: Neal Liu Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20220615073518.192827-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/aspeed_udc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c index 4dead40895dd..d771612e6387 100644 --- a/drivers/usb/gadget/udc/aspeed_udc.c +++ b/drivers/usb/gadget/udc/aspeed_udc.c @@ -903,7 +903,7 @@ static void ast_udc_epn_handle_desc(struct ast_udc_dev *udc, u16 ep_num) int i; if (list_empty(&ep->queue)) { - dev_warn(dev, "%s reqest queue empty !\n", ep->ep.name); + dev_warn(dev, "%s request queue empty!\n", ep->ep.name); return; } @@ -1035,7 +1035,7 @@ static void ast_udc_ep0_handle_setup(struct ast_udc_dev *udc) memcpy_fromio(&crq, udc->creq, sizeof(crq)); - SETUP_DBG(udc, "SETEUP packet: %02x/%02x/%04x/%04x/%04x\n", + SETUP_DBG(udc, "SETUP packet: %02x/%02x/%04x/%04x/%04x\n", crq.bRequestType, crq.bRequest, le16_to_cpu(crq.wValue), le16_to_cpu(crq.wIndex), le16_to_cpu(crq.wLength)); From 44830e11ae9e56120e9d8edba447d0d0c44bfbbc Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Thu, 16 Jun 2022 17:04:10 +0800 Subject: [PATCH 0577/1436] usb: gadget: Remove unnecessary print function dev_err() The print function dev_err() is redundant because platform_get_irq() already prints an error. This was found by coccicheck: ./drivers/usb/gadget/udc/aspeed_udc.c:1546:2-9: line 1546 is redundant because platform_get_irq() already prints an error. Acked-by: Neal Liu Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20220616090410.128483-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/aspeed_udc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c index d771612e6387..d75a4e070bf7 100644 --- a/drivers/usb/gadget/udc/aspeed_udc.c +++ b/drivers/usb/gadget/udc/aspeed_udc.c @@ -1542,7 +1542,6 @@ static int ast_udc_probe(struct platform_device *pdev) /* Find interrupt and install handler */ udc->irq = platform_get_irq(pdev, 0); if (udc->irq < 0) { - dev_err(&pdev->dev, "Failed to get interrupt\n"); rc = udc->irq; goto err; } From 7a96b6ea90a439f73e42b640eef2386c2c644570 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Mon, 13 Jun 2022 12:46:42 +0100 Subject: [PATCH 0578/1436] usb: musb: Add support for PolarFire SoC's musb controller Add support for Microchips's PolarFire SoC's musb controller in host, peripheral and otg mode. Tested-by: Valentina Fernandez Signed-off-by: Conor Dooley Link: https://lore.kernel.org/r/20220613114642.1615292-2-conor.dooley@microchip.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/Kconfig | 13 +- drivers/usb/musb/Makefile | 1 + drivers/usb/musb/mpfs.c | 265 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/musb/mpfs.c diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 4d61df6a9b5c..f906dfd360d3 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -123,6 +123,17 @@ config USB_MUSB_MEDIATEK select GENERIC_PHY select USB_ROLE_SWITCH +config USB_MUSB_POLARFIRE_SOC + tristate "Microchip PolarFire SoC platforms" + depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST + depends on NOP_USB_XCEIV + select USB_MUSB_DUAL_ROLE + help + Say Y here to enable support for USB on Microchip's PolarFire SoC. + + This support is also available as a module. If so, the module + will be called mpfs. + comment "MUSB DMA mode" config MUSB_PIO_ONLY @@ -146,7 +157,7 @@ config USB_UX500_DMA config USB_INVENTRA_DMA bool 'Inventra' - depends on USB_MUSB_OMAP2PLUS || USB_MUSB_MEDIATEK || USB_MUSB_JZ4740 + depends on USB_MUSB_OMAP2PLUS || USB_MUSB_MEDIATEK || USB_MUSB_JZ4740 || USB_MUSB_POLARFIRE_SOC help Enable DMA transfers using Mentor's engine. diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 932247360a9f..51dd54a8de49 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_USB_MUSB_UX500) += ux500.o obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o obj-$(CONFIG_USB_MUSB_MEDIATEK) += mediatek.o +obj-$(CONFIG_USB_MUSB_POLARFIRE_SOC) += mpfs.o # the kconfig must guarantee that only one of the # possible I/O schemes will be enabled at a time ... diff --git a/drivers/usb/musb/mpfs.c b/drivers/usb/musb/mpfs.c new file mode 100644 index 000000000000..99666ef8af06 --- /dev/null +++ b/drivers/usb/musb/mpfs.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PolarFire SoC (MPFS) MUSB Glue Layer + * + * Copyright (c) 2020-2022 Microchip Corporation. All rights reserved. + * Based on {omap2430,tusb6010,ux500}.c + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "musb_core.h" +#include "musb_dma.h" + +#define MPFS_MUSB_MAX_EP_NUM 8 +#define MPFS_MUSB_RAM_BITS 12 + +struct mpfs_glue { + struct device *dev; + struct platform_device *musb; + struct platform_device *phy; + struct clk *clk; +}; + +static struct musb_fifo_cfg mpfs_musb_mode_cfg[] = { + { .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, + { .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, + { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, }, + { .hw_ep_num = 2, .style = FIFO_RX, .maxpacket = 512, }, + { .hw_ep_num = 3, .style = FIFO_TX, .maxpacket = 512, }, + { .hw_ep_num = 3, .style = FIFO_RX, .maxpacket = 512, }, + { .hw_ep_num = 4, .style = FIFO_TX, .maxpacket = 1024, }, + { .hw_ep_num = 4, .style = FIFO_RX, .maxpacket = 4096, }, +}; + +static const struct musb_hdrc_config mpfs_musb_hdrc_config = { + .fifo_cfg = mpfs_musb_mode_cfg, + .fifo_cfg_size = ARRAY_SIZE(mpfs_musb_mode_cfg), + .multipoint = true, + .dyn_fifo = true, + .num_eps = MPFS_MUSB_MAX_EP_NUM, + .ram_bits = MPFS_MUSB_RAM_BITS, +}; + +static irqreturn_t mpfs_musb_interrupt(int irq, void *__hci) +{ + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + struct musb *musb = __hci; + + spin_lock_irqsave(&musb->lock, flags); + + musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); + musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); + musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + + if (musb->int_usb || musb->int_tx || musb->int_rx) { + musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); + musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); + musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); + ret = musb_interrupt(musb); + } + + spin_unlock_irqrestore(&musb->lock, flags); + + return ret; +} + +static void mpfs_musb_set_vbus(struct musb *musb, int is_on) +{ + u8 devctl; + + /* + * HDRC controls CPEN, but beware current surges during device + * connect. They can trigger transient overcurrent conditions + * that must be ignored. + */ + devctl = musb_readb(musb->mregs, MUSB_DEVCTL); + + if (is_on) { + musb->is_active = 1; + musb->xceiv->otg->default_a = 1; + musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; + devctl |= MUSB_DEVCTL_SESSION; + MUSB_HST_MODE(musb); + } else { + musb->is_active = 0; + + /* + * NOTE: skipping A_WAIT_VFALL -> A_IDLE and + * jumping right to B_IDLE... + */ + musb->xceiv->otg->default_a = 0; + musb->xceiv->otg->state = OTG_STATE_B_IDLE; + devctl &= ~MUSB_DEVCTL_SESSION; + + MUSB_DEV_MODE(musb); + } + + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + + dev_dbg(musb->controller, "VBUS %s, devctl %02x\n", + usb_otg_state_string(musb->xceiv->otg->state), + musb_readb(musb->mregs, MUSB_DEVCTL)); +} + +static int mpfs_musb_init(struct musb *musb) +{ + struct device *dev = musb->controller; + + musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + if (IS_ERR(musb->xceiv)) { + dev_err(dev, "HS UDC: no transceiver configured\n"); + return PTR_ERR(musb->xceiv); + } + + musb->dyn_fifo = true; + musb->isr = mpfs_musb_interrupt; + + musb_platform_set_vbus(musb, 1); + + return 0; +} + +static const struct musb_platform_ops mpfs_ops = { + .quirks = MUSB_DMA_INVENTRA, + .init = mpfs_musb_init, + .fifo_mode = 2, +#ifdef CONFIG_USB_INVENTRA_DMA + .dma_init = musbhs_dma_controller_create, + .dma_exit = musbhs_dma_controller_destroy, +#endif + .set_vbus = mpfs_musb_set_vbus +}; + +static int mpfs_probe(struct platform_device *pdev) +{ + struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct mpfs_glue *glue; + struct platform_device *musb_pdev; + struct device *dev = &pdev->dev; + struct clk *clk; + int ret; + + glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); + if (!glue) + return -ENOMEM; + + musb_pdev = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); + if (!musb_pdev) { + dev_err(dev, "failed to allocate musb device\n"); + return -ENOMEM; + } + + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + ret = PTR_ERR(clk); + goto err_phy_release; + } + + ret = clk_prepare_enable(clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock\n"); + goto err_phy_release; + } + + musb_pdev->dev.parent = dev; + musb_pdev->dev.coherent_dma_mask = DMA_BIT_MASK(39); + musb_pdev->dev.dma_mask = &musb_pdev->dev.coherent_dma_mask; + device_set_of_node_from_dev(&musb_pdev->dev, dev); + + glue->dev = dev; + glue->musb = musb_pdev; + glue->clk = clk; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + goto err_clk_disable; + + pdata->config = &mpfs_musb_hdrc_config; + pdata->platform_ops = &mpfs_ops; + + pdata->mode = usb_get_dr_mode(dev); + if (pdata->mode == USB_DR_MODE_UNKNOWN) { + dev_info(dev, "No dr_mode property found, defaulting to otg\n"); + pdata->mode = USB_DR_MODE_OTG; + } + + glue->phy = usb_phy_generic_register(); + if (IS_ERR(glue->phy)) { + dev_err(dev, "failed to register usb-phy %ld\n", + PTR_ERR(glue->phy)); + goto err_clk_disable; + } + + platform_set_drvdata(pdev, glue); + + ret = platform_device_add_resources(musb_pdev, pdev->resource, pdev->num_resources); + if (ret) { + dev_err(dev, "failed to add resources\n"); + goto err_clk_disable; + } + + ret = platform_device_add_data(musb_pdev, pdata, sizeof(*pdata)); + if (ret) { + dev_err(dev, "failed to add platform_data\n"); + goto err_clk_disable; + } + + ret = platform_device_add(musb_pdev); + if (ret) { + dev_err(dev, "failed to register musb device\n"); + goto err_clk_disable; + } + + dev_info(&pdev->dev, "Registered MPFS MUSB driver\n"); + return 0; + +err_clk_disable: + clk_disable_unprepare(clk); + +err_phy_release: + usb_phy_generic_unregister(glue->phy); + platform_device_put(musb_pdev); + return ret; +} + +static int mpfs_remove(struct platform_device *pdev) +{ + struct mpfs_glue *glue = platform_get_drvdata(pdev); + + platform_device_unregister(glue->musb); + usb_phy_generic_unregister(pdev); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id mpfs_id_table[] = { + { .compatible = "microchip,mpfs-musb" }, + { } +}; +MODULE_DEVICE_TABLE(of, mpfs_id_table); +#endif + +static struct platform_driver mpfs_musb_driver = { + .probe = mpfs_probe, + .remove = mpfs_remove, + .driver = { + .name = "mpfs-musb", + .of_match_table = of_match_ptr(mpfs_id_table) + }, +}; + +module_platform_driver(mpfs_musb_driver); + +MODULE_DESCRIPTION("PolarFire SoC MUSB Glue Layer"); +MODULE_LICENSE("GPL"); From 4a691b8c157a339e35ec71e432edf17a358215e7 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Mon, 13 Jun 2022 12:46:43 +0100 Subject: [PATCH 0579/1436] MAINTAINERS: add musb to PolarFire SoC entry Add the newly introduced musb driver to the existing PolarFire SoC entry. Signed-off-by: Conor Dooley Link: https://lore.kernel.org/r/20220613114642.1615292-3-conor.dooley@microchip.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 41bddd55c324..e73c77d479bb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17169,6 +17169,7 @@ S: Supported F: arch/riscv/boot/dts/microchip/ F: drivers/mailbox/mailbox-mpfs.c F: drivers/soc/microchip/ +F: drivers/usb/musb/mpfs.c F: include/soc/microchip/mpfs.h RNBD BLOCK DRIVERS From afbd04e66e5d16ca3c7ea2e3c56eca25558eacf3 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Wed, 15 Jun 2022 17:24:32 -0700 Subject: [PATCH 0580/1436] usb: dwc3: core: Deprecate GCTL.CORESOFTRESET Synopsys IP DWC_usb32 and DWC_usb31 version 1.90a and above deprecated GCTL.CORESOFTRESET. The DRD mode switching flow is updated to remove the GCTL soft reset. Add version checks to prevent using deprecated setting in mode switching flow. Signed-off-by: Thinh Nguyen Link: https://lore.kernel.org/r/9df529fde6e55f5508321b6bc26e92848044ef2b.1655338967.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index cb8742f2a4b0..3d716c7fd34e 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -159,7 +159,8 @@ static void __dwc3_set_mode(struct work_struct *work) } /* For DRD host or device mode only */ - if (dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG) { + if ((DWC3_IP_IS(DWC3) || DWC3_VER_IS_PRIOR(DWC31, 190A)) && + dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG) { reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); From 098c4d43b91a269e89f60331a26a3f3b914677ed Mon Sep 17 00:00:00 2001 From: Sandeep Maheswaram Date: Mon, 13 Jun 2022 10:00:50 +0530 Subject: [PATCH 0581/1436] dt-bindings: usb: dwc3: Add wakeup-source property support Added support for wakeup-source property. This property can be used to check and power down the phy during system suspend if wake up is not supported. Reviewed-by: Matthias Kaehlcke Acked-by: Krzysztof Kozlowski Signed-off-by: Sandeep Maheswaram Signed-off-by: Krishna Kurapati Link: https://lore.kernel.org/r/1655094654-24052-2-git-send-email-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/snps,dwc3.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml index d41265ba8ce2..1779d08ba1c0 100644 --- a/Documentation/devicetree/bindings/usb/snps,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/snps,dwc3.yaml @@ -343,6 +343,11 @@ properties: This port is used with the 'usb-role-switch' property to connect the dwc3 to type C connector. + wakeup-source: + $ref: /schemas/types.yaml#/definitions/flag + description: + Enable USB remote wakeup. + unevaluatedProperties: false required: From 649f5c842ba3acfe6a06a36229759f328e98508a Mon Sep 17 00:00:00 2001 From: Sandeep Maheswaram Date: Mon, 13 Jun 2022 10:00:51 +0530 Subject: [PATCH 0582/1436] usb: dwc3: core: Host wake up support from system suspend Check wakeup-source property for dwc3 core node to set the wakeup capability. Drop the device_init_wakeup call from runtime suspend and resume. If the dwc3 is wakeup capable, don't power down the USB PHY(s). The glue drivers are expected to take care of configuring the additional wakeup settings if needed based on the dwc3 wakeup capability status. In some SOC designs, powering off the PHY is resulting in higher leakage, so this patch save power on such boards. Reviewed-by: Pavankumar Kondeti Signed-off-by: Sandeep Maheswaram Signed-off-by: Krishna Kurapati Link: https://lore.kernel.org/r/1655094654-24052-3-git-send-email-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 3d716c7fd34e..050b2ba5986d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1817,6 +1817,7 @@ static int dwc3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); + device_init_wakeup(&pdev->dev, of_property_read_bool(dev->of_node, "wakeup-source")); spin_lock_init(&dwc->lock); mutex_init(&dwc->mutex); @@ -1978,7 +1979,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) dwc3_core_exit(dwc); break; case DWC3_GCTL_PRTCAP_HOST: - if (!PMSG_IS_AUTO(msg)) { + if (!PMSG_IS_AUTO(msg) && !device_can_wakeup(dwc->dev)) { dwc3_core_exit(dwc); break; } @@ -2039,7 +2040,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) spin_unlock_irqrestore(&dwc->lock, flags); break; case DWC3_GCTL_PRTCAP_HOST: - if (!PMSG_IS_AUTO(msg)) { + if (!PMSG_IS_AUTO(msg) && !device_can_wakeup(dwc->dev)) { ret = dwc3_core_init_for_resume(dwc); if (ret) return ret; @@ -2116,8 +2117,6 @@ static int dwc3_runtime_suspend(struct device *dev) if (ret) return ret; - device_init_wakeup(dev, true); - return 0; } @@ -2126,8 +2125,6 @@ static int dwc3_runtime_resume(struct device *dev) struct dwc3 *dwc = dev_get_drvdata(dev); int ret; - device_init_wakeup(dev, false); - ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME); if (ret) return ret; From 360e8230516de94d74d30c64f0cdcf228b8e8b67 Mon Sep 17 00:00:00 2001 From: Sandeep Maheswaram Date: Mon, 13 Jun 2022 10:00:52 +0530 Subject: [PATCH 0583/1436] usb: dwc3: qcom: Add helper functions to enable,disable wake irqs Adding helper functions to enable,disable wake irqs to make the code simple and readable. Reviewed-by: Matthias Kaehlcke Reviewed-by: Pavankumar Kondeti Signed-off-by: Sandeep Maheswaram Signed-off-by: Krishna Kurapati Link: https://lore.kernel.org/r/1655094654-24052-4-git-send-email-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 58 ++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 6cba990da32e..7352124355d2 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -296,50 +296,44 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom) icc_put(qcom->icc_path_apps); } +static void dwc3_qcom_enable_wakeup_irq(int irq) +{ + if (!irq) + return; + + enable_irq(irq); + enable_irq_wake(irq); +} + +static void dwc3_qcom_disable_wakeup_irq(int irq) +{ + if (!irq) + return; + + disable_irq_wake(irq); + disable_irq_nosync(irq); +} + static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) { - if (qcom->hs_phy_irq) { - disable_irq_wake(qcom->hs_phy_irq); - disable_irq_nosync(qcom->hs_phy_irq); - } + dwc3_qcom_disable_wakeup_irq(qcom->hs_phy_irq); - if (qcom->dp_hs_phy_irq) { - disable_irq_wake(qcom->dp_hs_phy_irq); - disable_irq_nosync(qcom->dp_hs_phy_irq); - } + dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq); - if (qcom->dm_hs_phy_irq) { - disable_irq_wake(qcom->dm_hs_phy_irq); - disable_irq_nosync(qcom->dm_hs_phy_irq); - } + dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); - if (qcom->ss_phy_irq) { - disable_irq_wake(qcom->ss_phy_irq); - disable_irq_nosync(qcom->ss_phy_irq); - } + dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq); } static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) { - if (qcom->hs_phy_irq) { - enable_irq(qcom->hs_phy_irq); - enable_irq_wake(qcom->hs_phy_irq); - } + dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq); - if (qcom->dp_hs_phy_irq) { - enable_irq(qcom->dp_hs_phy_irq); - enable_irq_wake(qcom->dp_hs_phy_irq); - } + dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq); - if (qcom->dm_hs_phy_irq) { - enable_irq(qcom->dm_hs_phy_irq); - enable_irq_wake(qcom->dm_hs_phy_irq); - } + dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq); - if (qcom->ss_phy_irq) { - enable_irq(qcom->ss_phy_irq); - enable_irq_wake(qcom->ss_phy_irq); - } + dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq); } static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) From 6895ea55c385c9afdd2aec1eef27ec24917a112f Mon Sep 17 00:00:00 2001 From: Sandeep Maheswaram Date: Mon, 13 Jun 2022 10:00:53 +0530 Subject: [PATCH 0584/1436] usb: dwc3: qcom: Configure wakeup interrupts during suspend Configure DP/DM line interrupts based on the USB2 device attached to the root hub port. When HS/FS device is connected, configure the DP line as falling edge to detect both disconnect and remote wakeup scenarios. When LS device is connected, configure DM line as falling edge to detect both disconnect and remote wakeup. When no device is connected, configure both DP and DM lines as rising edge to detect HS/HS/LS device connect scenario. Reviewed-by: Pavankumar Kondeti Reviewed-by: Matthias Kaehlcke Signed-off-by: Sandeep Maheswaram Signed-off-by: Krishna Kurapati Link: https://lore.kernel.org/r/1655094654-24052-5-git-send-email-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 72 +++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 7352124355d2..1046ea8790ba 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -20,7 +20,8 @@ #include #include #include - +#include +#include #include "core.h" /* USB QSCRATCH Hardware registers */ @@ -76,6 +77,7 @@ struct dwc3_qcom { int dp_hs_phy_irq; int dm_hs_phy_irq; int ss_phy_irq; + enum usb_device_speed usb2_speed; struct extcon_dev *edev; struct extcon_dev *host_edev; @@ -296,11 +298,34 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom) icc_put(qcom->icc_path_apps); } -static void dwc3_qcom_enable_wakeup_irq(int irq) +static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom) +{ + struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3); + struct usb_hcd *hcd = platform_get_drvdata(dwc->xhci); + struct usb_device *udev; + + /* + * It is possible to query the speed of all children of + * USB2.0 root hub via usb_hub_for_each_child(). DWC3 code + * currently supports only 1 port per controller. So + * this is sufficient. + */ + udev = usb_hub_find_child(hcd->self.root_hub, 1); + + if (!udev) + return USB_SPEED_UNKNOWN; + + return udev->speed; +} + +static void dwc3_qcom_enable_wakeup_irq(int irq, unsigned int polarity) { if (!irq) return; + if (polarity) + irq_set_irq_type(irq, polarity); + enable_irq(irq); enable_irq_wake(irq); } @@ -318,22 +343,47 @@ static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom) { dwc3_qcom_disable_wakeup_irq(qcom->hs_phy_irq); - dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq); - - dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); + if (qcom->usb2_speed == USB_SPEED_LOW) { + dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); + } else if ((qcom->usb2_speed == USB_SPEED_HIGH) || + (qcom->usb2_speed == USB_SPEED_FULL)) { + dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq); + } else { + dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq); + dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq); + } dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq); } static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom) { - dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq); + dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq, 0); - dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq); + /* + * Configure DP/DM line interrupts based on the USB2 device attached to + * the root hub port. When HS/FS device is connected, configure the DP line + * as falling edge to detect both disconnect and remote wakeup scenarios. When + * LS device is connected, configure DM line as falling edge to detect both + * disconnect and remote wakeup. When no device is connected, configure both + * DP and DM lines as rising edge to detect HS/HS/LS device connect scenario. + */ - dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq); + if (qcom->usb2_speed == USB_SPEED_LOW) { + dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq, + IRQ_TYPE_EDGE_FALLING); + } else if ((qcom->usb2_speed == USB_SPEED_HIGH) || + (qcom->usb2_speed == USB_SPEED_FULL)) { + dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq, + IRQ_TYPE_EDGE_FALLING); + } else { + dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq, + IRQ_TYPE_EDGE_RISING); + dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq, + IRQ_TYPE_EDGE_RISING); + } - dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq); + dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0); } static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) @@ -355,8 +405,10 @@ static int dwc3_qcom_suspend(struct dwc3_qcom *qcom) if (ret) dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret); - if (device_may_wakeup(qcom->dev)) + if (device_may_wakeup(qcom->dev)) { + qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom); dwc3_qcom_enable_interrupts(qcom); + } qcom->is_suspended = true; From d9be8d5c5b032e5383ff5c404ff4155e9c705429 Mon Sep 17 00:00:00 2001 From: Sandeep Maheswaram Date: Mon, 13 Jun 2022 10:00:54 +0530 Subject: [PATCH 0585/1436] usb: dwc3: qcom: Keep power domain on to retain controller status If dwc3 is wakeup capable, keep the power domain always ON so that wakeup from system suspend can be supported. Otherwise, keep the power domain ON only during runtime suspend to support wakeup from runtime suspend. Reviewed-by: Pavankumar Kondeti Signed-off-by: Sandeep Maheswaram Signed-off-by: Krishna Kurapati Link: https://lore.kernel.org/r/1655094654-24052-6-git-send-email-quic_kriskura@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 1046ea8790ba..77036551987a 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -756,12 +757,13 @@ dwc3_qcom_create_urs_usb_platdev(struct device *dev) static int dwc3_qcom_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node; - struct device *dev = &pdev->dev; - struct dwc3_qcom *qcom; - struct resource *res, *parent_res = NULL; - int ret, i; - bool ignore_pipe_clk; + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct dwc3_qcom *qcom; + struct resource *res, *parent_res = NULL; + int ret, i; + bool ignore_pipe_clk; + struct generic_pm_domain *genpd; qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL); if (!qcom) @@ -770,6 +772,8 @@ static int dwc3_qcom_probe(struct platform_device *pdev) platform_set_drvdata(pdev, qcom); qcom->dev = &pdev->dev; + genpd = pd_to_genpd(qcom->dev->pm_domain); + if (has_acpi_companion(dev)) { qcom->acpi_pdata = acpi_device_get_match_data(dev); if (!qcom->acpi_pdata) { @@ -877,7 +881,17 @@ static int dwc3_qcom_probe(struct platform_device *pdev) if (ret) goto interconnect_exit; - device_init_wakeup(&pdev->dev, 1); + if (device_can_wakeup(&qcom->dwc3->dev)) { + /* + * Setting GENPD_FLAG_ALWAYS_ON flag takes care of keeping + * genpd on in both runtime suspend and system suspend cases. + */ + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + device_init_wakeup(&pdev->dev, true); + } else { + genpd->flags |= GENPD_FLAG_RPM_ALWAYS_ON; + } + qcom->is_suspended = false; pm_runtime_set_active(dev); pm_runtime_enable(dev); From 144a96f7f96e412c3367f51cf2c57f52e3f1110d Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 15 Jun 2022 17:20:17 +0000 Subject: [PATCH 0586/1436] usb: typec: mux: Allow muxes to specify mode-switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Loosen the typec_mux_match() requirements so that searches where an alt mode is not specified, but the target mux device lists the "mode-switch" property, return a success. This is helpful in Type C port drivers which would like to get a pointer to the mux switch associated with a Type C port, but don't want to specify a particular alt mode. Signed-off-by: Prashant Malani Reviewed-by: Heikki Krogerus Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Nícolas F. R. A. Prado Tested-by: Nícolas F. R. A. Prado Link: https://lore.kernel.org/r/20220615172129.1314056-2-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/mux.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c index fd55c2c516a5..464330776cd6 100644 --- a/drivers/usb/typec/mux.c +++ b/drivers/usb/typec/mux.c @@ -281,9 +281,13 @@ static void *typec_mux_match(struct fwnode_handle *fwnode, const char *id, if (match) goto find_mux; - /* Accessory Mode muxes */ if (!desc) { - match = fwnode_property_present(fwnode, "accessory"); + /* + * Accessory Mode muxes & muxes which explicitly specify + * the required identifier can avoid SVID matching. + */ + match = fwnode_property_present(fwnode, "accessory") || + fwnode_property_present(fwnode, id); if (match) goto find_mux; return NULL; From a37599ebfb656c2af4ca119de556eba29b6926d6 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Wed, 15 Jun 2022 17:20:18 +0000 Subject: [PATCH 0587/1436] usb: typec: mux: Add CONFIG guards for functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are some drivers that can use the Type C mux API, but don't have to. Introduce CONFIG guards for the mux functions so that drivers can include the header file and not run into compilation errors on systems which don't have CONFIG_TYPEC enabled. When CONFIG_TYPEC is not enabled, the Type C mux functions will be stub versions of the original calls. Reported-by: kernel test robot Reviewed-by: Nícolas F. R. A. Prado Reviewed-by: Heikki Krogerus Reviewed-by: AngeloGioacchino Del Regno Tested-by: Nícolas F. R. A. Prado Signed-off-by: Prashant Malani Link: https://lore.kernel.org/r/20220615172129.1314056-3-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/typec_mux.h | 44 ++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/include/linux/usb/typec_mux.h b/include/linux/usb/typec_mux.h index ee57781dcf28..9292f0e07846 100644 --- a/include/linux/usb/typec_mux.h +++ b/include/linux/usb/typec_mux.h @@ -58,17 +58,13 @@ struct typec_mux_desc { void *drvdata; }; +#if IS_ENABLED(CONFIG_TYPEC) + struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode, const struct typec_altmode_desc *desc); void typec_mux_put(struct typec_mux *mux); int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state); -static inline struct typec_mux * -typec_mux_get(struct device *dev, const struct typec_altmode_desc *desc) -{ - return fwnode_typec_mux_get(dev_fwnode(dev), desc); -} - struct typec_mux_dev * typec_mux_register(struct device *parent, const struct typec_mux_desc *desc); void typec_mux_unregister(struct typec_mux_dev *mux); @@ -76,4 +72,40 @@ void typec_mux_unregister(struct typec_mux_dev *mux); void typec_mux_set_drvdata(struct typec_mux_dev *mux, void *data); void *typec_mux_get_drvdata(struct typec_mux_dev *mux); +#else + +static inline struct typec_mux *fwnode_typec_mux_get(struct fwnode_handle *fwnode, + const struct typec_altmode_desc *desc) +{ + return NULL; +} + +static inline void typec_mux_put(struct typec_mux *mux) {} + +static inline int typec_mux_set(struct typec_mux *mux, struct typec_mux_state *state) +{ + return 0; +} + +static inline struct typec_mux_dev * +typec_mux_register(struct device *parent, const struct typec_mux_desc *desc) +{ + return ERR_PTR(-EOPNOTSUPP); +} +static inline void typec_mux_unregister(struct typec_mux_dev *mux) {} + +static inline void typec_mux_set_drvdata(struct typec_mux_dev *mux, void *data) {} +static inline void *typec_mux_get_drvdata(struct typec_mux_dev *mux) +{ + return ERR_PTR(-EOPNOTSUPP); +} + +#endif /* CONFIG_TYPEC */ + +static inline struct typec_mux * +typec_mux_get(struct device *dev, const struct typec_altmode_desc *desc) +{ + return fwnode_typec_mux_get(dev_fwnode(dev), desc); +} + #endif /* __USB_TYPEC_MUX */ From 40a959d7042bb7711e404ad2318b30e9f92c6b9b Mon Sep 17 00:00:00 2001 From: Liang He Date: Fri, 17 Jun 2022 11:46:37 +0800 Subject: [PATCH 0588/1436] usb: host: ohci-ppc-of: Fix refcount leak bug In ohci_hcd_ppc_of_probe(), of_find_compatible_node() will return a node pointer with refcount incremented. We should use of_node_put() when it is not used anymore. Acked-by: Alan Stern Signed-off-by: Liang He Link: https://lore.kernel.org/r/20220617034637.4003115-1-windhl@126.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-ppc-of.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index 1960b8dfdba5..591f675cc930 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -166,6 +166,7 @@ static int ohci_hcd_ppc_of_probe(struct platform_device *op) release_mem_region(res.start, 0x4); } else pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__); + of_node_put(np); } irq_dispose_mapping(irq); From 9d6d5303c39b8bc182475b22f45504106a07f086 Mon Sep 17 00:00:00 2001 From: Liang He Date: Sat, 18 Jun 2022 10:32:05 +0800 Subject: [PATCH 0589/1436] usb: renesas: Fix refcount leak bug In usbhs_rza1_hardware_init(), of_find_node_by_name() will return a node pointer with refcount incremented. We should use of_node_put() when it is not used anymore. Signed-off-by: Liang He Link: https://lore.kernel.org/r/20220618023205.4056548-1-windhl@126.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/rza.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/renesas_usbhs/rza.c b/drivers/usb/renesas_usbhs/rza.c index 24de64edb674..2d77edefb4b3 100644 --- a/drivers/usb/renesas_usbhs/rza.c +++ b/drivers/usb/renesas_usbhs/rza.c @@ -23,6 +23,10 @@ static int usbhs_rza1_hardware_init(struct platform_device *pdev) extal_clk = of_find_node_by_name(NULL, "extal"); of_property_read_u32(usb_x1_clk, "clock-frequency", &freq_usb); of_property_read_u32(extal_clk, "clock-frequency", &freq_extal); + + of_node_put(usb_x1_clk); + of_node_put(extal_clk); + if (freq_usb == 0) { if (freq_extal == 12000000) { /* Select 12MHz XTAL */ From 196a58bdec7c324d6d862cba19069b77ddd48b90 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Sat, 18 Jun 2022 15:06:16 +0300 Subject: [PATCH 0590/1436] usb: musb: core: drop redundant checks In musb_{save|restore}_context() the expression '&musb->endpoints[i]' just cannot be NULL, so the checks have no sense at all -- after dropping them, the local variables 'hw_ep' are no longer necessary, so drop them as well. Found by Linux Verification Center (linuxtesting.org) with the SVACE static analysis tool. Signed-off-by: Sergey Shtylyov Link: https://lore.kernel.org/r/3f8f60d9-f1b5-6b2c-1222-39b156151a22@omp.ru Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_core.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index f7b1d5993f8c..bbbcfd49fb35 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2684,13 +2684,7 @@ static void musb_save_context(struct musb *musb) musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL); for (i = 0; i < musb->config->num_eps; ++i) { - struct musb_hw_ep *hw_ep; - - hw_ep = &musb->endpoints[i]; - if (!hw_ep) - continue; - - epio = hw_ep->regs; + epio = musb->endpoints[i].regs; if (!epio) continue; @@ -2765,13 +2759,7 @@ static void musb_restore_context(struct musb *musb) musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl); for (i = 0; i < musb->config->num_eps; ++i) { - struct musb_hw_ep *hw_ep; - - hw_ep = &musb->endpoints[i]; - if (!hw_ep) - continue; - - epio = hw_ep->regs; + epio = musb->endpoints[i].regs; if (!epio) continue; From 7d34b0717c058f1d4a80342501d1711b8ac539c6 Mon Sep 17 00:00:00 2001 From: Xiang wangx Date: Mon, 20 Jun 2022 18:15:56 +0800 Subject: [PATCH 0591/1436] USB: ohci-sm501: Fix typo in comment Delete the redundant word 'the'. Signed-off-by: Xiang wangx Link: https://lore.kernel.org/r/20220620101556.2290-1-wangxiang@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-sm501.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index b91d50da6127..f5de586454e3 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -153,7 +153,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev) * fine. This is however not always the case - buffers may be allocated * using kmalloc() - so the usb core needs to be told that it must copy * data into our local memory if the buffers happen to be placed in - * regular memory. A non-null hcd->localmem_pool initialized by the + * regular memory. A non-null hcd->localmem_pool initialized by * the call to usb_hcd_setup_local_mem() below does just that. */ From 274a12ea4007bf62a3abdc5600f85cd4de678169 Mon Sep 17 00:00:00 2001 From: Xiang wangx Date: Mon, 20 Jun 2022 18:42:43 +0800 Subject: [PATCH 0592/1436] USB: storage: Fix typo in comment Delete the redundant word 'the'. Signed-off-by: Xiang wangx Link: https://lore.kernel.org/r/20220620104243.4979-1-wangxiang@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 64d96d210e02..7449e379077a 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1178,7 +1178,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) /* * If the device tried to send back more data than the * amount requested, the spec requires us to transfer - * the CSW anyway. Since there's no point retrying the + * the CSW anyway. Since there's no point retrying * the command, we'll return fake sense data indicating * Illegal Request, Invalid Field in CDB. */ From 5c586db8465274ce5db64171d42a099ce89ec905 Mon Sep 17 00:00:00 2001 From: Hyunwoo Kim Date: Mon, 20 Jun 2022 23:42:42 -0700 Subject: [PATCH 0593/1436] usb: host: ehci-q: Fix ehci_submit_single_step_set_feature annotation typo I found the "argument" typo. It seems that "argument" is more correct than "arguement". Signed-off-by: Hyunwoo Kim Link: https://lore.kernel.org/r/20220621064242.GA698757@ubuntu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-q.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 1163af6fad77..807e64991e3e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -1162,7 +1162,7 @@ submit_async ( * This is done in two parts: first SETUP req for GetDesc is sent then * 15 seconds later, the IN stage for GetDesc starts to req data from dev * - * is_setup : i/p arguement decides which of the two stage needs to be + * is_setup : i/p argument decides which of the two stage needs to be * performed; TRUE - SETUP and FALSE - IN+STATUS * Returns 0 if success */ From 8709115180c612bd8e6686a7b6c6fe94e5b51cdc Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Thu, 16 Jun 2022 21:44:59 +0200 Subject: [PATCH 0594/1436] usb: chipidea: udc: implement get_frame The chipidea udc core is capable of reading the current frame index from hardware. This patch adds the get_frame callback to the driver. Acked-by: Peter Chen Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20220616194459.2981519-1-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci.h | 1 + drivers/usb/chipidea/core.c | 2 ++ drivers/usb/chipidea/udc.c | 14 ++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 99440baa6458..a4a3be049910 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -49,6 +49,7 @@ enum ci_hw_regs { OP_USBCMD, OP_USBSTS, OP_USBINTR, + OP_FRINDEX, OP_DEVICEADDR, OP_ENDPTLISTADDR, OP_TTCTRL, diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 5359b2a2e4d2..6330fa911792 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -53,6 +53,7 @@ static const u8 ci_regs_nolpm[] = { [OP_USBCMD] = 0x00U, [OP_USBSTS] = 0x04U, [OP_USBINTR] = 0x08U, + [OP_FRINDEX] = 0x0CU, [OP_DEVICEADDR] = 0x14U, [OP_ENDPTLISTADDR] = 0x18U, [OP_TTCTRL] = 0x1CU, @@ -78,6 +79,7 @@ static const u8 ci_regs_lpm[] = { [OP_USBCMD] = 0x00U, [OP_USBSTS] = 0x04U, [OP_USBINTR] = 0x08U, + [OP_FRINDEX] = 0x0CU, [OP_DEVICEADDR] = 0x14U, [OP_ENDPTLISTADDR] = 0x18U, [OP_TTCTRL] = 0x1CU, diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index dc6c96e04bcf..0c9ae9768a67 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1651,6 +1651,19 @@ static const struct usb_ep_ops usb_ep_ops = { /****************************************************************************** * GADGET block *****************************************************************************/ + +static int ci_udc_get_frame(struct usb_gadget *_gadget) +{ + struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget); + unsigned long flags; + int ret; + + spin_lock_irqsave(&ci->lock, flags); + ret = hw_read(ci, OP_FRINDEX, 0x3fff); + spin_unlock_irqrestore(&ci->lock, flags); + return ret >> 3; +} + /* * ci_hdrc_gadget_connect: caller makes sure gadget driver is binded */ @@ -1807,6 +1820,7 @@ static struct usb_ep *ci_udc_match_ep(struct usb_gadget *gadget, * Check "usb_gadget.h" for details */ static const struct usb_gadget_ops usb_gadget_ops = { + .get_frame = ci_udc_get_frame, .vbus_session = ci_udc_vbus_session, .wakeup = ci_udc_wakeup, .set_selfpowered = ci_udc_selfpowered, From 18171cfc3c236a1587dcad9adc27c6e781af4438 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 14 Jun 2022 14:05:22 +0200 Subject: [PATCH 0595/1436] usb: chipidea: ci_hdrc_imx: use dev_err_probe() Use dev_err_probe() to simplify handling errors in ci_hdrc_imx_probe() Acked-by: Peter Chen Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20220614120522.1469957-1-alexander.stein@ew.tq-group.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/ci_hdrc_imx.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 097142ffb184..9ffcecd3058c 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -348,25 +348,18 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) data->pinctrl = devm_pinctrl_get(dev); if (PTR_ERR(data->pinctrl) == -ENODEV) data->pinctrl = NULL; - else if (IS_ERR(data->pinctrl)) { - if (PTR_ERR(data->pinctrl) != -EPROBE_DEFER) - dev_err(dev, "pinctrl get failed, err=%ld\n", - PTR_ERR(data->pinctrl)); - return PTR_ERR(data->pinctrl); - } + else if (IS_ERR(data->pinctrl)) + return dev_err_probe(dev, PTR_ERR(data->pinctrl), + "pinctrl get failed\n"); data->hsic_pad_regulator = devm_regulator_get_optional(dev, "hsic"); if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { /* no pad regualator is needed */ data->hsic_pad_regulator = NULL; - } else if (IS_ERR(data->hsic_pad_regulator)) { - if (PTR_ERR(data->hsic_pad_regulator) != -EPROBE_DEFER) - dev_err(dev, - "Get HSIC pad regulator error: %ld\n", - PTR_ERR(data->hsic_pad_regulator)); - return PTR_ERR(data->hsic_pad_regulator); - } + } else if (IS_ERR(data->hsic_pad_regulator)) + return dev_err_probe(dev, PTR_ERR(data->hsic_pad_regulator), + "Get HSIC pad regulator error\n"); if (data->hsic_pad_regulator) { ret = regulator_enable(data->hsic_pad_regulator); @@ -458,9 +451,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev) &pdata); if (IS_ERR(data->ci_pdev)) { ret = PTR_ERR(data->ci_pdev); - if (ret != -EPROBE_DEFER) - dev_err(dev, "ci_hdrc_add_device failed, err=%d\n", - ret); + dev_err_probe(dev, ret, "ci_hdrc_add_device failed\n"); goto err_clk; } From 9dbdac024d4d9f3fc234399cb8c1f1cc6d2bcb2d Mon Sep 17 00:00:00 2001 From: Artur Bujdoso Date: Tue, 24 May 2022 18:25:40 +0200 Subject: [PATCH 0596/1436] staging: octeon-usb: move driver out of staging The Octeon usb driver has been in staging for a long time and used in Ubiquiti routers for a while now. It's been built and then tested on real hardware with several usb devices and it is proven to be stable and ready to be moved to its proper place in the kernel tree. Move it to drivers/usb/host and adjust its Makefile, Kconfig and defconfig dependencies. Many thanks to the developers who made it happen. Signed-off-by: Artur Bujdoso Link: https://lore.kernel.org/r/Yo0HBIlSXOBM+//9@crux Signed-off-by: Greg Kroah-Hartman --- arch/mips/configs/cavium_octeon_defconfig | 2 +- drivers/staging/Kconfig | 2 -- drivers/staging/Makefile | 1 - drivers/staging/octeon-usb/Kconfig | 11 ----------- drivers/staging/octeon-usb/Makefile | 2 -- drivers/staging/octeon-usb/TODO | 8 -------- drivers/usb/host/Kconfig | 10 ++++++++++ drivers/usb/host/Makefile | 1 + drivers/{staging/octeon-usb => usb/host}/octeon-hcd.c | 0 drivers/{staging/octeon-usb => usb/host}/octeon-hcd.h | 0 10 files changed, 12 insertions(+), 25 deletions(-) delete mode 100644 drivers/staging/octeon-usb/Kconfig delete mode 100644 drivers/staging/octeon-usb/Makefile delete mode 100644 drivers/staging/octeon-usb/TODO rename drivers/{staging/octeon-usb => usb/host}/octeon-hcd.c (100%) rename drivers/{staging/octeon-usb => usb/host}/octeon-hcd.h (100%) diff --git a/arch/mips/configs/cavium_octeon_defconfig b/arch/mips/configs/cavium_octeon_defconfig index b6695367aa33..97ceaf080c0c 100644 --- a/arch/mips/configs/cavium_octeon_defconfig +++ b/arch/mips/configs/cavium_octeon_defconfig @@ -134,7 +134,7 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y CONFIG_STAGING=y CONFIG_OCTEON_ETHERNET=y -CONFIG_OCTEON_USB=y +CONFIG_USB_OCTEON_HCD=y # CONFIG_IOMMU_SUPPORT is not set CONFIG_RAS=y CONFIG_EXT4_FS=y diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 0a993c47273e..3bd80f9695ac 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -42,8 +42,6 @@ source "drivers/staging/rts5208/Kconfig" source "drivers/staging/octeon/Kconfig" -source "drivers/staging/octeon-usb/Kconfig" - source "drivers/staging/vt6655/Kconfig" source "drivers/staging/vt6656/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 2800ab9b2d1d..1d9ae39fea14 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -11,7 +11,6 @@ obj-$(CONFIG_R8712U) += rtl8712/ obj-$(CONFIG_R8188EU) += r8188eu/ obj-$(CONFIG_RTS5208) += rts5208/ obj-$(CONFIG_OCTEON_ETHERNET) += octeon/ -obj-$(CONFIG_OCTEON_USB) += octeon-usb/ obj-$(CONFIG_VT6655) += vt6655/ obj-$(CONFIG_VT6656) += vt6656/ obj-$(CONFIG_VME_BUS) += vme_user/ diff --git a/drivers/staging/octeon-usb/Kconfig b/drivers/staging/octeon-usb/Kconfig deleted file mode 100644 index 6a5d842ee0f2..000000000000 --- a/drivers/staging/octeon-usb/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config OCTEON_USB - tristate "Cavium Networks Octeon USB support" - depends on CAVIUM_OCTEON_SOC && USB - help - This driver supports USB host controller on some Cavium - Networks' products in the Octeon family. - - To compile this driver as a module, choose M here. The module - will be called octeon-hcd. - diff --git a/drivers/staging/octeon-usb/Makefile b/drivers/staging/octeon-usb/Makefile deleted file mode 100644 index 9873a0130ad5..000000000000 --- a/drivers/staging/octeon-usb/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-${CONFIG_OCTEON_USB} := octeon-hcd.o diff --git a/drivers/staging/octeon-usb/TODO b/drivers/staging/octeon-usb/TODO deleted file mode 100644 index 2b29acca5caa..000000000000 --- a/drivers/staging/octeon-usb/TODO +++ /dev/null @@ -1,8 +0,0 @@ -This driver is functional and has been tested on EdgeRouter Lite, -D-Link DSR-1000N and EBH5600 evaluation board with USB mass storage. - -TODO: - - kernel coding style - - checkpatch warnings - -Contact: Aaro Koskinen diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 682b3d2da623..fd9264cf6c87 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -306,6 +306,16 @@ config USB_EHCI_MV Dova, Armada 370 and Armada XP. See "Support for Marvell EBU on-chip EHCI USB controller" for those. +config USB_OCTEON_HCD + tristate "Cavium Networks Octeon USB support" + depends on CAVIUM_OCTEON_SOC && USB + help + This driver supports USB host controller on some Cavium + Networks' products in the Octeon family. + + To compile this driver as a module, choose M here. The module + will be called octeon-hcd. + config USB_CNS3XXX_EHCI bool "Cavium CNS3XXX EHCI Module (DEPRECATED)" depends on ARCH_CNS3XXX || COMPILE_TEST diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 2948983618fb..2c8a61be7e46 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_USB_OHCI_HCD_S3C2410) += ohci-s3c2410.o obj-$(CONFIG_USB_OHCI_HCD_LPC32XX) += ohci-nxp.o obj-$(CONFIG_USB_OHCI_HCD_PXA27X) += ohci-pxa27x.o obj-$(CONFIG_USB_OHCI_HCD_DAVINCI) += ohci-da8xx.o +obj-$(CONFIG_USB_OCTEON_HCD) += octeon-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_FHCI_HCD) += fhci.o diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/usb/host/octeon-hcd.c similarity index 100% rename from drivers/staging/octeon-usb/octeon-hcd.c rename to drivers/usb/host/octeon-hcd.c diff --git a/drivers/staging/octeon-usb/octeon-hcd.h b/drivers/usb/host/octeon-hcd.h similarity index 100% rename from drivers/staging/octeon-usb/octeon-hcd.h rename to drivers/usb/host/octeon-hcd.h From d3bb436deb78478bde129a322ca2f6e75716f4de Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 9 May 2022 20:21:29 +0300 Subject: [PATCH 0597/1436] gpio: pch: Use dev_err_probe() Simplify the error path in ->probe() a bit by using dev_err_probe(). While at it, correct the messages since the called function were changed in the past. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-pch.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 3a0bd8795741..dfd651e04831 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -357,16 +357,12 @@ static int pch_gpio_probe(struct pci_dev *pdev, chip->dev = dev; ret = pcim_enable_device(pdev); - if (ret) { - dev_err(dev, "pci_enable_device FAILED"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to enable PCI device\n"); ret = pcim_iomap_regions(pdev, BIT(1), KBUILD_MODNAME); - if (ret) { - dev_err(dev, "pci_request_regions FAILED-%d", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to request and map PCI regions\n"); chip->base = pcim_iomap_table(pdev)[1]; chip->ioh = id->driver_data; @@ -376,10 +372,8 @@ static int pch_gpio_probe(struct pci_dev *pdev, pch_gpio_setup(chip); ret = devm_gpiochip_add_data(dev, &chip->gpio, chip); - if (ret) { - dev_err(dev, "PCH gpio: Failed to register GPIO\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to register GPIO\n"); irq_base = devm_irq_alloc_descs(dev, -1, 0, gpio_pins[chip->ioh], NUMA_NO_NODE); @@ -396,10 +390,8 @@ static int pch_gpio_probe(struct pci_dev *pdev, ret = devm_request_irq(dev, pdev->irq, pch_gpio_handler, IRQF_SHARED, KBUILD_MODNAME, chip); - if (ret) { - dev_err(dev, "request_irq failed\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to request IRQ\n"); return pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]); } From b65bb2c148913c4020d06c9798e5e1bc18105f4f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 1 Jun 2022 20:10:13 +0300 Subject: [PATCH 0598/1436] gpio: pch: Change PCI device macros Use PCI_DEVICE_DATA macro. No functional changes are expected. Signed-off-by: Andy Shevchenko --- drivers/gpio/gpio-pch.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index dfd651e04831..ee37ecb615cb 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -37,6 +37,11 @@ struct pch_regs { u32 reset; }; +#define PCI_DEVICE_ID_INTEL_EG20T_PCH 0x8803 +#define PCI_DEVICE_ID_ROHM_ML7223m_IOH 0x8014 +#define PCI_DEVICE_ID_ROHM_ML7223n_IOH 0x8043 +#define PCI_DEVICE_ID_ROHM_EG20T_PCH 0x8803 + enum pch_type_t { INTEL_EG20T_PCH, OKISEMI_ML7223m_IOH, /* LAPIS Semiconductor ML7223 IOH PCIe Bus-m */ @@ -425,15 +430,11 @@ static int __maybe_unused pch_gpio_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume); static const struct pci_device_id pch_gpio_pcidev_id[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803), - .driver_data = INTEL_EG20T_PCH }, - { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014), - .driver_data = OKISEMI_ML7223m_IOH }, - { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043), - .driver_data = OKISEMI_ML7223n_IOH }, - { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8803), - .driver_data = INTEL_EG20T_PCH }, - { 0, } + { PCI_DEVICE_DATA(INTEL, EG20T_PCH, INTEL_EG20T_PCH) }, + { PCI_DEVICE_DATA(ROHM, ML7223m_IOH, OKISEMI_ML7223m_IOH) }, + { PCI_DEVICE_DATA(ROHM, ML7223n_IOH, OKISEMI_ML7223n_IOH) }, + { PCI_DEVICE_DATA(ROHM, EG20T_PCH, INTEL_EG20T_PCH) }, + { } }; MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id); From 281aec87d09b6eb343632e1d6a5a4587569c1ac1 Mon Sep 17 00:00:00 2001 From: Amelie Delaunay Date: Tue, 21 Jun 2022 17:23:47 +0200 Subject: [PATCH 0599/1436] usb: host: ohci-platform: add TPL support The Target Peripheral List (TPL) is used to identify targeted devices during Embedded Host compliance testing. The user can add "tpl-support" in the device tree to enable it. Acked-by: Alan Stern Signed-off-by: Amelie Delaunay Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220621152350.145745-2-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-platform.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 47dfbfe9e519..0adae6265127 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "ohci.h" @@ -210,6 +211,8 @@ static int ohci_platform_probe(struct platform_device *dev) hcd->rsrc_start = res_mem->start; hcd->rsrc_len = resource_size(res_mem); + hcd->tpl_support = of_usb_host_tpl_support(dev->dev.of_node); + err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) goto err_power; From 401e9d73225a3a382d475de2234500f038434664 Mon Sep 17 00:00:00 2001 From: Amelie Delaunay Date: Tue, 21 Jun 2022 17:23:48 +0200 Subject: [PATCH 0600/1436] usb: host: ehci-platform: add TPL support The Target Peripheral List (TPL) is used to identify targeted devices during Embedded Host compliance testing. The user can add "tpl-support" in the device tree to enable it. Acked-by: Alan Stern Signed-off-by: Amelie Delaunay Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220621152350.145745-3-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-platform.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index f343967443e2..6924f0316e9a 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -370,6 +370,8 @@ static int ehci_platform_probe(struct platform_device *dev) hcd->rsrc_start = res_mem->start; hcd->rsrc_len = resource_size(res_mem); + hcd->tpl_support = of_usb_host_tpl_support(dev->dev.of_node); + err = usb_add_hcd(hcd, irq, IRQF_SHARED); if (err) goto err_power; From 54bd6c9a3b7b1ccb34a4d6ab64c4c53469c6aacd Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 21 Jun 2022 17:23:49 +0200 Subject: [PATCH 0601/1436] dt-bindings: usb: dwc2: document TPL support The target peripheral list (TPL) is used to identify targeted devices during Embedded Host compliance testing. The user can add "tpl-support" in the device tree to enable it. Document TPL support as described in usb-hcd.yaml. Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220621152350.145745-4-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/dwc2.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml index 8d22a9843ba5..1bfbc6ef16eb 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.yaml +++ b/Documentation/devicetree/bindings/usb/dwc2.yaml @@ -11,6 +11,7 @@ maintainers: allOf: - $ref: usb-drd.yaml# + - $ref: usb-hcd.yaml# properties: compatible: @@ -161,6 +162,8 @@ properties: property is used. $ref: /schemas/graph.yaml#/properties/port + tpl-support: true + dependencies: port: [ usb-role-switch ] role-switch-default-mode: [ usb-role-switch ] From 77515ebaf01920e2db49e04672ef669a7c2907f2 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Tue, 7 Jun 2022 11:26:25 +0800 Subject: [PATCH 0602/1436] devcoredump: remove the useless gfp_t parameter in dev_coredumpv and dev_coredumpm The dev_coredumpv() and dev_coredumpm() could not be used in atomic context, because they call kvasprintf_const() and kstrdup() with GFP_KERNEL parameter. The process is shown below: dev_coredumpv(.., gfp_t gfp) dev_coredumpm(.., gfp_t gfp) dev_set_name kobject_set_name_vargs kvasprintf_const(GFP_KERNEL, ...); //may sleep kstrdup(s, GFP_KERNEL); //may sleep This patch removes gfp_t parameter of dev_coredumpv() and dev_coredumpm() and changes the gfp_t parameter of kzalloc() in dev_coredumpm() to GFP_KERNEL in order to show they could not be used in atomic context. Fixes: 833c95456a70 ("device coredump: add new device coredump class") Reviewed-by: Brian Norris Reviewed-by: Johannes Berg Signed-off-by: Duoming Zhou Link: https://lore.kernel.org/r/df72af3b1862bac7d8e793d1f3931857d3779dfd.1654569290.git.duoming@zju.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/base/devcoredump.c | 16 ++++++---------- drivers/bluetooth/btmrvl_sdio.c | 2 +- drivers/bluetooth/hci_qca.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_dump.c | 2 +- drivers/gpu/drm/msm/disp/msm_disp_snapshot.c | 4 ++-- drivers/gpu/drm/msm/msm_gpu.c | 4 ++-- drivers/media/platform/qcom/venus/core.c | 2 +- drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c | 2 +- drivers/net/wireless/ath/ath10k/coredump.c | 2 +- .../net/wireless/ath/wil6210/wil_crash_dump.c | 2 +- .../wireless/broadcom/brcm80211/brcmfmac/debug.c | 2 +- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 6 ++---- drivers/net/wireless/marvell/mwifiex/main.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 3 +-- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 3 +-- drivers/net/wireless/realtek/rtw88/main.c | 2 +- drivers/net/wireless/realtek/rtw89/ser.c | 2 +- drivers/remoteproc/qcom_q6v5_mss.c | 2 +- drivers/remoteproc/remoteproc_coredump.c | 8 ++++---- include/drm/drm_print.h | 2 +- include/linux/devcoredump.h | 13 ++++++------- sound/soc/intel/avs/apl.c | 2 +- sound/soc/intel/avs/skl.c | 2 +- sound/soc/intel/catpt/dsp.c | 2 +- 24 files changed, 40 insertions(+), 50 deletions(-) diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index f4d794d6bb85..8535f0bd5dfb 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -173,15 +173,13 @@ static void devcd_freev(void *data) * @dev: the struct device for the crashed device * @data: vmalloc data containing the device coredump * @datalen: length of the data - * @gfp: allocation flags * * This function takes ownership of the vmalloc'ed data and will free * it when it is no longer used. See dev_coredumpm() for more information. */ -void dev_coredumpv(struct device *dev, void *data, size_t datalen, - gfp_t gfp) +void dev_coredumpv(struct device *dev, void *data, size_t datalen) { - dev_coredumpm(dev, NULL, data, datalen, gfp, devcd_readv, devcd_freev); + dev_coredumpm(dev, NULL, data, datalen, devcd_readv, devcd_freev); } EXPORT_SYMBOL_GPL(dev_coredumpv); @@ -236,7 +234,6 @@ static ssize_t devcd_read_from_sgtable(char *buffer, loff_t offset, * @owner: the module that contains the read/free functions, use %THIS_MODULE * @data: data cookie for the @read/@free functions * @datalen: length of the data - * @gfp: allocation flags * @read: function to read from the given buffer * @free: function to free the given buffer * @@ -246,7 +243,7 @@ static ssize_t devcd_read_from_sgtable(char *buffer, loff_t offset, * function will be called to free the data. */ void dev_coredumpm(struct device *dev, struct module *owner, - void *data, size_t datalen, gfp_t gfp, + void *data, size_t datalen, ssize_t (*read)(char *buffer, loff_t offset, size_t count, void *data, size_t datalen), void (*free)(void *data)) @@ -268,7 +265,7 @@ void dev_coredumpm(struct device *dev, struct module *owner, if (!try_module_get(owner)) goto free; - devcd = kzalloc(sizeof(*devcd), gfp); + devcd = kzalloc(sizeof(*devcd), GFP_KERNEL); if (!devcd) goto put_module; @@ -318,7 +315,6 @@ EXPORT_SYMBOL_GPL(dev_coredumpm); * @dev: the struct device for the crashed device * @table: the dump data * @datalen: length of the data - * @gfp: allocation flags * * Creates a new device coredump for the given device. If a previous one hasn't * been read yet, the new coredump is discarded. The data lifetime is determined @@ -326,9 +322,9 @@ EXPORT_SYMBOL_GPL(dev_coredumpm); * it will free the data. */ void dev_coredumpsg(struct device *dev, struct scatterlist *table, - size_t datalen, gfp_t gfp) + size_t datalen) { - dev_coredumpm(dev, NULL, table, datalen, gfp, devcd_read_from_sgtable, + dev_coredumpm(dev, NULL, table, datalen, devcd_read_from_sgtable, devcd_free_sgtable); } EXPORT_SYMBOL_GPL(dev_coredumpsg); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index b8ef66f89fc1..9b9728719db2 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1515,7 +1515,7 @@ done: /* fw_dump_data will be free in device coredump release function * after 5 min */ - dev_coredumpv(&card->func->dev, fw_dump_data, fw_dump_len, GFP_KERNEL); + dev_coredumpv(&card->func->dev, fw_dump_data, fw_dump_len); BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump end"); } diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index eab34e24d944..2e4074211ae9 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1120,7 +1120,7 @@ static void qca_controller_memdump(struct work_struct *work) qca_memdump->ram_dump_size); memdump_buf = qca_memdump->memdump_buf_head; dev_coredumpv(&hu->serdev->dev, memdump_buf, - qca_memdump->received_dump, GFP_KERNEL); + qca_memdump->received_dump); cancel_delayed_work(&qca->ctrl_memdump_timeout); kfree(qca->qca_memdump); qca->qca_memdump = NULL; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c index f418e0b75772..519fcb234b3e 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c @@ -225,5 +225,5 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit) etnaviv_core_dump_header(&iter, ETDUMP_BUF_END, iter.data); - dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start, GFP_KERNEL); + dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start); } diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c index e75b97127c0d..f057d294c30b 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c @@ -74,8 +74,8 @@ static void _msm_disp_snapshot_work(struct kthread_work *work) * If there is a codedump pending for the device, the dev_coredumpm() * will also free new coredump state. */ - dev_coredumpm(disp_state->dev, THIS_MODULE, disp_state, 0, GFP_KERNEL, - disp_devcoredump_read, msm_disp_state_free); + dev_coredumpm(disp_state->dev, THIS_MODULE, disp_state, 0, + disp_devcoredump_read, msm_disp_state_free); } void msm_disp_snapshot_state(struct drm_device *drm_dev) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index eb8a6663f309..30576ced0a0a 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -317,8 +317,8 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, gpu->crashstate = state; /* FIXME: Release the crashstate if this errors out? */ - dev_coredumpm(gpu->dev->dev, THIS_MODULE, gpu, 0, GFP_KERNEL, - msm_gpu_devcoredump_read, msm_gpu_devcoredump_free); + dev_coredumpm(gpu->dev->dev, THIS_MODULE, gpu, 0, + msm_gpu_devcoredump_read, msm_gpu_devcoredump_free); } #else static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 877eca125803..db84dfb3fb11 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -49,7 +49,7 @@ static void venus_coredump(struct venus_core *core) memcpy(data, mem_va, mem_size); memunmap(mem_va); - dev_coredumpv(dev, data, mem_size, GFP_KERNEL); + dev_coredumpv(dev, data, mem_size); } static void venus_event_notify(struct venus_core *core, u32 event) diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c index c991b30bc9f0..fa520ab7c960 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c @@ -281,5 +281,5 @@ void mcp251xfd_dump(const struct mcp251xfd_priv *priv) mcp251xfd_dump_end(priv, &iter); dev_coredumpv(&priv->spi->dev, iter.start, - iter.data - iter.start, GFP_KERNEL); + iter.data - iter.start); } diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index fe6b6f97a916..dc9237069921 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -1607,7 +1607,7 @@ int ath10k_coredump_submit(struct ath10k *ar) return -ENODATA; } - dev_coredumpv(ar->dev, dump, le32_to_cpu(dump->len), GFP_KERNEL); + dev_coredumpv(ar->dev, dump, le32_to_cpu(dump->len)); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c index 89c12cb2aaab..79299609dd62 100644 --- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c +++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c @@ -117,6 +117,6 @@ void wil_fw_core_dump(struct wil6210_priv *wil) /* fw_dump_data will be free in device coredump release function * after 5 min */ - dev_coredumpv(wil_to_dev(wil), fw_dump_data, fw_dump_size, GFP_KERNEL); + dev_coredumpv(wil_to_dev(wil), fw_dump_data, fw_dump_size); wil_info(wil, "fw core dumped, size %d bytes\n", fw_dump_size); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c index eecf8a38d94a..87f3652ef3bd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c @@ -37,7 +37,7 @@ int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data, return err; } - dev_coredumpv(bus->dev, dump, len + ramsize, GFP_KERNEL); + dev_coredumpv(bus->dev, dump, len + ramsize); return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index abf49022edbe..f2f7cf494a8c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2601,8 +2601,7 @@ static void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, fw_error_dump.trans_ptr->data, fw_error_dump.trans_ptr->len, fw_error_dump.fwrt_len); - dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len, - GFP_KERNEL); + dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len); } vfree(fw_error_dump.fwrt_ptr); vfree(fw_error_dump.trans_ptr); @@ -2647,8 +2646,7 @@ static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, entry->data, entry->size, offs); offs += entry->size; } - dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len, - GFP_KERNEL); + dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len); } iwl_dump_ini_list_free(&dump_list); } diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index ace7371c4773..26fef0ab1b0d 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1115,8 +1115,7 @@ void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter) */ mwifiex_dbg(adapter, MSG, "== mwifiex dump information to /sys/class/devcoredump start\n"); - dev_coredumpv(adapter->dev, adapter->devdump_data, adapter->devdump_len, - GFP_KERNEL); + dev_coredumpv(adapter->dev, adapter->devdump_data, adapter->devdump_len); mwifiex_dbg(adapter, MSG, "== mwifiex dump information to /sys/class/devcoredump end\n"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index bd687f7de628..5336fe8c668d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -2421,6 +2421,5 @@ void mt7615_coredump_work(struct work_struct *work) dev_kfree_skb(skb); } - dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, - GFP_KERNEL); + dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index a630ddbf19e5..cac284f95ce0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1630,8 +1630,7 @@ void mt7921_coredump_work(struct work_struct *work) } if (dump) - dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, - GFP_KERNEL); + dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ); mt7921_reset(&dev->mt76); } diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index efabd5b1bf5b..a276544cecdd 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -414,7 +414,7 @@ static void rtw_fwcd_dump(struct rtw_dev *rtwdev) * framework. Note that a new dump will be discarded if a previous one * hasn't been released yet. */ - dev_coredumpv(rtwdev->dev, desc->data, desc->size, GFP_KERNEL); + dev_coredumpv(rtwdev->dev, desc->data, desc->size); } static void rtw_fwcd_free(struct rtw_dev *rtwdev, bool free_self) diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index 9e95ed972710..d28fe01ad729 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -127,7 +127,7 @@ static void rtw89_ser_cd_send(struct rtw89_dev *rtwdev, * will be discarded if a previous one hasn't been released by * framework yet. */ - dev_coredumpv(rtwdev->dev, buf, sizeof(*buf), GFP_KERNEL); + dev_coredumpv(rtwdev->dev, buf, sizeof(*buf)); } static void rtw89_ser_cd_free(struct rtw89_dev *rtwdev, diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index af217de75e4d..813d87faef6c 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -597,7 +597,7 @@ static void q6v5_dump_mba_logs(struct q6v5 *qproc) data = vmalloc(MBA_LOG_SIZE); if (data) { memcpy(data, mba_region, MBA_LOG_SIZE); - dev_coredumpv(&rproc->dev, data, MBA_LOG_SIZE, GFP_KERNEL); + dev_coredumpv(&rproc->dev, data, MBA_LOG_SIZE); } memunmap(mba_region); } diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index 4b093420d98a..cd55c2abd227 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -309,7 +309,7 @@ void rproc_coredump(struct rproc *rproc) phdr += elf_size_of_phdr(class); } if (dump_conf == RPROC_COREDUMP_ENABLED) { - dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL); + dev_coredumpv(&rproc->dev, data, data_size); return; } @@ -318,7 +318,7 @@ void rproc_coredump(struct rproc *rproc) dump_state.header = data; init_completion(&dump_state.dump_done); - dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, GFP_KERNEL, + dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, rproc_coredump_read, rproc_coredump_free); /* @@ -449,7 +449,7 @@ void rproc_coredump_using_sections(struct rproc *rproc) } if (dump_conf == RPROC_COREDUMP_ENABLED) { - dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL); + dev_coredumpv(&rproc->dev, data, data_size); return; } @@ -458,7 +458,7 @@ void rproc_coredump_using_sections(struct rproc *rproc) dump_state.header = data; init_completion(&dump_state.dump_done); - dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, GFP_KERNEL, + dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, rproc_coredump_read, rproc_coredump_free); /* Wait until the dump is read and free is called. Data is freed diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index 22fabdeed297..b41850366bcc 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -162,7 +162,7 @@ struct drm_print_iterator { * void makecoredump(...) * { * ... - * dev_coredumpm(dev, THIS_MODULE, data, 0, GFP_KERNEL, + * dev_coredumpm(dev, THIS_MODULE, data, 0, * coredump_read, ...) * } * diff --git a/include/linux/devcoredump.h b/include/linux/devcoredump.h index c008169ed2c6..c7d840d824c3 100644 --- a/include/linux/devcoredump.h +++ b/include/linux/devcoredump.h @@ -52,27 +52,26 @@ static inline void _devcd_free_sgtable(struct scatterlist *table) #ifdef CONFIG_DEV_COREDUMP -void dev_coredumpv(struct device *dev, void *data, size_t datalen, - gfp_t gfp); +void dev_coredumpv(struct device *dev, void *data, size_t datalen); void dev_coredumpm(struct device *dev, struct module *owner, - void *data, size_t datalen, gfp_t gfp, + void *data, size_t datalen, ssize_t (*read)(char *buffer, loff_t offset, size_t count, void *data, size_t datalen), void (*free)(void *data)); void dev_coredumpsg(struct device *dev, struct scatterlist *table, - size_t datalen, gfp_t gfp); + size_t datalen); #else static inline void dev_coredumpv(struct device *dev, void *data, - size_t datalen, gfp_t gfp) + size_t datalen) { vfree(data); } static inline void dev_coredumpm(struct device *dev, struct module *owner, - void *data, size_t datalen, gfp_t gfp, + void *data, size_t datalen, ssize_t (*read)(char *buffer, loff_t offset, size_t count, void *data, size_t datalen), void (*free)(void *data)) @@ -81,7 +80,7 @@ dev_coredumpm(struct device *dev, struct module *owner, } static inline void dev_coredumpsg(struct device *dev, struct scatterlist *table, - size_t datalen, gfp_t gfp) + size_t datalen) { _devcd_free_sgtable(table); } diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c index b8e2b23c9f64..1ff57f1a483d 100644 --- a/sound/soc/intel/avs/apl.c +++ b/sound/soc/intel/avs/apl.c @@ -164,7 +164,7 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) } while (offset < msg->ext.coredump.stack_dump_size); exit: - dev_coredumpv(adev->dev, dump, dump_size, GFP_KERNEL); + dev_coredumpv(adev->dev, dump, dump_size); return 0; } diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c index bda5ec7510fe..3413162768dc 100644 --- a/sound/soc/intel/avs/skl.c +++ b/sound/soc/intel/avs/skl.c @@ -88,7 +88,7 @@ static int skl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) return -ENOMEM; memcpy_fromio(dump, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE); - dev_coredumpv(adev->dev, dump, AVS_FW_REGS_SIZE, GFP_KERNEL); + dev_coredumpv(adev->dev, dump, AVS_FW_REGS_SIZE); return 0; } diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c index 346bec000306..d2afe9ff1e3a 100644 --- a/sound/soc/intel/catpt/dsp.c +++ b/sound/soc/intel/catpt/dsp.c @@ -539,7 +539,7 @@ int catpt_coredump(struct catpt_dev *cdev) pos += CATPT_DMA_REGS_SIZE; } - dev_coredumpv(cdev->dev, dump, dump_size, GFP_KERNEL); + dev_coredumpv(cdev->dev, dump, dump_size); return 0; } From a52ed4866d2b90dd5e4ae9dabd453f3ed8fa3cbc Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Tue, 7 Jun 2022 11:26:26 +0800 Subject: [PATCH 0603/1436] mwifiex: fix sleep in atomic context bugs caused by dev_coredumpv There are sleep in atomic context bugs when uploading device dump data in mwifiex. The root cause is that dev_coredumpv could not be used in atomic contexts, because it calls dev_set_name which include operations that may sleep. The call tree shows execution paths that could lead to bugs: (Interrupt context) fw_dump_timer_fn mwifiex_upload_device_dump dev_coredumpv(..., GFP_KERNEL) dev_coredumpm() kzalloc(sizeof(*devcd), gfp); //may sleep dev_set_name kobject_set_name_vargs kvasprintf_const(GFP_KERNEL, ...); //may sleep kstrdup(s, GFP_KERNEL); //may sleep The corresponding fail log is shown below: [ 135.275938] usb 1-1: == mwifiex dump information to /sys/class/devcoredump start [ 135.281029] BUG: sleeping function called from invalid context at include/linux/sched/mm.h:265 ... [ 135.293613] Call Trace: [ 135.293613] [ 135.293613] dump_stack_lvl+0x57/0x7d [ 135.293613] __might_resched.cold+0x138/0x173 [ 135.293613] ? dev_coredumpm+0xca/0x2e0 [ 135.293613] kmem_cache_alloc_trace+0x189/0x1f0 [ 135.293613] ? devcd_match_failing+0x30/0x30 [ 135.293613] dev_coredumpm+0xca/0x2e0 [ 135.293613] ? devcd_freev+0x10/0x10 [ 135.293613] dev_coredumpv+0x1c/0x20 [ 135.293613] ? devcd_match_failing+0x30/0x30 [ 135.293613] mwifiex_upload_device_dump+0x65/0xb0 [ 135.293613] ? mwifiex_dnld_fw+0x1b0/0x1b0 [ 135.293613] call_timer_fn+0x122/0x3d0 [ 135.293613] ? msleep_interruptible+0xb0/0xb0 [ 135.293613] ? lock_downgrade+0x3c0/0x3c0 [ 135.293613] ? __next_timer_interrupt+0x13c/0x160 [ 135.293613] ? lockdep_hardirqs_on_prepare+0xe/0x220 [ 135.293613] ? mwifiex_dnld_fw+0x1b0/0x1b0 [ 135.293613] __run_timers.part.0+0x3f8/0x540 [ 135.293613] ? call_timer_fn+0x3d0/0x3d0 [ 135.293613] ? arch_restore_msi_irqs+0x10/0x10 [ 135.293613] ? lapic_next_event+0x31/0x40 [ 135.293613] run_timer_softirq+0x4f/0xb0 [ 135.293613] __do_softirq+0x1c2/0x651 ... [ 135.293613] RIP: 0010:default_idle+0xb/0x10 [ 135.293613] RSP: 0018:ffff888006317e68 EFLAGS: 00000246 [ 135.293613] RAX: ffffffff82ad8d10 RBX: ffff888006301cc0 RCX: ffffffff82ac90e1 [ 135.293613] RDX: ffffed100d9ff1b4 RSI: ffffffff831ad140 RDI: ffffffff82ad8f20 [ 135.293613] RBP: 0000000000000003 R08: 0000000000000000 R09: ffff88806cff8d9b [ 135.293613] R10: ffffed100d9ff1b3 R11: 0000000000000001 R12: ffffffff84593410 [ 135.293613] R13: 0000000000000000 R14: 0000000000000000 R15: 1ffff11000c62fd2 ... [ 135.389205] usb 1-1: == mwifiex dump information to /sys/class/devcoredump end This patch uses delayed work to replace timer and moves the operations that may sleep into a delayed work in order to mitigate bugs, it was tested on Marvell 88W8801 chip whose port is usb and the firmware is usb8801_uapsta.bin. The following is the result after using delayed work to replace timer. [ 134.936453] usb 1-1: == mwifiex dump information to /sys/class/devcoredump start [ 135.043344] usb 1-1: == mwifiex dump information to /sys/class/devcoredump end As we can see, there is no bug now. Fixes: f5ecd02a8b20 ("mwifiex: device dump support for usb interface") Reviewed-by: Brian Norris Signed-off-by: Duoming Zhou Link: https://lore.kernel.org/r/b63b77fc84ed3e8a6bef02378e17c7c71a0bc3be.1654569290.git.duoming@zju.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/mwifiex/init.c | 9 +++++---- drivers/net/wireless/marvell/mwifiex/main.h | 3 ++- drivers/net/wireless/marvell/mwifiex/sta_event.c | 6 +++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index 88c72d1827a0..fca3ab948f6c 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -63,9 +63,10 @@ static void wakeup_timer_fn(struct timer_list *t) adapter->if_ops.card_reset(adapter); } -static void fw_dump_timer_fn(struct timer_list *t) +static void fw_dump_work(struct work_struct *work) { - struct mwifiex_adapter *adapter = from_timer(adapter, t, devdump_timer); + struct mwifiex_adapter *adapter = + container_of(work, struct mwifiex_adapter, devdump_work.work); mwifiex_upload_device_dump(adapter); } @@ -321,7 +322,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->active_scan_triggered = false; timer_setup(&adapter->wakeup_timer, wakeup_timer_fn, 0); adapter->devdump_len = 0; - timer_setup(&adapter->devdump_timer, fw_dump_timer_fn, 0); + INIT_DELAYED_WORK(&adapter->devdump_work, fw_dump_work); } /* @@ -400,7 +401,7 @@ static void mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) { del_timer(&adapter->wakeup_timer); - del_timer_sync(&adapter->devdump_timer); + cancel_delayed_work_sync(&adapter->devdump_work); mwifiex_cancel_all_pending_cmd(adapter); wake_up_interruptible(&adapter->cmd_wait_q.wait); wake_up_interruptible(&adapter->hs_activate_wait_q); diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 332dd1c8db35..5d8646f16162 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -49,6 +49,7 @@ #include #include #include +#include #include "decl.h" #include "ioctl.h" @@ -1055,7 +1056,7 @@ struct mwifiex_adapter { /* Device dump data/length */ void *devdump_data; int devdump_len; - struct timer_list devdump_timer; + struct delayed_work devdump_work; bool ignore_btcoex_events; }; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index 7d42c5d2dbf6..4d93386494c5 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -623,8 +623,8 @@ mwifiex_fw_dump_info_event(struct mwifiex_private *priv, * transmission event get lost, in this cornel case, * user would still get partial of the dump. */ - mod_timer(&adapter->devdump_timer, - jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S)); + schedule_delayed_work(&adapter->devdump_work, + msecs_to_jiffies(MWIFIEX_TIMER_10S)); } /* Overflow check */ @@ -643,7 +643,7 @@ mwifiex_fw_dump_info_event(struct mwifiex_private *priv, return; upload_dump: - del_timer_sync(&adapter->devdump_timer); + cancel_delayed_work_sync(&adapter->devdump_work); mwifiex_upload_device_dump(adapter); } From 2c8845fe9342b8801185b4c1b9261c532901fafd Mon Sep 17 00:00:00 2001 From: Amelie Delaunay Date: Tue, 21 Jun 2022 17:23:50 +0200 Subject: [PATCH 0604/1436] usb: dwc2: host: add TPL support The Target Peripheral List (TPL) is used to identify targeted devices during Embedded Host compliance testing. The user can add "tpl-support" in the device tree to enable it. Signed-off-by: Amelie Delaunay Signed-off-by: Fabrice Gasnier Acked-by: Minas Harutyunyan Link: https://lore.kernel.org/r/20220621152350.145745-5-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 3f107a06817d..2c9613d0d395 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -52,6 +52,7 @@ #include #include +#include #include "core.h" #include "hcd.h" @@ -5339,6 +5340,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg) /* Don't support SG list at this point */ hcd->self.sg_tablesize = 0; + hcd->tpl_support = of_usb_host_tpl_support(hsotg->dev->of_node); + if (!IS_ERR_OR_NULL(hsotg->uphy)) otg_set_host(hsotg->uphy->otg, &hcd->self); From 7828466cff6b38c2a8ea7cc43958e3abe04342c2 Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Wed, 22 Jun 2022 14:21:13 +0800 Subject: [PATCH 0605/1436] USB: serial: use kmemdup instead of kmalloc + memcpy For code neat purpose, we can use kmemdup to replace kmalloc + memcpy. Signed-off-by: Slark Xiao Signed-off-by: Johan Hovold --- drivers/usb/serial/garmin_gps.c | 4 +--- drivers/usb/serial/opticon.c | 4 +--- drivers/usb/serial/sierra.c | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index e5c75944ebb7..f1a8d8343623 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -988,7 +988,7 @@ static int garmin_write_bulk(struct usb_serial_port *port, garmin_data_p->flags &= ~FLAGS_DROP_DATA; spin_unlock_irqrestore(&garmin_data_p->lock, flags); - buffer = kmalloc(count, GFP_ATOMIC); + buffer = kmemdup(buf, count, GFP_ATOMIC); if (!buffer) return -ENOMEM; @@ -998,8 +998,6 @@ static int garmin_write_bulk(struct usb_serial_port *port, return -ENOMEM; } - memcpy(buffer, buf, count); - usb_serial_debug_data(&port->dev, __func__, count, buffer); usb_fill_bulk_urb(urb, serial->dev, diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index aed28c35caff..e31a6d77da3a 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -208,7 +208,7 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, priv->outstanding_bytes += count; spin_unlock_irqrestore(&priv->lock, flags); - buffer = kmalloc(count, GFP_ATOMIC); + buffer = kmemdup(buf, count, GFP_ATOMIC); if (!buffer) goto error_no_buffer; @@ -216,8 +216,6 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, if (!urb) goto error_no_urb; - memcpy(buffer, buf, count); - usb_serial_debug_data(&port->dev, __func__, count, buffer); /* The connected devices do not have a bulk write endpoint, diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 9d56138133a9..525c7f888c90 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -453,7 +453,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, goto error_simple; } - buffer = kmalloc(writesize, GFP_ATOMIC); + buffer = kmemdup(buf, writesize, GFP_ATOMIC); if (!buffer) { retval = -ENOMEM; goto error_no_buffer; @@ -465,8 +465,6 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port, goto error_no_urb; } - memcpy(buffer, buf, writesize); - usb_serial_debug_data(&port->dev, __func__, writesize, buffer); usb_fill_bulk_urb(urb, serial->dev, From 04b3b6ae8be7603b22b0404f4ac81bd1f439be8b Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Tue, 21 Jun 2022 21:52:30 -0700 Subject: [PATCH 0606/1436] staging: r8188eu: Fixed a function declaration coding style issue Added an identifier name for function definition argument 'struct timer_list *' as per checkpatch.pl Note that for the same line checkpatch.pl will also complain "extern should be avoided in .c". I am not very familiar with the codebase so I decided not to move the declaration to a header file. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/778c21724752f2de136d82b31c9ffc2bf35ced55.1655872968.git.marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 36ea79586992..7e2f5c2f9111 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -24,7 +24,7 @@ static u8 rtw_rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -void rtw_signal_stat_timer_hdl(struct timer_list *); +void rtw_signal_stat_timer_hdl(struct timer_list *t); void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) { From dd875fb747998b704ab76a8bc8b24f25b1ec3370 Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Tue, 21 Jun 2022 21:52:31 -0700 Subject: [PATCH 0607/1436] staging: r8188eu: Fixed two brace coding style issues Removed two pairs of unnecessary curly braces as per checkpatch.pl Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/f08a494f324cf5a3b5ed73aab6b3a432cb1da67b.1655872968.git.marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 7e2f5c2f9111..38b7905dc88f 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -1365,13 +1365,12 @@ static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe) a_len -= nSubframe_Length; if (a_len != 0) { padding_len = 4 - ((nSubframe_Length + ETH_HLEN) & (4 - 1)); - if (padding_len == 4) { + if (padding_len == 4) padding_len = 0; - } - if (a_len < padding_len) { + if (a_len < padding_len) goto exit; - } + pdata += padding_len; a_len -= padding_len; } From 3ff13c76b04046cafce36625c619abca73e627f0 Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Tue, 21 Jun 2022 21:52:32 -0700 Subject: [PATCH 0608/1436] staging: r8188eu: Fixed two whitespace coding style issues Replaced spaces with tabs as per checkpatch.pl Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/68cb57799d9139740f94eed9080e2d08c522e74c.1655872968.git.marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 38b7905dc88f..d42ff210ee81 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -17,11 +17,11 @@ static u8 SNAP_ETH_TYPE_APPLETALK_AARP[2] = {0x80, 0xf3}; /* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ static u8 rtw_bridge_tunnel_header[] = { - 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; static u8 rtw_rfc1042_header[] = { - 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; void rtw_signal_stat_timer_hdl(struct timer_list *t); From c99c8bc93844c7eb2b167d26dce4a9d18be96f45 Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Tue, 21 Jun 2022 21:52:33 -0700 Subject: [PATCH 0609/1436] staging: r8188eu: Fixed comment style Fixed block comments style as per checkpatch.pl and kernel coding style guide. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/fe45dd24a6ffcb4902a5efacaae63028f7c7a68f.1655872968.git.marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index d42ff210ee81..14dd2344fa4b 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -204,12 +204,12 @@ int rtw_enqueue_recvframe(struct recv_frame *precvframe, struct __queue *queue) } /* -caller : defrag ; recvframe_chk_defrag in recv_thread (passive) -pframequeue: defrag_queue : will be accessed in recv_thread (passive) - -using spinlock to protect - -*/ + * caller : defrag ; recvframe_chk_defrag in recv_thread (passive) + * pframequeue: defrag_queue : will be accessed in recv_thread (passive) + * + * using spinlock to protect + * + */ void rtw_free_recvframe_queue(struct __queue *pframequeue, struct __queue *pfree_recv_queue) { @@ -1745,9 +1745,11 @@ static int recv_func(struct adapter *padapter, struct recv_frame *rframe) !psecuritypriv->busetkipkey) { rtw_enqueue_recvframe(rframe, &padapter->recvpriv.uc_swdec_pending_queue); if (recvpriv->free_recvframe_cnt < NR_RECVFRAME / 4) { - /* to prevent from recvframe starvation, + /* + * to prevent from recvframe starvation, * get recvframe from uc_swdec_pending_queue to - * free_recvframe_cnt */ + * free_recvframe_cnt + */ rframe = rtw_alloc_recvframe(&padapter->recvpriv.uc_swdec_pending_queue); if (rframe) goto do_posthandle; From 8821931e614d8ff2f58a4b06b3f2fecc66a462b8 Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Tue, 21 Jun 2022 21:52:34 -0700 Subject: [PATCH 0610/1436] staging: r8188eu: Fixed some blank line coding style issues Added blank lines after variable declarations as per checkpatch.pl Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/cf4d4f7a58c9ba4510bed6748f78491c91e3e6f3.1655872968.git.marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 14dd2344fa4b..cc91638a085d 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -237,6 +237,7 @@ u32 rtw_free_uc_swdec_pending_queue(struct adapter *adapter) { u32 cnt = 0; struct recv_frame *pending_frame; + while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) { rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue); cnt++; @@ -327,6 +328,7 @@ static struct recv_frame *decryptor(struct adapter *padapter, struct recv_frame if (prxattrib->encrypt > 0) { u8 *iv = precv_frame->rx_data + prxattrib->hdrlen; + prxattrib->key_index = (((iv[3]) >> 6) & 0x3); if (prxattrib->key_index > WEP_KEYS) { @@ -777,6 +779,7 @@ static int sta2ap_data_frame(struct adapter *adapter, } } else { u8 *myhwaddr = myid(&adapter->eeprompriv); + if (memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) { ret = RTW_RX_HANDLED; goto exit; @@ -1022,6 +1025,7 @@ static int validate_recv_frame(struct adapter *adapter, struct recv_frame *precv if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) { int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter)); + if (ch_set_idx >= 0) pmlmeext->channel_set[ch_set_idx].rx_count++; } @@ -1049,6 +1053,7 @@ static int validate_recv_frame(struct adapter *adapter, struct recv_frame *precv retval = validate_recv_data_frame(adapter, precv_frame); if (retval == _FAIL) { struct recv_priv *precvpriv = &adapter->recvpriv; + precvpriv->rx_drop++; } } @@ -1312,9 +1317,11 @@ static int amsdu_to_msdu(struct adapter *padapter, struct recv_frame *prframe) struct rx_pkt_attrib *pattrib; unsigned char *data_ptr; struct sk_buff *sub_skb, *subframes[MAX_SUBFRAME_COUNT]; + struct recv_priv *precvpriv = &padapter->recvpriv; struct __queue *pfree_recv_queue = &precvpriv->free_recv_queue; int ret = _SUCCESS; + nr_subframes = 0; pattrib = &prframe->attrib; From 6fe391dd5d87cb166bccc66dfb603e1f3e41db5a Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Fri, 3 Jun 2022 13:02:09 -0400 Subject: [PATCH 0611/1436] platform/x86: thinkpad-acpi: profile capabilities as integer Currently the active mode (PSC/MMC) is stored in an enum and queried throughout the driver. Other driver changes will enumerate additional submodes that are relevant to be tracked, so instead track PSC/MMC in a single integer variable. Co-developed-by: Mario Limonciello Signed-off-by: Mario Limonciello Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20220603170212.164963-1-markpearson@lenovo.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 45 +++++++++++----------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e6cb4a14cdd4..5d1e0a3a5c1e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10299,21 +10299,15 @@ static struct ibm_struct proxsensor_driver_data = { #define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 0) #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 1) -enum dytc_profile_funcmode { - DYTC_FUNCMODE_NONE = 0, - DYTC_FUNCMODE_MMC, - DYTC_FUNCMODE_PSC, -}; - -static enum dytc_profile_funcmode dytc_profile_available; static enum platform_profile_option dytc_current_profile; static atomic_t dytc_ignore_event = ATOMIC_INIT(0); static DEFINE_MUTEX(dytc_mutex); +static int dytc_capabilities; static bool dytc_mmc_get_available; static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile) { - if (dytc_profile_available == DYTC_FUNCMODE_MMC) { + if (dytc_capabilities & BIT(DYTC_FC_MMC)) { switch (dytcmode) { case DYTC_MODE_MMC_LOWPOWER: *profile = PLATFORM_PROFILE_LOW_POWER; @@ -10330,7 +10324,7 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p } return 0; } - if (dytc_profile_available == DYTC_FUNCMODE_PSC) { + if (dytc_capabilities & BIT(DYTC_FC_PSC)) { switch (dytcmode) { case DYTC_MODE_PSC_LOWPOWER: *profile = PLATFORM_PROFILE_LOW_POWER; @@ -10352,21 +10346,21 @@ static int convert_profile_to_dytc(enum platform_profile_option profile, int *pe { switch (profile) { case PLATFORM_PROFILE_LOW_POWER: - if (dytc_profile_available == DYTC_FUNCMODE_MMC) + if (dytc_capabilities & BIT(DYTC_FC_MMC)) *perfmode = DYTC_MODE_MMC_LOWPOWER; - else if (dytc_profile_available == DYTC_FUNCMODE_PSC) + else if (dytc_capabilities & BIT(DYTC_FC_PSC)) *perfmode = DYTC_MODE_PSC_LOWPOWER; break; case PLATFORM_PROFILE_BALANCED: - if (dytc_profile_available == DYTC_FUNCMODE_MMC) + if (dytc_capabilities & BIT(DYTC_FC_MMC)) *perfmode = DYTC_MODE_MMC_BALANCE; - else if (dytc_profile_available == DYTC_FUNCMODE_PSC) + else if (dytc_capabilities & BIT(DYTC_FC_PSC)) *perfmode = DYTC_MODE_PSC_BALANCE; break; case PLATFORM_PROFILE_PERFORMANCE: - if (dytc_profile_available == DYTC_FUNCMODE_MMC) + if (dytc_capabilities & BIT(DYTC_FC_MMC)) *perfmode = DYTC_MODE_MMC_PERFORM; - else if (dytc_profile_available == DYTC_FUNCMODE_PSC) + else if (dytc_capabilities & BIT(DYTC_FC_PSC)) *perfmode = DYTC_MODE_PSC_PERFORM; break; default: /* Unknown profile */ @@ -10445,7 +10439,7 @@ static int dytc_profile_set(struct platform_profile_handler *pprof, if (err) goto unlock; - if (dytc_profile_available == DYTC_FUNCMODE_MMC) { + if (dytc_capabilities & BIT(DYTC_FC_MMC)) { if (profile == PLATFORM_PROFILE_BALANCED) { /* * To get back to balanced mode we need to issue a reset command. @@ -10464,7 +10458,7 @@ static int dytc_profile_set(struct platform_profile_handler *pprof, goto unlock; } } - if (dytc_profile_available == DYTC_FUNCMODE_PSC) { + if (dytc_capabilities & BIT(DYTC_FC_PSC)) { err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output); if (err) goto unlock; @@ -10483,12 +10477,12 @@ static void dytc_profile_refresh(void) int perfmode; mutex_lock(&dytc_mutex); - if (dytc_profile_available == DYTC_FUNCMODE_MMC) { + if (dytc_capabilities & BIT(DYTC_FC_MMC)) { if (dytc_mmc_get_available) err = dytc_command(DYTC_CMD_MMC_GET, &output); else err = dytc_cql_command(DYTC_CMD_GET, &output); - } else if (dytc_profile_available == DYTC_FUNCMODE_PSC) + } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) err = dytc_command(DYTC_CMD_GET, &output); mutex_unlock(&dytc_mutex); @@ -10517,7 +10511,6 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) set_bit(PLATFORM_PROFILE_BALANCED, dytc_profile.choices); set_bit(PLATFORM_PROFILE_PERFORMANCE, dytc_profile.choices); - dytc_profile_available = DYTC_FUNCMODE_NONE; err = dytc_command(DYTC_CMD_QUERY, &output); if (err) return err; @@ -10530,13 +10523,12 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) return -ENODEV; /* Check what capabilities are supported */ - err = dytc_command(DYTC_CMD_FUNC_CAP, &output); + err = dytc_command(DYTC_CMD_FUNC_CAP, &dytc_capabilities); if (err) return err; - if (output & BIT(DYTC_FC_MMC)) { /* MMC MODE */ - dytc_profile_available = DYTC_FUNCMODE_MMC; - + if (dytc_capabilities & BIT(DYTC_FC_MMC)) { /* MMC MODE */ + pr_debug("MMC is supported\n"); /* * Check if MMC_GET functionality available * Version > 6 and return success from MMC_GET command @@ -10547,8 +10539,8 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS)) dytc_mmc_get_available = true; } - } else if (output & BIT(DYTC_FC_PSC)) { /* PSC MODE */ - dytc_profile_available = DYTC_FUNCMODE_PSC; + } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) { /* PSC MODE */ + pr_debug("PSC is supported\n"); } else { dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n"); return -ENODEV; @@ -10574,7 +10566,6 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) static void dytc_profile_exit(void) { - dytc_profile_available = DYTC_FUNCMODE_NONE; platform_profile_remove(); } From 46dcbc61b739b0822855875e7dd8d8f471f50253 Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Fri, 3 Jun 2022 13:02:10 -0400 Subject: [PATCH 0612/1436] platform/x86: thinkpad-acpi: Add support for automatic mode transitions Some AMD Thinkpads support automatic mode transitions. The actual transition logic doesn't live in the `thinkpad_acpi` driver. The events to activate this logic come from this driver though. Populate these events when switching PSC power modes. Co-developed-by: Mario Limonciello Signed-off-by: Mario Limonciello Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20220603170212.164963-2-markpearson@lenovo.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 5d1e0a3a5c1e..2df290cee0a1 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10266,6 +10266,7 @@ static struct ibm_struct proxsensor_driver_data = { #define DYTC_CMD_FUNC_CAP 3 /* To get DYTC capabilities */ #define DYTC_FC_MMC 27 /* MMC Mode supported */ #define DYTC_FC_PSC 29 /* PSC Mode supported */ +#define DYTC_FC_AMT 31 /* AMT mode supported */ #define DYTC_GET_FUNCTION_BIT 8 /* Bits 8-11 - function setting */ #define DYTC_GET_MODE_BIT 12 /* Bits 12-15 - mode setting */ @@ -10278,6 +10279,10 @@ static struct ibm_struct proxsensor_driver_data = { #define DYTC_FUNCTION_CQL 1 /* Function = 1, lap mode */ #define DYTC_FUNCTION_MMC 11 /* Function = 11, MMC mode */ #define DYTC_FUNCTION_PSC 13 /* Function = 13, PSC mode */ +#define DYTC_FUNCTION_AMT 15 /* Function = 15, AMT mode */ + +#define DYTC_MODE_AMT_ENABLE 0x1 /* Enable AMT (in balanced mode) */ +#define DYTC_MODE_AMT_DISABLE 0xF /* Disable AMT (in other modes) */ #define DYTC_MODE_MMC_PERFORM 2 /* High power mode aka performance */ #define DYTC_MODE_MMC_LOWPOWER 3 /* Low power mode */ @@ -10298,6 +10303,8 @@ static struct ibm_struct proxsensor_driver_data = { #define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 0) #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 1) +static int dytc_control_amt(bool enable); +static bool dytc_amt_active; static enum platform_profile_option dytc_current_profile; static atomic_t dytc_ignore_event = ATOMIC_INIT(0); @@ -10380,6 +10387,30 @@ static int dytc_profile_get(struct platform_profile_handler *pprof, return 0; } +static int dytc_control_amt(bool enable) +{ + int dummy; + int err; + int cmd; + + if (!(dytc_capabilities & BIT(DYTC_FC_AMT))) { + pr_warn("Attempting to toggle AMT on a system that doesn't advertise support\n"); + return -ENODEV; + } + + if (enable) + cmd = DYTC_SET_COMMAND(DYTC_FUNCTION_AMT, DYTC_MODE_AMT_ENABLE, enable); + else + cmd = DYTC_SET_COMMAND(DYTC_FUNCTION_AMT, DYTC_MODE_AMT_DISABLE, enable); + + pr_debug("%sabling AMT (cmd 0x%x)", enable ? "en":"dis", cmd); + err = dytc_command(cmd, &dummy); + if (err) + return err; + dytc_amt_active = enable; + return 0; +} + /* * Helper function - check if we are in CQL mode and if we are * - disable CQL, @@ -10462,6 +10493,9 @@ static int dytc_profile_set(struct platform_profile_handler *pprof, err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output); if (err) goto unlock; + /* system supports AMT, activate it when on balanced */ + if (dytc_capabilities & BIT(DYTC_FC_AMT)) + dytc_control_amt(profile == PLATFORM_PROFILE_BALANCED); } /* Success - update current profile */ dytc_current_profile = profile; From 867eb713180c73335447a9bceb6c4c4c3e9d47c4 Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Fri, 3 Jun 2022 13:02:11 -0400 Subject: [PATCH 0613/1436] platform/x86: thinkpad-acpi: Add support for hotkey 0x131a On some AMD platforms if you press FN+T it will toggle whether automatic mode transitions are active. Recognize this keycode and use it to toggle AMT. Co-developed-by: Mario Limonciello Signed-off-by: Mario Limonciello Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20220603170212.164963-3-markpearson@lenovo.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 2df290cee0a1..f11866225ef3 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -159,6 +159,7 @@ enum tpacpi_hkey_event_t { TP_HKEY_EV_VOL_DOWN = 0x1016, /* Volume down or unmute */ TP_HKEY_EV_VOL_MUTE = 0x1017, /* Mixer output mute */ TP_HKEY_EV_PRIVACYGUARD_TOGGLE = 0x130f, /* Toggle priv.guard on/off */ + TP_HKEY_EV_AMT_TOGGLE = 0x131a, /* Toggle AMT on/off */ /* Reasons for waking up from S3/S4 */ TP_HKEY_EV_WKUP_S3_UNDOCK = 0x2304, /* undock requested, S3 */ @@ -3735,6 +3736,7 @@ static bool hotkey_notify_extended_hotkey(const u32 hkey) switch (hkey) { case TP_HKEY_EV_PRIVACYGUARD_TOGGLE: + case TP_HKEY_EV_AMT_TOGGLE: tpacpi_driver_event(hkey); return true; } @@ -11038,6 +11040,15 @@ static void tpacpi_driver_event(const unsigned int hkey_event) if (changed) drm_privacy_screen_call_notifier_chain(lcdshadow_dev); } + if (hkey_event == TP_HKEY_EV_AMT_TOGGLE) { + /* If we're enabling AMT we need to force balanced mode */ + if (!dytc_amt_active) + /* This will also set AMT mode enabled */ + dytc_profile_set(NULL, PLATFORM_PROFILE_BALANCED); + else + dytc_control_amt(!dytc_amt_active); + } + } static void hotkey_driver_event(const unsigned int scancode) From 755b249250df1b612d982f3b702c831b26ecdf73 Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Fri, 3 Jun 2022 13:02:12 -0400 Subject: [PATCH 0614/1436] platform/x86: thinkpad-acpi: Enable AMT by default on supported systems By default the ACPI platform profile starts in balanced mode. On supported systems AMT is supposed to be enabled in balanced mode by default. When checking the capabilities during initialization, set up AMT to be enabled if it's supported. Co-developed-by: Mario Limonciello Signed-off-by: Mario Limonciello Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20220603170212.164963-4-markpearson@lenovo.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index f11866225ef3..ae819ece9900 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10597,6 +10597,11 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) /* Ensure initial values are correct */ dytc_profile_refresh(); + /* Set AMT correctly now we know current profile */ + if ((dytc_capabilities & BIT(DYTC_FC_PSC)) && + (dytc_capabilities & BIT(DYTC_FC_AMT))) + dytc_control_amt(dytc_current_profile == PLATFORM_PROFILE_BALANCED); + return 0; } From 441ffc52d640733adddcce7f9e50996ea59731f3 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Tue, 7 Jun 2022 20:46:32 +0200 Subject: [PATCH 0615/1436] platform/x86: acer-wmi: Use backlight helper Instead of retrieving the backlight brightness in struct backlight_properties manually, and then checking whether the backlight should be on at all, use backlight_get_brightness() which does all this and insulates this from future changes. Signed-off-by: Stephen Kitt Cc: "Lee, Chun-Yi" Cc: Hans de Goede Cc: Mark Gross Cc: platform-driver-x86@vger.kernel.org Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20220607184635.1127913-2-steve@sk2.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/acer-wmi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 9c6943e401a6..e0230ea0cb7e 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1615,12 +1615,7 @@ static int read_brightness(struct backlight_device *bd) static int update_bl_status(struct backlight_device *bd) { - int intensity = bd->props.brightness; - - if (bd->props.power != FB_BLANK_UNBLANK) - intensity = 0; - if (bd->props.fb_blank != FB_BLANK_UNBLANK) - intensity = 0; + int intensity = backlight_get_brightness(bd); set_u32(intensity, ACER_CAP_BRIGHTNESS); From 3096ab5b902a35a6dc2d154ab60bd6de7ac323ee Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Tue, 7 Jun 2022 20:46:33 +0200 Subject: [PATCH 0616/1436] platform/x86: apple-gmux: Use backlight helper Instead of retrieving the backlight brightness in struct backlight_properties manually, and then checking whether the backlight should be on at all, use backlight_get_brightness() which does all this and insulates this from future changes. Signed-off-by: Stephen Kitt Cc: Hans de Goede Cc: Mark Gross Cc: platform-driver-x86@vger.kernel.org Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20220607184635.1127913-3-steve@sk2.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/apple-gmux.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index 57553f9b4d1d..ffe98a18440b 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c @@ -291,10 +291,7 @@ static int gmux_get_brightness(struct backlight_device *bd) static int gmux_update_status(struct backlight_device *bd) { struct apple_gmux_data *gmux_data = bl_get_data(bd); - u32 brightness = bd->props.brightness; - - if (bd->props.state & BL_CORE_SUSPENDED) - return 0; + u32 brightness = backlight_get_brightness(bd); gmux_write32(gmux_data, GMUX_PORT_BRIGHTNESS, brightness); From 537c7933c8e4dbc0064bf3e84d3a36d92ea66952 Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Tue, 7 Jun 2022 20:46:34 +0200 Subject: [PATCH 0617/1436] platform/x86: compal-laptop: Use backlight helper Instead of manually checking the power state in struct backlight_properties, use backlight_is_blank(). Signed-off-by: Stephen Kitt Cc: Cezary Jackiewicz Cc: Hans de Goede Cc: Mark Gross Cc: platform-driver-x86@vger.kernel.org Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20220607184635.1127913-4-steve@sk2.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/compal-laptop.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index ab610376fdad..0942f50bd793 100644 --- a/drivers/platform/x86/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c @@ -324,9 +324,7 @@ static int bl_update_status(struct backlight_device *b) if (ret) return ret; - set_backlight_state((b->props.power == FB_BLANK_UNBLANK) - && !(b->props.state & BL_CORE_SUSPENDED) - && !(b->props.state & BL_CORE_FBBLANK)); + set_backlight_state(!backlight_is_blank(b)); return 0; } From 5b54b4d4b46348265bf1ceb001473f42c71d8e4a Mon Sep 17 00:00:00 2001 From: Stephen Kitt Date: Tue, 7 Jun 2022 20:46:35 +0200 Subject: [PATCH 0618/1436] platform/x86: thinkpad_acpi: Use backlight helper Instead of retrieving the backlight brightness in struct backlight_properties manually, and then checking whether the backlight should be on at all, use backlight_get_brightness() which does all this and insulates this from future changes. Signed-off-by: Stephen Kitt Cc: Henrique de Moraes Holschuh Cc: Hans de Goede Cc: Mark Gross Cc: ibm-acpi-devel@lists.sourceforge.net Cc: platform-driver-x86@vger.kernel.org Reviewed-by: Daniel Thompson Link: https://lore.kernel.org/r/20220607184635.1127913-5-steve@sk2.org Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index ae819ece9900..e23a5398ea3e 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -6798,10 +6798,7 @@ static int brightness_set(unsigned int value) static int brightness_update_status(struct backlight_device *bd) { - unsigned int level = - (bd->props.fb_blank == FB_BLANK_UNBLANK && - bd->props.power == FB_BLANK_UNBLANK) ? - bd->props.brightness : 0; + int level = backlight_get_brightness(bd); dbg_printk(TPACPI_DBG_BRGHT, "backlight: attempt to set level to %d\n", From ef233eafe5adc54ddc39a1b6cc483dddc744bf97 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Thu, 9 Jun 2022 01:02:12 +0530 Subject: [PATCH 0619/1436] platform/x86: Move AMD platform drivers to separate directory Currently, AMD supported platform drivers are grouped under generic "x86" folder structure. Move the current drivers (amd-pmc and amd_hsmp) to a separate directory. This would also mean the newer driver submissions to pdx86 subsystem in the future will also land in AMD specific directory. Reviewed-by: Naveen Krishna Chatradhi Tested-by: Suma Hegde Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220608193212.2827257-1-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- MAINTAINERS | 4 +-- drivers/platform/x86/Kconfig | 27 +--------------- drivers/platform/x86/Makefile | 3 +- drivers/platform/x86/amd/Kconfig | 31 +++++++++++++++++++ drivers/platform/x86/amd/Makefile | 10 ++++++ .../platform/x86/{amd_hsmp.c => amd/hsmp.c} | 0 drivers/platform/x86/{amd-pmc.c => amd/pmc.c} | 0 7 files changed, 45 insertions(+), 30 deletions(-) create mode 100644 drivers/platform/x86/amd/Kconfig create mode 100644 drivers/platform/x86/amd/Makefile rename drivers/platform/x86/{amd_hsmp.c => amd/hsmp.c} (100%) rename drivers/platform/x86/{amd-pmc.c => amd/pmc.c} (100%) diff --git a/MAINTAINERS b/MAINTAINERS index a6d3bd9d2a8d..2a34deb24594 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -996,7 +996,7 @@ AMD PMC DRIVER M: Shyam Sundar S K L: platform-driver-x86@vger.kernel.org S: Maintained -F: drivers/platform/x86/amd-pmc.* +F: drivers/platform/x86/amd/pmc.c AMD HSMP DRIVER M: Naveen Krishna Chatradhi @@ -1006,7 +1006,7 @@ S: Maintained F: Documentation/x86/amd_hsmp.rst F: arch/x86/include/asm/amd_hsmp.h F: arch/x86/include/uapi/asm/amd_hsmp.h -F: drivers/platform/x86/amd_hsmp.c +F: drivers/platform/x86/amd/hsmp.c AMD POWERPLAY AND SWSMU M: Evan Quan diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 85c396a43048..e7f10287a894 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -196,32 +196,7 @@ config ACER_WMI If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M here. -config AMD_PMC - tristate "AMD SoC PMC driver" - depends on ACPI && PCI && RTC_CLASS - help - The driver provides support for AMD Power Management Controller - primarily responsible for S2Idle transactions that are driven from - a platform firmware running on SMU. This driver also provides a debug - mechanism to investigate the S2Idle transactions and failures. - - Say Y or M here if you have a notebook powered by AMD RYZEN CPU/APU. - - If you choose to compile this driver as a module the module will be - called amd-pmc. - -config AMD_HSMP - tristate "AMD HSMP Driver" - depends on AMD_NB && X86_64 - help - The driver provides a way for user space tools to monitor and manage - system management functionality on EPYC server CPUs from AMD. - - Host System Management Port (HSMP) interface is a mailbox interface - between the x86 core and the System Management Unit (SMU) firmware. - - If you choose to compile this driver as a module the module will be - called amd_hsmp. +source "drivers/platform/x86/amd/Kconfig" config ADV_SWBUTTON tristate "Advantech ACPI Software Button Driver" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index cc2a74713313..a0e417c34a9b 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -23,8 +23,7 @@ obj-$(CONFIG_ACER_WIRELESS) += acer-wireless.o obj-$(CONFIG_ACER_WMI) += acer-wmi.o # AMD -obj-$(CONFIG_AMD_PMC) += amd-pmc.o -obj-$(CONFIG_AMD_HSMP) += amd_hsmp.o +obj-y += amd/ # Advantech obj-$(CONFIG_ADV_SWBUTTON) += adv_swbutton.o diff --git a/drivers/platform/x86/amd/Kconfig b/drivers/platform/x86/amd/Kconfig new file mode 100644 index 000000000000..c0d0a3c5170c --- /dev/null +++ b/drivers/platform/x86/amd/Kconfig @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# AMD x86 Platform Specific Drivers +# + +config AMD_PMC + tristate "AMD SoC PMC driver" + depends on ACPI && PCI && RTC_CLASS + help + The driver provides support for AMD Power Management Controller + primarily responsible for S2Idle transactions that are driven from + a platform firmware running on SMU. This driver also provides a debug + mechanism to investigate the S2Idle transactions and failures. + + Say Y or M here if you have a notebook powered by AMD RYZEN CPU/APU. + + If you choose to compile this driver as a module the module will be + called amd-pmc. + +config AMD_HSMP + tristate "AMD HSMP Driver" + depends on AMD_NB && X86_64 + help + The driver provides a way for user space tools to monitor and manage + system management functionality on EPYC server CPUs from AMD. + + Host System Management Port (HSMP) interface is a mailbox interface + between the x86 core and the System Management Unit (SMU) firmware. + + If you choose to compile this driver as a module the module will be + called amd_hsmp. diff --git a/drivers/platform/x86/amd/Makefile b/drivers/platform/x86/amd/Makefile new file mode 100644 index 000000000000..a03fbb08e808 --- /dev/null +++ b/drivers/platform/x86/amd/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for drivers/platform/x86/amd +# AMD x86 Platform-Specific Drivers +# + +amd-pmc-y := pmc.o +obj-$(CONFIG_AMD_PMC) += amd-pmc.o +amd_hsmp-y := hsmp.o +obj-$(CONFIG_AMD_HSMP) += amd_hsmp.o diff --git a/drivers/platform/x86/amd_hsmp.c b/drivers/platform/x86/amd/hsmp.c similarity index 100% rename from drivers/platform/x86/amd_hsmp.c rename to drivers/platform/x86/amd/hsmp.c diff --git a/drivers/platform/x86/amd-pmc.c b/drivers/platform/x86/amd/pmc.c similarity index 100% rename from drivers/platform/x86/amd-pmc.c rename to drivers/platform/x86/amd/pmc.c From 31a1e4a5c104d3b235d023ea754e22f43863d6c3 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 10 Jun 2022 14:41:58 +0900 Subject: [PATCH 0620/1436] platform/surface: avoid flush_scheduled_work() usage Use local wq in order to avoid flush_scheduled_work() usage. Signed-off-by: Tetsuo Handa Reviewed-by: Maximilian Luz Tested-by: Maximilian Luz Link: https://lore.kernel.org/r/63ec2d45-c67c-1134-f6d3-490c8ba67a01@I-love.SAKURA.ne.jp Signed-off-by: Hans de Goede --- .../platform/surface/surface_acpi_notify.c | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c index 7b758f8cc137..c0e12f0b9b79 100644 --- a/drivers/platform/surface/surface_acpi_notify.c +++ b/drivers/platform/surface/surface_acpi_notify.c @@ -37,6 +37,7 @@ struct san_data { #define to_san_data(ptr, member) \ container_of(ptr, struct san_data, member) +static struct workqueue_struct *san_wq; /* -- dGPU notifier interface. ---------------------------------------------- */ @@ -356,7 +357,7 @@ static u32 san_evt_bat_nf(struct ssam_event_notifier *nf, memcpy(&work->event, event, sizeof(struct ssam_event) + event->length); - schedule_delayed_work(&work->work, delay); + queue_delayed_work(san_wq, &work->work, delay); return SSAM_NOTIF_HANDLED; } @@ -861,7 +862,7 @@ static int san_remove(struct platform_device *pdev) * We have unregistered our event sources. Now we need to ensure that * all delayed works they may have spawned are run to completion. */ - flush_scheduled_work(); + flush_workqueue(san_wq); return 0; } @@ -881,7 +882,27 @@ static struct platform_driver surface_acpi_notify = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; -module_platform_driver(surface_acpi_notify); + +static int __init san_init(void) +{ + int ret; + + san_wq = alloc_workqueue("san_wq", 0, 0); + if (!san_wq) + return -ENOMEM; + ret = platform_driver_register(&surface_acpi_notify); + if (ret) + destroy_workqueue(san_wq); + return ret; +} +module_init(san_init); + +static void __exit san_exit(void) +{ + platform_driver_unregister(&surface_acpi_notify); + destroy_workqueue(san_wq); +} +module_exit(san_exit); MODULE_AUTHOR("Maximilian Luz "); MODULE_DESCRIPTION("Surface ACPI Notify driver for Surface System Aggregator Module"); From e244a46a529a9a4c43ae3a2b4bf613e260ec8f81 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 14 Jun 2022 21:41:17 +0200 Subject: [PATCH 0621/1436] platform/surface: aggregator: Reserve more event- and target-categories With the introduction of the Surface Laptop Studio, more event- and target categories have been added. Therefore, increase the number of reserved events and extend the enum of know target categories to accommodate this. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220614194117.4118897-1-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/aggregator/trace.h | 80 +++++++++++-------- include/linux/surface_aggregator/serial_hub.h | 75 +++++++++-------- 2 files changed, 85 insertions(+), 70 deletions(-) diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h index de64cf169060..cc9e73fbc18e 100644 --- a/drivers/platform/surface/aggregator/trace.h +++ b/drivers/platform/surface/aggregator/trace.h @@ -76,7 +76,7 @@ TRACE_DEFINE_ENUM(SSAM_SSH_TC_HID); TRACE_DEFINE_ENUM(SSAM_SSH_TC_TCH); TRACE_DEFINE_ENUM(SSAM_SSH_TC_BKL); TRACE_DEFINE_ENUM(SSAM_SSH_TC_TAM); -TRACE_DEFINE_ENUM(SSAM_SSH_TC_ACC); +TRACE_DEFINE_ENUM(SSAM_SSH_TC_ACC0); TRACE_DEFINE_ENUM(SSAM_SSH_TC_UFI); TRACE_DEFINE_ENUM(SSAM_SSH_TC_USC); TRACE_DEFINE_ENUM(SSAM_SSH_TC_PEN); @@ -85,6 +85,11 @@ TRACE_DEFINE_ENUM(SSAM_SSH_TC_AUD); TRACE_DEFINE_ENUM(SSAM_SSH_TC_SMC); TRACE_DEFINE_ENUM(SSAM_SSH_TC_KPD); TRACE_DEFINE_ENUM(SSAM_SSH_TC_REG); +TRACE_DEFINE_ENUM(SSAM_SSH_TC_SPT); +TRACE_DEFINE_ENUM(SSAM_SSH_TC_SYS); +TRACE_DEFINE_ENUM(SSAM_SSH_TC_ACC1); +TRACE_DEFINE_ENUM(SSAM_SSH_TC_SHB); +TRACE_DEFINE_ENUM(SSAM_SSH_TC_POS); #define SSAM_PTR_UID_LEN 9 #define SSAM_U8_FIELD_NOT_APPLICABLE ((u16)-1) @@ -229,40 +234,45 @@ static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p) #define ssam_show_ssh_tc(rqid) \ __print_symbolic(rqid, \ - { SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \ - { SSAM_SSH_TC_SAM, "SAM" }, \ - { SSAM_SSH_TC_BAT, "BAT" }, \ - { SSAM_SSH_TC_TMP, "TMP" }, \ - { SSAM_SSH_TC_PMC, "PMC" }, \ - { SSAM_SSH_TC_FAN, "FAN" }, \ - { SSAM_SSH_TC_PoM, "PoM" }, \ - { SSAM_SSH_TC_DBG, "DBG" }, \ - { SSAM_SSH_TC_KBD, "KBD" }, \ - { SSAM_SSH_TC_FWU, "FWU" }, \ - { SSAM_SSH_TC_UNI, "UNI" }, \ - { SSAM_SSH_TC_LPC, "LPC" }, \ - { SSAM_SSH_TC_TCL, "TCL" }, \ - { SSAM_SSH_TC_SFL, "SFL" }, \ - { SSAM_SSH_TC_KIP, "KIP" }, \ - { SSAM_SSH_TC_EXT, "EXT" }, \ - { SSAM_SSH_TC_BLD, "BLD" }, \ - { SSAM_SSH_TC_BAS, "BAS" }, \ - { SSAM_SSH_TC_SEN, "SEN" }, \ - { SSAM_SSH_TC_SRQ, "SRQ" }, \ - { SSAM_SSH_TC_MCU, "MCU" }, \ - { SSAM_SSH_TC_HID, "HID" }, \ - { SSAM_SSH_TC_TCH, "TCH" }, \ - { SSAM_SSH_TC_BKL, "BKL" }, \ - { SSAM_SSH_TC_TAM, "TAM" }, \ - { SSAM_SSH_TC_ACC, "ACC" }, \ - { SSAM_SSH_TC_UFI, "UFI" }, \ - { SSAM_SSH_TC_USC, "USC" }, \ - { SSAM_SSH_TC_PEN, "PEN" }, \ - { SSAM_SSH_TC_VID, "VID" }, \ - { SSAM_SSH_TC_AUD, "AUD" }, \ - { SSAM_SSH_TC_SMC, "SMC" }, \ - { SSAM_SSH_TC_KPD, "KPD" }, \ - { SSAM_SSH_TC_REG, "REG" } \ + { SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \ + { SSAM_SSH_TC_SAM, "SAM" }, \ + { SSAM_SSH_TC_BAT, "BAT" }, \ + { SSAM_SSH_TC_TMP, "TMP" }, \ + { SSAM_SSH_TC_PMC, "PMC" }, \ + { SSAM_SSH_TC_FAN, "FAN" }, \ + { SSAM_SSH_TC_PoM, "PoM" }, \ + { SSAM_SSH_TC_DBG, "DBG" }, \ + { SSAM_SSH_TC_KBD, "KBD" }, \ + { SSAM_SSH_TC_FWU, "FWU" }, \ + { SSAM_SSH_TC_UNI, "UNI" }, \ + { SSAM_SSH_TC_LPC, "LPC" }, \ + { SSAM_SSH_TC_TCL, "TCL" }, \ + { SSAM_SSH_TC_SFL, "SFL" }, \ + { SSAM_SSH_TC_KIP, "KIP" }, \ + { SSAM_SSH_TC_EXT, "EXT" }, \ + { SSAM_SSH_TC_BLD, "BLD" }, \ + { SSAM_SSH_TC_BAS, "BAS" }, \ + { SSAM_SSH_TC_SEN, "SEN" }, \ + { SSAM_SSH_TC_SRQ, "SRQ" }, \ + { SSAM_SSH_TC_MCU, "MCU" }, \ + { SSAM_SSH_TC_HID, "HID" }, \ + { SSAM_SSH_TC_TCH, "TCH" }, \ + { SSAM_SSH_TC_BKL, "BKL" }, \ + { SSAM_SSH_TC_TAM, "TAM" }, \ + { SSAM_SSH_TC_ACC0, "ACC0" }, \ + { SSAM_SSH_TC_UFI, "UFI" }, \ + { SSAM_SSH_TC_USC, "USC" }, \ + { SSAM_SSH_TC_PEN, "PEN" }, \ + { SSAM_SSH_TC_VID, "VID" }, \ + { SSAM_SSH_TC_AUD, "AUD" }, \ + { SSAM_SSH_TC_SMC, "SMC" }, \ + { SSAM_SSH_TC_KPD, "KPD" }, \ + { SSAM_SSH_TC_REG, "REG" }, \ + { SSAM_SSH_TC_SPT, "SPT" }, \ + { SSAM_SSH_TC_SYS, "SYS" }, \ + { SSAM_SSH_TC_ACC1, "ACC1" }, \ + { SSAM_SSH_TC_SHB, "SMB" }, \ + { SSAM_SSH_TC_POS, "POS" } \ ) DECLARE_EVENT_CLASS(ssam_frame_class, diff --git a/include/linux/surface_aggregator/serial_hub.h b/include/linux/surface_aggregator/serial_hub.h index 26b95ec12733..45501b6e54e8 100644 --- a/include/linux/surface_aggregator/serial_hub.h +++ b/include/linux/surface_aggregator/serial_hub.h @@ -201,7 +201,7 @@ static inline u16 ssh_crc(const u8 *buf, size_t len) * exception of zero, which is not an event ID. Thus, this is also the * absolute maximum number of event handlers that can be registered. */ -#define SSH_NUM_EVENTS 34 +#define SSH_NUM_EVENTS 38 /* * SSH_NUM_TARGETS - The number of communication targets used in the protocol. @@ -292,40 +292,45 @@ struct ssam_span { * Windows driver. */ enum ssam_ssh_tc { - /* Category 0x00 is invalid for EC use. */ - SSAM_SSH_TC_SAM = 0x01, /* Generic system functionality, real-time clock. */ - SSAM_SSH_TC_BAT = 0x02, /* Battery/power subsystem. */ - SSAM_SSH_TC_TMP = 0x03, /* Thermal subsystem. */ - SSAM_SSH_TC_PMC = 0x04, - SSAM_SSH_TC_FAN = 0x05, - SSAM_SSH_TC_PoM = 0x06, - SSAM_SSH_TC_DBG = 0x07, - SSAM_SSH_TC_KBD = 0x08, /* Legacy keyboard (Laptop 1/2). */ - SSAM_SSH_TC_FWU = 0x09, - SSAM_SSH_TC_UNI = 0x0a, - SSAM_SSH_TC_LPC = 0x0b, - SSAM_SSH_TC_TCL = 0x0c, - SSAM_SSH_TC_SFL = 0x0d, - SSAM_SSH_TC_KIP = 0x0e, /* Manages detachable peripherals (Pro X/8 keyboard cover) */ - SSAM_SSH_TC_EXT = 0x0f, - SSAM_SSH_TC_BLD = 0x10, - SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */ - SSAM_SSH_TC_SEN = 0x12, - SSAM_SSH_TC_SRQ = 0x13, - SSAM_SSH_TC_MCU = 0x14, - SSAM_SSH_TC_HID = 0x15, /* Generic HID input subsystem. */ - SSAM_SSH_TC_TCH = 0x16, - SSAM_SSH_TC_BKL = 0x17, - SSAM_SSH_TC_TAM = 0x18, - SSAM_SSH_TC_ACC = 0x19, - SSAM_SSH_TC_UFI = 0x1a, - SSAM_SSH_TC_USC = 0x1b, - SSAM_SSH_TC_PEN = 0x1c, - SSAM_SSH_TC_VID = 0x1d, - SSAM_SSH_TC_AUD = 0x1e, - SSAM_SSH_TC_SMC = 0x1f, - SSAM_SSH_TC_KPD = 0x20, - SSAM_SSH_TC_REG = 0x21, /* Extended event registry. */ + /* Category 0x00 is invalid for EC use. */ + SSAM_SSH_TC_SAM = 0x01, /* Generic system functionality, real-time clock. */ + SSAM_SSH_TC_BAT = 0x02, /* Battery/power subsystem. */ + SSAM_SSH_TC_TMP = 0x03, /* Thermal subsystem. */ + SSAM_SSH_TC_PMC = 0x04, + SSAM_SSH_TC_FAN = 0x05, + SSAM_SSH_TC_PoM = 0x06, + SSAM_SSH_TC_DBG = 0x07, + SSAM_SSH_TC_KBD = 0x08, /* Legacy keyboard (Laptop 1/2). */ + SSAM_SSH_TC_FWU = 0x09, + SSAM_SSH_TC_UNI = 0x0a, + SSAM_SSH_TC_LPC = 0x0b, + SSAM_SSH_TC_TCL = 0x0c, + SSAM_SSH_TC_SFL = 0x0d, + SSAM_SSH_TC_KIP = 0x0e, /* Manages detachable peripherals (Pro X/8 keyboard cover) */ + SSAM_SSH_TC_EXT = 0x0f, + SSAM_SSH_TC_BLD = 0x10, + SSAM_SSH_TC_BAS = 0x11, /* Detachment system (Surface Book 2/3). */ + SSAM_SSH_TC_SEN = 0x12, + SSAM_SSH_TC_SRQ = 0x13, + SSAM_SSH_TC_MCU = 0x14, + SSAM_SSH_TC_HID = 0x15, /* Generic HID input subsystem. */ + SSAM_SSH_TC_TCH = 0x16, + SSAM_SSH_TC_BKL = 0x17, + SSAM_SSH_TC_TAM = 0x18, + SSAM_SSH_TC_ACC0 = 0x19, + SSAM_SSH_TC_UFI = 0x1a, + SSAM_SSH_TC_USC = 0x1b, + SSAM_SSH_TC_PEN = 0x1c, + SSAM_SSH_TC_VID = 0x1d, + SSAM_SSH_TC_AUD = 0x1e, + SSAM_SSH_TC_SMC = 0x1f, + SSAM_SSH_TC_KPD = 0x20, + SSAM_SSH_TC_REG = 0x21, /* Extended event registry. */ + SSAM_SSH_TC_SPT = 0x22, + SSAM_SSH_TC_SYS = 0x23, + SSAM_SSH_TC_ACC1 = 0x24, + SSAM_SSH_TC_SHB = 0x25, + SSAM_SSH_TC_POS = 0x26, /* For obtaining Laptop Studio screen position. */ }; From 2325d4dd7321cd569f996c5d091f4f83efb25693 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 8 Jun 2022 22:45:16 +0000 Subject: [PATCH 0622/1436] KVM: selftests: Add MONITOR/MWAIT quirk test Add a test to verify the "MONITOR/MWAIT never fault" quirk, and as a bonus, also verify the related "MISC_ENABLES ignores ENABLE_MWAIT" quirk. If the "never fault" quirk is enabled, MONITOR/MWAIT should always be emulated as NOPs, even if they're reported as disabled in guest CPUID. Use the MISC_ENABLES quirk to coerce KVM into toggling the MWAIT CPUID enable, as KVM now disallows manually toggling CPUID bits after running the vCPU. Signed-off-by: Sean Christopherson Message-Id: <20220608224516.3788274-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/x86_64/monitor_mwait_test | Bin 1485656 -> 0 bytes .../selftests/kvm/x86_64/monitor_mwait_test.c | 137 ++++++++++++++++++ 4 files changed, 139 insertions(+) delete mode 100755 tools/testing/selftests/kvm/x86_64/monitor_mwait_test create mode 100644 tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index dd5c88c11059..f3c2f074b948 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -28,6 +28,7 @@ /x86_64/max_vcpuid_cap_test /x86_64/mmio_warning_test /x86_64/mmu_role_test +/x86_64/monitor_mwait_test /x86_64/platform_info_test /x86_64/pmu_event_filter_test /x86_64/set_boot_cpu_id diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index b52c130f7b2f..ad1634e5659f 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -84,6 +84,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/kvm_clock_test TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test TEST_GEN_PROGS_x86_64 += x86_64/mmu_role_test +TEST_GEN_PROGS_x86_64 += x86_64/monitor_mwait_test TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test TEST_GEN_PROGS_x86_64 += x86_64/pmu_event_filter_test TEST_GEN_PROGS_x86_64 += x86_64/set_boot_cpu_id diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test deleted file mode 100755 index 598b597e1eec1b15296043e2e174d1e0a1164ec7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1485656 zcmb<-^>JfjWMpQ50wxAK21W)3h6hp(U=aw(z#y?m49o`+4h$9yTnr8jsthV%wJab( zIELwf&<3m!2^h^F0O5n|082sn3<41KFj`TG8>|pUBkKd(=KzssaPS7JgV9$wAYOsd z$okkA7#K7>`M~NmBK=V4j3_Xd;YSIChUo*@1;PbP5b**gh&y4l0z{YrMsq;KSaC$P5gozL_7ms+z%q2fF}L{DjtC* zZV(DlAAlzQAP6GvfhK<779^Y<(8L!MLBh=fO?(5?Uj}I62SOm`YoLigfcjSfO*{eW zUkNnv3D9@}N5UvE8UmvsFd71*Aut*OqaiRF0;3@?8UjN!1U#DGaCjU)0CK%Y>wyxc z{}()(k8m7j_^FJxI-oB=-VXL? ze51g~z>wkrRqN5&q9Vb_z+iYF#iLtB71Y!8u$2A1hL54dE~T4ARf2(mq4hv1-!4%9 zlYgV=%{6=suVoDnfcYQzH;SGBDdq9#wcWplkKx6wV@wPlowB>v@G<;n-MEI2q1krZ z8a@VwQbmu>XNH&dgG@Qjx?l|-cr3-^IExCXkN;w^10zE>YcELs4@Ul0Pz)VstpaIe zU|{HG%>Ws9qLVdY4Ie|Pi^p-+aHv#Dw+O_Amr6PQ^V)*krrOSG3RYex?P_=l?96?Q z3=9lAPBAbrc=Xyztl?weXWb7P26(Z?ju8|RaBs7K{DRfnk5;33`{HUoh7ypsPpsx+ zc=7ls*xN@|gS@>9q?Wb$2UDq;NADJu1_lO(ooWoAAU3>ooOQ`+K5&2Eqx1Xc)nI3M z9B)zSU|?YQ|NsC07dMUA8JcaIK#EF5j=%j>`2T^Se}7#K=5J-YXTZ0dGrX@0@j z>CRFr?s425JgR~elHASuj6R*mU(9>K#n8^){DQIWBW6hQv%bFlof&58ZsJY#poyuU zp3}mub7*3!8$naaimvz12n2ygH;YO)L#K-h$G0O5rMe)lNB0imW3G>o1>_|&b3(>C zerJcIGtch*#Jl#vQv$&e@Z$Zi|NmdS0ufI^!~+m<8$?_K5f?$k84z(CL>vMUdw>1^ zPgbfABIFvfO#SnOfFED*fLzTEBA7tL-=F{gzxV+nK7)vNAmSy6cmg8sgNR!{|Njqo zaRp4C0|}f25l2A8eh{$>EVBi~Tn{2vfrzCbVgZPl4I-w2h>0Mg2Sl`kwKRgsYLGzL z&;S4V*x9^D+3g9w?F82^y;Q=(Sy8$;;r=dF=Bt{^vq)G;tb9p;y3a17snm4Si5G0ZX4F(edJx7`4hdaYcbI*Y&MJQD-Mt^ipF z2E%V2y)`NlFM3QF7(lh6gyAKReW0p{fq{wHqx0ws<4%x-i;9Ft=X;Ot2!$6$3qS%O zJv-p6eTobW-PIf~*mM{eT)MqE4FB)+2id;E!O@#xm%W2G!@dkhZwANapG*$?Q;vfg z8v%v~Ua+%4jMDJvEm1Le(XpI?A>J{s3D8IVuJ&-L)bvoiBVl-!(sA zacq9Z*y*Ce<9YBI+l%9e7#KV|k2p3zW#VtS1Fl4CR1ypi?37|)VDM}{C-8Z-M{kHq z!oJ1pG8|kw{~vczNdU!)PiKir#*0cRHU`IT8x_aSqc7fSGcy?ecWr&^xU<;7n;{Ss zN{%~rIC?YeWMO1r2ypCXQQ6f53ddOv-V6bT2OL9RoMd5O@Mu1wV0Z}}am_U@~+758#REoP#%m1OL?Hh6i38W@cb`S@!q;|NZJ9$4fYRGrahp%)qc8G&}I(s3Ri- zzq|_rgW+4x&Wmv#osT@4pL_@i@jQOu0+SVCwh5HoW|NrlBkoRT)SDi#BF%hGVSvr}Hr|#vX>an_nK(s$u}?-{Bw)QLPlZ@4#k12CyEGQU3qA7-C;W z{{R0!4d%(0-XI>_&l5sBe|G-e#p2-25WEjGpVIl;@Bp}p+WeFilzm@FFJ@ry+_~%4 zsa;$Q3=BTKqM#WopI%uI#m{(R1H)@(myQ$7e_8okKyB8R1Eo1cDK9B)IZ!GH>U>1U zB1M7=|F#p3oi}!>gEB6cgEuJUbL<1f@qUo=K>7V;$07y>n15jE6~V2`T_7C@)i2@} zF)+N$1^F1J-iEED8>R;|SG4PegEzzLS@7_&VdHPH`TzevOpQFmT#zaxbJ;-VivIuq ze*!3sAW3l3zyJUDgW94mR)AQb7U+w4AQs5oFQ$N4pfG#U1!94wuU<6#`~TnY+kOz+ z@Bk*Lid6DF`Z9ACA>%PUWfnx|2u|&%6SJS28I`Jb=Vlv`14tps&F%S zc0N7sqN1RiR*>kE{9s2WIJ!zyRQUy2R6uGbs&F%;b-Jji@C&-A2zWOCVJfrS4RRc) z9`fjJxeGGer}Mi<^I^t){7&8s9-XZg|3L*pz< zDht5$8kG%TdW#Au-SKPgQMtgtz~IpGzeL)j@d(H`q^bdKzejJ23aIyY+(ktK)KT>4 zbWu_8=yg#sIPRh%V*o1KJ6%*XUR>G3z|d{s*?H`Rl^QdHV>jRaT~Ij=!vmc@Dl9LW zMA;ZTJCDDZ^^=vsqxlVoXXg!%Zrdg0d<-7lAu0lnod@?BIC(P|9ti68Q4#U!d===@ z`Oq=^g_aK^C{ZiCPy`jWt#3;lc7Y-RTp90=$o6LN=;n+ropP%4c_wi|9?=W=+XHe6wNP9c$gW$ z>A1Jt!=tx0;YG0#sIOZb;L%%K@gfbx>293?@^0$^{uT~UvhJP=N>Co10v@fGN?1HP zoj5#>w}OPgrT%fSY7q0~t$(1l8l;j4_2~TjV*4%zhW(epIpkfpfZ>4`WwEeOwy|bp zK&m3Z<-^Ve5#9{DeAyTn_JM+D{|6^;h8K??feJAO#}LDBh6nclaPnpd4Su1w6Vz<0 zC@{RVk7XSLL+A0%qlO1wSO`Jl!eJLIE|w{Sg3NIzqq8@IW8)uvP6h@C{^{WM7BoJ% zSr`}sVDTa03~5V*yr}&H3AWDnFPL^PFt~I+0EOORu>CI-{{R0UYIp$T!=*dG4q=Kt z3~F$({|5yCxV{0UbhwLO)IpT7f(kFFA-Dhi|Bn;^Apd!G{xLid3brHog*QY?j!);K zear|yh6qCZ7_$@R$3sfY;C$uM`P^}*8OR6S%-^p=ym#=u{7xTG4FL+zeO@3*!vl^X zFXsJ*drx^gy7wIa{r^89)bIefo&)6ou!}$*da-Rg*t_MO&H~{6)eG1E|NplhC@Jvh z4(8~t7TCwQ4m5c2Vx0gRL#MOIi)}j~t~~le2I@-3ox#rD4B!^4XXk-#XOVr0ptuR> z4rPEix$}6?_v_&75peLmyy1ZtpMHVesu3Lv4Y`Hz#*KxCH^U31XjqzhVFAk1ko4ym zYItBLFR0BO5(>%39?fqmT)N#wJUX9ybUym*vAXkvOXqQL!wpopaTp#r&H^qXUwq() zgz=BJwpK83``1!0jB5ZVwI*%YPpHP96dtohLk6PnM{7bXTnK==Rv)!T8go z`6Z)=<+<`39+tm~E_*b;NB~teE({EZq3t7Nvq9y9W4KRmy@g|#XXig?j|ns&+MRFl z;?Xt+2A}R+29M6eo|f-RIbS+4GB8Z=>^$nxU2EXc`oARHv3ncH&o3$jU`3al0zCY% z6kT6IEqYiUM3jj?fBgUNaoiPD*FY+QAD~p*U8~@c{NaTR-0Va0_{{!=-R!wP{{Qc; z6#hKug$igi+I-F^cZL5Tn4QHY9<9^HLDVncc1&9^Ij!UKhwna2eSt;BnlQ z0W^5&aom-I0n`dvUI6Zx`E!gz)Uy zISem>ipv?GkZZkN`q;Di2#2rb)6zpeo$p@=`GP8>y$J#g3@_L~?9TTu@*uSs2ecM* zjD4BI%FKYAW*tL4JOA#V4=PJQ-TUS@91act7$v_oKl{^sjP-@DA|y+zg5uf&R84ow zf@!##Rg_(5$-@bE|T8wroj5ETxOP8Jo9)|31#zd=3p&cB|W-#k0dxElWV=yp-z z@ag>S-J4^};MHql@uDk>fx)vo%)_(uphxSaQni;i85kH4?Zs{<4o}OE9{f&D0v?@* zJV31nP^ZqLyJ&?+x7P*_#*d&f$kXy<`4vygk45Kwn7wXzYJT+XJmJ{wrvM&d?0o0b z`PfJEx5wpo9+zKuSRO0kckGUn@#uVEc**1YXAjNGKAq>idRe$VF24sWI1W+Z(|H1> zz@yhi`#)IjSZSSCuM0PXbG$Udqw|(e=P^*SoB0e>XO;4KGT!&K{KMZa`2YWZaKAzV zQapplNE~;3@bG5XsmjU#9%2FK_kEzTkrzo{{{MG1Jn3q9;HA_5|NnO~M0zvq>Sls9 zT2_GSB)wY<3=oMfxI_X-Li84>HRA&6&A-v;t`{*p&}pIqZb^2AsIY*#(0TNQ_C`=;21@x8rJyNmhkz$2 z-9ysq&ZnRuFi<-oz@?iTT*w(7cv1QpoTMy3eNW^L7Xze!;@f%DF~qa;3aAw5{2ttS z+N1eRMrVl%i%X}EipGoWVW9HPMTO(VSq?S^{yi6VfF>^ZT@QhZ%7c$sI*)Zv(uwwF z(7a}Ofxqn~69Yr%#~q--Hdn)wmmf60V03AH;nMlSk$>vJ%P$-m4|aZZy!_Cm^8~2o z^zig%*vZMvz~E!~0unnDpuRCY@M7Pm|Npy7WehL*bUrZr@7wv%amNXedS1{t%J**` zt(U-BVD-4+fv|lFUfv8Z+Cchz6?{4$d33uPfUWWJX7KHNxbK3OH-pFJS33on85lf! zLqz|3SYGH3m2u#oe7sXc1#B8*6v`Q7gsTjw6!z>q;K{%KsAq2t%YTnkovl}gzLYj<(KkX9+uaOt_J#cKHMqK%)kIne?f--!L}J5a13zV z5#Z;|;28Si+(&RUDP$gYZ#$8A@P#<2MPuR7>vELAr@JBo#FOv^Rn74H>e=`nR1iB_ z%9omfif_mNJd9u9f&nGKY>_I(DG#5?Xgg9ltZJCE(OVrF0fn*<%FlK%Mrf48fQtKn^M70Erm>_vkKB@$hIZQQ-i^J7{Q=!*K_bi#Nm0 zcF5p`tcy3pz7^iy3@)89Dh@9yKY#-D4Ts@@oxY$@33uFS=;F=bxZ{GiH^eI$96sI* z`)omiAsHY!ut0Z>O2G>okmha|6$g*zBL<*RTmF{KpdyyhE#l=W1_p-Ci>{q7H4i#o zerS1tzeV})|NoAcU%piM3m$@UVPJ4IJc;bM|GVIhGduutp1_M+?;*|uJI?TcBMHuP zcrh2O`G^51c);O=9B|-}1j&E{uDeEs#qqeC1}J!6EDd5{_~yXD$luD$!oc9#U8ez( ze$f{MsvF88K;>fRk8Tf+U7-5R@c)aWtf0=no5zbaYe2;hXdFOD43t1To9jIOJMQ#w z0hK@~HE#?vc=VMWoLKf*_<*})S^rrr`m{9SJ_(4F5}11a`*565zfWKHdy3X21LY-?Q7z1C$OF zz$u`+M#Tmk{g8kMhd3zhNf;h@k^2tR4hN0;GrOo5cqqH5I7G&Q6QgIRn+1PcFEazf z3khomhHg;l@yw_5l}G1s&rUZ5kIU~~JaA%Q=yp-j=&lv<>HGvP?HxPi96Q}ux?N>_ zJJUFzIY7X(+s(qW(+y-{4l^4AsQhv8^=8;v#SH3pId&d|go!^m&>+ROZ>#`l@YK<> z^QdRH>k3axH;$rbp#15$BfP3DjfW1}Sp(?eO(xc#-rL6co}P-Od~y&4)Qa zosj*Wy>$t`op}j9ozHxFQv*DYyJawdQu}eY0ub%dY3-MQA= z{2dEH%MNN(SYCAb!}EY+=MAJhaF7W!_;2so=@#%pR2Z801F$Fl9+bqd;Rj3nZ(oBV z(?`XiyGF$a+*nb7q*8Fo1t(Q-()H|)3wUwh_5c4K%rPno9?CH)2A-X9ph74Esd2+E z&j2b6Ily(TN9#8ae%E7$mppna{)5uHfJf_bkIotu1<<_7_Zx=)J3~}-KoSNXt>5@t z4*&Z9|K+-0ppg#HJi<56?z#w2P7rk9pK|O)$(R5C9Xs7L96OJ{eE1ur2$J4F0mpb5d|OAMafbrzod>%YD* zV`5_f6=0y5?iVM085p`lR5%R(`*!|uGd zl<&0+s6FS=&ER4AqC~(tLZI}s;s4h>(Eb#-Saa;W>9}JOsHW0j0gbPK9kFkvi#NlI zD=+{5-v`=y16KH=^gk20*Z@_$J9R+QRjmg+JC8s#90r#g;8~)%FF~EfT9M9M`y9bT zHol!XDiV&JF)9KtKK^56aO`wZ5qa@_8K}?(wHadtm>If-K@EkShAf~-z5|ZkE-E69 zJ1>Ch%m<(vFaRxKsozL$St^b%B09Z`5;`396Uj=eB^^Z&o$f7i~B zjyqoXc{A98M&))Ivp|~%`z-uHRRUy?&hS8n0Ve~)i+3;n|99;!Q4x9Z8_n0Jd!_vE1MTl|5+Kjtvx~G)GyZYL$X7yqAwLdeJRtK$wWsKicIP*3Cl*yMeduHFnUZax41-?jCBiHc)y{(n!+ zdysy%XRnByN9R4C&gVXiuV1J|GB7m1Wh{OP8hAu10MaISz{ihVq3zKC4iC$79{f%L z0v??gKtsJc9^D=*Jh}rmcrc#wXnw`$VR;QSesr$rvPZYW4G+x|9*iFj!{&=XNyD@A zBPb8UJ5CVCf;vrx|6gc>{B!{1j>C}j9v$MR&kmq)kL43AzH z#{Zs{2g_VMx`Q}8S}&D809gXEA;BNiG~F4*3QIE}J6@c81{yCq0BWZ|tpWA3x`PB> zF9P}3X@aNbNgu`&ka%=pa;>WM8}49ZoWokw1<^MaCT>s!a2e&A?^R_Ty=?iyBbJBS6+xd3;_ z0t^p?zIgN$lAn$>X9zGbFoI(BaM}b=`2y;S{Rs_z;qdDJf5(PBDj<0V{?>I23=F=# zIVuspy<1d3BR8P%_w0^k@MyhVQujh=F=%-5HMrXAJo=g!l8!tY!6J^`H7X(=owvY^ z7Q+KCuKr>LmoF3iy%~1aGeVms-OeoFxCWJrpg8(pEC4Pn{}*!vbTbEZyMkuuUuc3H z-aQ*^5vWnzdb@O{XY)}GU(2ujtvUby{|9*mv_#>sPv`R&yZ`*rhxtMr zG^*73-tb%O%Q-0wDDwxPg0=H6$nw{GApgCvUc|uAY{610*WUxXaOr#y>llMHzY5E}!5|}FyjuwB$R2&o4^OYnwG1q!Md08; zn7;idD?{gDkl_zp4d1pNaO9tI6yz8E1_p-iT80BX~^Vg&xQuM?Jco zL1GLq^cONPICj2t+#wL)&9HMJD+5C}!@f*cZ-(X{Ec{ar8UAnn`yUo}0gBfRA;rv# z3W)s@(XodoIEL=qu#V#ZXv7l~6`){|=&lz5^%B5~0zuPm951&000-|2P=C_?Jn-Vh!~g$52KaV@v>X117{Cge&Wwc`@E2sjNn8djM>haei$ZEo z8K?mwZr%(#&q57=w;Z(GK-Ckd<#6yV%Zr4E|Nr}RCL8#4KIqK00r?o3LXqaPJeuEV zr18H$V0eIElSKtIB((4GItd5ppyMM@x&hCozG(i&ie-R{!2>jS2pT*G&252F8psGx zB4gS2U>(l^P;->S@W2aKh;E6)jv?T&C6DGe0^Ri@*cD5BgM@McD4u_^LJBWv+sGE| z!+D?;G>s2H73&ihewP##4v*#|0xq2oKxG3WGC}R<<~JIK2SE1hdxYe#<18wW?uCzv zz>5`Mp94`VO>LifI1fk=BAU&NWD(E`o zzJdy-7wU6CH4kVNTQ3`=B4KDH$ZGMyOP?79#^# z*roHAN9X;0Q{6xV2QPB8Ky$GU48GkWD!#3kN;0AS8Biemc6&8|wRFDn?QW_7tXf#!-{XuymHji%h+w+v#kkQO6@XLq@R;U$mG`!7O_85n%Kr-K?5 z5mCOamrCcsCX-rSx@%N8!1j1_-Zwn3Z;u;jWbfCDi<%$cfSaj0}zq`#@q0rM{pZB3S9ZS77&ebl&%DK4#&-zwPada!p1C z-)=Qu%V#BGKAq1XraPs8T&SYrYx$-0l}Gate?e0wjypKq!42_^@S!zuL)_suNH!L^c$xrO#&iWb6aT{g z|NsBp)gs_VrAuc5i$~`n!vilWKY$CVrWv3qm)6^koi{;E22g@=+>sIJ&9L(vXcRUC zk{>{Q@z8E?yYk{KaE?#_RYLIo2&gR#x9|KvgngiX9mGCPh^lIm?+ucDp!^55 zFACMo2(DGO5V~>LmSvi&2h?2I`Irrq)?duM3F`ls%J_7CFuY{=->1_=W#>~i zP`}t9$eY0f>lBGkcZrI?zK$T!gviGi(KrA9cj^2Gnz1bajb3;ADtLAtkBIWT{LZKI zt8eEQPsV%v@(iAq@5;SBTHltG`u3X0cv`+Ied}ZSv`p5g^D#J`dUn?se_NVB#Sf z;Fh{)=Mj(Ax24@K-7YFTj@`a8`!)oD@|Q=qh>AzIty&--!;6!uXlY&`5SHf8@qyF) z{{TJ)aDw;geD`7&XjT04Q=k$T)Lsnt==|W>dEM|5r03;o_yo3K43uKK{bfA9f9&>G z@aX*D(R#^|f9esB%P%|`kGx=ZXJF`dmN7i()A`J!^M0=g!wUmY^7K~l>^$1-EaTH# zqVeCWH^<_?$K|)4m*07SW{@n8^S4_uf`%)1gGzKCP_}>fB0>uk2Bje$-C$7<(ERDA z7niiaA@JH39KIgiyFmpVRIW`MEC-&QeFd5(f#?LAckBfR*gXCg(0W0rKCsNY7kL^W zn@To8ZGwv4&;)g!Kr8xQI__Wy1`U4jZ~L*c9X^y35ey3R7Y5fsBeY<5Ky}J#Kzr_< zpkB$0U~dMH#$NE?*1iY9-VC4w`QpblPR;?1zL5o8OraSbZ23=eo7KL#2!c+qj~ z|9?;;ewI(?SMUh_J5UYt2oz!73Lc&BpkV?U(qF3$jztf~qn?aMJ)7S!mY#c=0I~=+ z9s(*4g28!^mh z4M^Oh+l#})@`DGzlb3);=P3`!Iw6!fdJoGJpmClLMVCF8oo+;XXnr`HHo>#=AY@A1 z@BnyH98wB{!|(qK|Er(^A7y<~x4#NxboufFP%gOq!lU^GBXao_()^zfvi=FY@+lN- zphxFd@XDv)&flO_P=*Jsj47hgeh4xP6Qzk#QRTEN3GppjIKUXTACmmfKT zHg50)eCI8X@3%pP=H*wQwAiS@zyKO$cv%D*m~~Mx zc+sx_VzsD%bAIdFQYC1Q6gm7s?gLHIy^IDW+XT15!{tpV%5)}>4-WnB^7l*Sz^MF1o8jd?6K-ud&EKc@ygn)Or7=UVV z$L61w{8J8a9ydJTz`yPP3)##6|AUPL1rdm$0b1tu5>!!x2fH_bjCu%~mPN^_FP>id z|NrGm&~m9z#~l|yia>iNK#hwpp`fZS*rW3@BqcS!;b{G~&jOJaR$co4f4>u`vpnG% zlm*&p(tHgx*6IpcA|Mdz&ERNxWG6c#v~=3%5eiC5)4&UZz~AY>)>l zC_#BJ9`-o+n$x3KCgOz|vdNlYlXuE7GBALQw}kdIL1sGcXn>jwYG>=Hyx_g`|Nn~> z&siDx_nZKCWcgiAG#_N_4gBBh_&GAJ`4>-_Z|6a9!{YLz=2wiZxA>2K=qSbEGi@|)LT{s?{$6tiCK$1q@Yj6{Z1DXyTV-N4-VPIg;ym z^Dmx~y_a9V-iy?_1oel)Jv$-GFdf4jJO6=}SDoD%zzACQ<=c5AwDaq}BzJEHaHj_} z5HjVsZ|eca9bWF<4E$3O(QI}R)JXX5)A_6O-3!lu|Nnb-9&3GDB4cg2v@Vj2{ zIQW>QyBV}h#qv;@M(0J%gW!S4?7Xh|-SShJe&2%Q6r)F{fKTT)pU&t1FMD>oarkup@&Jpv3V3$rad>u$sDS!fJRaQ~%?}wp zIA3~na)8|K*~#Y78Oq?%{NN9NOFYOE))@l)Et!mM z+oSV^NAn3rpUzSa&=iya$gpl#2FR>bD%jAHJP+#(ff5N&w+7szeDB-&<^ScEGr?=| z9TT(2@s`pFjbIJ$MCtI)8dJpJeptbmj2u%oFhJ%xEk|NC~Wemr$UEnu!Ahv6j;%L^qD;PMJIEbY-<0QN5= zLDYdA4R%ur=Qk!s{uWD+2q+8~L8X@*hzBaYIAH7TL2d8OgC5_MvI|_i! z4guR&0FDcY*=8WU-JpbZsbuXpCPt8AP*S@Ni8j!3+d!~#F3-+`p3Ns2eLDHTX|@v- z{9YWMoj)O>VE6KPbh9--VD#WT;nB(F(aq@5$>h_?2`QcqgY35U5a4gw3u1LvaDXN? zq2op1+$iAL$px8*f~3q-kTMXI1VGyk#5}qMK^e1?(WCj%pORn?YcB!*7EqFdtcd^c z@+i18aA9EZ?c{jb1Li=?_vsGf@aX*T(hDpGD!2RuUS@+i;QAC6Zl0YCAZ4{+8F2bz z2PFwm=8EyKt`y*JnFr1%g&^OShOS`bZ?*mR|Nmide09RyE8x-T!2wPq$nGrwxwpgy z=GIbB83F6hd3Hipzu16>c-RhmbhCSOGJ(RaMBKx=LZHMAl=%;Pbb{jJ1Gs$g>=Zx> zKd8hJ&`S2sLV=gDpk_40Gdv(On@=!$bTS?W-(nFH>TF`Q;?f?#-&chy-hxl9Wf|PZJ z3V3#Afbw$*7qqGYg%P-zX7K2Y1sBsLsh|o5vf$jKGXh)#dUU?`>3rbRc??nmg7y!4 zbccfXo3ValVk~j;><$osSp{D2*%`{=*_i=WF&|;o>&fu>StBCbK^yrzelj2!WTNb6jBK;^2Y|^XnIQs6t2w={*-Wn0>-jJ zpo9(NW6*ddD4q|Le8duNuOC6$BdrHY6k+}YX@|w1XE#`H>1&Wtpn&@h+ON6~)Pn{M z`+$2vpr-eW^qY`bxe(BBXt%S3M|U*`sDUfd?W_S>;iUmuApjCk0J)X-#ddI+1m5_e z;L%+z01;gX6&3L5Q~+fQNVnA@=&p`N3%5pe~UDzssUBJLLf%BFNcTbA&>4-0gujL4)D$taDH$7R+8$``2jgU zAM$_(!xxWEFAne?D^MZS?Zg49f_1<>d+$ewTftzn>MS?ht4Xs~VeAlpi#J&rqoXUAVp z*lCdF&9G}eBLl-e@fdH0{WoI08D5-U4qC_yt`|KzjXjRDfyS*~CW1^l?f~lXGQ11{ zaXJe)z~>lv90!f`FuVlKyFd(l2scn26pMAs85kfE=TRk6;S!(~cMvClb@(htnL(WZ zns50N+IbbUOa0|+288=8BLw(c4>N$K7VKj{!)7mZ%BR~|;(xJ1=c|1Na1}p!85umfi#ehq zK@DiW-cTmcs8}+%rOM#Z9W4M_?_}P5l*yx;8I*lxJS-zP_*s&QCs_ zCqdhYU#tNK(Gd<0kQNsP2GDphIHQ9C9GvyRIllBNILGt1Oa=9NJ8yzEC3Uth9WDV{kK_m*`0Tvs(;Fo3qIt5{hf)5u zIkdb34b8VK1)XK`Q=Y$lD+6c~@;%4y0FBGfnqM-uekv{I`~(^@cI*t$@aS|`@az>~ z^0d5Ib{tXy9RROFaA9EZ>2%@%ISlHk){_6Ap`PQf1!4AByL0fjW`T3V507qpkJkUC zuMuW|x~K@=P76?GYldfmd7!+Jw1j~HBGCw!s0K-R!X=vE68#_v1Gq#UTp}UPo8g7{ z5(WlHvALI@k>SOx4WQwFNPP`iKj84~m^@^`9;j{tozntJs7fB)0TLdT*NU`22M&2K zUiRqqmiMqcSEdCE@_QgZM902-25RR)%AIZpj@O5f%1g^@CHfw{c@I1~UwUZ1_RzfO z(dnV^Vk@{g8lm9P{9C?E+N1fk!f^-iP7jYxkl+yxSU7jy1P>Q^9CrY37Xc3%fug1v ztYoJLDBym;eY+DB44R9P_6LGy$vh$JpF6(>gA)d5tq#1s)*Y(RdI^%IJV2XiK}i#I zHU+Hy^XNPV^X!*yKMkMmGKJQYrJTN?73mS+RO%<;(d{bH{Odn|OFt;__xkWDcvv3f zZvnM$J-S^%iI~4-54dP@V1SqhX-9OsX|x{TZ#@ah3C(p14E!x@AQPL92!L`uXrAft z1dncC1#oo)+9(OK$fNnkeg5_|Q0J`qfPzP-tAt1MPx&%&kLH&O$6cXe=&SHj8C-%e zfX56yj=Mra545+f(^cao8>n9liLcIgQ2K*Mw;8x6>;X!&)@~dnuU~TEQx^l`rmm4v^$IgRKOo90ktejR5(B*12;S_KL8aQK9&#oTOWZUH2I(><1r-T zn|~_sw}RF$yq*SXcY1cd0WBD1@U(VO5#VpN1Q#C!#fqxoBSzzrji|3PW1^vTQL;4lK$A0YEM_*-B80~JR|<~1J?0MAjrhb66-m%f4a zD|mFfDtPv~uqk+Sy1_yM9s>9O{QtjG0hGnS+eyK7&kRt3a%?^W14QB^XrC!q;s8iu z?R=E#Ic)-{z5rDf9?j3d%cx&;gErHHGnIsg<>4Y@kKO=z56jEtTAeq$!!+Q7+^vU7 z4LJ{abiVHl)9`3^?Q-9epEf#{b3 z;Gnq&+5^J@3a=OOpd%6{>9J=3t!Jp`VBnu}0D18YD4l}(5v>PGLXeu`Q`rMprhEq)f&h(^w4N*x_UQFe@UZ+?&IK-w!2J}^7@OurP|;N` zs(B4u#&>?a{75-KgMaFQ!-fYA2kdM}_h#572Y2-WkgI*?qNOhnQ0aXUG?D;5Vb8Pk zOQ;99HTe6r4#@rBvFZCSO#lD?-*TXY8_NCm_y2#-<|B+A&2JeYQv;6Qj>wl@^6Y%) z+5GH*FXJogsDp8~Vas!+-AoT-OZ}|~$|Dc$| z@Fck91x~k}KODP5R5UI>XuVJ(`2B)M^E*bx3yz?pkvuw!IhqeLHvd#8z2&K0qN3o@ zc^@PO-jn76KFpTk#nT`E|2IFC_w7~DD^Ulz6FeDk{{`qgAV@fYR)M`Z_XiYC#~6Jr zpOxN)l^o#s^XYu{niu3QYc~P@Rxwb?-wCZjN?*V90~cptBW8a`@?z^{z8ytQ2k#*1;3@djryWR33VEx+{2SUhrW2;M4ifqtlt=#l>%kG@%WPA85Mx`WqH*;7C>b1qwH4x`33- zpb1Uz2?nt6{)d!4{-MRM9U^^He?@q`^%yvL{Ch17Z=ZR9)5ktE{UGxW?@R!tj|r&h zLuV#h`e=T`u@BUz1!tWXXHS6pDJ78g!jLxcN)|?j7i~*HZDI$|s&9@L?4W|U`3Ohz z2S&{D(47NW3{pOpIDmRV-2ob{mr4RXn(H|jO65G7D-<5^PdNZ;8BRH*aG^vV6i~47 zWN=9c7J!78;eo?D6+i`^77HxBTO@chyoi|rs%b$InsA9TpjNK)3~>1kwO<2azYWBG z9GA4iqf?hoT z2TCm^`X1fFuQ?(90}T>`it0a$L2I&{zzO=b;epTmdz>_)L4z|+5{Gv(fc)tK_h%1i z%prO@N`ylF8v*h!#G|r1AAr(95M0}RQ1GaL-3%&^k;ZG9t0WjoRlA)uKwD*0zhC&w zzvqC*3~(&K(!1dS$ha#s#3pz^dZ8so&~_uej(+%#jDtK5sN|f&G4%GO5=`;VH zOCHIWJQy#$Ug6Ps@im)=wWC1kHPBpGH>XGI$V#5J3mzfdatQ@W5+vX!u$lFG~iE0zmexl}LMZS4ntu z7b$r3`k2dmSRO3C>(Lzq8bU683Lbsm0vZ|tr&#`$%ivLU4+&7WrR_cg0|U$(y)0bd z&_T3!T)Le!TtS_r`QXaxpoiv9a3#*|+Ii6N@=Mp&lcl+!HkG(X^Kk_a%O4*6PT;OH zEZxJxQx_hdi1>jf2S{po-3G4bJgl7rN}qXjUhwD^0*xZPheix6z7FpIt(ds{z(o<1 zmO!z|_~Rw02LsAb2S5p94LoSSff5GyRM6Udki=HF#0OBAf0_asPXVuCZM{^I=F#gS z_8+uyvh%8k<%c3$&(1$D-hTt_Bt2kwz_sN-2`i{RJPg_M_#zZsKpg_-4A5-FV-L++ z(H@qsVjW}nCm%Sx(*cyS|H0cb+@O@*IE8@$BJme40a`QrB4Y|te(MCseBztM zMDb!r&?p_;%VLRKp2EUE2`&6BLE)eO6%_u5S`L(QM7wle0PUQE zhW}Mi__rP?dEudXBih6A1?bRW{>g`2IxigFnE(p=`|uzJhdt|L1_p@4J-7ro?B7g6 zDQ+f!_TxduNWd)((Abkl=Wox>D=(5jtDeAXJxiiN+Z_MD_5z0wsFm>I=ofGa7yw$t z0cm+CgIl1b2B7tvo%dg;fE*0bEemShciw*?h%gW|jpf7mqIjbrc#V$-Xf+S0f<3%* z0Vw4v!RtItP(rep#J~WNkcCSqfF$HmJp*co;P%fX@Q@5>?J5@keEkgaPbrdrF8=|G z!2A;esxndi|CjEM{kJHZkTa0#$~{3oJB4#+>CVi1(!gdyq0 z@Aw;WR860sm#KTQDTe_ZBG`3yR83FO#qaBX1o zc258uxdf8f4wnF%w+L(=xM%Y+>?>?NK7{Y~8O9F=Ee`t)7JXp=I!EjHAy9z^UPK03 z1uO#+Yqn-6;q+*(=3ppgiaxya0;mJX1lm~y?s%7hTyHV~RAx9Zgo4cb3o-A(r~m&w zI^RRgf|&c_3`FdO%Xe_}F~uIjRka17@LB@f`d%@GP9^Lw&we(V;Es34) zUrYx#_us#W-@(KH9peWDI%vNp^8Cw-e2}{CS_aT4w7`ptpnbTV%%GtSP;C?FbbbdH2jI195}-XpFM7X$oh^yBp9N7rfk)|GIzR1O7z-M~e{Xo; zMdUZoK#lfm0g(A%+glHmD0_es>)X=zAd`GL-+@nS1(oQaVK>M4msi-B7+ej%If9#w z{PGOlr5c8}U-M3AKFrwsTb{ptHF)IsN9WDU4_ZHzy!7avY zgoY>MF_2T+LP2L`eyiXG4fTMAzgw4ss&2@@WJw^r9zF`|x_^1e4<0)Nk037`Yhh@(`gBKe__p3IQTOS*1**8;yMm61 z59aW+yu{!79XyH)8p#F~?%>{&EA$2$So@~CNW<_XzdS?dkIN4fKQ#Yf^lZNMAKImR z?bDs5;LG?5G#32<)C+C?`+&dwG-y>(caj8XM1#L|4kH7Dcdv`8yr<<6{`Pm^nD+ur zaF+1+bTfKdUf^#9O}%+^dkKKnLjCn}E|XSOsW%|Fe&vBF7j!oGv{5|9`lI@8kdfUouVy^)(^=DaRck z2l;e9+}Dr@GRLFamJ#HFB_A0WUdDmTPumYNd<;IFFZX$XRlMi~NjXELuFCK+7@piG z0g=fE$$)~_quX}33?IY3gd~ueFTz3MpyLLifj3_UYvA2T1_z!d$nnib6kgs3wNbil z3&E-{_;x<@=>!GyzJg@1sf-{~LB}O{blduZY`Xxl?d1mshL?*WdQD|OyZ0{cb4Ui2 z#;0DK1QulkW>z6>>fT?3p#JW12j7E*YH5_{u$}s42HKsUU=d5 z5!OEfuiD>{?#-~1l@YYVY*%=eH^aX4EN|$J4INN_v-5^W=ezxtS>6mD2OqG2SA2I* zaL5B&`}+eZsr(iy-HNS3VgS!C8~z8)8G*LwNW75lWMJ^*-v`>x#lXMaCLrzLd+z4v zjNr5WZh+h&3o4TjK-|%s<<0P7<)Z)pK_>z}2i>m0@xtpdXrCci-f_nqkeix+{ND+x z3-)c!0!>sO0d1HwJn*7$(f|K1-gJOc66nOtZUztjeL~$V6FfUFg0cx{mZAAYQu7a? za<2a>M;UTKJ3zpPWE{)#X4q+pk8D20h z0x#AV@Bwc-hn8O+;Qke88sG50kKzL#%Lkxs6`lv5$i3bUu1~@8|Nq-FpviN+o{l8X z5ArjLevy};Dbopt|2@AS0o^PGHC6+>Kn+o!gI)a66H(7({%1Hf%i5!t#T?R~>E$u< z*tL1eHMJMqdV-+R=KCuUdGLq5$H8AxphX?MELI+wm%zF}vyZ2cyBiZ=GEid~PkAtY z_vq!Z!Zh;&XzAp^U!dzFq(B2_nI9lVe)Q-(1?ucT^0NojAgG0m-$4^$n%9wy`{4m{ z;suY+UmnQDoq!m3-lOvuQvV3no&tx1N9Jv?qGr%3s?R(aU%#-O$;#l7$)f@mX7*9x zK(a{lCa7)W(Rm^|7G~oq6dRE}0IP3c?oS2>MCT8WnI7MNA{p9w9A*|C*CV2Df=A;U z&^<7qSu+jLAq)l{ojxiSKAkQq4xocZJz5Twn1gN;2mswCkif4Q0=iOQ4)jWaCD1Dc z)XF|R=!>&9~l>o{X`@et`+-gBSKOlI& zLWVbkN8=mN)@F~+XD?1KV}%qoorhZwl&~9uCOS(DL3zw0!<%7eH9U_sWOy^Ym^<(P z|JK|5Qx14E9s!vEno|O|vtBUAfU-!l1^8l~*ZX1d0XiK(;6)pFt;hzDfuJ)Z!G#C^ zwjcXAvcYAT`@H}E_g!=bEz<#6;&GV~Tn-3idNb_o0tHU%0guk3U|stpvq4*nKu2o4 z5SaJ>KQy%78y?uFoDCXp1Qmz9pz@{@F6Qw8QV-S$-;U_G17t4Pj2FRR z6F|eNpiSIe9(kYx-380}|EnCG0j>%l<;8iej{sHY(dU0^}|Nq_1AcsUBd?D2QfDvS0sH@>gkIugkmxH|p z_7d0+(3@;tbj${&op<{`WP(!jE^kmeOnJ$`us<~0n<4h)&+p*QGQ>ZQp!+fY1{>an z)=!29z(#?KN7S|e*dE8uJ1;cB#@_%fhXd9A-5Wr`{ld5xbQ*JsHMlj<466V4gHN&8 z1L}UiXa&t$f%XVTgL2saopzwDd7v@@l86qxxH1d0!wj-d5vdD1AryQM322b=O~8x) z8(10kRe%z1Z;cA*cxuA~FSuVZFo5#}=pHA57jr-YZzs-%$qw{kB z|8_T?0GDn*4#NXJ-E8{=ioF?L_&#S~;NRvf3|9Kyg@2p3fD8XNXMV5&`vQu+89G^1 z__sL=1@Lck76hF$C=Jme4mz98rSlO;izrBoh)3spur82Fv3(PY!H3zsc=L>bAtDOY zk%o+;JBB)fSKok!5hPy3&HWF$d<(P(5L{04bRKnWdCTA0#|XMiV;|ExmII*khSsry z?>6}m205_g@QbhmOrX7tJCi_zbxrx8R?>lPX3#;z7m7irNwEj;gN~B|o%#f7M;IPZ zyuK?t-<#ou?#%!HyIoXdJbGXXgR_?an-^KmLPG zspeq-oj!2zg+N-T;K5e{9gZx`kNDF%3z_)0RSO+_!~se^e4Rg@J)KI4|&T3l?pD#CY%#511_sX7hsCf?zfum@RVf z5kKdJv`$A>h$AFA9N8UO{+F_Q9DJwHS;&F1TRd%oW4J5yBn!}x(^+Wo;?j8-6wcrs zEmDlIM@`nE% zE$_Q_{&d_?0ggJzk;OabfLr&DVUPrM4wTfLrv3l#*=?f&76MlpjypDhk`ZX8X5Yhn zQ0M18JLrG|kLK@;&CeNM2uuSXA({kfT*J!O{VVtxKzH33%>$)r#~m*~W>kTO13;~a z!@IzD(@7SB(h;~7acb)S|HqkAK+TL!SzB#Bh8GnxLFq!&P@9io-@$bp2cXyF2(D&j z=sf&FDj1ZjLB|j_>;c)(dfRd5FU(A{0dzqQ__{rC4gj5l5@2{B_(k+oc&>R6z`zjg z(am~7i;n>`7Xa#SIEKL7Uo;nFI$`&7A-jL779Ycl9iXh$E!wHY$FPqT;r_r?VE0D_ z!Q6jfH^>H%`$Y>t!GV(L=Yy_Fz~cVdQ{e7bfVy7++5O;UERa(@{(^S1dNjUqU}RwE z_E%~CXp(Y*ICit4-XjzG;{9ZZTfeoaa56G5aFnuo^6z?M@6zoHD?@jF z22CUG5GeI#*k@e;-ggf^s0z3bL8qwfn@B=LLL%_rG2B#l0hAS3Cxh3^fozQ|@Mhp?@KknX*vSE^^+EQ6?AljR25O$XxHSos&q^6UXT@~B z_uLDLj{l(4fAAfTk0R*Yln*b&RztnHq0F0MC+Gk%PtY9@H^6r8dr$`Q*9&P?kYhX< zj~O0t?6w2Bq8@Ct9jNobQSQyKlMiP9K8tdYmiO$itQ$HB>RwM}Hjv{ScYvI|6LfGo z*bc)3`x44Q^&i+oGl*L~kX%@@3hKfRkVPV((L*E`?f_f&LI}f!cPD~84|d@LkVY}M z3k51rUATE7=zIfTWi^P?K#trAy2TsjJc|m@d1zqcusHAPN_aGa)>(NRe8uUwBcZ~Z zVc&!bL^P@(qR~bL6o7UU|Nr-BJOauv@OsfP4!Of0>;gLY?Kdc*L5X%}2|Q_`CEw2z z{{L^-4L*FUgbUP7gOrb;-o}qz|NkFr21zk`bT)%h9zxzR+;PW_3eb@>j^KG0Q2Xa> zug^&y#}LoU&pbQ7>;!FL3k7EukIt*Uy>+NJ2wA><)WMk;9zY1 zr2(y6yZr8j3sPj6LdXKw}HdAV+|$XeJ`NaBxG9V@B~mAcI|xWxPu9lduJUb8gbUxU(v;gGC7dt^$8G_pYp1m@l!%25ARDnj1tv$Y92c^SpegFR>S^*x4 zM?IR)GJAAtLxva~VHe`^%QG0Be0dVo;ez$|LGkoHhY=J{;p=$8d0S+_UpLC~54or~=*40bcqJ>LGwS2d z4i8%f0R{&CmMfqZ0{G&IZi#P)8B4BtbRP5R{0}=R)@!(?#&x1dhUo_nU zcfu7wmh6K!o|H=&Ud&huDm-FTJV1`N0Ck_htIS`^f?TWtcDx3NX#sb<8hA7vbU+V= z<4-RIb@V=YcD~&AgCfU!cy`_ZJN)ELTn@j#1my5rKA`5}!AJZa+#wJ@fbUFF0C@zo zl8xcDI%2>9Mj_rv;h>!`du16sk* zd?W&?00Nco;ELldtmXqPI|X+ezJd#NP-zZYM%?)xw0<9a>N-k^?s@PX&x>hYpoo6q zdGNhxnq%X$|BN07U#NQ?d?T0U*!cWEqhsgMG{?p#{~6O98=wAXgjPfREr&o+04X;? z_0Wbzph!I6$iMxlXSc}#hi}IiA=}Wqon=79o=4|>SN`o!5KRSFoIX)K&}Bdgwz=es=XO@a)B;?0=2MU<0>_s&{>KXla7PdV>pI^PV)t=T5;_B z0~ri&eq-R#&H7r7kHM!mM}-44dMx162})d`X^~)1W0?bVwb)!x4(JWwF#HA{M1<7e z&Bqu$nh$AMe&lbd1x;02@s_@6u3}*#Si$KL7U=0Co?_TrwTfA3^d&E zV%I!Y(AXw_YcqHe@~eF+Fe$?WFXqmJ94)+}#+zYh5~v6Uok(^NTxIP8*#N4}4G+9f z?Esw>?W4ls(g~ggy-@?J)SniBX6DX&Tz*WnkEEQ3D#(eP?*!1q)o_6iDJiHMoX(_Z+5t z%TWe~eFqA>8D4Ke8a@Np$7(3~RZq7;z3UUGjz*#qp^ z`K#N$^?ymcXXi)9&JUiwP8^1pJP*E9aOK~A@-@$d=0l7g%?C6rf0fv}STdA;aIy4Y zDSZVRDoDQMaqyjm$H5nR9=#%yIzOuZ0bS_RD{^56xaDy9fn%$SkO*jZ0;nE_trK+& z0i{py3NZ!HiPP{xy0b=w<2Z{7NbieuaCU#RuLIGUWSIl*O!B%wdT2*p6t4w!CYygV zI_~_7*+V;l+M9%44Ili%w+$RspfRLNj-Z)B(0N16M-)I&2c91Toi8p>>&>w90xYLN z$|_JX1!`+}Se9$-#f;28441z|L3 zq;lUx@S*W9=FVbe=&l6~I|ze~1$EZ-Fil;7&D7u*?_0p3s{sm4@PX~1^Ff}!$e0XT z_T&t1RCpwV&T%*j4wGIRNND`%0r>!Rja3=9~N$bY$rD z)u1-ZGth{4CyUC9AK>vA)18u_S^p#8MG0#`7ua<^e{mOlgevH+h29Vq1;Yd25rh}% zGg%orT~v5pAc`f`$tXFQs)(Q2})UK@kLAQ^L>8zyKOd@aSw&0ZrnixpZz(0qwp7b%6L= z4uJM!>;NChXAeqB|Dm0Ba9!~ts2OyWEX?WqTGm-OdUUsf8m}PZKs{kl`8WeK2-b{jQ zQ@t@wEd`CLV3<0)>HmKp<{TBcvCTayCm0wQnD#ZTo8SPd#|nHpp%a|oi@8Ho6kc4L z4)umF+`1P_jJ?;+Bq9fSN2GG$>@O;t^MFxfjP!S1Q{Gb3%ku55qgN$~7j^}~&-UJw!8A0VH zxTBHQ>7rr;8Q$Vx;ARBX?g}1_J>Z0+0IJ}?dz>13R5URcfr0Uui;4;33y+te38eQ2Ku)j#IpH|;>`i__7Zryr33=9ks4BU*MlnUxDzgYU>|NobIpyp=h`xhCjK&?Y?rg?c6e3z30 z!wY55QHq_%Ub=w=KzaU!14JFj#@DUTaeK#*7o5{TdCv5dC@i~|2!Zyie)GIERo z*9$K$zXEZedvqRqaRV*`I?p2%Ts3spYjpF2T2X@FR+Kx3;U&!yOGt5esYn|M%>!QPGGnJP_q^@U@BG81U((ewj>b0cd)@L zkpSKC;nB?ma)n3pZ$|!>eV}_QT~s*0YV~lbb!h(0#NPrsdJ=A~7B00G&A*vTvf%2B zaH%tB{>@V21XuS7v@9Q+I}@6JvzAD~)hzg0vPI z-`rpXHRas|_RRq$&S#(ta6rpxpqI0(DFk=_&mRFTa{y0O8XkZ&rT_GRODR@UP-^t- zJo+LVJnalBrEn!iM^N{#$-$ceUQRjo=BTiMZ$hyxhos8RS70aqFHw=$_n;OuC~@EL z0Eh>=c2~j&wB`PV;}HhX4ZR)+wI2Hv>Y!>t>O4T|99~EsfedRR)J5z|fT{amq7ng8 z8v#-q@Z#-Z28RDzR6y6gcD^z^0A+&RvTp%Ik56|GSl*|*1-#7h#m>Vh=A+9)E|Gaq z=gsh<|1f;q9(?D`Hb}5m9EJodxbtRsz@v8xc-`cS1>LL+pb1XL&SNh`z_a15t=}L$ zH&`hM>A``!bOEU0>ezgQEx_=AEC049j$tpJmO{c6?32z{`wkXD!|BEEL!cv+9(nX` z0b2?hm&~~R|36eA=w_ai5LaG8D1;nzaQ}rps=|v9g)0#XK`m#HiDIYl{7|ZZ13Z! z_htwH3FUzLU?4^jhyhALpkA5b0T=%5Jt`HTL4llu3=Ey1>wXl#F|d!j2o_O67#5Ua zT2KQr7i2*bhyk*o0W^{cu>jP`d%+Dh=7<8+2cQ%VI)2Hc9%>I%0Gx_JokCD52RZEW z0S1PM|65d6fQn~G?%dY_(*#ltk^ot_0HmvT33$n`PwyIV{rF<)0g$)AUIK-g2sq4| zk21ZeIl#aW73tgE0`4G!4&%OWcmS+!pH`7K1L#tw7ZC>-7}H+G!3P>(EnxwTCxY5>hW}r<-UM~QSnEJi%||#ui!&kP#~$6Ri6BAP_#;R?xZV9i z2%^OqBn#C7E>~GCIrtcYJAZ@D^0DmZXgyh?-Tac#qc?!Xqt~T_19S=yNL}+G77xoq zCH$6BrJunKK+v4B1B2lKDE zD77Mx)+6XH43B*?*0D6aU~31p9zo?&4Z>V6Omnlbn;VW{ZUCeyVQ4 z;CuO<-#|+W!1a?CND@?SzF1lSDL-97d$mC4m3b!rdvT!x8u;heF-!noGRdN1c;Lm$ zR+uN^r^5q18Z&Tw!Go5}0ghqNjsUnmd|?H(YCmXu#|xPf&@xy4);Ua|I-*v@vv-P0 z2I$Nt=u)8?xMiQFK`jH<2Ji|3X`l~%h|DqU#o7G-|GRn3AMt`Fs})*L^0#(_2JMcw zsHlKu1wd^*Uk1Yi9-XHgJ9|_VKneZeL#EbCB{I+?fgr6;N|z7Pus3Q32iNJmvUKJ5YdvZ_EYv zAi!Y{9yZ*S2Z?Hw1t{?K)cZlR!A<*E>u=6xC=!TXaa7x(c(csMx;AnXe)awDQf6oOkJ-iQD z`T$yY4|OMK7;r|zsm%-(75EE#t+tHV;zyAM68t)19=$!`2aG)D(LDzDFt{MW3 zRfASyaCFy;y!h1!O4vtVFloWc+KkDNn0V{BlgPnp$IutfIiQpb8V+whq5x_HP6g*4 zP!ILR^hT6!aw|xtg44zF1b@2-cwpVp^59N$aDoQ)lVN!u+(8Bn<%1?JUOdYF{~uDO zoXG$GKPnP*bYU21K(;%S0o*0pw{#u&UOdf4NVFY&F@F-=BRespEeKn*g}$iDM)OE0 z$G!#Y92{O;Y=D{TjxhH)rny_NCDqUuN*LyPfJek%RKm@DKN0R;A_u@7LtmWALUZp_ zPzkbc(YgkQ7jkf;ryz{Jjp<}(>_L%_Zggk>xXbzCSUoH#Y!K$+>~W&i%b_pCv;P0@ zZUvRlpqjb$K&d8Z!XDcBgrsX|Y1%zS6jYeLya~=i;Cu>7V!cxpK;_B)bqx-N2VPi! zUDJ8=#rg@L@BR`Th z16u?hvRH#@Q#AI_RD@df(hKYvNO=G{pU|V*{>7AXCeWCA?91+QCgcmg4G#o&9^_xt z_$xCn)suh9fyUqNsd=T*{8J7oUTFN8SCX0oX2Q?Yg{x1^E6D__cPuT*fT>S*^mRd1 z4;qdH54eMeAz4NL@q*f-{4JmrncW7U)&l4(S5V8$@Z@X3vO! zG^#HG4sX~v=SBV&&{E%K3&zqnF5Mn1paXp#L&rP2U5+UL3VsbhBIlG1&h<0LP2R zj$OA-f%lzxSh_ouNT8S|&kj1J13b^>(e3WxVc8BEcqqN?(d{1K(HZXG(Fqnn9?t|1 zMTQ!_4SvBi0XzZZ+1aAf0ou*+sUNhOs6}Oh0P=oE&+aWMAZee@=N{cMZy6fB8D2Rw3U1`d1{a(sMG-!jW2qu zSQ$Y6?5+i^uWx?A2%cvKX#vgILZ&G})0d!W$^_6LXNKVc&?t2QXfEQIi%Jn_uCRph zg=iJ1=;}QBqNf{DM1qG?;VuW)^APt3bTjV+%|{~|l$j}zBGRYx`MwXE{TN=%=mU9W z3OJ@fXU;bs0R zwzalEu3~2?;qz!d;&B+Be?eni9F98*8bBBD8XnjQ+EoQ^Awlxd-ej;_J>cb`W9P?i z^VV-A=HQu?lb|_7aC!xoV+S-WKbFY4SaOtpunYjttDN-cW$6UZtAMNobr+i72*9$f z;r}3T&PB4%HyLyTBxs*ARJ~{CrC`uT?at3WofmyNkMT1eMA`A<(ak#Z2e^!d^!HzK zpG8?e1nN&i@`y*bZu$>iaDTc)G8(er1-#M9G4AEEJD?e5&^g&Y-KL2@ctNMP@V9`{ zw@!QXiq|!hDY+n z&;0oepy2KmndH$Ma+QH!(23(Sf4+wRzo3_dM|XjOM`w`+Xi=1hz7|tp8+i%(lzT}|9DVs3++ktZ4_Y_$dhrD4d?1=-K>&5!7IS zGyo1Y{suJw_@^9bIaI>Y_!HCuDB<$ygd8OAz|dT$qF(l4ryOV-&2G?SF=#n}faXuf z%a2_;FZw3m_R+lI(Rmy^BE-L_^H9S#{)T7#B@!OJ?*F4>JuMIT@Vg%X-Nyl~9}m6| z;oo+k`2c_O53#aadqJ%Om(GiwFZdUA9<>EE1>@&|DDHQJdt8xc-@G(J`g#wK;@rD^BV3($$nD_r>fj)9!I0(4Bl506eB70>|%0>@pz zDi9a!1Wm1hmX~ONdR{duD_$!=-P?Jp`5=c6<0;Vb zg`FYCIY5UwI$9p66L0>hU-rnO^OHyOF^<;{;pOWt(D=X`P~8LDKMQg_ta9x93_DMu z+a0_f9K2)(G))SsfCNB<0;mNh>~Y);A|=SiFX$$~FX*P=YIvZzf`h3<6f_D7UP^iZ zT4jL3DXp}(y;9z;mG33SKSkOv=TJYGKM|X)z#*2%fWu~3)KlA5#-9&9cN$p8QUq4z^NhByX01~~>g284%&1_uQOcyvC0(fIBE|A@$_=-9Y; z#|Xzr$0)~W*vF>s4Ty`Sl_&%>udyJc}WV z_4On$pY3%Qm}Y<7lr|xY<7Fkt9a#)noG(G=p+VC{78m&5lnGhfFF})b6S8<-27=Y` zf)6{Hkj3}X5zJ@E;(rM`SRba3Axq$;I(XI&T#sf6z63RLLGBYmKDR52AxjuM41~}p z^71{n?1kuK$P$GX+%Ucv_!?YC6eF-|>AK_oKm*-LB&0p?E;aj|1kHWWn zIUj{@^|Bv@Z~d|!g>UmRABAuGG9HC*_tGDQZ~xLBh41iEABFGuQXYlx^pYQi@BH%r z@BjZ1{&NA}SB~JjzPyhj@AmRM3g7+ZeiXjP%k?OH&zJL2_+BsjQTX03>rwbVFY{6O zzAxiZ_ABCUsay<$^^W}ULe%8x= z6n^&0dK7-n%X}1m?#p--e%?!e6n_3odlY`bOMMi6;Y)cGe$h*Q6n^o`|38rZU-I%j z3cvK_eH4D#%kwDw@|XKj_!TeLqwp(V&PU-_z3fNfSHG-B;n%#(N8#7Lj7Q17Xs-wl$lLGXJ({2TwhEe-45_3&ih1@MnYgH3&ZF%!-#e2tH^g=4A|m z58CbY(g(o@om=tJ2EktdGEWD=UkKvMAo!q#S}%DJe9))iSIApAo!q7-Y@SU z_}f7G&mj1q+ofObLGVF6)0b-ye9$QA%Q*=CE|C5n1b;V(UxVO-uE2VkgW&H4$;Tl0 zpp}6yeGvTpAbA@EA2jUoQU}2Y-IMWB2EhmIj(o|3;Dc_8dim!w-2b3s24B8G@Q;Gb zzk}c(1M$xw_{Tx~JqSK%#P8)A1pg#Rehz|v3dHY0@K1yIH3;h=Jcw_D;DZ(kj z{~k!a4}uSxt$1mJ;DZKbU+N(E4?*f>5PZ;qm@jz{{Kp{qKOf=#e*)saLGVGBy1cxD z;6DS&pF!}SgZO(8e9*exmunFGmmv8$2tH^P?8_bmA9U;I%Nhj#4M=?sf)Coi{4xf? z2OZA)(g(qR4^nS~;Dbi2U+N(EA3^dm2tH^*>q{O4A9OU!%Re9B{s&#D{PGQg4?2D2 z+ACPC$LFYAr*3)=){sSG?^wsd2V~9`Z`%uuHI8gQUqL-5ae011W zF3_^O=f0gUcUFSN_B)SvGl16UFm!q|9DFaotDxVTVP7hAc}~a+HsAmM4Zrz-&&~4U z1l&HkfFj|paG!H_n;vlffpI9 z3=I6+KtmVXd{hK|J74l|D^U@0;os(>BAn&c@T)${hkwd}hM%rkuAmu!ta`;C4h{c& z90NeSuzfo^y%_=(e;EFEZ1~|81QK)H;n3;Luv3|VfkE*&*cpZgUIh94{|_=U#H0C$ zgW>-yCg0ANjyo*6ycu@tFfcF#*f4=r?yKsDkFLo>wWu2YKhB~8Izc0g(Q)S`7SJWB zD?l2J!5SGM8YgsnGh{pz0Ih_Wa@_Dh21wnDJKhjm-8`C)7#RM~Vg%bN(c{gq(+OGg zj2^hHE4@MI-x_}FeE(t}J7`<99Sd9T~k)eW13=&Iq`^4N!d`Ye4!Op!(i<{r?~D7?IYz2fSpLfxkr;v|i%vYiZbc zH)yRSsA1TAl+p49e;XeY0|Wo|IVzyGq~Rr(&gcB=?|LxDs1$f~-g|L?4YUSJ-0;6+ z=SvUE!;U*{^m;Sw1T_oyEr&~TUq*hKIdn)`P5gO;=y^m#LYP4Q?w0NO7CG8S|Mi=5a0|E}GBGCtiQDh7uC zBjY@KBmeuho-E-s{O{R%6Xffipk}Y(fnBmLpiKunDvmptT)Y|ft?&kMLsU3k-0}ns z@bjoRc8AIMbbbdJ#o^O=!iVv)$M+i^ilCz!d^AsZTHbQ$4f^lF?|K95L=R^0=86}L zo}7m~I&XP4A7b>>yyXKrvmRuqDtJMTBPazo^m#J`cv#-p32L8#JpppozBB!x1*R@4 z9H2wM!aPBPi6trmKAqoRbQXg+Au1Av-#j{xzwojKEiLkBu2C^y;BScmpEX^gA_0z# z7q*~*=WdW%P$W3+VCeT|0H1cV?*Yhs%L^d8K%v!qlo1*aj@|5_pnL2AvL!|(05o{% z02-hL+06^GyYm((W;&0($Y%t_ehWCQSiazI|MVBUvL943L55nvJ0lT`gFyR}!aX}L zI(Ghd-0>R}b74C{SX(X%%}4!c=gZ=e~KIjyrBl@MhTQ20GMM2V@xI9S_aB0Uih6+Z!J6 zWW4)=%L5c%zLsB#-90*A`E>HPn~6|}GibO_#$|0O;itp`fyhwcPr4)83WtKmt< z5XT)eCU`S|tpII#dU4qO|NqE1U&}8=J3;e`(76-nGFya~Ur4ipN*f1|n?P$9JdYm) zod(m*u&-bO=p;vOPy{spVBw!~2owzgoYxHxfGq)SczO}%4$hC@`{f|>U7-EZDB%a{ zB@!Ec{Olpa-!pkA z9`aB;?!ovAbeqq?7c8JT|6Tl00MfII5emRZejI#ZaX4*4N;iutXkkR_fl?93Bo?cO zE$FnK@=)+TRM7q^(1eQw=!9s2&Kebt7m}cJ7eILwl+y$pI}d+n<{}6jH#b58@muEnBA3w}#QJ~3W&~O2G zNxlY}`zk?s1KoXw2jIF*;Ep>FRta+)IGvH=zU^r410R(Ix5gFXujV%roi!>vFCK%= zJ*iRQaqK*Rs?OA<^Eh}jzatX^L$`|x4|uj5R(~P82Yk#A$m^hacckzFi@)9hc0XwH zkOA%n#>2?^Vd0HPVW9oQj-8(zAtx7jG{4CJg{4D^M>mTq==cOs9BLRIaBP0$P#W6# zL6w2Qk--*3l(-{BOg4B=#Jl}-{{R0E-Zl=ipT8Y6hT+leqoR@Gq0Iv}lD`$y&-Q3O zk^wprasp^C9H>Y*?xG?9YNNSyhp0G!td#)G{272)3a=+4Tzyw$3RxKt@o@l@Xj43xSyVx7 zAf%(z~I<<;Pu&n6p!O9ss?Nf44|?X92=mp`Ow?}(khVR(QTv309pq9 zj}c|L62Ck{^K+(Bqm*tDu+?y#9=$t2IvqPNbY5_5e(?8$3;#xT%R{As&5wARf3cKs z!q3v3Kl^kqn860xBk|RTdBFrW28QOx0wuY=t=~!_e7kD{d^(SV-TNY6jElk7@_UJs zkLCl<&SRkR)1wn~+l_=rcLm3P0Z+^K{4Jni$kyASJL_I~biVM>eB^0)t@uWYM<)x| zw$|GvzWnkG;F)pIg*3YhL2I}ed^(SVXQy9qi*Yf4_L6acHUxCL8u(~F@;G=xFvY`| zMHMuq>!bO=!}1V+Gw5y*-_~!X(xB{Y2%X9Ww=cly#HaJe>u#vyUu+lUV(_v2TXF?- z`&;KLAI*m#Q!OtR9e!y9+A)X}UZ5(^qu17VGZ({)2}>Bk_hEW;{sJeM0?@=csL|fb zdiDSR|6ngwurV;egVdwfvfHfS`a(gPi{XW?5z6`+u=(Bf9xoPy^9lo~{{H3J z`PsAcI%MfhXs}N=ze~5CZ|h0^K21gjhT|?OAD9^!K({e{W4-^3mqDN;r(1T)vpk+EI>x5lf z-2(76 z9<;;+qPFods54)p*Lt!<%cb*B<4@31snQD$-;OhuT;kt*uK67JPNUb1&CmZ`e)j#E z;=R`Yr8`@{l`uCSV{~o(R_D`Pqw;~NB+j)rkMX4$=q7e>gTN8w&+32w|2up;&Q#LT z{F)K0j=u#o7V5~q_Z&z;^Fc<(%g-FYUvpHv*ZlnN>m^_{B|;#-wY>WK|G#7N+5ay= zx4nbb$lm<>|9|saM#s*t{H_2Y4Tva@c)71UQj%|1l{&-_`mr#_(})G>x}<7kMp-~{`dcX>o@*Z z(0zblhw!%+|NsC0Wg=+q78VkaFn~035t$QI-njJkyMwC1)vH#m3N}3H$-n-f$H5nh zy*3Uzz^QLh=b`3D^878JO3=6SgyA>GT_Ew-iqLe~{GYkRy7?HROXr2okDvubVAXXD z3=9Wfur@znZ~npP$Uo(9^Do9yR@au>rRSS}F_osdw%jgBZ2ez)Y{CwZ#XkJ&Pk0`D zsp#Cx;_0Y)z_s&WiI8LSOU9C@#>b!~l^(s$jM0ZXZ*<;jKFE0RHP68pVvUbL5{-{R z3BCCMWAhQ?2#jSlj2p_~HKpSHlC}j(#X%apB)~5VSz+aPx8I&Wo>4 z9(*YP5^`+(0ZPQBPh5IgKy7&j$HoT?f0!9wUxsQteefllW9JF5@PFpldpb{e^qRg{ z$Hj2)1yAz>evf34HV?*6{~v*rANx=;$EBA=2&9{Qv*og@4FG1J(_OgHmvJM$uQe|NHQ4f^>l{5!m^1(dM%Qr{{GB7ZJHG&lH z18J4r10s2Mfk@FE4|o}xZA~BWGDy@Z?vR8QjGe3^Afsf3KqRjKh!o{}$jcCY7``U2 zlijhKfsyT{E4c0h1vdjI%{Bys+-(b5t5=rac?=Xx4IrCUK(@&$fk<8j5GgA6fR~~1 z9~)?up4$%4YCe!MTac8jHHhT31d*cVU}Yfr5_wRA9c-EzNJ`cOMDiMeNKu0aAlD%s zzrioh(E5$P12mBB*!kNrr1N{IV{bF4yz%I~x(k%^K|Q-*P=VvpE8+kuEC8j*3TKOTpT=$Cw!%n}2cgw}6YB_Z%ga z4*c7WJ2d=vD0yNF%3mc#%|AR#ML~*6`CVI{lyEsVzh-va1!{XZcK+Du0t)U+ulb?n z8K^~Ld9iG(2k5Hei!VHTO%A$Pv6XNXJ@e=dV0`_Ue_I%{i{&N$7SQZp!!Ned?t||+ zj=3^0mbOD0O@|E+90nJih9{xLVaYSYZ{YR%uVvFFxV9W9(Qs`3#av?9e2lU42fWZM zIe=VX9%%l>SaP}f7ZZOgXj;;>L<{Z>!5oGZybCf)_j2RlOo>OYsRO7q?X?YG z&&BX!i8KR)M=!4|NE+l_k6u$nh_nSrx>Xv~>UCjYXtsTOhnInozYR1y1inlW+%g6o zG7;MO7t~_cIOd`v2R`ak&Zjp;MgEwJiae-M2s%}r;WZaD9XNJg10M;^zo;`rg~PG) zeCIL8=6{T(T>RS(I2e2b_0xPhU;1=D>U{q~;_v_eph1~fsK~v}_b)(u1VLh+5HXj| zf1U4NfYwWa1Wme2R5&0Ko$p`V1l`lydZ1L!u{Vs-#j-?&r@XQ8?S2LZhUUMlJ4%1)(h*{|dQ)i4yj|;cx+1tDfj+}>F zx^2&c^&ajPy#^LK)y@0xHZMctbAiSV@y5r7j1E%Vwu^7`GH}c81gre#*!V=igOQ=r zM`em*=jm?VZ6M{(B$#^?UAR?ef(&VVoXDua!1>9ATXrc(5@bIIC+}Q{{%+now|N;l zZT&z}&loru7#bgfnu0E!qUN`G891+T@}34Mko5$sS9JqZveCDB8M=A*f@IEi`lw83 ze99ohz`(7$8)W16qabtmT|af|t_G{pFStqpl`yThOM03Q*Ec^t;Lz}l zsq;pstPn^;Co9Np{4JpKhkbf|RAhX5LsS;*12rR$yQnO10PW4(4eA9s?g32`I_?Ge z?zIExzU~*GBFVASk)`<`Q;ED|H=`r7)1T&tOeJj12ke_49B}Mpa%}#sz~5p9I`8%v zqhs@7M$hJhES}AWSRDBme<|AIc-#@xMq~gPa1UyLV<*$=6E2+}njbLox2XO9|G)7$ z149FQ<9`sz-vT=K-|zsW-S8bW5id{@=GX}8*$X&+JFdVFzR{;UL}h|w<3k1k1_f8n zi_MP&TsnC*Zt^m4UIq059x<>nFm&pk2MJv64pEuXDXV>xm!a_yDB2x4FS~TgTHge< z6B-|ZW_}xgfk^&VK~UrW`*8*aMh5;CmVcmwE)O|^9H(^0h1>S&4Uh>=5ey8RqIYlb zg07gI;MjN`q}rv^_V^7@V?%*cH0mZObG>SO#KYLY;K+H!rBikD4PJ(qTR^>m#-|Jn z4$Ll`x(h%;8~^_Q-`%1zg@J*A*+oT!zvUFDQ*fZZ`7BfOg9Dwq>u>NfcyzM5+~j2d zuMh1Ob-lsM@a>oae+y{2X*X}#4PJ)MbIs2f`CIP&{r|u7dgq76=Zs7<7#jbBNdDFn zfB*mg4qCh*P*U7&s(gc&!QtC6g_88n>)?UB#^;~_Z2S)*`CDg$dLj=MN<14MF)%nV zlsI;N0yP9c!N$NG(D;jifjNM`wG?F0hl4-ln;&pAA7Fo(`uG3;M&1cGco{&sviY1s zr|ItNybLd+{{8F(3oseaF;2JOJ z!1yp$28I{84Xg|v-M06x@-nR_28Kq+PR!O|5F4^pvxSQXbWN|}CD6^lFG|1u|No-l*Z=?Es=ixv>NQXt zF_y45^VVMHWpHSC)=z)F3L?^2+$WO;1hf0FR$~r}zukkW;PXRmZ zc#8^XO$*3Touc{>agZxJMb)nHg6{6(Z#e}TO!~ph-vWvxP)**ll>>BSrHcxv{{HXL zeEPp<^NIhS&FBAvwvAbU?C@+p`QNko)PK+B(_ldZh~POeM+3wGDOG?mK+X97pgA@L zpH5rb>%0s;ou*!Hv_k`K+>SaC7`05)RPbJkT;6kPc9BV0dXis33gtEeB#GNDNeA^Lh8O)b9ipYTywbkZA!B zXMo0P!F!Kh90Kc^0zPkcKWOI-$WTy6!^iRyzyB@6OD`6HRe(g`bhZRP@I9g2X@?KuP39Vk*dyQ^1h|^>>d7`1GLOEh?Zh zEkLS4e258CAY#4HGjoqaPPhS^Bn~#oMJ2$aw?_puIsiydK$e46eED?RN?ZXa*^ie&`(#}}S0aeM1+jZY_tmh13g73Kc^N=={IWi~ z%**iNWfm(#v+blyybO#U$64(!@q!W|1Ahw#cs7Q2)n#4=aK#F`CbpAz^ITpAP$K!~ z(aE|V#0HI6{r?X-r0j%8C+`xF(8V7fove#MtZv?7RP7-kQP5zaM<;6lh>fb<6(j`K z?hImev)X_h-pOiu0OS`|GYF3zB4+^MeVoI~@PbAC|9_9;hi@=BFnAt6Zoulm@S5v? zuz*MNVF}MpHXqC1{LP1085o+YIaGbRjZ2<*^x8%);bM4kr;m{#t=aY!_y7MEr5YZ+ ztgE^I|My^KJp!USSzRykGVpI_JqO|GU*u(YS@8?B$bxtB5-x^apm7q9UeisBxfncp zZEq|Fji>W7Ff{%K?_q0Q$^a^AL0j1PTS2Qo8-IZ}xwTFO8_}ZzD*Ql+2((fW6n~)7 z+oN|6xGa6~>HYuzFL*!x|Nr90m;e92u_{~y4dn`UgWaSGs-Zbqy)N=HG(*&j^0(Y$ zV_*O`>R)>Q`u|@Q6pf(0=eHXlGyM4fzwt0=t5ow3Mpwyij?K>+92<{;vf9hu-~azN z{`RO$&o2#b{8^frms;xG_$$vnHIKjb&Cmb;Uj~8tL9Dwk@G^i_a0>9ZfELPum>m2q zAPR(8_*+0@MIODZQx|c8l9PRO>T2l=8P8sO0uI&gy%f7u2+3SfRk*!UJl( zh;BX)s_g{$TmJs}|6dhUNZEo2{?@mDKrwOoJTHR+f6IeE|NnywJOFCZG8|ywZ#@U< z>GZPBUdYAp610hPKd8EU;rZ$R|NWrujz{NVP&O59_k+elKn7a8cn0EvazBXc@Zvg%3ud<3mPfgF{&AGFF7BwPU6t(Wlvv_5bD5y+CS7xO{-K+8Nq3KCvS_y|hrTfmhz zC|QDP5}(dbpyRDdpM#8aQAq%8=gR=CX({mOj!~(2x%kKb{}69Cy+ZeP0Z0Vq?PL%K z#oK`(5rns$KwN~kL6v)_i;BhzEs!|E>(U@D!s|RBF2w6CDxglqi(fB6PDSy33;5_g zpH9fZf-i2o{Qn;w2B%-*@HF)F!Rluq;~*T+F>Ij4Og`O^69j#_=YZ{eIrlp(6na4J zL5ch-kO(LgK!F?qN&y)l5tN_^1BoDl!X3m#1O+%4j6q_EU{C>Z5y2n|;(~&~v-9u^ z4iEDRn}vY^yb+ea?H&^Y z19W)o;7iDzFF)vnwCkE}!_M$Bi1D`{0Zp9uK$1=82T*146PC7{ZH+)`U^ei# z?PX?Q*dfcn(6AHKTjO7J@C6^Jk*5k8{RZv*^x$8A45s;|+qeJ!UwDBQ?sT&*o&c&5 z7z_@8r`14{<1Z8%Ss7Xn@ONmiFfeqBZaU4&(0Yl#m6ru{QqhvrybQMg8JQXQ`#`f} z9?iCiQ+XK}N?2d)V%`7WqnkAtY@P!L*f`M8uW#$y5*|=<7&Pm+G=%|jYxRrSEvyV4 z-J&t4K-QP2aCFzGu)LVo!pZ=;?jEZC`HRvN&`^!t1W?PpwG_1GqV;WwkVm(u3bMZc zR}KFgetYpE2-GClqXIgc@I`e91L!v9z!cD&KWI`J3{%m4phrs{ApeW{uUk3>I&B2)4UAdSc^~bGH~#>fR-CKoZ;wXwLQ(t0P+yS%O#&d zRgZ!~aE1f_lw*xQ6EhVQ_@^9jXgS8;QV5d!m6(^F!QXNRR1GD7N`7b||01FJhdh5f zX#Y+(>)TVj3=L2IHlN_?WPNywm*M4)AOHV1|KKm-Z2lq1-}>k0|Nq^rCr6+ z$;)uRQT6;uUeHYb`-Uff8_qCxvaSZ{y7Ck34N#HIz~2hmItX?o{~}Ns&md4D*m>jN z3jtNom@72FcSF)R=zJKJzyJS(w-a_AYB;CRDH?f-m!Vs<{UoR!;V9v3IHS?Y>I!n_ zBL)5z&}n0hyhf)$O>stsmmmItd(5EFhSp`h9?ziFS>sR8^mw^|N3W^hG|=1&PoD?l z$Nvw%u`-?nH3vAGPg!<~z6Qnm6mWB*`9~aoJ7}j*^ABtOwo1^H<_nwVA4>e~xsU-! z;Ta%fpi?EyKcx9vK*te)RJUFNwGvb}oqz;Rv+D5^;Lz#>g%-$vn|^>!K!KJG&8Ppr z-1Z5y#?M710+eMv7(akgCaB}@V9;jjR5@O;co{`9yY4xp5SG8 z{~gr9&OX7*02;k`c@eCFnZF&>w{KMS207vT|Nk#RlZVZ}SozyG{Qdv`^^wL?mY~xx zMSq{*Wq8RA8kRl9(kc2D!~<<5Z9D~PzITe=0SUbM_y7M3@Dlk(aII{sIE#zn#oHD} z2FpYIZ6AOC|NrvYZ%|Qh+X#}l(!$69nlE$=0bK?A1w5z<9#DncT>qlPh?SxF$Nv(3 z59meopw%+`@(dowA?r_?EjUY`7~b~iWt}#Qi@~w+4`}4TrSq9buWj`#E(ZRohduaR zet`N^GIN>1M})ozG-hS6JX)&j(fO?N{fo=$pu($EzS~7bLY3hI1A{H7M_9`5VHu;M zQPK&U5BT!>FVX}A`1}!$eT)pCE#@ykUF3Zrd%=q#Ul{)X51Qg*V%QHF76UCZd?^Q7 zy#PO35A5G?(BK95REg#{79QQQ!N+(Re7a3l7J&}^xXs@(8{7*JH8}=4A&CXF2ZF&v z^MXe&%V7`8!$qPmtwAezW@2Dywq`GV=h2;Q;0Rs>>Cx@1;M1L~ z;nDop0aWP;cyv1p`0zWQ_3ZWh@7sCaqti!4!?U;Z04D>3=lA;_t#3gh3g8(f4}RCP zp3H0>orgU;&l>&*HCi}cnEQdsVAg;wAgB7Ma2Q?!t!Yy5>~&!QtB~+vJmLBMBY3ix z@gT@b4v)_BFAR)9+DcS3K$n_vcpPVq-ondZ2U?(UoV8*LC^s@NcrYIG>~+!k@2U75 z?2db${4PffFL{3d>H#`Q+J}Gr3*XLl5iAT0KAP`+82@{8+FEYmWq7fMACwhpR5(0( zStYjcGI;iy*zacoU$W}Pu>-VK%cIlGqq9tapSAS>sL>=*BI40&TRMY_;YCCfDD6Sl z&-IGVJOT=8)ybw%Zvsdy=*VWz&UGFv zpw;=y99S3_JUiPgSU|H3tm)gq9Yl-GpgN3|b2I4Zk$DCnCA}`J_CB4ac_0PN4-WWr z>i*uu%izHZj+*0b2`r#~2LppgC-3LOybK=4StYjff)4rvF~4r&1$8Jut^aeIK*K7$ z+d+DdvmSv-G#{}*8si18y8#c)FmN$27``>U?P~Z0#MiI~o$j$0)Y`$!vKzR}+KpYrCJ$hLy!a&F9^vX7b z@iKU5f^XLLIQW~nMAV}<;|H{!{vUFe!K3*#W9c`DAuqZ0xfnp}qr)Iaj)N9(d3Ih2 z1zm9O16o=8MgiP_05z0A8A8JFfJd{fYY(Um#AEmkQev$Cv+uu0FKgp zk_}o5dPD)#9s_N>1m_-)Uekl=Tnym#&&@83ppi_M$-E3Nu6r{wbeE{`fEG$Op8&PS zZ0GVa>{J5nHvlyY4gWJ9`+h_5SZ9d}k4N&i7vhGXVT{8b%|HJ0x4hs1FEHT&HF*R) zdaGGFnP2<^_t)=xwA;Sf2`b0_^S2xXDKmf3W5~+zax2gO|GR`h8Nb&wdMX#BfPB$- z<^TVeOL#zaf-DorgPk{Cf@bkh%3IL=v{!erf)Z$mXXh7>Uei}oxEMge?9prc`64$1 z=)zIZqOBL8?PZ>wH(bE8Xda;Tx9?uWfzDw=DSthVAGiTt8wOv$h`N5oImh&9~|9w1cU;L$q`lv`6gIt4wtD?B`o9|YOs(K{V9Yyc5;i10Xm2xPhk zD^!r_uw&;%SHlB_Ck-#XT*$+~06LGz1GK!p^LICM^ADzy)Ou6Ut%6HIvwJ@n`CCDo zGCjJhIXpVwxf(usaTes3)&q|GQ;tAayhGP1f>*GB+B#6h;Pq}E%|94-fQkW+<_ioS z-7$wbz?PKGhAFE159+rZ>2_uTwfB;nfAE#$d309`cyzvd0lKE$qw^?8?gex653X`` zk6zKn$>7!xWZ4m@{_A#T@$7s9ax!Q#88m^+>uUHUI@YK2fn&_!v#mhkyOkmrwrv|L+OXF$JRI3XDG)!aoAzPlNEc!1&W4 z{3S5{BnW>Bh_CtPC1|CgC*zx!EnwHZEs;mqeg%Be2zX5MMYbmc!^`CV|Nld{F`f(z zudgD~Bq*f^!>)m8u2WzriS_6$v+!uHRbcSwt+gnzd%?*GIzqWr-J{#sqq~;j#ZL|} zU)-a+SiqyZR^Y`8hyYu+D~Gl-2c-Nu3=Ln8?pll2dl2?{beCDYUWnj_dUQSoPkV=g zP93`fnrQ*`z&$$m7J!!fbcb_zbZ(6R&Gq*t{0B8xTLZw^1HORT^@QO8*Vaq?eNLdN zv%3|f&8IsAx%gJb8p*Cmj8%(L6oz_r^~!lT#bMmM`Fs80cE>++wlbnPg&>n>;U z>~>|~KiB!qrL#2!l!+LRd2~(%EphVb-V1WUi%IOD76@3#r5mgUl&V3q{?5HD?9RO= z>MoYG6ZqYaId&d*>HOi^`mI~0sq+T^34Yfbpu!%sNu&8Sqh;(2{`NeOmu_gg&hY5= zZSXkwfW?#9)x*P*qihSz`tAY_sQoXiL5)gS`?TA2hAU`ak?RD{&g1;@pyj`1HXzS= z_sW<%cGpUHTzu`>UCPiMa)ZUA^Fr(Y5*GdworgRauYp4O92+R9R9Kb7`}7tw`dWT3 zKjLxR6||9`!K2&tM2d$tWF0(zE9hWIk8alq9=)kI;KvZf9-iRYdH;1czdVDbYX^Tj zGbr2ZI(wYr9T>dN2UAC>c~bcGgbt=ydJq zo(f7qt(QuZJ-WfE$fLWq!=uyUWg&Pu5~Tg`LRy#sG7k!mM+?X9QVGv)U(ku7H@clz zx`jXse@=ti$tOAw@SpNvJOOe-uM;E4me(`D?E{bQR#2)1U-Os2#K7RwT_E5K(g!-6 z)uY+Ax&>TQd-m=H&9}W^{kreJZ+C6QYi(%0@oaw2=-KUB;M4idyH}*%r&r~IXSa>Y ziyBr?i1N2=VPs(NZT(+*-J{vo9o4LzU-td?Xtw1<6Sm~N=S1ri>u|M^=)SQr>y>{MoA@a#MSE?E81rLMgaTgU1&;-hhBcQ%s=W$4r zVK%5449Xp#BO^R|O_%j@F}#ps0k3i?sq^VA;PB`*oz=_50J1iS1(fr@`Sg}<@aR0` z(d!`L(fr_phvpH`k^_Fv=0_iVINuyjWVq3NpOYwc$mUI2%K^YXj(b=v&MTU?+o{sh-WQ6^s)+nr&w^ zp+r5`=Y9V@n`=}!{`0pa|NZ~p6V%cN2MXw1Z-@s$>mNM2S#E%ZK~wP_-4-65wH+Ry zYlb>qC%n`GH-SNysj?ng59&pkZe9;wEn)>qbgkW>6+g!hfLabIpd8W7;M2VUG)wWa z5UkOG0W}f7ya4HA`}J@!yr}dB^)-%wPG#k6uwdYC1x+ORbejgQ=Vds~>c1Y+OL#pE zv15h5briqMfb_Ji1vGKum~FR=kde zuMaA8+qU(7X95b(d;0N_l?)xPF^6C8N(`ox`9caE>kqL5EFlY$Oqm%XJI#4$) z{D()c2Zu-V0RfLr(S7Sc9V6cTV9IrcNAoZCGFOjo*A+h9u^k@0zAHR>OBeVs$1VWf zOUB{b`O>G?Mc{`|=dBlCidh*zYixe=x5R_ijr?HcZ#@Z`)dQ7LovsT&i>F&b3s60d zvxcnWWdONwKZtnoOC0R15_^ws(Xe&A436Nj2airxPp~TlcD>+dU;wXO^?>A-moGrE z)6MMBdEcXxRT<;HdbW6pqX@`lFM+_k(6pu{M^z~9o&$bhsxjKB3f*t#l^ zb>KAmG6Cf7&f_m682|tG>8)V&>HPoVj~FOZ9|I*8K5)Ky2HKMv#{kN6rt)if8D5?Q z>-zrU5?JMtmrp=Bxw~|QM>nhZT2M;i16?(l)&JldD64D@`q>V zNsmqokLHIzKpDWX`5`+f?gV@o&v|t6o?8QoZ(}ryyqI;Ik>RBd zXn^YgBYz7QC`~lm9;rhKZ?pIN{)0lpP6jlPo;=M*4PumJxaM+6scKW_@}22k6$48T&vBl^vOD9bRyP%Tv%r$DlH1(VzeS zLB*l~IBtFZp}79sYLM%-K`q2y+k>ll8D88u#>nte3N)7X$(ohH@IX83s@1#<%`X`1 z10j*x{rms_cG0OI!B>p+kzU;_?9jsIW#4a*;q9yyAjubupacc#z4P}O{P_R>C1~vi z$RXhJ`6cUb9KNy!If?c4Bv(T$UX}w(f*s=3&BE|f^f$`p8GdtM zQ$dz@_JW#*KAo+gaWj|B-VjJbkw+EMNA^8oc+%rIxP1t6HE1%V#f}wJw0(1I{>j7N zJ`=PDrTHfte@j28YJ&^}dK?E$v@m#f{!Qs-=xkL1HPu>ggU%ndy||T^;f2pzP#4>l zbrmne3x~J+{&%;6to3bu>%;G&TV4kmHYwfVaoiO&#?AoRYhO^nf%Pq0Jlc64-w)BG^Ew23#S|@ab&@ zHKlwyKlyaN^XNPd9^~}t1ULR($bSaSErQvgwLP5&`CHzAR)lmzeeeieySH9t0^M8= z?(n?ekpNw;V_Q-MDo-RldTm!P=Vf^D>=h_U*v4<>Wq5H5#D*l!?p{!OOzGtCXxR`Os{Q-1B#*hD{M_=v$ zEq2%oDg-^cJv3VX^S3%eYA3Y{UIvB|HIH7~*rlKf5*#TnCcXeCDz1&Z3@=(iY-nUb z)7Df-+7fuV3la&C{*kNUlb0vJ$1Fnlh9_Un`uqRCPcqmwK9H2{(Rt9nJLHdoM>jOy zp?!C7XZD4rC@6{V1r=ZnKHXq3k8ZFE{ua;)5+0CptXp&g$g$lFodFUa-BTgCEI`4d z(?i3fGr#~kQPVva;!KI|sUVMoCWyiF?9H}@<)F#hmOqe|Y|0XZ$7ehTdt7h>FT;x- z5F6t0mlr`wyCKoj4UU_aTfvQ!2m_C92L+E#aJYGNZw2Kw&=`Yf_g>Hx`-|gm{{Q#1 zZUwhPA!d1Y9^r3p0ww6q^B#<+Jv-0B(nIqbM*gPXpc$iYFYLen`wuGRJS^`QJ@e^& z`7+?&|Np+-SprZy;5LGLRWREkvD*f^%F+X78$3OEg6*3DvG4phH2bcC2B|u~zX$_4 zqsw?fm(nu-~RpgVf^gTy%l5$=wd;wZ~vgRB{UKEcABU_6M{#xtyd{8 zD9OjD2snc7Q0-=2w3wH{w=+aV0mPT^=mwX&p5UpbP8St}5-E>f+kcCA8D8vsx(`(C zfGQQJ$sWC;B5%Pp>Dfh~8u__LCpf+NKt^0%Y?lL9t^Z4SK^=AE6zS1<7;NxTkiiL< z2DjcW;qi z4EKM5j?P{7Xnx~?GTd(g9_}{-IT+jsa0R*Vz>|IdJv!gN==l2YKWNC>)$pX@$t(uY zMj+5If9Jbkk6zp0MZ64IVE7_H9z3RR;L&W$0y4?7^BCB$9}9UIUKBss_um&ZU;#ST z(XqRXqxD-|k!N$A07Hp3Xtk{c(%{W?a4~bl!>98D%Jhc|1A}LG9jF8=Ipf(Ir|?>0 zf=4&AM{|V$L+Nhtm~Zo84$wL3>$?3pT2IzL^67l{ViqFQUxknx@%MnUfkwq zVtAPinuh?_Td?pxfgax5k;8jcw>wAc0Z4djF<=RAQP5_}s{jB0zc{VW%7ADdK+h8Z z&o6iW_Go+qTH)%^X`+IZI$OXCV+{|acy#N4k81F+)crf3m!U)%x!0-8%D@2b^YCvJ zy*?jQIP2b+58BgyZayzVZvbPb=ur?im;+R#hkzR7-PXsQK^5kIkK@kZ5fyN?YQ)UI zVEE1Oz>7=5pqq5TF((RA-n&HwG{Vt&{DlVxD+8#A0JVxfgPN+{dsILxr9GSf>+`og zWCHE2Kk3-{Vkc-`9qcBb&VPpgUo?n;S~JJMjkK1}EDQ{t?_cl;u`;-J>p3?5y(h#n zm4E61$Ic^;jen=I2;D2;0JSu$S;1TO!Rw3ngBDM`c*zdBTIndLW^btmS>I{k*d4~= z(djGzI?LUsvsR$fmBW#L+mTLJ36JBhpc{o4U>3C82DQ~sbzW=y_5VL31AqH!P%ow1 zkAweYr>}-%w;vDx$V-ZH9=*xOS&0fJHeR`Omm^K5+rv3=Qs$g3bz2 z@MZi0J-b2TMZO3q>m3C9l$jZP+6sr^B~ap*@adHm(coeL9V!BvLu{GI!oUF1FY#Ij zoNgO_dh)lLvp{+jptW-hp8PJSJv(_Wg4$r7mKXS2B0=Z0b-P?)aqKn$o#f!d_yHP9 zC7k>xJ5TVR^I-&S;%~Xh%)rp=_rJl0gMq*G3^M}*|2B?>p8=(_4No>yFb0*bY^Y%J zEM3gMt$^8~;a`d)|CB=x4gWGhCoeg2{&Hyemk(mPbcCoVxNu%~X!uv^*!jz$qeevo zEY5iybfio3qx+5xzamOF9a{cF3L5@x9xM$%E%;kNOJEv)8uGVzfo_`kY0TfckQKBS zqoIP;h#%ZXYp7sj;BN)3-T*m(zhxUQ1L(R31qS}s?GUC01Al7>9|Hr(^ww$+qv2l# ze@iNa6~W(nQV2Bl&%0NShv6lt8i%$oK#8?f5ZX9OX|`bDZwUtNQ+fX)h@X|Ao3&sL zxVL}Y8MFYFp_4UX4rrLLRL%<5R(XG)Z|jBVY9B)9MJGmHzZRdmHAtE7(n~H zK=~i3%%9NC$_29F2V>o7tUdfUvw0c#SzoV%mG6jz4Vqtd?Dpeu?G6)xCT*l-?a~<< z0pVIWg0`8qD}(BsBIDOKiSM;nR4}(uHblGX}Q_#&E z&;e)AeXkz9pi6lfJbJf++knQ}3=G|@g0sQF`*IF!|F^5*TTs`@l#2;;_K-pAfznt| zeWuCQ8b=~>?1t&i%xQo@-0Fq-o>Zy68 z6tvCsArH=?lE3BQumAr+n}l!v0*wrQe<8xj#L&%pX(lB2V*mdC@7wv)r@KT&!lOG! zCBUbo+6*<057g#rwk^+w z*5r^mmx;Ic{rBn4Rd^W<+C>LC(8{qpOvAC;O$S=6@VDFs9cXu|^Ai7w&I6vkJYpW8 z=B5whhvP0PCZN;}R0`c9EBH@!Uh-fLQITk_;`q-$^?{Vv@pDkeC>(zW#o ze`_ZT0|SmswzCIcW(j7LfkzU!UVay4dmRG|NO0mAO_go(GXSye`^7#bnoSjm*8P| zS^fhY`H=FU;insaE9hi!u=^ePTO+|1vIX7VTjzsW>V(B9Y z6J+UrkUYrJRUih~(kT#D1b?eF#L^a!r9R)mLFEE!#;`K*x2iG14DMou*YJxWOpw7n ztkATx2*dyzoC{$^@VCBu4(hD%-WKCwc=`F;|NmegnDMth{|5E}1Apt?Z?Gsn2{99t zG&ez*Ame9)%mTT48;Aimz6QdI;BPJA0tZ$N$oMJW;O_nz08LX3U~5=I_*=`sEVdy2 zR?zA74Hcjud&L6tSslbakk#oBCdldlkUb!)--8%nt8YSB5&W&p5UT?VxENkaegiGu zV=z4VlK}77ykc6^j>3|1dImc0$_FYkq)gVpj#1&Ih2* zm4vI|CD4q&Pj`w+!f_WBaP{xm>jRpQ%~8ql>1AOA725%zupf);4X@U>q&u&Tn)19|{7=L#=vNTt6{0G%YrHLTx z5Zb=`; z-yj>h9a&1|gWQqe)0@fS(+N2O*t7G!M`s3yPv_g$mX6JT{zJ|iaP55J(R`G{zgy=S zsI|lX6f{i#&ZqM~=n%KgBQN5ffX4P+R5*MYpLZ8Xbh|RRbf>bkek)<+KjFxKru9I{ zX2;H>9-a4mI{*80zVc;!@5A`|g~pSA|6k7nMZr=~V-FNQ-6AUx!Qavd>IF9+VtFk9 zuTQ$2cs!a9adaMU{l2wGj*@N*>*%35Ew;x1cVH-~CwUK~OV=r3G|xZt2tRPz}%KV*-x7A)<_q z%|{tK1zap&m-cnLsF;AfEa20bnsD4T1JsTIHMBUunF*8t6*^rVKoK9{)0ykx(dioS z^7D7lS|k@0P)!P|cM);WTJ!J!fAFyM%M;+?Q-~rY1)$ayM1d7(ZWe|j&2h!mNVY?-AF}$>busuPh>Ot6|AlsB6Y!8sQ7=&#E z(#r*5w}Z_52O8S%<#h&G`3b^)BEZG)@)?BvEP;#RgPe&^FZcIg0L5Y#M>b3+(ldrFRLKz{lYv9FY_SmVvw0h z5OxU2%rFQ$2xPApgzXPfV+Ubdfy9j{3{(e$Y9i2N z2&BcJ4H5#k7@|Q1Z!hn0P|)|k2Ss#41(z9rYct&VO1SZ$`wki)Z39qWwV_5ugQ2v> zq2+&RHptkLNJx`U2x6oPKM%u88?Z5;b`5B|Fr*a;ns5XgQ(6EqA{JzX57-DRh!Iyn zC3G+ELp~mcmp|Wu2CjJ@EZ|~z`4+-965?Ta`4GZpx8h=Wc@@Im15$Gm!sY|1*$ZJm zw&Y@Xxe>xXo5scPaw&wZw49sa<;-^=U%#9L5n2b5ZiBFyLDE$ab{Qz1^C0YEP<$pq z*dcse3@^hV?65d4hL>Itb|lD3I|$nfq}K?-HV5fdgRmt)dZi$2DUe=12wN7Um+2iW z&VRfG#W|-5f9pFi3ly49-ck_fIiSjc!IKrdjQm^-FMqy)#Q!`{{6pAA0-*SZu-Pp@@eg5tOyOd9c@n~QTguJw za_<|E?_O?$2<-;N!zu`S4i6W@%Xtv?ycjNqmy;muh2~rgFWVsOCQ$rTLD=;my?GFJ z0!VKXgq;M^8wO#gg7kX5`Tzf=$=!edU+RMhEfAp!A{0P`G>8xb5rQCs2Sl)g2qqBm z_s+lnFMr(m_aD)Ho8ZxH=Fx5M(JT5ml9%CS97qx&3tkVBe9fctAJQsf(5jFhpruQo z4VRFmAD}hD9=%Sg;1vg;g?=fZ#R5-0fX39V?|_;nqEAvmTmDTCrh*m;KKJMp=oY=1 z%Eizbz`?&=^l~Z}Lt1A5&x?0*jNqY;mb;*peV|Js4fNV7;JFt z6kj30-};-GfdMif?bG>d-vrRyf9LlX9e!X_O5*l$fv1nZ`*wbLar^ea|NPsgf(`3D z2;WA~ZQ#*);hResqe6)UXnngQ=wb~<&*meHF!9niEeA?CY?S$1XMoniw4N*}b^OLI zP|^z;x``D99bvl{?6wklk8abR4$u-S+o>~n8NhdTc=Ynl1g!>YQ3kC+Kv|OO4JydG z!Tv&9l?yt*7wYsE%D2HY-=*EiK3wJt_F?JGmyor!4h)WTMm@+zE*~g zSGF7|k>KBU!K3p&|2Ahv(A*)!v(JyQGw^SN`dkJn%C`lBRl$A#4m66y23o-j(%%~l zGG6R8Vo%04Cq~c+a?61dDgJFgzPZ#fDwMpk;o@&)Wny610orMl*2(12&05?JnuBOn z07Yi!agT1+D3E~VasK9M;Ang9(b>xZ3Ms8y|NeuP>h%UNdUQ^e011hMgu20OpKe*p zcF@+L07jo~U9;)D44%C#!l0!-|Nj5?0o@XR(4(_e0Ax!yD?8YVgC5;rllj{~D?7b< zO@ur;dq4dB|9>X~Xj@w6dymF{5Y}AqNm!ODHQA)33vmiTmoP33Qu0+n6eU^9F=d22xGJ6TiP zco|-Ed32kmOaslnzVzu{3ko6cUK>e|&R&q^P^Wkve9Gbj2_a9$uRfj6US!<>WvsoR z0P=x&5Y)bh*zMWr%HYFz-ly}@3umyhxgb+Ln!$;U(X-Q)!=oD#NX>^CJ-WdbfzI)1 z1;vre`fHDF+dWf3N_s)IzHs;sPKEp}pFl0sPSyn= zxo)tWPp57b$P|@-|NkFjVtDx*6i~f7pspILN9VEETRjjN`sEXl_U^r4CxTWrUjw&e z4}g28ogaKPUwANn_hDr4VRV43JGDGs`r+k9P<(g(e{oxok>Mq1k=~0&5mpAY`LpIX z63BC6X-F$Ef4A_02CYwnR&n#U7=Y4Xx9vHQV6X1=5YR%d|NO0>E4DnkO_#UuG8i7< z-zL^_sU!$e-gxx7F?w`uuRG%ekYMLA zka)|b5>}A%w;q=N%6<8_iR}RO9$PMzZfQAC!tT*&>e#}|;A(gP*}9; z%||4BK-YT1?huCD-|W%(@AYPnPE!_;%QgSK@Bs~9gQk~2XMp;2+x}^Wc%{V@JXOp3 zXEMl=Zyun5=+{DN6H0u1drMS6TL<{tg#Q2k@87Fp=h6Afqw~J!#W%j4Pr>PqIY)&9 zv$iB&(l*xiW?qJudqKUuZdZ<%*8l(iM;cb2)C?L{ zp9soFy|%5*ybLdP%w=SF*#KTi+0I(r3^~fGPa1sMES5!!fgl4|U;YNo!A@`thn(cy zdCoD^w>O^&JX6~I#shT4wuBF8wOfgb0Qhcg7toM{kBY*Jn^*t+cWi#f;?a53wet&q zizc|-tx-{UvHvP)1So>Bn?=Qk@vW=j+vW#Mpu-|c1U!yFI!`n{3=L&qxcEag^y>frj3+t|sTvzIFdY2F)cDBw z^Z);hhdM7D{K3L_q4S_BKR*M*!Jiz>5BV7nI$nO}nS2b?{T2Wvc@1As`7#4E5Y`OgJzi)2|8>7ef3m%MzOP~AjuTN3Y@anaB3TorLXn6@L^&zVsIzW@m zp!o6V)bQ#23yTj><@zEA#hjz1&%wDIJf+YATE7HZT*KiB+n5X9MD-H1_N?1g!n4yw zMZ&i;RRZkDSKtyUM@7J=^S9w!`1p%Y=X=lq%L^8;Jvpp!_kxB?OjJCY|1yG(#MM03 zEu#V&V-PTW`~9+CuZV?f>$eI~pH3SU*UqoLo!4AiUzd10Hos*o{_1($iE9}d=djz3N&UC02(f`0PR8d zc<~psUaa|ufoG@78&Eiv_Iotjs4(!ifVLEZ#+C$LPjNMTf=GX$^*R#o7#Uv5gB{9n zjKKkPmQGfn~VSczm!C*S3Jg`2a*TnY_PlxNFH>I5wtx8l?M%Qg602Q`1k+i zLGXkgNQ~haLp&(6DS##KgCu8wf)Cza0>uf)^`Ln-7ZnMgPKB4CVKSF)6P1^q|Nj5q z4^C}j&ta*pM9#BQM+KaSULF9iaD4j`w0Q)yP7t&h-J|n8XbYw3TSkVLHlT^dkkDWc z(CF%8P-C@Qw!{xqU;hPdz3u$v)5~J#YIqX7VZ!h~INkDZ9QIM7o=mrzd&J!Npwo-ne%JH=%q+aY6 z+3wMNkg+51Kd8?0v^-L##lNitvVu<@-dm%%8I*)=*|CR7K4qBDM;Bg#O8#8!zkvD?I#M7A6#3H9u}=F$24wG24iY#d6&!7XZVi@2o1CcdP^qw}(jUg=X0 z%ljo7{M(pa4WHQP@wb4c6m1+zB|(SQA7f_l>||@GW@ISgbZkDu@fxJaqni=rGhUa@ zN6n9ZH&`&Z@Vh+n=ynD5gi0Wye_^7{MMh3+NDj2_)QDlfPG`~Tmy^NmO6@0Y7U?TOCIplmQ5lV-N<%i@hKQNa2&0AcYPL==T9QhP#5+So4-daxplDIqv)S|Nno-P{+NXl}L^u zKE0~k(OeAR`yw;gL96I$R183C;Q~!@uu< zYwH32K2RF!t^pNIB`OvWzcv47^yn<&Xukd*JnRpW?7aUHv}OX5pFDa^Uq)~-xbg2} zVFQ@~URw>CDq-et1>N)qa$!H{K$X%OaK3?T1^2MdQ4s(gxB31>^$XCs1}!R}FhN@W zV#Wzx{sIa_)C3Pr&mO&|h7nv0{M%UAV9xJP1vTs}Uzg1G;NR!`AGD#;qxltwBPjTq zfBY$V(tLoi`G-aM9gi6eHjIp=S6=T*o8b8UhDR@JUN{$nZ}JZ>{(UwU;IdZp2WZe^ zhDSHcA;;z)yyZDQy`qkxTnw(A2fUMQntT|q|9=klPq)(#pKc+aZl@2OE-D_rt(QtT zeL?HsYCvrS&^|}dJWywdiiSf+iHgh%(83E)b*A9cdHe-vnY;)8z7iD~!vmo69yC09 zd1b;u<0LkqyHgoFG=G8G;hh&eG{1ZFny!f8V({#A0G*g}E{u!8g?}HvM{f{^6aPLI zi{=*s9y9p&nXtJqo@@SRQO@g;{LRIR$B@4Tv{1mK*VHx~5m+7Wj2^x5j9$Giy8l6E z&@_RLiTBWa?b7K2IvBc|(X;U{zd8d0f4>Vm1A{N)+Z_Vx3=E!)e?gQFzyAyG-kP`U zFA5((yMJ=*psfbKJir??UR*l)@4r{C$Y0P{jc;!)JE%J3@N9nm1C*i_JQ=|kt7(9m z2rEwh`wvbDAkQm!^zzDwf$k>qQPJ>8c2SWj(eUVe51Qvu0O{m-5%`Re0n{E)0Lyyx z@_q>AVgPC7@L@dd-Rq+H-?KMF{0GQK&9&g`mTEvsK~or@{+!`ASHo{FkAUiKa6ChD!%NTs&R{;sR|X#4 zX8hai99sUDICyq`@@PKB=+N+Aq2#qg!+*|_r!Kwm-(2|jeRpj5UBur$8MH^J*VZJM zi@}wD+im}3nfbnqza9TShUO#CVpH%=aC5_NFMZ(ldi1h-hJvHc0F=&OI)Im1I52?I zozn-OZXrmzJHX%43tH3zT5AZ}Be5UUq63AS1881W!w0mm8jlUq#QUrIxSvWf`>Gme!MgQ+u`-Wr<)0M<5UZ%M-Q=(0m(uKkUx=a6~(ZX8DcBQ zcd$qTEywc!m8}f?44@q7Am9P=od?IuUB5wr&*anX^})CGKuIR(3f2^OsAAZ*{0<^O zA%2`11PxFh(CJShDh?&85S#eWYzp}O|G(otMn(pPmovai&5nb-0?x6}A}{NgNE0%dWZUXlHdy_FYS__y(S@bCNY)oT+DQ&DygG!6mos~9-$V*`!& zb(-(v1}*k31+A*+E>SUX1ufAMGyL{49V7zw9B6B)hjI;QS=o6uWD{7RCUAmGFvhB$ z8Cg9mR6S_$_$4z|^(?Q?d0<$|{<_n#p^DL#zap^K4k{w^H{tC)UE}-Ol{KY&l2UJ0Io_{eB%{T{-Ufx)c zaW-J%&O(|xFU3Jl-2*BdUb2D$3&W>e=spDnFvzFi0Ji=1|37Bv@V>kYYV2Z|#r=BI zi^~5jph*!(f88+*bk&I`_=3!eHKjhJCniT+QV*GnycL+2v zW||xTnymp1QN7SP1R8^STT&0|s#JOOMsV_PbKq<_P?G0y{1Ei0B(B%I6F_|j&_GDb zfszpL{6Zk3Lg}mK7X~(*<<6i(uQ+yr5~oM!{TB;Cr@dLmsBn~Md33rmcs3tp_W+%m z1zx)GV)7TzF&L%%9-ssMKqpmzx-t%+{j@W=co{$f9>-n5wG&7M=zdPfQ75Impqs;^ zVV?o|u!M}~&qxm?a$4=0204Tk+94Im7-zMI2sYD&TjtC?PnnpO(2s(iC zL&;;0gRdk!6i;{CTt%=`L6B>8{u4{NMvxVsrNYBadd=6Lz3wzkD8@&tA@3 zzwbY!Jp((Ri0bw=zL5YOI@I~YaTh3m82(2}&n@6n^bHSqc0Tmz-2xuK_1N+M|NnYW zFAa3qCTNJpr}NYfP%Y+h9CDF1C=r0zpdld`8#G7@V}ttdFg9p0FpLe_`~qWxR;a_+ zpiw>;8`LX=u|XFUz}TQ&^)NPQrwoh@+EWZ;gU^uMspG!WS=fLR;>}h^h(3)n@-UN7Gt5m_I^MFU= z5m2xmM%*9k2nx9WDVsA7@u;a`6iR0u+v4Su~kd>){C zEjc_oU%l83>XCz1WVdmGM?}Gkz(E@yK_lSvzy}tI`E-8p1?_|D1~tA!R6M)G1bn;8 zBtYdkhX?pp3~nX{hVo?aD76vTm=qO-*Bbot44`A8Ks`mz=A#^*o$Q{?$2q{qje$0G zfY)LhF@Yv-!IKG~ZNWaB&;MU&Jy3t#6Eu#|{1!A-%<=jte0;AydfPe=$3_?_({suJ&%B4YNwjRhgt)LU0zz%x}I&}qf9&7Ut=F&pY`3NsSJw=9> zpm`&ZcP-)Sl@hb8}t*@ zmUmz)Ji0|xS`XA8@acR89&3Kf_~PJhkbV`A{@44!8kzq8{}1*P*j7k+2)=Tr+XvKB z1jjG4jS9%Xi=d^S0<8z?>O4TRL!IxyiG=Z}Pv;L0Z59p?MBpx}XW z+ULveUH|@r;sI>?GY?QoV?6S@0dk(3Z|8BxFwf3wpt>D;fMN#d6cmrn(hj8Z5WFs< z`IiEJ`&v-Th=2Vj&(1HNjekJ*w(+-v_eUHDZ}SB;zC4?chj9t6(ghyJT~~kxT0J^rH~4hc?(l5>r@-G1D$zh^iurJUSi#KS0;+F3x2xD9l5 zTsLb~I%r1~e@hc6=Oljs9Vz#~4hVu6w%%umwp>W)F0jPok z1s$jZ3JMkeHc^mvP^dfs_efkp6%B(&ckG1MGLU@c(d;^d5xkMxb%qD%P_{PkMR?t= zGkm*Mj(b|(DY@&>UE2UEAv*89NZSD#P|cm;(Ru$h2iQHHpn4f}N}{&w1fR}#p5MQD zcG`Rg=f!89okw4o?D+TJyI15rXm4&elZWMv(z8CDp!K#OBVUN^`1k*1B`6@^=cy!+M>HPE}>n$t8OLOorgbM@1{!j)6h8NQgvM_k;0@YCe|NoZ2cxeeXiNT|}wu6Dc_2s|+ z|6iU1Psc#oub$2SSW3)1oBwf?h^}CV+)o7xQgC}3bOG)+*9q*UPeDSUF5*k@@N?(C zm*7staaT}<&G0hq@BjZVlD@Doq)l)&Jn(YIAJCF`i23mO08rbQ!=qbvb2jJz)Z6^v zD}MR6v3qv@2d#hsT{Qwa(4^GPr(3ztm!Wj8XSW*%xE2QWY<+qi z{`+*>o=gTUeR1P}Sq-ukR9-dfZcFB6VD#xc;BoK)s}JJ`aQz0lD$~fL`4>xRi$^!; z4AzXM&a1HtTLm;$>ibnfmYl|6{C8AU1L^fo9>F zb^AfWt}Sm%R6UL#?%3?d;CcMWgw1{oK9-M*g`n-Q|H7bDM!1ew74@(?JK&0W0j z|4Y!}^PrQjek4M*f{u#78XVUW!NCDK?*r;iQ0fG)W(OxDk6zQ+CcF$U%;4uYG}zWA zg3cXj1vQUDgFQNbgLHUw>w{Y%pvwq6I^P+BIw6q!?a}SV@mc|qAv}5m{(E#@^f>sC z)uXwFPk^CR)uZzQ=uWSv9^Gsn$K60>HiJj!cTkihftD)m1?LNo<{t_rx}XCMn-4I0 zbh>eP9DKy;)9WH8;CUQ8I0Z_k&8&YCAWL;PqGJzxbpG>b{a-4(PXIKe3Cd3|)`9B3 zPS8%z5-X2RJ&#Ufkc}WIpI$eC*IPV#d6ONv7N|oa18hwlxfot-UIrS! zKH$@N;4r9caRqICJP;j=F+UXwT@eF1_kq9VDX88Dts42_(RtOg^DH9ql%|41n17>a zU;^mOj`uGXg3<#G%uF5N8P zjm)mC2TIMGbva;ucY!TaI-E8EX(7Ep*V2fW0eal21L%H&4WM()e7YH4 zf``zL9{}+UPo{uGK>bEUS^~9GK=p^K;Wx)n&(6P&A+Cl`LO~UY2BG1 z`r%?`V6f5UZvh?JZlitNMMVVEWa9^~!SG-_%)d>z;g)_48y(RtI=@PMn~Nzf`937>9R89iPGpX7h9b)osTl+DUTMX21$V z@$xUIX|pXvMcBjgD1R$xuP*4mXh`&eq7antLDAL&NJvwhfjzWQ4Qs&Wl!bkH3 z=s@v0F%SNIfuKX?Ep&Jpnr$XT@V9`@kO6s<16&Mgyj%|oBe1ugQCLp?5Og$xgLUVAN#h+jyo9^`Mi1CC4+W=9JXmXenq zo%dQUl|=e{M*79L9+!dmr9Hwss63uf!ACUAm*JYx$nZi zO@__YLWZT}jfdsIvh$ALTml$bO4yohraROf^y&QQ)A90J$s!v<3+@T$TYk`{e-aOkj`WE#NDcK*{!aiwbBD z0H_cG30Hu`klKKtCLCy=4y=k%ivyiJqY?)_c}6-8(uJ#MLNpseT9$)~O5Go^pjKaR zib{duf6y=<$Z(Iw9u*J`x=zEV^U;e^&<>7f+uk@(b$h%;1=Jb;qrg z+4=s(j-4RM8WkSHOCFssK`SRLLG#qS9r2)r=%8ydJ7ZM92NDE$^qQWx1XVq(M?q94 z=&qmRE-K(nfG;M1%;|jJdH4m}P8QISe68SnPI_6@W5Ksj@pv8w_c=jjtbj)^>xNj+ z+AS9qiOw1o1@KZq(A~_SF>>&l63`__zDx`ZFEnQD15MWQc=YC|aJ&`+$18L^uDeEs zC#BhnrIa7!_IEGtZe(EqUCZ;p(nW=*1hj`0eBux2?k-ud!G_;n+?=`Z|7(6|ItE2P zLp^FVf%?F(nDvR_WoXv*jNxTqEGb6R&-|^kU>r*5sWxbCCr7S~4$|@~w*1ZN21lK?CQEbR+ zBah}I649}TLH2hWL({>F&O4xMjEXs6^DLEjSQ$VE(Ogl5y{K& zLO7q1;bjfHp9YGD1dxk5QTY!V zy=n*bi9q2dz`xDfhw%ZpK6=6EWBH;a*Q2+DmBGQHg0b`s|F&RIlTE>=H<-zz^B~yW z7J{W$9Qn5ic{IOd^lU!F*m9}#ji=@Ja#N6T96p^7Jv2Xh@b6>r=sX1KAkFZwJXoUb z)0-m3=)>>#4CK)EQqZZgmVbQtot}Gu8(+xl7(q+4IedEK{`+*ss7Uzo?+aseZMjsE z@7a8e(XruIU0J@b<^A&GKArbK%WWLt#o+*w^wFe=i^CVhzwr_m^Mb?Icgl z&!FJD?`wIPzXf#m=IguQa5g;o(sLbnQyVC*Kx^RMfF_GTQyB)JHI^2jr77SA93CwP zO3e8+T~q@2HGNbP_%%aR3ivhWfM>nODeEDSLBf|jRshJbFv z^#R?#?xI4oBn0jeT!I8OXc`u@p6EDeeeHj&sp-udP}qlnQqQb$#z+ia5qxD-! zc!M2-XXh86UR~vEE`|~hkIrYiK%*`%c3%Z8l79*A9lZDK1fBQnUBty;c;H3i4Ny=* z41w2+rBWV^M?m&~7epMM;M1!cc7>b4xAV>GH81=@u0!;7z~dR9@gtAUzaGtR1fXp; zk8ay@YP_J~9)<39Q0dWnphUu>`G|lEsE6_nY%q8v6r}&fX>LY_PSCL+r92+pwo}!3 z8D3xJmuGmHGFff3&K(!tyF@cx|K1UR^r2CsIgF*?H zM>lJL8ZSdL2WWy!z^C&)#J(pt8Nl~Xf*QCl%rpQ0e?1Xge!}x7UDC%+P@U@m3I@<= zsl6^L*o#bYPz$yjM>aim8##%1bc^$EV{++rxZnZ4@P-|*V?1Gb&XM2ekYncok4}&&pdB1gtrD)S2P$4VHvTws z<_u5WDd?!#4bb@Z0puaX2_DV%3?*Km$%3!oMqsx)hevO{fQL4_XXlX@|IRalj%_yr zT}bKC9W3F&c*uwGfk$UBhet1HyRNW9hX$zi4q6ldslVX!)yF}TU<@9|ok1lr!|R*S z`V%sr37X9O2g(|t&E+T9Knv%m27qoL?=|`PA9;lbct#U4BA3ct@di?qix=9zb8G=OxG$OcG4RoyPTUW#X zhPRKmf}9WP{~mAM^An=br}L*{=Y7zH3{U}&&eI;pTRUL9H&pTHfN) zy%ZECKHY0U&U$SCns|cPJy!~JE*HdZ{%sPVJFOTGcy@pF!)%$=5OH!EvRh%|G#uA z)K%SkK^{!$wCJ7+igWO?o7PMGu7^6oY2Y>M-5a3uDZjIUl2fU!XZJqPrnYW(mgX0X zo$f59(jLd%!Fe&I8+INke``I+>-vly&9;jqLGy#4(>p=Q)9~AiL!F@0JNJTek%#qO z(5ZbTtS|O%V`OOF3$h<{vm|K8OY>fE660?Lo#y9(dI?#30s})g*mY>0OeZdsi5ra(K&Sn=uG@=0gRm&nqL_-|Kj9t2Q7H==-mrSl`oEg0om^yu|s^yusbnZdt}sriME zjUIpdThNx0UQ;^_E(ZQ>2RxEl+B_IP{C|LOFX))EmPfxq_JBj-|NsBsI}7=t`%6}QkdS}53zX`? z>KH+_7O0e}{R_&SQ$d;6qt}rUbTq@S|NmY1w<)@|UMl5v>~&GuYopEIHk}Ey>FywC z(MF1Ew`PhXWILWq$5N11pYElgT<7F`D5Y4kJFTKHg=k9&0cXMA&UWK<~CdxDhz0o-r>@^`4gZ2mSZs<*dB3%S8W~LdE$2ZCk~_hr zh)3r|{%uSzEkTnFpsdNr2r9Mt7a!tp4h4zzikhpziUi2zsLj2g48jaD|0NS>jBuM1 zqfHKfOScRILnBy@L4kqc<#X`V21F`UhJgX1jq&Aqn0N+%i#%MM<>huzs_C8!N=wjU z3lvw)|Ng_vt!{9E*Lkq{AqOPs@wb9TioP9Du>sG;TC`PH@apJ(Us*OK6J3zF_b zK_!)eOGoJjP}9ewyBFkQP+}y9yK?1f2r8 z&L&o27>HGixFMB{|sKUpWVKr#W zXVA7TaN37dhcB;zb}{rOF?ND0P-vqMoV=?*iJ^HfD7F}Ux|f1z{+2&K{{J_;?FrhA zU!sesA3eKW?g)5vTfCUOj*$Vv0Y?)kh8R38WmL-V`gW(NfYwiy9(cJOv}L7xE;s>n zTfc~3$H?FT={UUH2--#gDP~`oJ2Eo7R00V!zfpyht|FkV6}`5B%8=64E16}v2jh?b z4?G}w2a=55n}Na*)(AafhMJ7J!AZjKfKP8WW9udU`3E!)Irh3=ZGP~#6D-5uDyRlZ zx2>R-iBI=ZP?N;d@(6#+C1;319*{HN{% z3rdKFmyWfr`1$`oqfc)(Q|n3o`G+(wc7kO*x~GEbKA-NTAZtCkg9^G?nwo#)@wbR- zF)%d$$mDOWG5|XZE=D;J^c|ztFV?T{;5|J+OLkq!oc~-RyNyfd!J|F%}gDkLJA~moxCU z#CU@;G^j}T=mxiWI}bT_9%+08nlx~1e!{VWiNA%@gnWurh!TT=}RAil(jL=56;>kep}dM-R(S{4GIWK&_;;pmG}2foau>WMJq9 z_fDIC>hrg=L^3dRo@hP@FQ~y%9^DMLEx_6(zWo2+3~p94zP$YD|9@y<&<(Gnv33w% zJ_Kd?PH@!%X$64Bwjdeh7%y^0nF{K66*Sv4Rq(e=R|KUHP__Vv+0;X=2l%HRP&@>wNE|z_fU^G&F$RX_y`Xx5t5gaS z%Akcf-@$b@s3PTW-6Fxj;M($pzePU+lxV=i6p-4&r5jw~dO#|umvs!F`{R4vE`atk zw{PZPU~uepyJ!urxA^-PgBmE1%mFQ%TsuF5y?z6H8ng$fa|24;E*%n}8@>PY&p+U( zdE61ylxQ*I0L3??a^Y_-25SIC1f+ff)lIIg|4Y;$J`vz=Ed#HdgtqLCd31+^JNyFt zt)MGypb_EH33k0J=mh9@;LGj~fX~1Kdl2lfN^a1u)khwhhro-YTMR^CqXqT?44{z? zP@5XG?*4_FHE8QMG!KJI8&AtC{4FgesEG^|sYrSFiaIEUkn*rcFE~qfgZm?$2OA%P za&z+o2glAM{4Mvm7#Lpko@RxVfnZm9Shj+)DSr#-gjYzr0d%+%B*a@Y-h)~VAmf`K zFoJS;i=8L~sQce?T$zEvr5jvtg3m;lW{;AeCurix&mNru(0mLX<#;Lj9#k!Z^Jw=} zkX4-*KqpW^T>vV|Az1^wwXFH)e}314km|ehLh~aI$IdJKt%n#G7{HCe4JII0fC?E< zv3Ss(fuS4R;sZAZzuOSs7+e8zR5G|+-T_L(jlV#o2fyDT&~28`c3|)Va61q*vIK7j z&IkgPfQWYBTN@A`sU3I+EC6m3je(@x<#j&|(cEIZ3|#|Nk4fTwvsHS*ZeYdM_xlTtTt**$ySP z%#3lymIN&6+yb2%3Mt+pcA<0;Hp5cIYbB6Ph_rf96~(5Rpa${<+?@muXlo6$^=HD{ z|Nr-c4&i(eHV+*6poTAGbu)hpH>h;$M#O!GFk0M~g9V^*59tFO2RFFECl7*>K?y7w zL<%8?xF6`6HRQ4z+JJ%f3XpmPkhUN+iGX^W-C-G^!VNlF*)G7q0BXK>Zv_?DKAkT> zy#e3OuaM@vXXmljZ?NY4YiVeI9jP5}0a6Y!4z(Ts4K!4!S^#gy^Ml+DDQY3@_?udw zc08zsUW%n1Z;c*}j-5w3kAs>Z&CeM-!Bq=?OR*s6ESM+!t?+0qHw8uOR7e84#NXP8 zn%x~uaV8*WcL&l42Sw}7*RW`i>U` z_Dh^#?PvJ66)`%rd@DKZ(C{y|WH0|Vum27f=ZdyK4Y1-W-VGi0eyS@wcv!0NrM`7hJM;9s!*})p_}K z7-(D+w7eLc=Q?{KjT?goYX<%n(8hRB9RNDE5486Z+->G>J_lO(+v~yT+35@JdGl{$ z2HgYe*!+gk#qtAxD>HZ|1Kh)K?feYwUX;#u>40=}KrK3Mu#&x?Ap;L>NGkz4)c0@; zBZCY7wz;4tAt)J~hD@7)6Jd8RcpMwl^#xs20ck&X_JVpZU>~5kzSRlbyaIa&bpB!I z1D9^F-#uDSmd5&azI$oM2uqKkfq)rmpaKLm5WwFGT4)Px|9gP$2mS2|*A2d48#HI& z(G51*v-6Bc>&cS!4OXD5PTUw6Kn+Gnx7M}wzelg*e~(T`Q1JWz05#ZJcYOu5M!6iZ$#}$r@es6I3U0!|Oz)6Ud6@+| zSfTU%i?gZ-ue5^tjF9AooUpnXA%mPR=YY?qLc^n6KFTl*^!;GL5*9zK;_A&v!z6Uh)!T|ORs9@)B)&C5-Mjo73Tn(S3 zIKq4Z=`DZ~*1gaF|G&Hdy3xAx`-`J0j0~NJL6Zxumq4WsbTyqzH*6y6rPou?@fP1- z%vJ$~7}$~)tv~<&zl{6zAL)Q^Pl(Q!te~qIaT@V2V2L6_l9H3qb zDBZH~x9tISESmpo@V9P)bSXfi0Y2Rc1)%;Kq^I^w4z=Os)A_@(*`_6rzx9zFsQ3rZ z#-eIzQpc(#lfQL6E-lwpv1-ZTZ>_Nd)uFIvARp3%9=PAwe3-?t`M)NAYlt1Z>ksdk zI%{F}84O;|NA!iEjiuv=>a}&xxBvegJCA@WUH(?kwl;8kI!PB)#mF1&C@#y#jTL;ghn8I;i380h!W;_4d01GeA9l&*bCK<`Sm^$p33W&1=uj8?K=1 z>Uu%NqEGiyh`UcaHa-P6wjuL2F5PQEN$hnRtmg0T1vRuiJCAsDTX{hG>K?r&{2rDc z_*--&K`olMbzF|kZyEVpy6q7$UhLx0i^$;%u}|lBm(Ho6adjU^N%1035!A^9kKDO*gJqh3{CDg; zUOLC88{)A}u*ZBl54(0=L1bZ2J=0nTx-JsZfj9II_+I>;4L(J!gave@32N^TQPKN!t_24vV*dW+?+5???*h#QeBj?G z&fjw6@&ErX;$0XSUhaAfDHxg*-~~gg?t6IYgK+mt>Gz;%OHf-EH1Y#U_stJ}@-hm5 z2E{?~`tt2tuwgEc*nvy}zR*x$WatJ@X}CZdW{_~=ZxsNSUXNTm&p?|6KAqsc6v9r| z)+Z%q(1`_)&TF3CwG2q1A>+{r?wY@NHVd?-3d{y=@nHe=AaR9_N9R=Zu(^L9R8N5` z8PGUEE9eRn&?p0>)#%xI<%Q{5NJDY9I5<;*>M##TJ>|i82s+*D)hnU^ZQOyH7NBFy z7l6C`pb!I<*q}ip@YqiazbYbm@;9$lLC;8#`W`y9jnpCOjbQYEc2gkzR?p<)E*3gW z{4I;XW6G`@Tsqc*@)R`hxO9RiAbmT(cy`|N=$;GiU>ygK9D^&P&ej<}|Nnm-j2M51 zWS==IAosbbaClm~s0i>ke*?FJKt1OW6;MOS!lSzv6b7Ej$N9H`>vzxIFh&Op8%F*X zK9JtdYmiP+>$lRi$lV){&imkAPxn@k#V_oVq1_zFv1rYQSrEB^zvTdEG95adg5+rU z%!)^^2zX}2qnAY-bc$aq=%PaCtcwS9#230P|HY9R;1mKXP(T~aI}h`>%moD*)cA`_ zLD|crQ^JGs^2;CKIaJ7cBv5B8Ll%)UKnG$#6RSrjI6QqiKl^q*bLj?$G$Q4CH17os z&@=G2UIuk8tifY4{4I0t{f8W<9d#F!=2}590_kn|^d=zrzC<6I>U}z&!BTza2akh4 zm^`e(z1$MM7ayj>ivm{$SaRtAN>E{{QEzD%gMX{|MPGA3~IrgQ)gs&x$`dQ)Yb34pffOj zF!Hx%YJ$ssaL_k{J8X=Nyi5iw! zKoxLW_3C9&_pm&~-x3Cz0R)eUwO*>@g!;C`9nol7B?by}P@aR1Rv~7_LEQrA7^(t) zOD*U+Cdf<|c<|FxjgbM~Ol;M0kli~ZJ5#|?(qMGm6{9l#7;^S9jrt+(mr&F17{*i{1_0X9`+1#M-r)n(;kcww9cIy3>i zzz({e<|U}a@W9$CemUzUtZD%*F?uNj=7J{Z!NnA!8uK^~9y$Ptz6`t#I`NCYWu*XU z*cQ~R0u{1HUV-x!XfUXb8t{(KF7!L{HS-);v1eogS&43Ey%3!t@o;OXDy_l*24 zZ)HG5`_>b`{{Qbh2;RJU`?XN>K@Lao2{2$K8)X<6nt$q-z4T~4#^DGaLw)@W+IvFG zp7es;4O!uE5N;=f#c3!3pA-oqQyilD}H19<2TF`%Z5+AQ=^A*xvjZV%eug0%-( zyD{2>pUpx30|y_tA*dk@;v+Q##lZrQkr(KsI_dxnXny@=Bj{47#y1M!&MH_jxK#mK za}GHI22z@Nbb4@jbb@U&Jn%9EG$_?;`;Cc<;l-~tEDRpqTfu8BJ6jz(5m-OIcrw==JUWJbPfmiz+ zVSG_j3_9k%gpJXs)7aJWY3Xy{&M(jrUKdD}>BzrLM8(DO6Mw4!c92;suiR~#1 z185^*izq9o>~-hxw00LL+6_7Z3F3hlHDaK866_gpEA3e6N@xQ2>3rqc`4w~}T>Pzh;FU^0TsuL1@9tJm7&jkagv@7Iwt|uce-G$(W_a{X@Hh@`D}f^0rxU6X zJkA51bLv5!TedO8s1r)BYeIV<`P{Z{)c#Hj2{-#DoP;9<`VOa7|JgxF5LW%41~*L*wH??N&_EqztnCMXs}N*#0o1hi=mxjdT|0kzSRN{!;?e=} zF=*jH99R{2nA<}eJoM_(ITe)FUKA|^4>|RM!VNU!BnMUrQPK@w1@6Ik!GjsB*rO9X zV1v|}cj>TtX$DrcBGX^EqT)nj`-OTCx#v2 zZ;=IEyaH};gC-I>_kyxS=Uz}gfd@8+3uN-jwe?aRJG5N^Y2YLxB~Je4GPDqf_RTo9=a*YS2Uq%9J_UvEJ9zk-`E>sGY<|c10@NP&wR{E&-v>UL zFMK?u^_&1v1-1=ZD!zONUY`H`g`ps# z+n@_t1PB>gbLo5r&*0E?F`k`QJV1%}4+{eWB%8E~8i2-Ee?n3SG$DW!ibt;#Y@8L6 zX22t@|3K$&gUd^Z2cZ)lE*;=Sqp(re{CSWp0BXR3vcP`uGCFVuhW2K0j=DmsJ=YE% zl}@lVFQRO;-2~ZAs`4%)D z3+YZnCQHE6FQ6>+GWXg4|Df#Q$UpVSw^mTdaPhZR-uwR_vY5i~KlQpz=IiFU3w&6bm;__S00)-AR{WCmPbALeXja2zVZOwE&`t7fAOLdRA+YWyvg z(#T=K3u;3m_2S@zfsk^xH-Zs9VsXa^)NBX!3SBxMxpuy3e!=L`%Oe39Rs!|7x_d$6 zG|(lNpd$Qrv3$%n(F4so2q@w}R2LvkqL7 z`#`1`KvTKB)r_tdpqqfEg65Gsf45#LJ>=4130idyY4Nq5ES=!ddGPfbpU&@{Q$bZG zbjzYS=I>GB#pi9NUJ-d7fMh4&B+W$V5;052shQ6JD9Qn7IsDNvpH;ga* zBp4ZdESG{R?9yi*-K`)7XmS*EGz;TlPsZb}{M+oIh5E}G;QsCR7o9xttk}W`>Mh>6 z^8Y`qJVfN;BJ)`sJBB@Q3o3Qec1pq3Ts~#(Uxg70j-a92h{`c@(0p_V&QN3$IHL~>43KW z=WjKX0Sz30mr{dP=xK`LSkaT#DezMB&j0`59$GKR4bVA5*iht=7prDKe8dgu&w)G( zExhpzMH;+x02$WZngCk(+#A5*(K!{we3^9b|9>A#=pwuaprJdYHIAT=K(r?KTkfAm zUJ5!BY1k6B6coI~%cI*Lv=lUvzjfW||NkLHlHn!LD!xOS7ok-iq&R~w1wE(%8jL_% z3JR^aLA$$JGEl5#M6wn%eFI($3f@cxSqvHoT5p%f-)eLklxDzlaL|ca{+4zkK=>lztIW7^Z?UT{Bw*cfTAoBIMD$7eq1ew^rQ! z|NrHZQ=mNMzyMDl3EZIK4>Ujl8nt);sZCKvEiCv2_kyZb5Adi3WI`8X)Z!*+l&Bl; zsKs2+nnH|Gi(V5>m(Hn>?hm*>?a{dv)HHrEs~J?ff!RLL@g7ih0#@qLd5FK|n-+MM z3_M^89X{;@&rW!B3V1SJd07gY5ryYu&{iX)=~AgvuxWf2{+13A(8wTS=wkvXmmt=d zflesu#I}|wtrNCt2~xv?dVepaPJmXjg5w*+N1k(qI|gm;mj5I;iGVVK2U4EUJP%r^ z2aTH6PZB8c&Ll)^yceGT|NrHh6OefK=xzl^E_j6vXh^F06(fOBsS^KgX#Dqr2BknZ z%pB1P}2vLctGn&*gZPICN%%h z=WkC2x&Kh}0S*u5sh|ms4CwL{#OH)vL0L`@$VAswC83;*@;K_WHF*FKX zYYf`a26hI9YimJMOZZ&7=H~zZ&ESQjjQoAw+MqlIYEm@6VDjlrVP^8^2D|jNB&e+i zTSX6Qn)z5h=5P6lwAjArE@%L|mK9bCl-`8a=Fs(VDex)ymm7{EB^%H%S1%|9z08J| zB$jY9_*>Q<1C5Ozc**+^lnh)z9r*7rB#;y=`|-XTa6odG-%Bj+dYSqXl(Rq)1S<3l1i|Zf4ftEt1VK$V zXe}fLnq@|+g+Qxxk(OTXM{8n&>SIWg8+0WZqcj5pXu~RaT9&`{lN1BPF>sqY7250p zkLLQeKH+asU_SHi7nT3~E%W$5qfn6LP%ixbha14-A`JX3 zd7!?2cPnVGd4mN5e@iZ8W)0jt1jR%zD9AgHKnAl~>(xL7d@o4Wk$;;ZC{qUeKt>r{ zJKum8XrFcLyw~{|I!*zvUSETZ1#j#JSFarsj{MtVK}Wwcw%jhgTr0aCvb96*LDpq%x< zgMZ&#(0CZA5&avU>{%EX_*)-=y1JG(_*YTRmDuK_wtY zyUVB_((bASnFQ%aK-*n7JI$b!%kc90S#TzSjBogK{(m9C2+F^Z^;ayQyQ?8y_38Wp z@hxQd6YkY+*a9Z5|Hw`+v4t+U@Jv4D(OsDF&BcvTphN?n8oNQu8bGNLlJwxKr%Y5{ zc7VKur@tjO+vIwlIUsYv@7>P`ZE)XLd-u+yUL83!1Wp z?Ora{1r->3RQ@nCFyug;oZ{Hcz~5@K|Nno`V%3+%`{9`dbbWK{8(~n}02FwjiKSnl ztsdZQQQ#d@Dq=YLW1RvoXMsusQpZQOJVCX+9@N_33by@QNgJ#&2%DcY;1}GAXj^Rs zjdg%R4|RTW5@>=Pe@h=UqmD5@>DqF;grl<;WPaxfSIFJ*;Qj)*IhZNVz|eUR+#Kvh zZVocOoDb@tcYc47^#`6*T1^xY;hxFgdVVjcAq4L8K_daw^#esj^GXDcIphdp^A^3_iUcj6R)*eLK&1bl&Tn3aSxb94TdF=ms;v%U_Q1w|Fao zia_W<8o22XUX}O8r}MK9WKWJyH`siSP6HpvUUCn{k1uDv0fp7~7s0;}$-)~HTG&^8 zuh|V+LW;Ri20E~Q ze+9aVejaH21<{wR;Kki-0}V5JH17pb4E(K!PXGV^^6M^8iUqBt#T+s@dImHb4Vu&k zF91HZ3lbnsKj8t=vJIqt+kuz<@b)pdnNs`_V|?mP8>Cg?1d@WJ24Y$j1}|k#!W-C- zrV%KiLb}7C0q2+NF8u%h!fqC{K3NV@8bQW>Q_X;#KjCPM3z&!GBb z%~9kLp?tJsdcZ?7;O)rJJ-V6vtxq&T<6@v3YX}=!hgPnT5q5ZEav7+iK(1mfAc+uk zS$Wt_WNVY5Dnb1_Yy(kw{H>}xi5!Sx2AhR65CxeA0Nqgfa0jxbN5CUikWqh-rI5w1 z{M#;gbbEqEzcTq-H|!vCBXkPbEF?=^ARQXeX26y#6l;~iN|CGuH{QV3g7;sS@V8om ztOa+84KINvFAiy5hYh-cMd5>PlfY)7SPLH122KC9eBO@iTR*T;h_#?WH|Q>N&<biMii|K;}W|NkS_J@`OYEWc3v2JTjXYB$J$Ie*LIU;qEVJaQSSeT-;u zfDT=Md2I)%hJlV+BD&g_Ad7rJ-EQQ8oAZ}IDH>b^xPr<6MNyQYn|jdD2e$Dfk52GT zK13P7d-?zWmmjx*&Nu0v3L1Rz=yd{BLLlbLI?#4T%wpjuc+;Wbt#Yy=hFd%;bU z|NN~xQG+a55Vr$BGC>a5w-p?f;Bpfq+-AJ}|KG9K4Rk;Pe{1N+|Nr4#i=`Oj z&L%1^AA?FnQ0H{f7m&NrT9}Y2Z*Z&e#f(O93lk&+YGG~%4G^OgrTAKyE*%;#9ln5S zd(Z-ARnQHQkR6`P(cK$ zJTO*>HEw|@|M>~7yyZJ+h9TrAC|V)?N9bUN;q8|epkxTGG`E6VDxC(emmu;F_*4(w zEuhxM0sa=9egFSMyT#DCVbJ+}aSf2#CkeE50wu_B_Gv+L0x$3F1(j^zkom^nT8cU{ z?vHE5S_hU<+mucJ|Ko3=%7F3!))wmdXOI9p@ev+itvv#WgP{;3b|Bw(gL4^ZbLxfi@(4zf4|v_BQPV9ukrH2^gGgIFHt0h!BpfpmF2I_H9BIbAxILS_ZF zLYJa|3T%(=z2F6Vko86$-CIH3Igjo+$3bi2dMgY(I%N*N*w6|(AOC&lF%QUc3)nWw z&Og_ws>uD7AbCg+F-Iz_at7tKk#FORWd$6ksdlqI{q$T3S?{`cRf^Oq0gV)>8WpmkDU znPZ@)E@V!QL-Pr5V3|e|73_ceSJYeS04G9STZIF=Y28YDU;_Kk_03OB% zmzSUU^NE_HnG8B(1Aosg{L}yc7(F-iZlVIe;8IXG4l)G46dW%Y6GA7z{c&&y57#o* zo_7A-S-^L!!p-0;0htnmg$CUts~j}%gky3E)VO*19Ml9s%Lr&|$w3Q-P{(Sh z8)y9OmV68h*pt-PN1$zn$itkF(ZmM+7Wo&Ts_}t`Hh9e6@S9IJcu@#wSwUYkX#Zn3 z_~2RoZ9L|V7Cb8at&E^~q~;@xp!-d z;2~9_M{&PNGB6-5l@*hMjN*cty0G~W$S5wuD^NX7%qZ^5py&Vpcm8;J<}oOBfeRgv zUPpKf{r-1Qdk)+@Il$i{2tFhXlGb45HW4FkC7vE=Wi}u3Zh#U&P@bie|r@x{;>{zO@@~TK}~5`uL{u>z5Wv7ALr)?|NOd+ z%|G$)ASxvhDqDJ2K<0;aH~;_7zwd)bFZevM7t5CX|NrvcCW!i%&p_w4{pW8<04u)m zvTGBfKLAc5&1G<2`2^nN2+0PpB9~w`pmt&Ql?6v(23vh_WIJeOB6v;Q z%X`@S%)h}a<-WhT_!J)EEw0NU;rQt`C}^Pb>>Hj!15O<*d*NlwZBSXZ?>j7*?HB+5 z|5Exks0$7rLxu!cCwQX)Xo{tO@1_6$U!J@~sEc9-@)fo&N~gff=xyLFW-k|kYgde- zY7%7CC%91wixspg2D6<<-B`ihEC9E)j6q}5SlU|fm5cW-g3>Aem5W>7GeA}@T7y?E zmSL=1obn#L0svI;5MH^M0~$leUoQ__pn=;`X{W#i5NNyzY3K;lmV)*t5ko*VpsUGX zuDBBh*pD3Gu{rd%;p@9-LlCPLgOUf*xY*0z;HEHmo7BtepwWDo z?-8YHBdDVa^*yZ4Mr$8pw!GdmQn$`7m+Hipsb4+^PtKxe<=0P;3h<}%{{MezaUD`9 z{Q&22^niNF2HHRg=`kTUUXFrLx(}S?B-zTHM(|{$p@N*>gg5^7zz;{uArvN=Ve|RwdfSyVGGUW)U%mxpZgIBw} z^X$CpVF_NQ&)=N29yFtM0W_EfN(Y(;Js^kiK*Bv1RAYEt0=oi~OFVl^R9HNk!CST& zLFd|9LtO(pBod^+qmvEcjF+ztBYTj)6*Rm8-AfGJ;ElBW%A=dX>9~u+AJB5gm(B~o zcA``y1V<<6Rgr+B@xn`x3(>Q|>$^y+L+j>)(llZj40H{QXXmk(yr4NkNb_hP=yItS zO|wCZbRpBhkX|RE_+SIIb+G24*4zB81-J08ZTK+{R z0$4nPX&1=cst0($3lx_=kdvK2(Hs&1J{;u4Pf+6mG4Fb)!~hzdKHcCZ2XxJ>BWRiw zqmq639VG+vw}LJ>h3fZ!OiUpq2Ur5>W;o_z@t@(PA=n$};r;RuQl}PHw4x;x+83?- z?arVHS**pY54e2?+K~uZ4uwbrkSxZG*rM*){Fd=W{m1RYMVd<$*>P6ziW(bLiEyLdxj%WP0PektfMKIj_UmzA?Xc>#HZ)#EsL z|2HT&T+jwv*+2u?(ADL=MJOfc&k)c8b@0&%;I#~g`CCqc&L@GYhMeJH0?ts-#ulPr z_`VDjF^~!mmQ2u^+q6&o<)K*H6+WHkUPdhg6;00&L0f7I&F`?>jdT`5H^Xrk0Z8fZ zIt%14j3&uSq_S0M7C1&g`)6OyT>(yuAT}uQk=Dw;ECe;zAjc1R_Ljl}-m}|AtgiG?#k4gl}DMEH-twV4Gx zI1eg6J-VlYYi5KWVZH{HX#)QlUdGPE>F`_c;Z-LGXkjNC$Xv@CCA{CjYjqj~9To|m;s8xD-UQt)4!(J)4z%C88#dJ824AO(80zqVObG1P16`2a zyR`cE|Nk$xfXwTi3YuU6-R*N6Jka`Rv6< zqksRw*MstJJHQP#wB-PQt1&ZZ)*ZZ+%(wMPX(FO^jy90OGy{}`z{7$st{H)DyFTR6 z{6nDpkVh|%6m*FO)b$`ATAuLe-U?bU+3Uslc?tg%sFkm~eL6wIj-VBX;4^s^T>1b1 z<+ACZdj0zgxohw)d+R2|%2%X8p9Kg}#Ilx`UEuwjkVQ((M;W2VOZjxZgPbr0s&F3% zfYT;_OAoj#05A4JIdlrV`|-icVo=hDmbb7HfZ#YhsG<=1016+x6~(ppSSMCMv%TP@ zLi4Agjz8?5^#A|M37{q`*0#z^(C`C%wh>W?Re+j8_`N`fLJUXe=pJ~u0HY*&;>f@6 z8+6zx;a}7RAk^x2pNg|o@C5a6Kc7PAjLOqwu12PATn0d_tXZlu&pa1{+WS8&<+5ud@r;CY-y1yqjsfX>T<%&mf&5S=D7UMNUGiVXgiy`ZfO$&ex? z`;wqXZ`B2lUJ?CcEdn1v_rQTRym&PK<}PjV=mz_OAF{ClROy1+C_dd_FG2>spohmo zmkfdSTDCN>Gcdrn9q_S(E|>>T-R=Wn^l23lAPTF?c$X|Nu26FtOpE*(oj#j9`U z8_>-rhxz?4Kngv>OOST6r{*1x&bgquX3x%hF5PQELE+Q66cX5{UkgA6rh`G-BP>A2 zl6iE4TMNFuDr}DY+t|QIP`I*z<`#}IIyTrb@VBI}gU*(C%ip33KEK78!^7HHplG{C z=lvH;F2YKl(#_B!(4+IFM>p7hq}AadV|+n}qgdYKZ)as?V1OQd1lR% z184#aay&HnP?mF$rs?EgpyUg_+sPBuG~IWHf#GEx(pUzpg@@MQ#%!8WxrHZ%eFiB2 zdoF#V$Z+L;N|8Epwn{}o&Ep+<%y^0lT$C} zf>#v(aOqqNN-eIP-w`eQm)c)2lvkbwZI%ZW4TwpEmriFOHOZCpu=wO}t$mJdxIG&o zid2(?f~T_(L%=q@|Np;ae-2vC0!pmV66%F&FL<5{vK|7wv*Bg%Sy0@<3$YhWAf0w+ z;f)ULJ%Ke7F#QEORTZUD_9c9_b4{r~^JG(=S?1ycF#8boC*Oy!k+P#JmQ`Cr6dERW*O0a6kg^g~ z?SL{HWRWZARFfN!o<8WF#(qsEP=5e?;&k&N0}pHPq1XH^|G*9LLPn3yt)O;vhahCv zCj)=W4MxzW1kk0S8&R6>MPMC>HLIXmN|>fT*`NRaLl4J!DG2g8yfS$C9pvF&|EtXp z|MIsgf#fW~#|`nfOa(P9A=f^F+yFWg2z;|i=S2@~@OhXXmf$T3{LQZ+bI#CN*z+FU z1qINJQdTT|{H>Byl89x{~zp<=3m^UY>wZKFqX(UHh*Ds zX;}(tk(IDE|Kcj~hZ^=W0TkNZb3vUIpI&fJ=(QrOc>}qNs-y}O`tSe;wU_v}F}EBj zy#Wcgm;K-!Ti`_L)43JY0Q2ac3!1EgoDTU~3D!Y^+%Q#Q4r#oAJ8do<3Lpbr__ry$ zwmd1l>f8C%ryFd>ON+nYXLQ| zNAnR0pUwxM`3jh{56_W*TL}AqkLDMQp3QF< z9Xmu+S`XB};@>CP@Vl|j8mztonJRtV&i~Rrk zkx%C*P+wQ`(+e5pfB#>CHeh;ozIn;?A2iDh-p>RIn^2F=zrmfKL80T(?XKa`U9RBS zdBjumi{*!s1ds0h;6eQ32Rb(UF?ck-NLcO1;M2VxbmSo@5E@^B1UxJ+l*RZaKk?~& z=P`)t zm$Q$6E=p$rZzBHxdMhaYL2=q^J9R53gJY;?=U2xN&(15MpqsZVSQr>k?xW9O0o|?j zLOhy<0X#b5(RtXT^Vo~&(V)SWd*G_9^XQ9?XwV)d7Zn8$&}jTBP_3f*)uT5@#Q?kk z%%}4>cm-#Uih{>+7ZnZAWkD}eLLkdw-h&GDZXXo|pUzi4o!`KVKS9Ze1sp0qDjYt& z75{xKfAY7_0vFaTDgmJ52zxXCdvt>DTyIe^01XUvx~K@emQ9-gcEWnl;7^B(%70Lr z@oaw2=xh1DB-W81bkXgFhF_fJH$9FYTJZn>|K=C$9{l?bq4cP_l0R!2wbu!QZ@vfq`KK3xBH|Bjole&`r_&+xQ(jcvL{Q)cpaS zjCO#3dkFi#G{?>mmVYl_p`3?&$fI`;I1D@AIf7ye6spHvR1`p+)EB+nEDS!~AR+Kd z-<1pu498knKq1cH(+SoIiVl~~e?H*Yfa?oI)>o2ztc3-nj^X8F(47sPUtZn;4*>D| z_JYo&Zhr8?vy(@q^Pop}2>%by&Jdm-KAjJJG!HVK@X$Qp{NP9P4-Wn&6VUC#4}KV4 z>b%%|h{LCwhu^o8hr{wv(fgN@|Nj5q0cuyJbwbj|%j&=X|L+2g=cRQ{0ekMHFX%d4 z{>}rAojfYtA?$xZLGkD1{lEYJzwn4*VSvT2NAnvFk6vEi&72Io-hoq`X~iZ^29I9b zNt-wsUg!${|DT2^ZPF%y@)NwwaOphl(f9^*pruD=iHb&Nh>Ad`kBWjzr;CaTO1|=7 z1m!Ex2|6w+;{4lORKy({elYU4fX>MSZFy)1*?inZ#R3!w9-SXR#u>C;;_ukX#K7Q_ zT%sZXxs%9oFX-x;QjeFbL1zbm&Xe$L{0F)x9#j(b`lwiV^1EI0=q*t(@aU~kad@$h z8`_X;0kud#N2?2YG9K~NJXXTx(e0vQ;L&=ZbgxIUi;9Ae7QUVDK{+0@2$=y~N%W?u zIJ|6Q0AF4L+5Z5}_Rl;z-~SJ^@U%S2->MACCObg>W?*1w@JT-H%lOiV@q}mcNte#k zK9(=|Cmry#Jh>CppyJ8hV{RDiSZQ^n*%j9~B93 zrPB=x;p7MVK$*;=^Sw{!qZgY~7#KV)kCdu`%;#ZbU~pl4%-{GMoDg7Fm3V^+63D&H zj(b2OkRIJFDxkE4RLp=jxp*`l0VP5gl*$}(?qWlYia3K~=be%x4K*q%3?-1*_ONzQ z;V9ea(w(Ei0V<4LG+(x!tXt@l{1V~BS1$y>PCQ!L+)Ty|G$ic z*R$Y5ls%6h1-b6!Jy3H9;$Coi0H;L5ONRe_IzPTJ;sk~85qN5AoAmepe^9`@CyGnFUeew;o)S%Y`q_VS>15C~R z@a_M9@I~;Tn!uwo_JrYWkIuasV9C7`K-BTp8Q=dy?o{sF$^a7S1aI>9I1WC^6jWt; z9B-`vsR5-3aH=$92c0enI{st56nIVmWFY8r3ed?y|2>YkCVc<@pAXam>s<@d>D&1r zZGv|%%YSe^d*7$?rEjmw0iVv+jPL*ddo~|u1SP{Wo}h)HF)9i^-4JocV-3~}B_2MO zdqKvP?gus5zyJUL;`+o1mbjg4J!I}P- zIOtrF=dOm|d^(qc{NvmC$ES0x#dpvw-FMH8)=|>O8tzBS5L8dn+gjx*C4-=oQ_$hLZu_es=2S+1&h-oxlG#Gw7`I z|NK2pph3`|?ELK)L7|(>)8)Z<@&CidpP;gkztse^kd_a8h=L<%736u)k4pQD_ZQ4>?#17GX$j{%j5iQOTdShfzzEw_f}B;@afzu0CHb1 z%K?wxc`ukjs|HPubhkqC$J`g+zya^my%m(vASuzKx9vIT+!;+!3||1{vCg?CzQOh( zI`VIG=W*@M=Wy+o?>y9byz`i2=Ya#SSRD?$X9iu-(|NG-vLpYta9)Q4@7S83Gd4eF zY<|Y*(6QI_`~Ux)$2;eOY<4{Gf~E7Y!-4ngju+lEKW211@RG@~`2l0cTmz7*%LiUD zJ2pRIY<|S(&;fRtV|Tg0h1VTZK?ekSCWq^Q^fW&N8EX#GuoVZQFHJSOSg@9=Uz|*wf^Vt*aSKysk5HNGua)SM5H~sw?Y&?U~%b|VFMkJ z*HH?((63Y8qnow(0uKYIqL%RF-}lv{o8^N?=T-$!kb>&HKF~d>y{->zqWIf>F@th$ zxrIkB%U5x5ApzZ2RRh{r_51@U@oBquyBqj)_k!#*ykvMXZGvMji-5<$2P{5}Cp0w82`M4>PV%D3L+f{z?{ftP^~?b5#$p`{%xWEL4jFxo`2gXP#1$`J9sd+^dxj&^>J`%3#v6e zy1@rtdRXrT)dMB0FCq;={Rv1tVGXV|N?2dGfCXJoAl3ZeWkC}+;F7R6^+vQ~45Swy zdl+-@K7n$7d3+}#=XdjWa=c{z z1L`9)bo;S1{si@}_}c>+85lsS1Ux|HgCEN$egSsyp)@zZhc-jncOKn!93H*?93Gv1 z94~i*CBXe`WbxPY5H0F&t`3a+txjSL4BuQGIQUywKrX6dY5WhdvkbI<`DgQS0S{(B zfzCRXH2!=}eoc;-sbG^`KqtV1%6-t80$rdy&}*x`oRi^&S{t~@3EIbe{J@I;;M$nM zqnp8_JHo@G+abUMQdNWY{day`s095(g*t#d#_O~=9YIH>A*+4BPw3N8!`-;Q$d zw_XN~*FxGi9^JM(!8!Fme`~Wi$hP+fKnE(E0V{D}@aW}TxSW$=R|04ztJhRz8Ms}N zwv3bE#Z5MF;f5u=R)ITe$l=BB(fsg(M{lKoM`s57&==)MTaB*wu3JG+j>EzRwr26k$>OO<`)Vc zGx)c$u>V&%hKLW)dNgRO!!z040KEOQcWMWy0P3C#Dn@)d--F7JZWHDg34fUxK(~2; zTPNC})*QHD)IAkc=DKJ;fY=4v$ZsY9?yB~m6M`jKP|t!1G!)t025D6v1~sBRp^fX# zL!O#9JTz~4T3+C9>lFi4;$Wje!zi8ad^*4X53um*1`B~t{8|UvG?@&}Qihj&7$5L= z904_vEFbVU?FQ|ZN@v1`QvBJk<=kegWh>P!@T`$pE@NqAv*4YfHWjZtH``^KQLR0bSQ? zd6>U78Ke~)lAzFu|NZ|z<6%g9i@y=n6?~}-YWu^_%Z1ka-L)FKK()O~=Uh-Kd%@}o z+R_hZ9|s2~C^va_9`S8`!r$_imx19MSd@{!)qx+>s{I?x-(m)0fo~*I2Hp3Y{24T? z8pHqZzh~!BO>kWEcO2(uVCV+d>7b#flb|zVz%rl$Uq=9R8tGh+XTfzU=x_>8!pSQ{ z1f0A;@d4?a!jl(B2;4{Y2h9K@lGh9VjxGt%c83@IO^u+fR9KT2f9ub`;0ta#q(DD`A^#t00m`_ow?IWPBG4c3cN_o}1fV><9n|i`5$G*{Ac4LVq`ev3Hf8i| zKJEdU5(kxHmaU)$Du4UpumAtQYycg2kDA3ix>?x4eg96-#onE*pyUirPV#~b4E!xC zxEL6Yw}P6Dpi_Db4;*im`2PPtXmsLOE2ueGfk^J){zUTwM$hEijypj;|BhBr>(Qlq zEl9iJNssQWp!Tp!M=z+Y+OQX-Jp!~I3{;FyIq1^)>cu)fHU^LGUQoBvvH33-s1OIK zb>yFN#6@W-xOLij2z05dMZ;c@*$kj-$67(%Pmk`YAj3U6kGXX8f}}jU_ktSeFJ6Oo zfbwqxi+Oe)a&381q5^e^Pv>=*;?7Sm4!!*UA7mj&vuEcapYF9F1AR5GdRpG)?^R)E zV1T42&DS3M9ycIGmt*H`P)=OW49ba1K`Go-^NpkC9gpU{pm1a;k>lS64zT72jLmyN z!5~n|?bsWl@~`E93%~25?zs-%|NrNn3#!Su=Yr}k{+3CgZZBvqpy8(if6GG=(3u_} zRiHtgcO1wqyA7aLIK17ei&7%?eEa_&UKYZgQv!2D_BXJz7)z26%kb`HT?d2Dsl(B6tDE>fW_@13%8XXc)+yDLlU(esd2ezFFl3QFE?|?U_Jp^43 zG!0yO)9Tg$GL3@#%a3t_*K@S{~qUi{S%h6mXdbF0HPCvrLEzWH4>n z*Z==LAbG}P7pTYukEt=f03DzL%P&5bulOe&@_^NZ+b;2gDntHOPzG;30IgN|JAFYL zP!hg^n<}7o7Px=idZ0wXrF$)C&;xV@Tnp&hUzhH=5dLlcjtEd27?Gb`x~GC-3S2IA zv#^8C^l7;Y8gNMld)uQ^;3cTS#aDK*2;eHaz`Z_xmmAHG-owf;)ROC>4W#6n2s#~R zD>$6L@ptrsPNSK@_yH0Z{EcqE|NnpK{{!YvNZtmGV1itQa6jmJj|HF(G^7=D9Ne%1 zh4683vkSrkc^1U-=w@N|fD|44+gd?6wiBGZ__u*e0B~{g8QcKB3mRI2W)A+=A~psF zNQ&g(Z~e^)TC@ey%)sCB4iswLt)Lw2(>)c`OFq^B>NSIQBY--~pb4ke1N@!IphByA zE=U0+M|x<3JKY}q9^lFtl0jPp_+X_N$fuzGLN~ZR2GvKO!2L>CZ)pxMawb5{Qx>1W zd8&CWD5En%0u-LLY9JmFC@qF%tt>>=YU4*X6(wsu{`CJpLZK`_Xt5f&XoO`ghYkyr zytN6my8i$Z#1+si=F$x=d_ZHCns-3K-PZ^5Rq}1{))R13ZYs#p9-X&dX!$cRfLFR^ zegd@w!Rh1xe@E&kq?S*E-nak%K?nPSb@6xlF*7i{bpG`J{{%>S0d*N)p8gA3Bm*wg z7#J8{?g6!Klidxv!A(7+PJio3{uXcxv73brRMT__f+81^ToA?~>XDZ_KqkR^=T|^c z3@_zWp&jY$?4pa@e@NWYf0~!!<>6{Cy zbA385LE17d9lfCX!leV8C;wjnsRirl2CHlS@efpuft2vK8iCGZ+Vu|9se`!R@i;rE z6As$H^Z)3>sgM2N3uZG{YxE?+6f+=;E}i& zPs%~#$YAzMV^9Sy4>2E>ANX59`3k-E<0zGCIZz@7ty?{NgZ?`nbNX-K*?GxR^Qw>L zYj7D3X*qiEd)xx$-jn>T0pK14IE6#1*OwdM*6;$JcyA7beONaXV z|NlF|6}YS6lb7D$UNpF03qHR4C8!*OBwSD@LkMhRA7<6((Rl)?>f>d{tor^3TKHJL z;BQ^~4qovYUV_$PK8!E;JFfFU8|vpk*#=ezI(8m~SAdY(&-W9g*_ihZ;-fxaP<@>I z1fyC0=*3SjP_z69f2##ZE#n)P&ZVFX=F<6qzi~I{IC#cSi1g)~`~D;}M^3a4`clm%s5kDABI@2r`tR8$1{Y>dakYMQ-~X0hJ+0@$~;2s4#+6 zNT7BqtYE@uu{J+oG(>5kzKjGlBOn7gC<72LYe7D4eZt>56@L-~m28j#?d9(u|NlFJ zdvyz$LF>GJv-0;(X9i7&x*ERq=~dlf%FXan_7kX23~m&F8VQ}QpZ@=Uk@)EU{|WF^ z(s}9q|NpOFb%TomP&%Cix@HGnD*AwLFolg8D!dH-2|Cg1Er08&7oZRZb%i0N;>(^l z$oI)QcDr-59w<@w><-iLv<@@iZ8H`b1R3SyZ}EBa|9|sg#%{11LG3kH z(8lNF+sxoD5wwHc!2SVLP4IXA2VJ0}{O14v2|nQFF|6)&>0SzQiEHbV5&@6n;JyW@ zz3{T`2gv{69PPsR8cD`c^UllXpry6Vzgc&%f_jR*s&6K9GPv;j+;D988_eH&B_%1m z414weKP1;GzXJQNHJlN&O#2Cc>weH&P%;bKOVgha89kWH8_=`@xXsmR@Uj@RXuf+X zXu8VP@U5%i|Chg?f+7W!Yry#*w8X5NVE&&6zCRJs^ac48I*Z)G4(iRV0PQoz-9F>r z4sVscOa;v|B;SDLZcsZw$sO7bNPLCtxY$=n?SRHP@BjaQsfbj6c%T|`*9~fj42mHV zD2Dt3ow0f6EjT~(Zv)rP4jmRReLy`{{(UTLFQ0t}ttbU|;0$lO8oq^eA7AeK`~N?v zJOTA3L9q;(+yIY>feVZm@ovzPX&(5V23YvcdinpqBcfP=jGw?u7gx|3o_=80xG*s6 zU<0kC*$X0ldR5yeax%PZcn5OLTF{&*XlYy3zrX)MgMhsSj4$3mcgYvf66EJE-u(Rw8XtOj8&r@Y#;Wh*7^`+_RN4F=bfmS)Q{*)7hT;$d zkQ*jF|NkE}A>fhx12HG?LiRr^Y(hZ&<-F&h{b(MLk^(v(z~7?u0$fsn=LBj%YuKC7 z=LAke=L9~?gUksWefjP=EI)RG+cKagV)#d77lwec8a${JUdn@Z0e6C%mOh=}Mu|@+ zBoRdAgF_uu^!q@{0cd^la{mu-F74mN1nNVBQ^$Y)&Y7SK&B~vHQX}}>6%@mG^FcGs z5Ftpd^s??FEOJ172UyMVQW4aX>4tPRy1~7D!;`x}V@$5VVX#j)td9>d4?7Ryuc_8r)Dk=H<+Ce#R3n=?SDk#WIgA8bWQSwQT z=9=>dK=);UPiz3^EDuPl)uVGOX#UqLnPl36x; zbn`ym!NcJ6Kjh#6& zL0jcJ!E7JMDEN!R5LFcrENm}JKZ7a}aQ(v! zo_uxGyweRGg#o!3G8R+9)eUaafv$9g#1kk5y!`$3|9}4N;J{Anw0PP2`TzfYs$lPY zf5AHkoW%KCw?78$(|8I>W#D$8V?#R6KgZ+lChVZTQrv4KJvV1V^(cP+|NrIXCm=lx zVD&FQz5oB;C;2g~*akJFvK^si-YU?^tl$%ZwKwv%vPl z8f7l9LKGakh@PI~b(f@iDltg7k0pd4e7K{e?2jN0pEM|9>e9 zw!wvgVV^Qoo*5>8`5|cAAov%UYN`EW9CgDkQwCLH#RezJiK_g7M{I(3I%5 z4-` zkR{*XWz8OqZzMofN2iHOr;myU%Bn;TkOXv^s+*zHMJ1)X{Qv`armnSwiGkrbmZHKH;L&UYx_0xjA_D_x+>NQzMa6-?wMCeL;j<%uKEG$Ty8t-*dvx2V zcyzX?aDe8a1$$I}fcC*0{rVTYkT(D%GXXR@`MjaD*rVB2xs(Sqy#5z-ndk9i7g9VJ zK+9AwfaY{NU%fDUy7&KgR|bX#28QD8PCz|&cf)^y%f^lJk|kT)(u(1*Bzr009u$1S>^4aEu#Wj zi7DV=d5pj9l_;oQHBs^CyyemP-tm8kiUoMsNDJiTIAT6CEKil?**piwf9&M9C!__swc_Bw+X zi|{fsFtps}Z@CJZUJp@804;lU?R@Cd`O~BGeYcBBK*0YkDxmQBzeNR>yrul4{? z(GGUv?>5lN0p2aPAeY^4excw9z9TcL!aI)Dgxl{*7p}x zcR{oK(3P>a0t^h@F)9)+-7zW(nulFmZ<24yZ2d4pC76 zjT5wH^MO`gfYw37!V_HdG`pxIF#7anF#3Sj+O7d-h8JER|Ni&s-U`n3pluD1eCVV3 z+Nbjas)K)kMyES(fj2R{cl;k_0XpWP)d}We55^n(9V#G)THfGqk_Iubx%d&JB<*+w zTAP5B>sup1Gb>j>b&0$KgKO(I{?>TV5&&?hmZ&Izr~kk4xA1}1FLkqnZ~6Hq4Bjzt zfWwnH92`SJ9^I}Q9@ee~{LNmV5~A0G(WBE>qeH;4@egDucrqVoL@q}~!Lj)WBY3jr z=09-rzwaVwmsj#@aQy>bjQr|_ngys4b(Fs~mJc*C!8%KIi0OBFIu?^Rn$ggUT$&LD|NIfx!_P!gB;rL)fQV z3$)_BWeY!Otm7MhtG56HL&NW2{uUE%~5Z$dXG`I6(d4P47TG(PN<8 zp?R3UW3nJ9{Cz+P^&~itv^oiaDiG{>L=3!8^%Eq?fd@4|@V8#zf#;DA{2e^fpgi({ zzlj+X;n-3f=&mME+qVL|-oOQ9^#T5tN1zGu+x#uJK*`RD8x(b*by3h1i5`v(zqR;V zmJ5SsT@HiFECx^^@xq|_2Pc2q0Z|49NPW@{+JOizLV2T`;PEBG=+Vo{Z4HXA3-I{r z-2={kpgj=J!Q$mz~8b2 zv|$hGM*eLQ4Zl_RTbx0ATEX>My8-xiM^F)dyAfeOyGJi;H=6z3kh;*L*NG9<<^a(f zKa5;a*ng@~m|EnDI zXs%Jo_|M<+4V-u&WtQU(JSK|$`2YX)8uur9QA26qZoaE3^ zqhf&BUTD7n8gfns?Ph?+0jM&=W9tHtdSfK@Aj7ek3t9^fPB*s74V(<%z-)d2svH%- zhQl)bF)LUm?XFQt@#x*60+I)>Fmg5g_F}mLBWM)nWfZs&1(!45TvR-mO8BAe7Emdb z30f=L%?>JHTR@jdfeX^_pr{2M84fK-J-V4Zldpg#qIZK*lsp5hJXiuc-V8~hPq&aS zXbxBo)DCk|@c}v4)$o9;;kVrt4B%F&2DmAj?4rT}%7YD{>D?AS4h9DBzBRB<4NrE5 zsAx3&j_~Qc?$f(Q1=K9!pK=h?#sYcIr!z#Qz^C(_OJ@tX4F*c4peEUi6>nG>Kszck ze7Zwa3OqXxf>wO!x^zR7xq>F;L3_3;Ji7OQ+i;-GK%K{4FdhSq+d*`Iw(W40s)BM{ z1W1FlPv?2?`hj;KTO(dvJq}SD;n{i6r}L$c=1C80&=$_#9?-%Z&^8h9Vvp_`6$MYt zvp)PDFI+lvR5(EG)hzJTkBf?gqvi=$%@@9{mr5l0w}q(qG(TblSu0S=<=E@+ujP^p zzw3c+7Zn$77ZnQ^&JX-87dSu@0xuXFYE%pq_*q(VXK zf#DV0Ch)qDBa9#m;~*A=ce|+gv>pKM9ER17>p`t^xNZZu?h??tOt>A#kW_U@I5vXz z(AD#|_(QB<0`HS?WjqS1M*A0m;bjcrc#e@7M~OTC+UC-?RqAz*eBo2MyRA;O~?N70?j zb-fS+gG=YF=0}X6&3cXppD{Tee8A4X@AmN)l|2j)(AlB_D&@LeR3tj*sDR?Hvqc58 zdCs*`!6lb4JH$emKF~fY4p6HK6xptZ-;TSefO{Q2-9n&go(9lxET{qp z6;v;qeuIZ>@YMUz`sfB|mJwVZHCKV_BO5~=21t(s)b#+5#v*q;Ccr8ah#DNFeiO`8 zUfn8qZOy{y_+RA^$iJY16YAeq@UAb=@b_cTwv`|H{OylG_Xi=B#4ta*@NW}>dHQ7w zcvZ9uq#y=O8ob;M?)xyj1YO<&+9wUq>t3MNJ-kFvg_j6P;OWUDj4wBS1_u_jeG9Gs zaQJM+2hafkhdp|EgDXMdWy@m#>ZiR01r~UvF*vXoJ-Q(cPDHx^a)uTTQ-ffp+WxIT zgcoR`_5^TsmJZr41NYEW=n@@|PSgT&A`=5cbB>AxBd7-eDkYO4rDP1Wlng=iA(~Ob z1W`)*fv0(4W$8L3RY;{I=)ezm(Uq{BXE}E|)g=Xv9x=`Qbui#-ZaA(6u zMFMmm5U7xRv0fY0?KsBY`V723)|K%MxUBT)_EC}G?|1@gdRu06NL@FEzrAs=k6hvfAKSLGA=@}X+Y=i=>zF{x{5q39g3h@G zPZ_!}Fn}5nt?xlGQ=_86!QZ+ETzmSc_<&aiuVV%6w^m_iWneG>Cm)~Q9xxBwesDE> z3)(LU8dCZS?goP@UBhsYd<+cTJ}MrNjjz8zj)n}r zKu!z*o&50fC?B+604k3;_*=o}a&^0Ncr+j22VdCK8zA7>8P0KAB~lZEqg1TrQi+gfuj7B8&X`N1Rb(ff>#TYJwh5}#K7>9 z=M^koK@C?>I@ki*3IH#9pMwe;xPKL1HvIbkzq>?*1G-d0*RhC`q4^&xzwa^7aS5Q| zgVrx!$)E9H zGr;bI=GT|tB~+B=S3zig?Fjn=N*j)hS1LFiEwAu5v%UNOAKdAD`3D?CpmD2{{H>u( z&z5s#jQO{tq~mj-b`iu~DE^QHFCYYm3yL@^c+Jse*vOqnXNU^Ni!2q;uo5W!SRUeU z1szrk9==O{^Z&miX!tJb4YYV@041mx@D!*6gGVx&G0G^$gn|x21dRg9z>E=w86*1Y z|NobwU}IcBSxcY4eIaP)Fj5l@6iXcnFEd{K|L@ox&eG7MvX_B@L7?#$q;s$dr2Inj zApuWjcLB%FaL}$k0e;OX;ELttBGAcRptMv4Qif!z5C1-)ms>zn16a%~2PsA~Q-WV} z4#doVe?V&~ka7^q2Q-1wFK7Zf=mMZ4tkNcc$~y+feUSAry6JhG3@^DrvC=K00vg@o z0G(ACaT_$rb>9QDLgtJp3j=7di=*{GCuB~AzcUSV^JlN^$~;bn7d5`1ir0bR#bRFu zhL=@;VdV{|T?}f+dVaqJXK&x%)$^|rV@pALG|Npx~R9rw~I=eve z0WZ^aK(nGqWqSAf|NpVM^5qWD{Z_|aRKRY230i(&cmO={_kn+-IDbp`|MaX z@Ujs+84hXR_<&9a0lA#x#YS&X#swXD1gZyKx_4txS+GNUM_<+ zKVN~CC7}-9XDUG34hz14)_L9G??`_E&HHgLpm~4u^Z)-}CV(7_IUXCi`Tu`V^nG^^Ln z-u#1+zwiFz|NmVLFM&gAUn2tp!;Vv+@mSWE#~y=D0(Mc!0QG8La)S~$s4f4Z)e9O{ zFRy_d2o@`Zi_Lrb|3A3k1$B9lQ@BSrQyQqgxCdVCg_QrJenWNWFrjvkhp+{L%?jLttqqzpVWYiA@Xe${bLXLYjM^O8!R$C~8AgAdS1`AOAt^ zI}83+C(!Dg+u*hh11Oz9^n!Ap0muLaP5gPy-}DtwV+8AOAry1#Tr;@VDLu ztuCAjHU-q*??ubM94|6ALh>&MNEayoMkv7Yub&bq|7tt~RKdgVqg$S-zm#k|1jinolc0 zdIO!Y3@OJMI6(tL=N|t5kKAt60Qp`4!12f<71eL$0sE-D~jgMv+izf}X|;U%C0 z2IUt4e|sEnQCR^h$3Rk@EszB;F`%>Gj~@jIgC@CK-}1Lag6xE@dFgx(8c=XQ zwD*6vaN{G;dKdndhammkE-D@#+Ab;%j-5wa57brobZ-XtkD(jpAwwXbffe|9g#2w1 zAcMP0R2)2$uX=Re2hC(VS{~g2ax1viAoELgJ-T;;rWp`RE2Ob4tpJ^$)vV9x z(fYQ8%cJwT;kOqH5AOXBs^URmiZt8+K1HqZ2q@@X5UV>5L)+z`6x=fD-~a!R6!v-_ zR6NC}TSpZ%5D0aRk7Yhbi9BL4PiY*uvH&mS0Xx^HGoJ%=h8ZMOKudbSA;aJQ2(-Lc z0Xz){Nzah+gcwi^Hj{zj^)%4B z3TTDJ3ObAmTZQ%J-~azFzVm_(lmnL!9^K;n+n6BdeL69Ebh7hrb7F)v#>#^|nh(+Z zyw5P7-grjP33Z?oKRr6n277c~_Go@1aNNlN6!B?|Nj&V2d^%%PIF36BfO0MWws6MI z3-EbR(1>5J=+6{R25>*W`GtawX1O8%wgVo?EKMGa7ohXz4c@#Qpzr~mxB@oK5pv+_ zd1!oobLLSfVL$E+w&J+64#@7~&Me?`&%ce?MvK3tkP&pxsDZ2DTk!0%5GXS`Yk(Cp zgGk2)Yd!uJX>cND&FSP}XiVn$@s|N~Iu3v98_<5f-e5*>9|&Z3^9vsvy>c~=Uf!o5 zw}ai==)rgb?p_`i&t7LH&(6yporhq$ggu&V89^Jpk2`}-g#X_e%)#I4$jrdd>$KnF zxHD*R6GL~gLGurD{`Me{Lwb3gQ#lztl35@|r%gESEC8BVefb5PtQ;5`ym=H}J_mEa z>7l`!$KmC56n?|Y<0yQNm)lYJ0xy>%_@EWa950sr1vOXxmoRrav-ot!sBpZz1Xkj} z;E5Cl&Wxa71?{GSBsl&y(D^RMnL&Z>*?IZp)_?#1`}Srt`hZ%%j{Mu4p$U_}O^gXN zos_KO+xZ%F(=SB9UU1Q!3ATvAv-2;+DbnCW4NA;CKtmP{Rw|{sKD|+l;3NP#086yj zX3@GI}@^5oxd^r`w2Zb`oeV|i9oSTrl za}%hB@4VdL&BF)^>6eE=-Oq+<#ti0{gJRn}@}*p_(y=zqJRX zx%n{D>jTG~O+ZP%`QLy3mL%{jd5sDOwCPkW@nZcMP>0c3!K3*IieHaAn}7~f0(t9f zcQ6OoPcPL`&fhrhYyyg=*GrB&n=o)NFub09+!=JH7sKmG$DK_;QUAIVluvzoiO@ec1DT7d?vJCij$n~yU3c7BG$eTfRk%P#QDI;i{vhl|>8P>ZmH57ge|Xs}e_ zZ#fJ)!y;Ix^%8#vC``biW)qeFQE20FAZ1`1}9=OAAQ)bL8J9?9psL-us64;-!bX;j0c<&FB=j|?eH!xb|Nj+CB_f~z0UeO>9CS2AFvm+x@R-&&XI>`$ zsRufpOE$j^ z+ZY@+T))6!!vzbQ5|Qp;jn+&2ox4EJp9gln1899qi7L7!8Yq^$KGhwp^SZk`SmX6; z`1%d#d4-+l9m703uYu0*{p->B-7y4oma~ROXXy^46}_$}3=cSVw}R$mL8sU31TDBd zbL#JZkKPDI4{){r|Nnn`(4y7$wV+key()7-Sr2r~%F&4o44#dD7z7v?%0TNES{5>Z zPO~~9?$PUez@xWxheziv&*mo|JdV49jA!uCeB#ra0@~*L2_w27fTJm)_8Qs zf)1*Zfu4j5Iz`q4^@u9C|6DqMf)8na1{&D-@59FM`VhF@0dWm3|NsAbGbBGl*O{dp zX8^4*1KaX?2FT{y_Zh&45VamCX-0CaN9S>vTVKrB26kMDAc|#^eApO#I-hsCZh7(i zDFZ{d>z0?GBPCyGv9T~9$_vYSYC7z3GyT z)^zdc%!jN&?tBCqE&`oq>)3e!+8opLKyQwTV>ZW1JwQ#d<|6_wkW-=$!^0D@HmLK$ z2N(X0>?M7jJ}NvOohB+TOeTOQfp|cZKrc(cts`*#1a9BdZNb(Ve?1RWE;haaw=+9K zK8O!KYM^Y5diW; zM9YB^E08A=K%OW74MIZPKL_gmB~bUTfx3SS*!>`XfTpET{GnlZz@zmxD1G$%@-Tq9 z3$PA^gh#K7ib1#VaTgTFqGTJOfgDnZG3; zRHcC`mltPyLETkQ4H6AbV+@e=wGnIjn*CxQ6LMYy)l-fk;B5=t?B9+k@V9Kw>W{?XVB4olwJ{N>Iif@MpS-8^Tlm528Ne&;QcDZkf>;5HE3`NY<;h7Ni`3{i}~FQ3@=xL)WXjbGd$4F8d1%| z03IgX_7BwEM;|8i=(RNi8O8c?8n|)=WmpD;J>vW=zd)TbCy?PEz$#oA7}~{~e=+j+ z-TsTsM1Iznhd^z$&I2!x9R2$rQTijD_ZED6AE*h}dH;pWO-LQKr1MboBWC_q(23EG-;QvUw7MF8bNqe; zRCAYbemla#-;&A5z_9-YXkW(u8=&Eequ>S@Xq4Kcx8VV(9PI4{Ei3W_tzKva6)LWv zPCdvph`Bz!tf~n-42G8sLD}TRNzjJUURI%G&@Pqt9-XbAqV|QcA2@w>#ulh%il5!)XxWvB!JrspxABw2pU%ag+VK*2lg@@#D(-?*1^(&;~r2$ z{AD$q-}nR+bT1(WIWRcx0nJjsjE2ek^s>&3MTEuPJkY^4tZfNA3@_jR`~QDJ!x@%+ zAQL<9cOEi4@M7+Da5V9^fX;q{PTYW&WxqIL%)szc38m={b~k9tPs?!z1_nq))%=E| zTO5)fQEG(!plHIZ5$2&}d+@jjta0Jdy&4ox=*N}6@_-kGWzim;_y30`xEda4J>bYc z^?>8|8zePCoI&+O^AQe6r2uKCy_7BoO=vN^xNOA0@Os_^lzIYmZ1{^+?F)K+OQ*JD<5RHxM2@Y2j{k>-r4OV* z=NJnuFTNd8DB<-ue((V35YuK$?$UXV$5>bxx`ll^AE4TG@bx5qdGKzf&I2ILkn;E# zJA-HEkJn3J>+w5JKxU^vR}#IDZ)0G12|E7ehgo*di8G5@xg_uX@eb3Ij zKE15P(L4+<uv>U!08s zmALm`Oufm#fULyT@a^j}pzs1GxtDC9f&iTVVQ0~UM(cd|*FOTMX7DMQOF=!b&a2&m zo}epvzIt??hL;OI-8Rs%(w(57@Ug5%+xQ5&asg};B2oKv*26j-kn`YQB!Z6jC$ZlV z(5%nsYk8zZ!Kd?p;U$mnU%}_U9^pX0;e^4r^UdpL=>6 z(?I#(Y(Gl=#~ogv=BWoXygWNe3okxIGfy1a|AK{AcQYtmfC>pvm-slC2O6F9>D~=W zT&U%%Pvkl^M$~B9S^*ofynQ!hEHB^1V^SP zI5J-^ft2GY<@QTZd+Jjo0|WS8GH|+m@mYs~;iWu09UC5imK-6tN)Bsi$+3Gca)cu7 zSN81u6ABuyZhoTy+I7nTnobe{bDEPf6zx#dAluF3XzyCczJ0}j5)v%k1_hT{x3bsFV6tlOsEa&zcwGyKyCa%;>V-&Xt#@sh)?Hd5A7JxeI;*O4^(i2 z2AZ0GFnToK{qF(VDG55_7}Qbacu}(B?|<;fl1HzLEQ2R#;@bn&XwX2c1l-!zOC>GG zLHAqze+jy&17uh0fjU{o4n2@7U&eykX2)B=AqYyvFZY5PIxTMh|NjRC*Yg)=(is?D zn*Rqa|9WWwj>?lSBS31P=b1T%dvsp(?EDX!XY=XRwe{y@a0~(8EM}47(QO0nkAwCy zYZ(4-{-;o4=F_YD(~py(`JX|FmIME`V?Mn(Dgqw67@@$U^Oy(!`cEF;A9*l-@&H}x z1R9!`=sey0lfN#`g~snF0o=4$xFL-Pel5yxu{SbYXQV#EjJ_Wz*yElzWQ}FHH4$7vW@X>q$+K|doe&&U_76ZfUqppTe(k8Utt~2(8+~x(f2DYQ4 z6S=8m=#hLGVhiYYFUBLFnJ1*~v7|@y5ew8Z@Wmxf(9rUW+n<>k5ZP@4tla`G=U?b; z2gR;#x-F=_I@}$~04?G(;q4ZmZg30T*D`~HzeSvp0j0xf4=c7D`8NtcReE&WO4#x+ z_;zM+KqfjJn;lpfTMv{dfrjVRA@_p41XUa0d<@$D4c_M8dZ6?kV#7c5f-}@00j*nw zw;uW1CW5*Wpl!0xz$>gR50@_T=(e401L`HaYj{|@8}K)ShE^eq+`~1FF>rzI(F41n z-UGCx;(xslzuRHxV&GCuXm=hl5s7W&D-YUG0yjEA6)^06wD&K0{{R2~A{w;5wcA$2 zhKJ#09JrMU>O(N>1GU;-)P+NGaclAa|NmctI)|`w&XIp32Y<^B(AL<_<1g5185mxI zdK?qLrCMDdw)*L1DYQhh-wA39LGyR>8;%#p-!n5n%OP<22D#!d%rVrp^Qf!g0dQky zAECyNGbWj4)fD&ZF*zka7=QGeuGAPC%qqW~(m?tqXIDR|IQc~#A z%W4(C!*I+M)a+;hFPSzx;Mx4=zendwkIr}eQxEube)rTo0y-&$u?nQpARr6>(0&)^kDFzx3>}5R}3QDaI%U(}>@#_O} z0(T5^1v&Ye;Yr6(u(v%szk;9kaW&<$+IK}*HD+riDkZUGPL01o~pV~{jx2}rlUfKT^!(14PMdvEE*V2*)G;rh5siOkx=}F`FD!T%d^*!Pz~xT|Xf3uo3uEK22C$`*K@+XVk9TbLWAHqF1XLXRcK-F%eCpB7 zqS9^AX`|Bk9F&szTR|0~NB0g;I)&$8{?;B)A%W$jhFhRz+4_vHOQHFsn+ekH0NrsH zk>a5ZsY&=-zk-6T`A7yzDs*9BKn%EqfZ9jg3Xmy*1C5VB9)LOi8faNGs^c}E`*!~I z=)7)U}2B$Zb&LD=J4najPU7oOgn%{b1y8H3#iP0xe>B0vetH`P`@TfQROf(sYmJzXJR%p`Ze_ z+gaizBe*DbVDR94(Jfr6*nCO=9AO^En?b$;W$8}gm;XUamLTh)n@=fp3WJ>8q6{(_ zI`DIx0TkO{oi8te*2+%s&^!uqZRe{OR_p)%f87bXcJ4*E5-3htR3KxE;Cc?yPUwvR z&0U13Xn1J80?h#^cvv0+wX-BV_}wpf_OfV$=CK7pb4Q(^2m>vz&R!3SL(r}z(B2zR z(-AcB?b8hkM`$2|_E>u`UiIia2->n?;RC7@uf6yr&cF~C5B9=Ra45K_SnPt7;Kw|) zO;kMiJwACb7jwLv2pRx|wP$=fk9%~AsJzHo2eQ^#!lPS6#X~b#z@yWdYPFOA~9Q#0F3>s4lka+0;o}>lWi$2{R1|Ho7 z5gxr29H2yN;n7);;L%$U;nT_C)9E1)4!RAYz{023MaAQVyf`RagE>69OH@2OI)f#U zQi)@PM>m&aq=&T^2Y=H!P@eq3#NQGMnyc*&766TxduV=oF?B82TNWN5F~&n4+QA&) zN&Zf#4`0Fd@p*JtIC!-FFX4XSb&7$ZQ5ke-AE@gdlgq~N@->e)gBOaN+{}F zfzA+EO%f5gA|ASi%{C)kuaf~+CfM<_+?Oiw- zb}4~ksMnOm1-yTd!-bRK#r6gN{=ZoC5_Im$ftMB=QTj_E;2|&YV6=cw_i|AEf>KLy z7#{HHeEuRujDf+S;V)x}9%u(vorXuZGlz$^vxGR-J8Lg`}6|LI*rNJ70Kodw>&&Pq&AFM{hxdN2f=EN4GaexKHQv{{n%Fle2y zWAh(I{+4zo(604AOrq?y4=_D27mKk@WGNLpuJxI9sf@Q zm35$@gl(V`7+q96R2e=nFxW!tPteLM<{Xs-P`?B|9|F3fog;^h!Lz#^q}j1s95jYd zqT$(GFTqfv`0W^Dsf=g0zlBHVIZy3!0T0Gw9+ofaI6W-C^7kG9oe+%bIL+71k68Fy z%|P{HcesUTx4Q$lrFhLl^O%R`1rNn{9-1FP`y_iFgYIsFcb;JW;RX4p(?>Apk0ucwTfJWnge@R0kDcpvYY92inZ#Zh_+BPIn2=1~ku3 zcLAvDK`w_iK0r=|G)lle04KxNO3-1j-RnX5AGB7YLoeHim(Gs=hYiRoikqm#>{(~HBS(@Vjl(@Vmm(@O)?Nde_|cqfIwbtj_~SqeJ$Ox&Y8L&2jvLZb6}<8#og59m&956in{5v~7ALVU4}0-$wy zKY$LdhD=X^JvkMW{6U`NZvkC>4)vg8w>UHweY!P#x(hfOoO zKY_bx2Y)kp%<$k}f5Qc|AJntkT?2IZNw%l9yMhPf;g^TOz5>M|1K}|s{x;AaV8d^_ zK*NxrG71s-t=*ux$hn~Tz!$g085mxEfxFjJ+g$);6=V#}0Th^!P<^=xq-FxB#FGGf z=*2>C>k7Q%$3;cp<+WcR|9N!2@a*)L@ag>Tq4~kH(_h2zn+M|w&rW|(QO5yIW}cn? z2G9aS0Mda0bzTs~-0|fmi~+d<_TC_j3%eycF{?4A!UqVX-60PSlB7x@1n z6SAEzUKWCzkRbn*Kz1w%ym%-EYI1?NpgQ2?)t?~uzc?+%!0_@X{C)yZ=LS@Nyinc+ zO4d0l8sKASo`Zrw0aTH6yC#6I4fbLD?A!SfBy0d$J);m145|_oKn+og7t6RA7#t%V zqgoG?mUw`g-=Hf!G(W$PJHWv3QUH`NVCfr_LVY`5_-MO;E{T2)4KT0`pk(UN?T`Sr z<3%tpD7}UYcxs1Bc+3E$%Fe?t7ybGF{{<(=2W%kLe^Ca8m%qS!9=^ZWw4Z?i++uhM zx{UC}WAIIv;IMsp0W@Cz=sq(;+62%D&kJ(}@UT;fl1FzdIJI`ZkM-z=%*A&*DExnb zD6haKf+znV=^r*NEP>SMaZ%yuW(SQwfa1jimZ_lQ58dGQ5V&6O01ZP}hYRpGPXl-T zJPbh1I$u!byc(5Gl4n_94Q{!Cg8DQ{#Ni#iRL2`(XpU)L@#b@LBggC+T8T$ z4(0%NN;*YUKu&E91@)=ny#bqj$h`r-M9}?M(9SzV-%C|c@d0l?;cVBZf;*(p7zE8~ zzA(JU%rF6I{0H2|jz9@_56~>{CH|Iw;PCX<@aaxh@aX*N*?G+eS`}OR8}PTdgNn~y z@U7@BDhi+mp1|XKiOHc}cuh;YGP63^I23}K_qN3s3`S5>y$Re((pAr{*!&*8e5K9+t28TP}mnd2jyD$lrRB0dy?Iw-OznZf^~r?qmhs z%?BRMKlu6EK(qFsX&6u+!T~&k0PZJ%#|OHZJ+N2Ts-PjOQbUh!FAGS`T>?6M7M=+D zK6QpF2;1E;rD8^kSzj*q`^j0_Bp zonO8k<0vhF<+bJt2?qWaMo@#j8H(dUrX8PqzbyM|Zt|N2iB^N2iB` zPp5~5PbY&lkx5Z9>B{rjmD#&40K`wjhhc z^Aj|;H=ly--4lmy-9u6hn&*E=sVozVY{ofSm;^1wFb8Al0wIC%@|+gz+!WBJ!~!Q!1q-pFyVRmPl)(d% z{5(2K1w25PiaT(;Yy&mn5%q~3D1g6^WWpJ(53o9Q+GvpME900*Sxv zENlUjN9X$B-~DLj|V(>0UF3bj23z{ACWLT04Y8|^@vAzxq?S`xCUsDX@(}) zNiEKxMA3Xi0$is;l|s`mXbD;A9T3_ji9=CvvV7pOH7r{URMr(g@>l%#oR{syfp1T|?pUwMG8KLri7gB%S$2I6uA zDE)<~aDbXFprh*kmneH8l^T%vF5w3aT!XIg{l)Y`0CY`f^AQ1$PSEz6SkOU0hdsOF zEIc%Sdw{I5yv5&M11fxaS*E=fhScXC%`aG*Ex7nwCW9m_j}^UhHT(~%4=nF`@VnhL zJmAs%TckV^UcYsVv~`NKdo&+l^sqc!`q8781-$3LgYmcr<1x?9It7o;S00+T_*=X| z1+gBe?gr;8!vm0cJTbA0nG*9D%4vKl(MvbD>VnTHbFDIkR|5) ztqtE3r<&^;1waSFF^ap9?B`{I?JD8X>8b$BjGfOtjyr&l@qUrt%gg{e@RNg)zjZc9d2@}51S6=4%c25u59rPy zP-y}3-*ND~Fo@;R>6!t{FP**McEj;j&~bmDK}?U{fCyMqvvVq_<$oN!K?I_4DyTON zUEj0=Bn0k!y->f(47$MjgFYw2u0W7GdQDg8gNG*%>T@!@km&jM-=mlJB1k#_BHam* z?g2^v?Ed#39{-^E&-0+g0*)cRokw7yui?|3j~WA@O#t04DhWQ_B`O&{o&FA<&9$H` zkgEY2l?Kh2d3bb|CzSAd96T$S;$f_#3Ryt^{>80tAjgKN2xKw%bpFg@@aQde0G-+0 z`QE43M@8cQRd7?tvr|L`G`Zs0DHavk{DZZ`t=^>h!EgSl2l%%gU<8j)N+3ok4bawD zATn_C4|a&2<^zncPo_-(huZ4{FTPv`4Olub;PkIPN<$LeyBrwa74YaR*TCZ4*IzNb z%YoCo9B}Wt*X!c;t|6Lt!RN3e`SSw8{}BJ~f58IvuSd6dw^u~#$x^;*?ASTdkI`2Y4~)TBLxd+|B`2~1HVUS=nn9qW1Zz1 zzTIgW9-2oyIv;>0O??;-csAQHfaXw3cs&oE5lrzhRsp93&;ZJXFU$;}_z&IT(Ob-s z#o*KHdjK3XKf#xzUh(L5-2ocN?DhriPJ(3YQhv0ZNiVc6AFV%?(|Nn`Z}g}vC;FT7q3x)9f$<@J0-^iKHB&Y-}+P{PseUeJ1=g7Gk{zJ#35 z0F706X___x++O|~-1+;P8z`7Sg?qOcbQOy&(uDLraAgIWkVe_k0%~9E0u?-n32D$w zG-&ND=u|Nm{%warr<@lTKo*gNYII1Dwp^sXS)Vc5rSkx&bqlT^y4^Hf__rPRuy!*j zHiDQMrs2?G0bNf53s;xUW1uFNuPLbYf8cc&tp17i=zQhiO7pL!0_q(4_<+Ryu9MY7klv9id|rXJKuTq zvVJlKtpfNDUs-V}oPoio^O;NMN6;YX@dF3coEdyN|2M0s`~#^0ErRtpen3FinE}KF zt-gFwKO1&>S;rEPgS&H7G(an*3_P@RR1`e4T~ri&dUF{)F1`R2^Prm>%k9DIHom`j zvH|2CW{=hbB~iy%G{EO)gKi8#Y(YwduH8U7RKPL*Flg-i#&U?>&f_5M>%c4MzP+%T z2)d{2`wOmhpjI=;?s=hqj+w!+`ON>kU9Vj81xh7Nxy9 z#=!6*!VKiTYz2?bYzdFfY!08!YypqXYz-Gsp_UD*YdD~-Q_y}BPxxL>P|Mw=^RP$b zn+VXtFOP0mg9UOYhv5NGjDngN;HCxWG(OON0FTbUKD}xGLC2DT_MiEH7TkeGQ6Y%| zoD#r8382FO-`Rp(_7b`>x|j8x9w-gGhear8S<#DAp$rV2H+?#P`E-5*h4!qOprfKe z#}--osCblcfT~vu=n5hausgM7zzwTXO^?PSAeTct2X03hP3f14U|l`_NdfJd*Zz;V|G(8fEDPS*~PUe^U4ovssHTb}T@c!6hk zTtMr?A9-}%crEJDTfqq4nEgVk|L=ePZ2~QqO1K+-sg^!#s9-EEec;&eN43NXG%MA4 z(?jzXXlZ)$8wJ;1H%8D159F*&PzN%A!>2Ptz=eOCGU$eNPv7JZo}EWu&z#Uu%~)J| zpxdu0~{XAp%Xe?8$7x}OXQe5I?sD__EvxbhNmAiVGd?{bRK#=$v63c z=fP(zhTlNzEDkSZzZ?7ZXAdH=NtsJ!#+_GR$w4h3zg z7x3-Q74Yfh5d(KgK@L3UVfmx&q&+5_q<4?&e z*Vg}~ZXVsPGvL{gzZJBW0j=(A{at=0`<6!`= z0{p*I3AEqmzh|!qqsR9fu7)Q)6c2fJUfl)S^yJg|?uFkb&>Z-2(4<6(hfAl1M{fm- zS8t5506af>f>vXAcAKbpHXjjqv9A}j%J;aB<>S(4$3Vr`e~)%sPHP?p&{Q0IxA}{; zo0u71yz2e?|Aq4@P>N#+_2||0eZj#1&&Z(Lecpk45QYa{)cyVc|MeS$Z_*}sG}~tI z@GvlxFdh!@=(WA8!pZOgR4c;D6VUz?P!kUo1ZK_G83bcR4T7(WKxVFKcGo2a}#2AyhpeW|;?;HAbI zP*6kiGbo&2u$zLbs}gySZfDR64FmYvH_(9(paoK(&VJ{O=))6W+un~K1x>CyhIlr< z1vxL&1GMp{^Y?dl&^#Vw3%|#4@bn^Ror_QRV$h_9Pv-;ZYF;197yQlODy#E8=#-q! zcc2TLD)_hW2KfTCiJ|pC31=GUJo{PTn#!rF3k8WoN zk4|TUXdm#%8ED=S-0t=0b{7DTMOc2|Zvib3_32&?ampj;&Hx|FSH+ngn#aJ+9?&4} z|0&?({z1!|n}7T-Sqlwk@G9&Hka5b=DX;q={qN@YjG!F)?uD{714Hux#m7+ysG{r~@^7`z|-!W%ppU98~I?JV%RV*+Fi<2}$ChHyx?44xuDGYV&!K$T@U zhX-idps5`+Sl3){!NA{ghLM3`C1`+>zvVVKfOIzrfR`b9cD{$Ti}_pEF)%Qs_z<-U zkr}kQa3lO$u5R5V0Z`q8V-;d6s9kgX7$^b&+nCUVA?X2W0bRFn=f&nz0?j8CJX#@ZS@>Nqb_%0ugO(2- z-SyCQQ?HgFU|F)(y9Lt?sB3^c6?I^hUW0(wFs0e#)sSI{U5V%=Gp2dJfmvgRxZ zT&Xj>*bP2Fx7gw(=$s~4e}%v0%isV1U-bJkFuZ&P8o-42FkW<*>7#J8Bx~mI3jyr>|{fd4Wyc|@hF@V~GkQ~(b26WgLG`k};L0VKmO*Bwr z?EonG!V08LSb5-Kd4a!eD=4RRg6DMpLoTcVZE-)q-wL{h0CYq(@=76yJvk}{;2VlS z<<$$*RiM$ZYzxqFD(^fx4|?{7u>SY>e$9iq*umrbP0+F+#Zw-N=R7Pw@i&3mWc=;F z7#JA5dP8&>JUW9NJi2#-#)d$J1h|!|?abk!dEBEDEb3$Vp1&77pTPLnqcd2bySl*e z5~Lyf?uB*0zyF|hI-v4U+u6d$@&JDeXnYei2biBW0le_9yVwCT=?w}|t<}s7-LTDe zdzHbP?Y61$z(cw9BrK4@o9~W0gYR4OIPMHtw*}eL2OIA??hIH|2p&BLf9C zQY!^K9M*UQ6lCy@19-f+^F4U!zu|!wGxstxcyt~GH8S{HeE$Fc@6(+FI_$#P!mC$A z0~9(h?}Ekeu$4*LE34-$r~?6dH&{7|as0a}{exfvXn(0bJHKs3^N7}$EdXwVi>7udFANZN%q z2?(ZL(2y-`AIKs8=8vHI0GxLJg9jK}50na^CfSlmk6zYGDxjzqJ*~(Cjeb14E3ri6 zOOP#)hy)FUz`_SK1Z?2Z`mJQHM>jY`JuHvavVr2VwA-cIxxm%%BqW|8H)+23vm7b1 z!OOL~OH>TNDf&f$@4x>L^DK{*fM$$d)U5#Jez3WqX2nZWM7{bMbnz!Es6pEsV#)wI zcjFyseQFMP`w3)CHmJMT>mtekTCDBSD=MhK!{EX1aunR0=yp*t@L)U&EBJd^KP!QD zRb&f*x7fW{x*wDxK=I?z`4==h!0`f9vcXQT#=TghOw6Mje2^4q7AZRR{{v`w|HAnz zXk!GLlmi3OKm*(+(78)Q*dzmP1A%uUzVhjO1{xUw@2ddW$?)Rxm;e7?-$l%)gH3OI z0~(h`NnoIyX?Os%CP5Q)0Y~Rmk8XGHOpa&g7mx0E0T0V~3H}yPrvfzlVR?wZ4SbwX z=ld52mB7W|tF`&x==75f8H+%~+)fBuUek({3=v9bp8O8=)2+ofkc{ zeFZ!iKl)fctK;*uJj35B$_(1g4_fzi969KGG(Uq{i|@ff8*1Uv?dsqQS~Lt@M(U&Z z%v19#s14L}2UM{^LLVI7pFAut^S7CS*3n%8Ei#z^D)k^6Gx<9}Aq%e4wqey30E%eP zy3y`Z3!hGKrnUk^JS>@iS-ULD~ENGx@RN_cdJa(Hxx3Lx9=(cJ?+FBCov!QVO` z&*^%?oNJY94_IA@5J| z>3rV&;5{fId1#&o$6_y!6(k+`f@0PHG}G7mjlW|Bxc>#YE(~|E&EK{dG!g>N5@7fF zbUpyz`~9LDbmcqfHbh9e1kW#nH@OsnPc1J|;Q;N#dI?&|3`!TEa}+^q4Lu-X^s)`! z-e6IAVGq{AqViJsH@v+9-cj7iqVhrsEa?L^ZwhF=8$ZbIXP}ljD~JW!9r@z-J5W6W zj+B?6#?p&lJ5c6JK>htmpvnsp|DgKiFK8gs12jt7da14qyk6>xN9X0&68!QEFSK3$ z{r6}+P@(3bc^Fh7w%)GucI>V#08jM3bNuF7!c=nWh3Y(J(7B(Lw;Y>&85BT?Nb`ng zH@Las(R!%@v=hn`GQA0!EP><|aDN=4^z~)Pnj+Bnx@YHiP{-G^^DAh4{R(J-9=L+_ z=`QC0RX9GHpFJ!u7wddy2MwQ=+JTBsu`iGXl%R7Je7Z|HJi22Ad^A7%SUxUhY4&9h z@MyhV>gLn=!bkH5!hUe)%>%R<=$lXHe^1RjFXXF1!&C1)JCD9t0=mr;VUnlio$_fO zt+z{dd0O6q477UkyWIhuy2p6$#q%oAP&R1k$kEp`q3Hl6-TP|(h4w2z!3JxaT__Xr z0i8bZ50vVI9efyHfOo{cuz36b|Ldm^b3n@wJUhREqUkC)n!pot9MIzB7-)li=NoXD z4C?lS+Vh|dVc7y6pz{4Ge{&3|q;7r7-zv-q+NcN$GX7Q#kRWJi2Xu-fc$~1?+rdNg zppWH4{&w&=T`1!`kWm%TXo^Sk&wBngP;uwe`M~g!Z|8H5?;kxiuM@MBgbP$HgGZ@B z!&czVHh-Tk*d^fRm?z^gP)!NlI0x%;gO1v01s$mgiZ`TlMjhiJ>kmB8`ya3#$8l#3 zP@mA_xHISwT~O}@G$GC4+xh&ZA9ySVlKw#(#yVelYQA})RQdP62V*veXXml+%;0cp zxdB?D-Fg4TbV*Qsg%Yq$%fT6!0UUwfU*uN&{qMt=%<&Sm8WNPxL2XS1&~4X0{`0qj z4m$GHd)Q0v(dIur)pO|lJSJSg3C2U~c6?otev@X);GVfnS*+Jo^GtRL2_{2tbZ2Crg? zf%a=WKs#Hs-7P#AkG{-7iVu%YZw`-6Z-LjxApQY&ue9AIKPnT}@f^Y66OfH?rOSxa>*@BnifQ~xf zJPlMSGkEl}dWwQN;=E2mJdjzBPRJfD=sNPw4$v_9ixkkc=B)=x)CmsJL(&y=-K|G2 zua*d?BijvX9eech$_RpZ;M1O>LE|os{5&cQ5PK2B^)I#wGB6x>E&v5n^kJmYxU>n_ z)wkhP?-*iuAk?MvD0m#N^LyvD&QsrHmF73c>~lW z0r?+RYBXEOmOOCjeEx!aGBbnWf!Ft;<#x0oc&P$BK3{lGVFsPi_|gMhh%vmVe)|9a z>j`lA=K6yF{H>t%{fLoB(Bfrw=s;v=d4b3Aqo931NYf+D4?csYd?D?G<`WK`pq;Ns zgOe#P-MI`NmKVxA4ZrOK&BY<+Dne8|zp^7$pv(oJft3darnvq|F1WI)<2eVgBSNf>POJ=^e@Dp{r~S_c{m!fvg-Q{r12_H zo5ZC%y#TzHxJ4bbjf>r*^S9w!RSpi&)=5y`8a&>0ZZjavumf$GfweF??|Z-oISDi}UZnAX zE?#?boS8>u?Qdwtap8A)iZmMl9qojzXX%~}n$2pxRHp`8ci0VGdad~hyfU2m{Qv)* zN1=PeK<9TO*3)|Y151GpT%7RY_oM&+U!H)MPmuZq6iXh>Z%~)?X&4@Wq|OS^RL?dh zkIui2ohL!3XFg|UV6Z7K3ARb(2VdF*%@nSNPoOuBAj(J3JOXGLCS>UYf9omG7y!m$ zI|%iTJ3yx~I)X2%-RS_@-`g9+2D$>F*EW}(6MPW8NAn>@n~HikZmH7=QeK04dK}4wT5)XqO5&Ha-B&FnV-ecH9k`6!)>bRJw~_p23Clrbp-d&Qm)< zLlrODK-U0u9s#vmTDm}Ks<)caqu2Bc8z;kyM|q$||6#BkXnm_sZw2c<9Z>72^Z$#j zd4K2v}H{1;1)g13Y7aMkqg7}`h*}>Bl91O2zCOCJqG=Yv7?Qr|gzb%~6qxm=^NINg6 zvCO~kP_Ne&Xa4Ohj%f#9FoRa2{WLD;^XG^@bon zf)^j`0If-L(fs7t{Ex|l-~U4A_0~%z{DucQ4>liQJjTMOZ~3F>vj^j~V{8nL4Yf=R zrK%p?yd1B&84M3V{NcgBFNB%3TV$eRM+hqeX#I1`rP5a(ozFqb8jdG1Gk``HL0cn0 zOKQ?P8Q|-FH9^S-yzZC36|~I=wq*>or_Q50fWzas19T}dXm_)O2k3wj=rZr)kY&VB z9iH8g%kMmT12Q~1r-J51z=ug3Zvc51tgbiVvs~@S zqD}#AlG_U&U_T6sFptjnDK6d0FSvgF|DWR0sr=Fr6uG^;QY@SdyPQFx(rfyF3A_r~ znwgW~#iV%fD&*hHoD93beac?bgAi#pkaTf8XcC11-n|DEMI{l?b>0W+(s2}ne@_1Y z|IL-b0dy@6!IrlbsAD}D6nLOo(4+Ic;kW46mp>)Jn>L{74QXEj!_WW!UoV2Bj~AQo z{{R1aKV<#n-{5Zc6&(Dn_d&kw4p->>3_9621iV)u8zQFB{QEzD%W_bk$THLcw*Loo z!;Gs&hg7#K!wM$;R?v9#wqYR*86anY zjL`h_q7Y(t>B-k^2>U=Sc@EHB(A}XHppkN`w>IIWfA-sU)J~5FffAKo$ahfAU!`A>kYts544l0N>^d72Pstotp%Bgxh~hE*Y=4N4+B5z zVc2?uOz=^N=qHi$v%U-f^~?}{g3fnA2N%I7+JXibHGI0=B|N&zBRsm@6MVYsJ$yBf zdUk&E)%@qv`5LsC5HwKM$jHDj!6VsAz@uBp!}7ETzyD2-)=Q;tLCbG7Z~0h$DtGeK zyyo3&V-DK=(*e3M5mZ97T7oigXKjE>=c}{{ngIeH-Jsws{R)mUKCtr^Ilu$T6KlY$viMs-BWa+U3_wfkKwC%!e0mE~_&Y%5iD$2g1b9fxMTO(V zjnu#3s|z{6=W&46lg?`b&5VH7hH9rucyzla_;x<^>GbvRVdhcs>GX~8=`0NZHH2D0 z!3JLW>CyQek`6j=c`)Ad_%&~?;oJH2 z^*Ydetps?G^*hKr93J0qftI2Ocrf03u>qt3wDBJlf*|i6d!Y&z@=+0h^`}4{dc6b@ zfuNzzj&#t#O=o$)%blQeu1@@axfxWZfZYjh>4L{d4Ll&%xFOAEx~PEffOyN_au*yY z&kZkm^qNY72GC1F_WnhZ^ z$~s8!F!VYxI(B~OWc85XVF0yF8yFb)TS3?A!VQORGw`ua=iqOd3tEud4LM8}oYO(g zj(?y&eo25EEa! zg43tvW$2FA&Wj%1K^dSN@cMN(co}`26lPZCXNAYgiiktXicV1_ zaUO=&OQlL4$63Xpg0Q_Apnw3?m(99A#6TA|fR4b2+-r9-2z0L<^7R+|t&czzZ}SlY zaAgX1=W!PmP|JqFqnFhJbedBqi^@xBa2XCMAG@71K>qS*KA7Rr$p{Ismh+%SYapn| zfVGc2x_Ng#=4Jo|Jm}P%R?z8DAbp+2;KR!%w2MZG@i2hKSo=V=DrNw9^x9g8fy%0v zmjD0%pMbarK~xbW+_Duk|I}+MBF4k;LSKu4;U#D;$))oECI&xU zDa-eW8?;<1b|R=Lmp=eA z<^D!axoHzXcPqovZNrcM|3M}H%X;K=%c}Vh;%AReSvjcN!1rH)-HnvK4hr)y@V69# zTj{o2gn1ZVoL6UHc$okyE8*?0cF|eF(DVyx;$cm{6(ECHUmAnbFJ%7`e@i*2cTf*9 zFBjE3_HI!hkcpscgiqpF1=uaBDa^wFzR=`F^c<8V4XS`Ww96$tJ3oLniwJupgDXr= z%L_iBquyH&fa+VM^YbC=dBYodt?nJUX2P8lHUztvTux_JABSssL^o zfae(|cyxOQfKAgJpoVg(3*kjo{B5B5FpMQ!;QQnF zTR^QQNJBdsQGe8e*YPfax>OeA(#~2Auq$07Kr4nI8;)ziQS`S0G(h4CjUwo#Dd_YOi*9C**8e3eD;P_3IuA9UVD#zC zwrGCzul21@XR-so>!D6&kdHy_8PHuLi1@r+23i3A`ZRQ054;edg!3@W|DgIFTqLYu zD&c|;Dkl=r(@gaM-8Pfa{NsPA7HCy)H?vRgVo)ab=w00mibtq(b(>ExdUR%6fZW;1 z400f7-o&SOIYjMxklNR`VeWaM4RP-&sC!>TpZWj)^%Qvd1Z6+$dy)`O~pi^0c zL9?ADb{@@d8GSqdcy`xmcy`Abcv#*qUI#kC0dgP%=s1S5Nj{+ExwkwS@4T23@%O)H zr<=y>c1V8p)O-s{2k0vw7+wg2{M9!BHlFFozfFXtLxdePk_kG=;k^greNV}h$=li%$gH~>$AhKxFIy@(43T^13`;n8{Y z^)7Jv=&Sh!c?%Fcy!f|?u)#)tq2YDUgYm9sXDP?)2Bao7Xx0vN_X{|2KyoiJXYa2C zWf;)JRcJ!A?eQW!0Sz*{zGu*MUUn;xKapm>KFCscJ=_px8Wsl z8UfkKz|iTVA_E%FfF_gJ6X0Y5IxIuR@DgS^0gbnUriS-}cDcWppA8=IDDeW7M;@I= zeR>yw#1TcOV)KK4NM#XtRsg&l1W{hDE(DjC*P!7M4K8rNYQX8ETeOXXhoSKt1H;Cl#jcECviNEyF=#=-675P z^s4>oYbU&}lAe9^I_^SGXCDvtDH50kzvfgJ>lJ zjUM1=^5}NR@Mt|y`T@Cg1Et??(PeByB|Jd!hn5n%O`o%ZuIL(+>9G?!XI)X{(Fr-x z_P8T7kvoF3jK^_DXl4LSJTZ72cZB8zwAKT+NbZr1+koJQ|H>CZ} z`ywe9(KP?&%Fs~4I_l*xL4M(H}kIrz6Z{D&9|YW70QPa-H_-^21l`KMkME6~&! zsGp;Gu-EbbVd(h1V@N1u+l_@MWc&(scnfs8;9LF{(B<)lC6WCAUXl5Jw*Vd!S90CBoy*PiEQa5ena8^G8pnhFwXz0KcZ2s(lg zd=&3X(B2n_KVYYDdPsO!dMK1R5OW_{J|hDIEbtuvhlARW;OfeS-{nK=+Y)Q&onf$X zVZ@lOBDP^I(C}WfJ|i?e9A}-&2pPTd=#I_+EoCn8=#=ecGIE;(f`WgO%D|rPEOJ@!KcF=mfmv-RQQ7#M&-K=_y(77X3 zklmmKmd9D8piV=YJt}C{{m;O|!03w@_`P6*Iec~vR4_Cjv2f}90P2c>_IZQua)sCb z$m3}SPod*!pixz5dVX;#{8Y6!l|3)HW}wu0xyYtWg&kWAp%c?2{)(&7Qyl>!~WwR!UY|BLC?$m!l%cKv^D zw8@Qjq;%i;A3W~a^`D!eo3#PN>6YDkhMNJL=nFu6P@=bCWB}!a*RqiGg}8VRn!Na1 z1VQ7k+RaayN*_V?>bG7hx#7_bnU8P1RN|K6(QN{`568NQgTFJOdC&j!XLUO@(im+_$SE+-bomyDpX?QY0* zqn!mD#~nboEJ1dtgD0f;`%-b;C+!2uVfR~6#-2g#Mey#xm(xIJV}tz<>i>ZkVq4&w zPP_(+0cegp_2B>i7pfM>InGkn_78fF^G3>X;(x%AA@K*4Z*gH)tB} zHh&9f0Mv00Xj=ItXiqsLKH(S9!AfJxe5AWZ!Q~7n8-=1woq(>-?PdneX{mBBfmUfU zF))^Q6IZ*EZUg8`cHOH#UpJvwELe{(ay51wcNZHs7p1hTC0 z7pPh;J?;ZNssUwu2Q(23S@jAU;cWw*tc$1*LnU5VJtd*}cEFF_YJLfj2amq*d-2bazV{H)-0cI~Vj zAfJKePkgYhYVhc_efATav2?&03+xW0d7qOY$(A*cT(jpVH^YnTybKI4XM|uFdR7xhx0pv~IS1$@WkZi{XO4zvj3o-%&H|mT0v_GY2_B#!>(1;1cxw)9ueP(q z>wBQ_vd-@>E<6Jrjq@703pN3?jLD?Y88t??O1Q|o~W8;@>(iPmo=Dh<#6f!2O>ii0PI zI?Dy1Q$ijdo&KOHBni;kA;uG+<}|1~0WKFjK({}9D}B*$j?tsL+yksP!lTna0%Rz7 z8VaoUq6bJ{IcP$P1EhBX#94^;c(6xveFB3==kF2@kK@p;KlI8Zhi+!j+y?$Roihob zUJ1@Q9i;a1SJ1c$=wu<6ZhfEbbPk{HatW8t7pkDp@U{F>rVFZLr-Cju?sZZ551Np2 z?8s61@4&z9s0X-bfpp*r=zLZF7ErC>(_Jm#tNGo#m&YD_Di&y!$%{zDDp}AZ4QRB7 z1H2LAn`h@4U(G+Bj7NMrpTDqh{`((vw;2b>58a?uDV^C8KAp({o{VQfXRy62LZoj; z{%tNQ|1Cf8w}AEqcr@30Fq9;NhfVLl(6|GdzTs~LUuN0u&Ee9m?bDqc;nD5v0h-MP zr&ACIlm_*EIv+wLg9RKL&w@Pf)0r&b(y8sy85{vQO~~5=dc>Iv1H*oh?iXT_kbx*Q zkKPF&0iVu?9-YAfo}E`-Z-eA(&*nFbph@VLXa2z!${hpUH-X;YLyv!Sc~Bxjq>eO< z^n#o@!1<_~Rq`-51H3u zhAR8Y&Ctx6{gs=65wu$byng_!aaNtL=%sWiN3*UV$kfB_tXv@VKN#y74`Xdpy#4|z`r!WcIL>3rwWc^}-|eh~obAAt@i=?>QL>C9H}(fr_}`N@az zg%4;yALy<-XVBRy8X$4T7oZXXbRG?y2dX8&XKpqB{a?cG(Fa5|=q2s66Bh=ChBF+Xs-lw}JfYtit^o@DmzP0xDL6h14>bS#&p-75Snu~6 z;Dao{8+f7pIB>pty%bU2fhIP<#~62psIYi+hdcOazVfjA#NP{QM!9sWdvyMGY<|L6 zA_qPBruhiyyhljY4>lN*ufeBX^!lavbe9`=fDW2E4?6D{d?O48=x!K+7r#P4aRENs za*J>4TTo#qP@)Q+2LT7}@fQJhpy+u2LLnLv9bjdiy(0WRo&Uh0@6mbRN4rFYH2ZW`OZaHM@L~Mn(di62CQJj)1Ks#w0Ox@g8F0XP9N^PGKo?qC ze&z20uLSFS1zMa4N&uf;h}ix8|B@Y1zJk`_gU)pXP2u}=Rx7~GkpMLX;5?A20&pHE z#!+1Zj(;D^uQie$Fxy-WpZI8gda>B{@Bf$6Kn?a@Uh!)j47k z7;j zt6Ct}+IEV!zAXjai^Aclc?Prw193hcXxs#B-eHh=`#|P-z=F;5_z}=#10>KKz8z)c zZvmZQ_i_)oB@7y$>-GzMX%3G=F(~zX9>@ zOKwCuG`wVZ0G1X(@ei(D!1a8M3dajM@O70nDjcl`KzEn;OL+CNSiWooI|9-^1YLvl z3^FD85wz^D8?2bW1=Qe%dg3K3*gA-MaC(58K@ToxpzEWdN}-!nkjkNN>>MSm&Hw(F zvb|jR?f-v_`WbV4S=Qq?WE2>@{~-2d)yx0?5jFe^?r;W%*LUFKp`fYJv!JQbFR+ne z&<^0z2+)C|&tLqr1npHi3OdaQa*)aW7qjpG|L@b8tl-m`3~D=ZfX2(5d^)o=JUX)t zK&>c`f0*l`GF`9Pet%K{XJhrw%-K^ub&Pre98bCyph!qDhuUj`13-DKvkvSY@KGOLOJLp5C4iUGf1ii!ijV2(-vzhH?<0>5C5O2JF;rBZi_kxxefou9$( zVave4z*NQx*{9ISx^gdQ*75LOZct}|0lD=IN(bHS$61#{qXgyf!8JZt3mCE>Zi$2@M&ERW!sQjjHuZ(~Xv*@l!C?e)xW&gAsJ`Tnp$p5YJA|mo^{?*!m_9OIyQT+ze%%FO@*T6FeJ#f%XUUw}7^Y zyyOFkAu2Oa{sqO`8xD_N(~mtI42B2548$6*H)l< z17xX3w}*gZ^I=9%TJ&VR;L#f(;BoL359k6p!xJ8sr%D7?@RwZk=(Rn6mV@C1$p0SA z$2dGJzn5~>7>?423F!N36NZFFaFcr-u#;niEh$^bFnUBbiiM~NIPK0sSpyB#E& z4}z`pV7vx8i~OZW^Kk(W%ipCJJi8k^I2af_8JT>OZ+j%4^ks|!59jr=a_!`1@MQGj z@X-9^$ynsz$rxne%jjg_X?d`O9o&11J?xRpnzI9xXR<8U+~ZE*WdNR? zP71HD!ramPM!>Q2qG#tR(2DSG(U60n$Y7oK8`Nvyl}_bi@aQ!aKg+?;V8sv~;KA>D z!tlT00mq;hk264%khV*B<4hW}s4gfKI}LgFYmB>2Hcyuk7=*nE&P z7l$x2yk0y3+J&AP!p!he4Rli-Yu;n!us+|L2YIpG{0-K;zJ zgT}0`c{D%!(fo+1B+|3-nvqUHr#EK7Gj@0zIe2_T(uJh8KH4os3@Iy|*|Rb}iy& z0HwyX@D-bAvXLc87ELfCeJ2f^uT>BPRZq$Kd+# zhexl+e;>xDo}C|kH6M8Nh70&~9`jH<<-z&RL-CwPuh)Mt=Nf-2=spRr-WU#c(4JPt z$Ds6RdAFq6@Bk!}gU`zM={)`-EDe^7K=+0D^|B~9emlU=-wH|tzLpC7t)QV?(5get z*PsKln@=!#b~gKcZuOIuAI;K;p-v*Y@B^4u%&~eu0+BI54;x9(aA$qnEelCI`c=6OaHiJq8Xi z^J5$gFL?g^2i;v23zB{SkrsnU>w=`;LW0{4B>e~?{rxCdw+=}99O&FUL~w)3chJ(7 zUf#1eI2d+a0}TZ9no2>;^8z_*E~*Cb{Q(RQLATe2ga-4sfKsE!@xvef{|Bub(MDbc z0XnY++@j*&D0=+?H-k^N>WK&344}oGUY^}8Dixs8v3ZY51E?YF(aE~{0XGBWuv5?D zEnrb_8@%;xiL^&|D@YY+<7EqEI}m8?4pb!0E-X917Jsk#%mQpE&|u09=*0A54ag#tpEJ~KX{uD zA_xr+w6p%W&&|;MgR!m^)U^P)dS4?00|U5g;n8b*>po~e_9gVbR+#x*fsSkL zeEuR7WO5>C8oie{@Hz*>E)&o>A-$%3N5GNSe}seKh2XFM|6ln0`;R;XG@%>Rr*ZP= zWmPs|U^vd|c^}dW_vmDuve)jDSHXju5>AdP|d4s{`kRDIi3cS`!B|CjAPnB!|x5+?mJO=9j8@}b22c1*k#Np8$Bmg>+((;%GzxxLd z%Yz>LPA5D%e}E2A@v%HrdfT(pLBf;qh-YVpfM=(HXQu}TD37&*whx0hH}lIg_;j8! zJo#D$-v0IIbrSIDb`tOaHGB@f-~kShf_(8_uRAI20F4_Cvt9*i|A z79bG~55^po01(#!`QLxf z=A(=r&4(2{8~=iekcrd!CM1VY;5EK9!*S0V`02=-_cyYez-~R}YUe@pHxEZ26EDuADrt#=r z1HMoLl!7aKI{zCU@acwxgh#Kb38*yheCg47>&3*TfB!ugV^lIg9xDKyv(sxk=K!d@ zkX^Qpo8iU98>|eVq{rdW-B18>1~|WgQW)p}obC`6lb5UhfX16%7=8mauRK&47#RM* z+Lg=!0v^mB5}-qJJU|x$w;m{c4I0|7@aXJ;IInXHIC@@|{sXlnV^la`WgGuSVg8mD zP(=kAU3^jb?*IRnr68NSTT~u^f~?oH6_SZT0nwv!10>cx1)TL?>~8$`AAC9-$orsv z$EG9T{0>q&862pc7hgJ1Bkal`MUxXiv^%K%y_{Ka!T_N z1JIH0pdt}|c7LgeN8^zbf}kVBkY-I@bSI&#F!1PRjawMqC z@<*AzN4KcxHf{zF%^#ps0Td5;bY3lyGW`EvG=3|nb8y6?n^kr#sOfRT)AC3OuOaw4 z*~5_X1+?Mg`~Cl-CZL8|H>>DP&?1=wr4}IV3Lvr8110A?HII~>^yp^2zJ{B@NAt0d zrs~%%pzgqFMvu-24)7q@>(vnR{$F@~gdbF{fZ7Y){v4olLO?m%nuVRe6?C!!cwP#$ zP1L$VqBPUPx=Nrl*`qT+!lTnkz@zc!e`W@TG98cZa0QRnOC`!4)>Rs%nI7H#8Xne_ z3Z?NL%@qm^B|;vZUK-#LLeQx|%||#u>l3b*XhRMO3J2Xrt>Mw>1e&k}(F&mRI(lu- z?d4#25%Lkze)8ya(D3MVPO6hBiD<>i2#g5-x*f|*a zTRd~pA?P+kIN9T`&FIbviFnRX691#Fbh_r%NdV=mwD;DtR z22CP9{o#4=9gk11jka&+2hVPI4o|}i9?cJaG(Tr7b@1r625qup{Oi;0&EeVn@Q0`6 zPslnDkIws`oFw4`KV9PmJ2+3dfa*#Y(BEQs@FF05C_AHp7+pr?6utq;@5yq zb?&vT1+fd>|Njr3?+SGUUBU^DCl91Hi3_NpcjExxY4-RB=p^Cqw?L-?wI62!O+kKf z_;!q+zjYU=rfB{x&);?c#OgfQ{E&mc6?7gMc)jHVkdHe5g05t+@aPSG?{V-Ii-)Bs z%SvvBGIgJBR_>MD48FZSDgvI?B`Om9EwkAe82Go_gn4xS^szk7-=qyP)LQn>JgfEtkp zU$gXj|MO@*$mG!-au%hsV`pYy@U*jh z2-^DR#BuNii{)Yd);y5y-7YE?@KTDuRSQ%#G#~LmDx~=3!N)Oy?g50=u^^*LIY3M0 z=CCm^9CuNX0l5*hHNdx5N5;qU0e{O!RtAP|t}IOaE#E=cd3C#TfYzIGvw_0?m}m2| zACM5pVqswLvD^yweOoLG14Fmz?kn63t>5@t-?K6>IDT_c;b1IP@$6<%0nGq19tK~L z1{%`=-%;Sp2D%sR`HN!Ek!hB>3H&WTnHd|aw6Et_(oXfxnuCT!Ue^7;s9J*&fQyI-iJbXHzBLetk*$3G8 znNR15=7Wr$oh2#~9-ufhZn*|(hl89U;M3Uy=A?DZ$QA4ChNB+qNkafRi zVPF7x5OiEhODHJo_S!z&&%yBG33ywF1A`~5Q4L~%OEU1W1xW2h+X|3-x4i!U-=(`o zMaHGQmcg<4KO=u%F?zl1(fJowf-k-3^*PGmaqu0_YXeAq1s?SK01ifv&I>8cHmcy3df)jfwxEsbAwiMJdJ<8t#;`?;hCir&#^K5(u zYA<hZT$gD+Q?oxX&d!K2$YVI4PvXRn)rM`sME?OUUw;c0oCzcm_kLr3QikKP(< z1@I6{XN?L6sHhbHZ;ODsyPM00@u5d=;eXH0Gaj9%JsSW0`~RPrzdeP80Xl4@dCaSq zMa{$7MTLXEsRrD3au@K>1eYfsy`Ys0EFPAu-WNe@gF)w^fja3dzMb!16gV+6IDT^l zK?72d7#!8pmL8?>x@UT42-@F;b)BFJ% z;p=u$(Ev^HD<0u*ne+Sqf8Xvr0bk9hp3Q&d`TM$m|Nq}DD!+)Eq4g4f$2QRF`F7?BfFjFBb1A4$1;y1%Z_pfxJb3%Nwk`CHU~{{Qb|d62)QjfsH) zGzV02+N0ODWj6=Ii|5Zlfe9+7K;@C*9u9^VSHMD`ekXW->xTy;_$rg8uRp=9FIkY9 z4bQ=BLlAojOnq%fu80IF%g{Sa_j#j3iH zn}NS66@0gvt-?ZXh8LT^{Qv(l1bp^lHzc#Wbb^YT&L5!5KLg<9-%AgOi;O|8kb}7B zJ;+l+&p|s++Fe0IIsARxzyJS78O}i}oZkNesRWw{E}KBLA*gT4-|_~0BF+03Z4dwd ze|i7M|Nq^*(o?t@T2FTJ1~1@d==4z$DAn@lwSBgS1C*IT6DlvXteF`)kGCG+?*xr* zHrr}0;0CRQ69TV*KIzze;=kdgokk3hxCcf1Pg~GnhNMhcAr{JR;$V1j=NU?iAF=)ov^oQ{VaTUj zcf$%$=ja=MOFYQImbN$Mfd;of^S8x=4vJ+_VesjE<=N|^%kI+~oZ#{OmT%{E(12>|@*?O42 zbp@yu(;KSbYx#)3Z5ODG(98M}WUb|4{+0&N*|?pTd^h&L!}QVc>)ImLovHYCz#>U z?Zg4L_eYuj9I220kOx!er=z5SpQDm!2J_NLf^hU`5RkN8+V z=Wja4%D`}pMTPNYF=+G?+Rif7oC_M#tab3|3{l|#buuJg_&o)ka2cWk8prbJJjmaY z3kpimWo{nb1p*$O5}u&F`n`b)p3P4_fJ4QB!vhj59-YAn9*iG6n%^mSG@oOHg-U0k z2DrBH>^0#74FZB%z2JClzXcA9^B&FT89h7eI6OM}UV@s3@Olb%iZ5tWp)2%O=(Gu7 zuX%pI>#O+2$MSjcGtk5qd|C@MPz^e+9F)t2tw6c_$N!SUKD`bCEBN_aC0Ri&-$x$D zL1hht2k7L2&HxT@M*6^iP}FJ;H|PYhZdS`V+zgh7>bO8-*t&DL8A{*yc0T>!!+%g$ zeGWH+FXK~>ZdTPf+zg;zV_VX{|NlWvB3K=l8oFjPJfVvoP_uE(EOz(0t~j_>RA?3*0V<0iAa79dw)l$A8gX;Kopi z3I}MERluY5060QIK%v&n+Ij+%7X?{9g=ew~1bu&CT%g52U{FKJKE%A;`eM z;MshJ72-0``Q~h(B^y4S-+VjMI9?QhMi!u{r#m>|<-tGy|2NpEFz~m4I%u$T)g7GR z+j;%v5{S7To#()lji5v;;i37@hw(Tl>2mmV`lx7t7R)NV_-Vn+02*cD@aYawkpQ*f z`9Y<6w~vZ~Pq&YX1}Iv(gA+VEJtSUgfK7E_VED$mbrv@R6Mw4+$gkZjDxfuxjK_Qw z-@RmlG^(KOq0Wn-+e&zKW^psTgdFM$uE$*sPlDZLh@2RGK+~V#=zP&)4!WQd9-GZS z{(E#D;&0gxI$)C53S_lMuZ;m{__$^DzyJR|nr%GxnZU9bogcUM6R-At!| z*&iI6pYrp!rh&>^&FkL1F02e5ouUD=K!aJ}9Ocnj#o^J(nzjf$W5nN*25M?GzX9i4 z(B=YYVFiyR5JLhIU7#}8{5Q1w;M4gHG!8VAo8blMzLJ;x|Df%QZ>+5|!QrLA!~mX@ zk^?2Jb}J}Pz@zh&kLE4#U2Cil7J}-76U`6!`CFziFfi-~B?8d(qP-%PK8(*j82^E; zumWw6>gk(GZTH-oF;Tf>tt>tNvlN_rCiFMuXW zpc%H?M@8agBB+nl%d5ASgJIWePH^qId?mQHZ{EVe@S^TMs71%i50d@}k?w#<^K1pJ zR|ZLUgS*{FJS<<78-ok+6F)#rD@e-*a)UZJ<$(%4Ia5fX$KT5S`~Ux!9KW!t^yobH z;)@AP<=tQZ|G!@5(aYPphl63)c8DvOAg-9VnS!9JQw?Ixg0M2AzLCd%uIG9S*5Z(3Cpl03G)3_NJK~vho5B~p8 z>C^@dI)LUm!KQ(3TkW;&oW{-YV#^!kk&M!cX5B)NPM8jO{~a{H88HnqzqtaXK@9Gy zd-U2`O#{tuzV3$fUt#Ma5pw~ek{|^wpwm4)dTn_?mZx9)|No^1s92f+GXKX^u=)Ib zIQR2in+meyC1^jNN3ZR#)RTK~cBprzzm7rBvLbn^kTq zn9bkf3eJnHY9J+`lOHTE@HZa@)mh!DT!)}#%tX+R=ab-odaVYlKfv>}tp`fXeY=;a zfM!vAtW|Fu1XYz*jEL>ntp`f3b)NVDRt(v?+j^k%EO=ZK`|LRAzGSdX{2N7gf|k^v z&vQqD1`9wg?F7$rdvvpQft2;~HiM|v1Er#`4Z!C2c7SHmJz6i7D1gR1ns;9y{Q5d#wHgxt(c_pvwA@ zofhvb;L+K<0W@OV*}Q^-fuZ>!e+j#X<|&WnLjoR*H#|DQmp^)FUI6z1I-NK?jvs)o z4$(;Q=~RHudLTzUXnP7cMEEy~&f5nnQ(4174FO2^!>3c#a~3zs==XDQiY?j)O0m$R zp+SwLRj>razfm*|WDa_k0yp*$Sqj+=pquWSb@kDWya_WBk|y7SD#PQfy!*HrK;a8M zPv4{4bm0VUhW(%bdvX2-sN4rfMk}bRf;{Z#@t-$h0;t-3@^bkfQ1S!&8PrDKxffKN z_=4JPy|!!iax=Vezxe+@c-bbXbnMy--p9?~2Rc;&Ya-168NmATJ?h~AK_Jl<(9I+s zy|%6(V?SK@|NrG&&_-;wI|vtm{l?!S^anH*{QSjfkRn#F3)@-cV0MEpCBSO;pFQ9V z0@}+7&L5#3y}TL|Kn2Ge0hFm34#NY`v~Zl&y&p1ym*UaM;n93B0W_J|JMjZM==^w; zbb6umy+`L$k6uyHyZ`_1mjmVGN56~t(Ucm|63@`qGhbKgrUIfL& zyZs=0Uc7*aZG?(}dRQ;6K*V&RV&V)83@;8q#AZUpK$`?!tbvG`Ld8HWzZWwgViTca zpvzxhv_Qmqp<+@X^9mqholr4ZkXQ^vY%5eu5+vpU5jzMK69S2uK*aV!#XxtMyif>b zW;o8u)dyYT16u6>pT{X>18r7{J^Vu31!aCY)T5VmMjs?TKzqu~5y`$ZxmlkPiCY3r zk^CD)GeGKlSrb82^AQ2i#aIj;onMiZRyON1zW8|a|9{ZZ(kNAyB5|8^Ni-`)%XNB-@fUrWK-BOcve z93GY@O2omZt?vW1b}j!Ey@a>dx=r&y>x-L@3xFon+ClRY%||MHK&uWxD_6lgH^J?O z<_8}zqqd-Fx6Y%E2j8-IShE`Kg$L?y$eGeji?G<2KL>7xRYQSfN~ zZ%`%=5>oJJ{wGo<0#c&j(fospznztxfdO3ZID&EmsPB{k8WiY!{zCb||Nk$enZQ@s zfcIhV1La*vWP;<-v)ASbc;|ELCH|IEj0_Cl4)OE1ZsA~H@L_zG(#->&F!JfG67cE# z0hyX}5&$jw0WEh1?_}%-Ppi6EzTj_N$Hu^r;?r#cj#i&u-}jyeU$TI&XZ+3#n(gF0 z+64;KSD=|n{_QM&9@eafyFl~EfdWMdFE4{HDTm}2SSAAvulaOG34rEK4!-2^G&~Ke z<6eP=Tsq?gKzCmGc^mUw^XV*-@aXgsXgoDeE2uY zf$h-(RezxPJH`ZBp?C;1=mjzywA2jb|IX8%hKD^Y50>nEy#|zi9eZ8>fn%`Ow8zj+u&V7 zpu#G}quB6YEv0crr*F6#jGNpAB`bx~1w1#S3z3r}4jR|2Ugu|oxrvQH&X#1vT_ZAiK2(RTi{-!mI3=E##K^z{BX9KEUYM_=8`afq}pO324Z^+eM|q6EqKYjg5i95fq>dFDJvtp}|E7=#;GY zFBU!rb0fdNl%X6z^KF?RehQ4=e2USd*LG_gXoxL{!_)Fl z39Co52L}r%qk>MclK>|XNB-?Rbsn9kJgh9tMW8P>2v`^PymK=JrhHjj7R6G z{h&J2mP_TpQIY6@zKHc>k zj^B>6@V8z7g}>!_{>7n7#>8Q|o(X-P@V8P-O&KeWujyqN332!ocI%%W}k{Tfn2&;{#|{5SNE_76*Tu4=V!$ScL~;uL}cT z=XuZGkRu_m&n=qU4unu>8Q^ew%>-bU>NJ%S)g=obr%zwE2(# z;{pB_I~E3p)(<5ge7dV7d@O(Qx2iKUFo5R4LDJtZDxP!hgqZbuE4cph=(YX07_|QB z6v#Uc44|=J4WG`R&4(C$ItwH`4!-08mG>T<9s(YnAN)IQuBAD4iqySK0(;+q!K3*X zt1G|LM^GKA@bcXc*!mLCdbrMu9-ZGoi{f5R`U4m5wJlu4!SF%`Y9EsCKn(}bGNtC@ zjLrX9N}u|6*Qg|b){jA^fm*>J?Y z8XQ1F*81dy1A2t@2UL@Wg)7QqD(I}8!a z0f_~$@VmRHWPl`It_E+T0F6`h+Gc|MXLAw~o}Sh&DjEE((V+QvOCJ>j{^kG>vsXmJ zL-QqQsi_2LX;1-(r~nZeKAm0yKAm0?pacv`Jpvxboj}b$1`p^qERSAO`(|ziP(Jgt z{NmI3-+_PXF$ex_-#iXJV*+hO0nZ{8aDeXq1~ZE|JUZ`rc5=OlIP?Gi%hYcmhcS3` z7fN_E`)G17f*Xh)&7PpFTPWbsS;PU}%hu@zT9gc0+Tv|&^3tc%Q^KROP{6;_^okq>t98aD4%+C*GYI-mJ9H=`hc>)#h1Ll{{Qd%aqt0K^8p@29(#EXw7avrNZ|E3 z-|l=4NR%``{o!NzmcLyNJc;=ZyqJ(j+iLo*8Xt;Q2V9# z%m4qNO;@)-dlZhnIP>$*|Cg0tK*Qv=%u_fRUaUR_W~YDxeLk4Y`lErH!5iFJ0IlQQ z0PZBbUg^=xdweMe!>&o73z&ON4JLudfwoQNV0gg}IwibU^gsh>aqtVzULJi&a9LjQ z?DSDd;GcR3H2i|;aL`n&XY+9Z@J_e?FD{(?|NrIP&;S2}baQz01`8nSPSDCWXu}s; zcY>wXSch6hjjpl55LO~-%fZ0PrHm3!JuQZ&>|RA==yY`MKHc7omfwFl)k(M z8pP|h-8Y|u;lm%rD#a`3J6Tp!nG>L=ZMHM&_ZMi{8&q0*(gOt97 zD6N1feLj(c;e|g~Des5H91Oc2K%^rf(rZD|24HF1kMlSfUbKKsV!d03lr;ET?En4$ z4^AF0O(7191*weytL2>uGIl8>wJ<@9JqMD$c@&)4A^i);3TMzRK+onQjQmZ@zzyKP zux>}|fl^=CFhF7*H^U2=BamqBwG9Gs*M0!SGSU*kQoCkd^E%Mkfz3xaJU}scJk~Mh zrRhOXF$C^+fsF%=a|zaQGnB0J=(XhlnUuT_bWabcKhOH37Ca1Fw+FLN586Lf3mRd1 zJs*1V2(+1GcpwUN(gb2X2k1N_&`}`#9g(26MDro>9iZYG)Wh%m>)CnTv-$Z4(5`GB zezzZf&N2@O{j@i)*+U{CZjJKm#+Khd>VS zusrL*?|KMq2dI1iZ(;0q<7j@s?#X%Fr?Za3r}Nm0*_S}Gw?{ajqyEt48u0N2Xe>ak zx&|$6czp@ne(_|y3kjQ-FF|c%`1y{W%swg~Je$ukfxO_^>C4~?x1%=5Ga^0|fRa|3=Z-)!Ym(!Vdob@7Wuo!U!5E?6qwNi5&v1nd(GJ%8+{qn{_j) zp~=~&^O;X4I60^717{&ny8?Vb2Ll5`gNNnu@|JUTysQZDG)sWwpm(4+aE0Dl{3 z9?r+|by0{%=Z)q^>^_<=AY*g~K~dk!da4psj2{7KCm(*-A0C{yd^mr3bcS+xHv4ff z`t-Vj4p5UoU2X(Vzdn}b3H&W~pcBczxv+tj!fpaB^5`x7=+pW9#ktp@A^|kRTC&@t z*WrVwsOe(;h`PzwWe(b03Lf51uD zqtgxIu@{Wz|Nnm}3ywku1`oy?p!GZLPM|fgpw>O;Leuy&pt>BitFk*3v<<=sbb7%{ z&`cfN|DN3rKfqzmc-YhOE`K}tMrP2q$KDcIhL>HSxQ3+DUfaTM4u%(h_JRs>aC>qZ zi2nx8=VA8jbyWbL#{6){5>2*TG>RX%c}^CcYC? z9eILw3qleP=m;2j4}SMko}K5B4Fatz1IIl7M$vm^pppB>Kfs$Jm`apGcEP zk$3)YTc7A=4`0metkS_{BC(D<^(lcoMHpN4m z1!@&P)GF|yV4y_|kc#M~&38z8H2n5r<2}$M7I*{$F}{dYt}QI(X5eq}0w*lnDW%*D zFWztc|No^WD2>DGCs6rWQ3@?Toxy8v(Qiri=(P<48O8ci89e(8EkD~?9bo#f-{a`f zYbyuQw-Q+&IBr4hAx4m7i!8)_UrM+cUigFD#{&{TDg6x(yetCE+68DagT{ZfJ3#wC zc0s}cI;R$z;?b=EzMZrid`vpz#$3>l@oU%|CTJJMKG4!q&=uiNpMhcrRM7Fa%tX@x zn)L+j`S5K$P-2?m)5)R=nym2btpH8oH9!C130Z*XdAy+lG|B@?-kLugdpkg8AAHID z*<&^MvJXgm6MTOFc%tDzX`|t{{UAjz-0%JW4|U3MkIthn!r`td)d!tH-HM1$kIwgC zl`o8+qUuqG>3PfF0@@$&612c14QW0pl!3p62UItAzJKv;^Z)-ZLFWj8+MCc7-k_2c zrNQZe*nYwYudlmV=M{mrX4U0^=8zCsrZf#4kNg`&UxC&E_39cIgC}=AI$wj!Pnb%u zs@4Og;{2ek=(9ny@gA11OX24axO6`Fz`s$rWDhKD5@Q^8{qV?kY;ybl%`+eSL^u9(0f{JpF%|2hKNjCsCBb z)&*Uf2WoRfqn!uV&FTksFMl6sKQ%P<9%tP+4>VH?K4E~vqxED7x5x2D&_Wi_f)J16 ztX)uPk6zQ$h1?8=|3PaQKY-=|AZZaaF(Bn}yaA*Iv^o~NBi^GEy!r)H+Cn!#TYe}# z@6htUgx#Z4)OsH1)G|$|!HDy6ds%OO`v3np>;JjXY1U3wk3#Uoq$7B#1?wg7vSZfC zKmY&t=wwxa$c26d^Y{uu2bCdGFZ4VU_Cjt3(7}hnpqZ4`Kv2=v`k%i;1H|Zc7dN~O zYT%TYfU7D{UIP`HbspBT{RN<14lB{}ry@ujXc4yU{sL}>7gCQAS@{^asp9Zs1yiZq z3YHQn&t8WQ9=)Q|3%D5|ySqIs1^8P*W16s2Nx&za^+vq+IQW_cd^IL?{c=i!jp~d4 z|Nk?Tw!8rCbMdg0WdymVtq5|~2c%E{`KKiTl35`6oqxMXL>g#D%?p(EdW!{ox>-Iz z4pX@ZTAtE*u=y1uXf)H)n8Tx!=R;bjNQ6)40ob7ippqVZuAD1qH#71%DUcEobj}`R zoE+M|gXI&C?h+LVkZ#b`s-Si{blr(hw}Nl$6aE&^i9m=1&)*7K#|h4x;N=g{*4p`p zh@b?WcZRG1)TeN4)=^>f1Vu5XESW0-oVXg|=8s^b0 z;A8oSzhweg0dMDI4u)M@c)%T=qy})?rfdQS!wbu8;LZgk{9yGL*jfB7$>8SQ^B1P; z|Nnm(1`bkQN02%5Am&Ix%sJN2!SLea*8l$}yoiQ0O+Yczs`~%`f5_a#Rq)D`cOIR` zJv)!Qcn%(`0hRux+ThRuuf+qGJK%Ms?_L}Qt=t5yssO9s4p9$Q`WJMUCulPUWWAq9 zudQGoX#dYfO?A=;LaFwe1dvtKAn#s9m29)ZiW{d!Q%m-P~mTZ9F>ldk^Dezg~Tl=Be5|t zFhCCT0o_3g4nGg%{vm%m=$>wPr|=u-N)}Kn(4!gDDFmJUG6CKn1mz-rd4^bz&hMa! z`j>~nJGemS0mVATfHDGT8HNJ`_+aP%58&;2XbGC))2#tITDIj5T44cS73B!3{~;a* zwP26DLnL+3f-2;oVFC4ype+FYma6}ty+xp);BN&jLGtJobdLlX`hAIH?DNQiH%n1_9f^5I;7MOs=h&MqCk!{U-SR}O9xOf zGvP(`c96r5g44I||NsBJdTUe_48Ohjd==FE1ji>Rksp2W=q*SgC^}0aL8AxGOYcGJ zjGx^>Q@j@EM0(yhIMsni}ZC(Yl|4^rA| z+mQv1J|0l_8P z==}a-?PgRx44`rtbQiG%lH^b{Ai1gcOqXMsM_*>&Z zMI2~V=?i60jS3C`a7eiScnRw2g73df@#xk8w@E>5#j=!REZ~}o(W7@RsA=NUyA;&O zOz}7lsiQ#c0i^XakojN_V|I^D<`>}AaoyG)t^Z5J9KIcgoL|ETiZzz?(DrrnVGbY5 z$E7zxt!CtV=AreAN4G?Z2ec8=db=bMIUj*s1FmEEH;P^Xtwio_1~pJXNw)%Nd{rVy- zM}h7i0135#I$R#Twk}h-8D899@&EtJG*FQD@*eKxVA%B;Jf~+WQ3X!EcdJ3`-`AsT zpab=<9YaB*$X_5W8c_M%%_^G#O^tUzjg!`IrRt!5b?Y+_ula}s>hAX!;HfW2`40;E zyPzcN(_8+*)$jo51nuVMpazUQa>@m*X7=f2J(mtjx%{o)K>gm%Umo9Yd0JlMZ)al$ zEi?fg?(hfP>wd!D0lM=EG~x&8c6)S!j=2Mm|9bGdgNA86IuDl^dvu=j0gavTsJv*| z2&!FpR6JS_`1EE7@V9`@69i=i)SHDTAYz2S)dAd~IS#qG!>5x)<;A@>py3`CkSU&> zNBLVo?)2yem7S%VJ$gm?!OjOY5nMk&+hg4Vo|YF%rg`-8T6J?U>`H-@AI=rv2-x1q z!SF(A9rAc6Xzr=;5vXGV$D!*H-a>~SUw%jFFMD){sDN&<1-G>z zeR5EXi{V8wc*E@5mnXn|UC{QDm!M%Gq`Ykd>cjeg_e{C|c&P_bha8@Ku)!8b{*3~# zP(2O~*jDhs+);#TpKcZv{#MY~onx~G_!7KO&u-Trp!S#>xDFCslnP2Kn1RjT0=iYp zqnGz&CkMl>d`N&_Dgy_&8>nl&at*kWf`o@p=X06L7WDq5#S<-L5~tt;YAD z{sm$v(1YLQhDUFR@P`*wcmMncxe_#P{|&Sw!*Tcj|1Vd9SAaXVLv|U1j%Y>6zCNAD zVa+5^n+%qFK>@G4c*z1*2HM{( zqVlpGoPj~b8$&m1T{5I|(|Vvn3Y0oHJi2Y;K<%W?cd;*H!74%bT0XuE+F3ZEo7FFw zn*nsyPV0dREst(nV~|qteyHB^{~nB=i)8kJJAIn}JQVLmzmx$R;K1-=F-ZS;#PBz0 z?!oW?TK5v%9_;)9>Z*gLxIDf;^XxprKj8qV<=O!{^AWV^AJjwyjq7=Iv*v-q2E;$g z2d7M%+2809Sc6K$)^)E2l`?PXiB;h)Y>TFf#i7p zmJ4WYG03@L2l!j^Kx5+F0YAD~5B762d^^NcqTti{2xQM+Pz?>95`b=&h1J8L^G`q> z575MqNAoMtkh?g48)yK=qxqLVfBO;8Fbt#~g7u|f2gZ3c|57hog>;M@s0j*MFk)Ud z#q+oWXlReY^SA@#X4>Xo?)+`wCf{)f@DY5T#~r}O_JI#DOq<}*E9#j9%UBMGQq05h z6@Lq)dB_{k#=)@5k`LVat1Jd*EZpIQ_ywukfOg8bXE#zx8LoT0pP+1+#~@XT)^KV1uDuq-@mxJ;Q#-Zpu?OD55Std zL3oa5F@x+=NpIm`*p&;3=m~}3h(1`%!SEt|IjHmjyARf00JmE;x>*C_L4)Wu;C-zf z=Ah*yy{tdtxj`oiiGW&a9^iG9&}|)Hmx6aYg7OCF{0sh#g5dRRFI={ON+{m1pmqmr ziJ=_mqLUK`U$B67=7X2|dGu!f_vy{l_xOI(@Ec@}p=akApWcFm*K&}0)5WqzMW9aH zvH3WoXY(-u$HxC4XP1m?q&yl>+`yOw-ZIQYT0hjEsuh#;p<9Z-7;G*S*ed8Nq`Rpb8SD zw)N;d536m#J%P@%pc7FTJPy7^TDSP3*R=+0;Htm>|AY2#mNwtGk<=J3g|A2 z6cvNd{P{U54vzeSz6_51f}sMA{DQFxj{JhD29ErKxelPL9+3i@J1R}{Xg-pF)NBWj zC%SZgXlDj(9GQTY0`9|7KnZw!!3BK(sxW_xHz@UX-hZ)s_W%Fj>zN_t#S7`v|Nnyz zBYAO90CfK_XdACb^Bati^yqy40(6`OXu8c2e2RjL3WsB-3+S>f7Zm{ziv#3v2@s11 z#8LpU1VAhe5K9EaG61n8Kr9OoO9sSp0I?K6EDsP%1;j$~J{QFM4;*6-zmO9^*$jlS zAI7KKRyc|q`CMNYl?+fSSQ*L9;M)18^#FgzD{z^^S{(_R+12%l;$|>>>jOG-%ct{o zw?|3msZJjip5{|bodG4UStc|eWlZCLf54Gnkj;@_&;hFn z;NsY$*VZ0ng|`^kNi`AN3@)9Iz*c|F;b3?ntP47V)HVey{tGPr4J7_s=imQs(XA2S zb^LBHM{$CTdY}W+BDxYHrv;N^1IZl$%dv_^a5HrKsPJ@plz^f&1Cgo=JerSGKpI8R zO+4WG$nXF-S@ZXS+EBQXHmF?&&7Xz`K+{e9E#06Zwe$XqJ2U?Ohi=LRoA<){#Q*;< zL35BV9`Z6XOaR{_pL`EgrgXDT4hNMD70$@v3A%p^9Gm$TO0;AVKScnzqE z;AsBAS?=x8D=GsT1x#jX@?g9G=`UVB{{R2$Z4*Gp&o%xAU64|4;?e8Ou}c87H@@=) zcwVCUH@gSF+aZrm*10X*46lVj=@&G4!GM@yL3Rpc7w5`wP(j>$gu|utKy)muyzP{g z3+HBl9DH}2RScwtfq~)m0fD)c3~Jy;5h5vFvzUY%M@^v7PPKjwh~ExE=(TO^8>YOA^rzlsKeiG07{3Q zvXMyYb7AU5pyt7Pg!~&t4~Bu}w|hVl*=xHcjGN&F|MdU=Usj{^*FhsiGs3|0bo_ld zcX5`1jADHW+Qo^oea->gQv*`BxDWZY^#EwM$2*T+ zTkb5-e&+^O29M77u`kmW|NsAD;nDy9Uq1vJfY1+0m@mvfGBNC80C$~!{P*B@IRxq) zKqma*e6de8p(@6mbi^$BP{1v+>FTIS&O z3e@N~25o+Kz6hOV@ z5>}7aZ>5k_>0_D9QLF_z!L>JAz{B!=3G0ieFF}?(f6@CG;b!)?QtC9UZ`I{6LO9*hmj;+FH4)y zE!xz?&Ct#3(G2RyDwL>yJIYj|)OxAH%%hjpKaYu_;TcD%x<@Z-@J&XBZ$~*wq#^Za z^FtPoURJ)VjG(Jy*tMA$z>TA{37ywGdRfh9Gcka#A$Dl|$H2(oP`df`6KMI>Eh+@I z??w~EKGttXnM$>qA98r~vTjggU?`RR#(JfZn}Nxrmo)*rj!4u~lL2BnD8IE{s*v&M zW&N5DaoKB+Ue-=)29V22cY)%!^8)C?Uk6*TwIH`d&u3!zeh{?(z4Z9&JrlY`CpCin z8-dM!NhYxUAyE4jUVwdf^CcsO{jHS<`!k<_Lk42MM=$HmB}@$84>2$>IFwv{eF`mo zd}ICIz|A1w(JQ*hlZnBjm-V*?EbPGP$1wynEDO#R6Hov7@6(&W2ug&dpsVRy50r?4 zat34;$OE#p@$#uZ|Dzyl3qj%Ias0prNdMU2rGfwh12{2;dURe5?)?2CzJ!$llslxN zJvxuY?qUVyxL(`46F3|KmKyBt; z(WY|n*>`d3|NcW4nu4-4XuL|)2(+rbm(}?;Bg3~t3MB^Jyl)z~89>QOwe?a3C@FE& zKmt#+;VCHEC2xa+`O-a5FuNRr0xcMpJz8_;A6gC}^uFj&r0^SVbbi=l_*;W9&y-Wpy8{%tnm4i+`63`IBj zTYiI@mz|%$DnW#IQ1y-{5aq1-9rrSSi>du(?nj<>$bcBJ^f4dRqQ1XY=j6?%Da* zqt`{n!K1fF#eoB~%NX1~^5~TCXg9*~juznFDB$OaXM)Eod#Pgb!%n z7HI1>2k6kK7pso_`R~y!0y$;MlkpgM;}+;VG6^5cPyFqmZ5NK9uIPV{ZkHntpaTFV zds?3L=se-sDo7>V1qXxWi(+^FZ6-{P7A7nuZ#|e}R198bf*Ujp zK9)cETR>|kK_`&D1f9qa(dTJ-ioazAD9V}-GQLy+wQ0cd4RX2#=)lnbppA!}A3PZE zd1#*VVf^Q5dA5k}wX8>Pz<*E6qa~3ZoflmAx5XGRdh`Y`x>&@pGnPCC-R1zgQnkGp zG;`CPqoU!%c>3j2@VOZt-CMv(JjFxX1iA(>3}k)d5l~J5RiTjCj>A5kuU>ES=)B?6 z>;2!S^Ccvnd@Nsh@;e=MHT)0uFla9tENVMXgW^d59H~Bb z4q?0o;Z*$j{~wZxT@By9-0|oCfA3xvyO*Hzu{?WO-y0{=D_ z6~>kW{4Ko@UWf`4=#0RPAYMa_3Nr(L%Y9I+cRqhnaRfB^^&WhlfeYyJj$HKW?){%c(2+u!IhU57U+R^Tzd4Yf10sd_vECMbaB`g9S zy^h~OcNBPNUIv@%Yx%c4hhLt-m+`A3|F+Qoj{MtP8IU!)uz=2DEM@hz{9AU*Q}d{& z<+1Wpp3VRG%D6qdS#&%tU33{rm3%s39{+p@g_``5x*SL^1Jl@sI!iU(EZ* z#DLPFV)(`?Tfxo1;n6F~1R9_0Wu0vWYQMQ0LbQKC%glROA6J47Yk;(W%2C@t8lfod zk)4&`YX4Im0|ThM+JtUXzjAJd@5eydr{r|&$qG4-URL*TCQ#d@^nT+rP{Q!& zWle2kU?^R47&L#xy0Z?_0%33{xqP@=ln>(H&rVDX-;PZvE$rqsDC34Txih{UV=A$3 zJ;~p(7QH~P1hNny(y`o2=z^&iEAc`N{=!5hpL06l%Oh@d;{>FN&l$(L6#QobL zg;J;HN1%4nkCR|uBr1R!aIT;RqXWaYV+y5{J$hMtycroDB`ty`n;KU^AmZ6xd8~c>rocW`oi_ zNXdIYu#yfC#Siv4!?&XfrK>%9S*O@BF|=N)d;^Mp28WU-kQQZKAV`C#Ifw$AIRPr) z0k%@V4J6H)0irZA5(6c%sC&JJ=R;aGwe}zU{%{^$xh=y8$ep528S> zLwFb(-_Bt9eh`H!-!1A?4C+sElt6j~$o<&~f{^|s3&=;H{_QPr$HVe7Qo4oqXG_x| zMFOZl%P9d$IUMl*zr~&JAo!I*0F3&|jffjrBvR*z4@6WC& zM71v>8O6SpN5S#==p-mUQSIv?XdiTb7d)fn(fJj$3s(ZV5HZE2+xUe}3M=?N)7Aqe zE}+iOn^(*XKAq2?!vwYq8#oy}I*-0+UH|t#cwg+17pGn^Go-k58iSUdK*t84EpO2H zM2b(hjVfr2*t2_o11AH+i`UowgLJ-_{EC?YYO1MdI(YEG1#CEIW1QOhzyHBaXphdL zprtrzub3GO54d!`^Z=dg4mQZ6*Ys@~2g3_*iGTk=ZDBFr?&Tm0z{idulDOybc91A& zuo1i-yYnOHKD~$b9?cKzn|~UV+c*C(D7Q-E7vfLj7ZOY37xU*x;};9#08NUd@s}J- z<1aat#{c6)8vpf+jjzBr%(R{W&3-l?69Av%)BNm%NAvR!yFgN|h6kD-@;5)=w>(&) zR?hC&d10bQ`*)vS4}MS0lRmwo?r9th{>eOD{=Fhxj{hHl!Y7SCpAX3{ez09G{MS!j ze&u-irHke%{#HAXb;l2a0}(=jG(gAK()jav_|o|EMfh>K_7`YWt@)q;VU-u4DqpWc zgdfPNH2!>Xh&w^yQTz*J)x|Xa9~aVG_^+QrICQEIXbLi49;C+u;!;O&AH%0NoYAxK z(SLph2G7P z^#RDfB-WH0pqnuvA#~>@=)P{GCSV$W$>B8q>leNs`uCrKp;Q3mH>e+8g0@UR?JK?k za_nu!mo^HKkqKfVKap4QUd!Q?~p+3h|{t-5129hbb!|wq8@B>+Mo9(3yH{tN(#1Vd?Aie0} z#|~P0-y63zx=~VIQ%$pgx^(= zUi9$efP^0h8R5qP3O^2f;TH!wsg*$Z5jI5v$rRk-$ACZlK-S#mc)5pzaQLy~2*0Ty zz3AZwItkgQH=L7<@Z$u9A3MJAlLMVNNg(_Pn{tDlfx!c63ZC%$hqwI)vgS7D%NlmV z;m3v}{6ax`(Zi1mlK!~J2tO`R__5&&zkA@*lfiuhob6}Arp!Px1yA_>!5e-cYi@JB zv|%G0eyljcPZXpVJ^VnsD13UuxycAWZczBK;tRidpi@<$DF;{mLD-ZCBvbH&-w(Xu z2eRfi_sc&lgu{;oNBCU@=|vAe(9$5E-f$i=!jA_Oek}OHFAj8UErIYOY>EVuDR{!~ z1K#ihS#z7`(b~5q`X&@MFdoexP#}VI>!?^hel~8=z(V z&{)6|eh=`5AIO^9yf14&CwL=<53u%snQ(+(C`d1Q`0+u)kB^M-;{$~s6Ta}f2bvIs z`W#pI5jF)hp9zZvJmGf$Z}@?%xy|>|2DFTuK=?7@2tUx~^)&SG>-x-}&;OY}A5^&?Oyj?GFpdBHNyxa> zb?`PbQ4jt-7eLnVZxa#Iya1g){LG(U4q7`O2O{zn()dg6edf;(Q%K{#buW#-HlKjd-nkw6;%ts@}2JPtlk@Zh|V#((_; zXt~9~M+P387fRbadcz%df`{E)`QM-PXnu6S1HAS|+=KCxN9VQ1XCSY5XnyoK_>#?| z^W1A8L<00^KH%Wde8|D0^_xd;*?<0)-3$y2pZW8dKJ({$fyNX;I6@$ezXY@yAPeMy z(`o#-K%63wQ%|Sy=Ldj%b1;oRKLX^FS84nupVRnny-MT11)`6p@!vX@#$R$AUd;i?j(ACrV{Jnh!C0H2-qoZvh{0wT(p_ zl!99hls+;%pn2jjBJ%j<8K^Pd{Q^8bO2&BibboTjyW>FCL57b#Arxp3mFV$qDUfzZ znFJqC28~-|j^lrTj$4vD-n|vucq3>tEP?Uv`YPzCF?iG-G)is7e;HJ$W1VgAg1Qnu z#%)82ZXP7vp!M(g#34{->@n%zyUi9!GV!Rn^_<%aqSi|QO(. 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�DK7o(W3$ZwSZv%9=`Vv``8s$|8l|os{r>w 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 Q{;v~mUJGI|T7ymDZ`lq~d5p2s04AUg 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%0AGT2PDnEWC!gJ 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�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

ZWk2^RfZ1?47Lmo3=E}aKAjH@FM*e# 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%0D3PNLk?8@ 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 +#include +#include +#include +#include + +#include "kvm_util.h" +#include "processor.h" + +#define X86_FEATURE_MWAIT (1u << 3) + +enum monitor_mwait_testcases { + MWAIT_QUIRK_DISABLED = BIT(0), + MISC_ENABLES_QUIRK_DISABLED = BIT(1), + MWAIT_DISABLED = BIT(2), +}; + +static void guest_monitor_wait(int testcase) +{ + /* + * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD, + * in all other scenarios KVM should emulate them as nops. + */ + bool fault_wanted = (testcase & MWAIT_QUIRK_DISABLED) && + (testcase & MWAIT_DISABLED); + u8 vector; + + GUEST_SYNC(testcase); + + vector = kvm_asm_safe("monitor"); + if (fault_wanted) + GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector); + else + GUEST_ASSERT_2(!vector, testcase, vector); + + vector = kvm_asm_safe("monitor"); + if (fault_wanted) + GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector); + else + GUEST_ASSERT_2(!vector, testcase, vector); +} + +static void guest_code(void) +{ + guest_monitor_wait(MWAIT_DISABLED); + + guest_monitor_wait(MWAIT_QUIRK_DISABLED | MWAIT_DISABLED); + + guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_DISABLED); + guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED); + + guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED | MWAIT_DISABLED); + guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED); + + GUEST_DONE(); +} + +int main(int argc, char *argv[]) +{ + uint64_t disabled_quirks; + struct kvm_cpuid2 *cpuid; + struct kvm_cpuid_entry2 *entry; + struct kvm_vcpu *vcpu; + struct kvm_run *run; + struct kvm_vm *vm; + struct ucall uc; + int testcase; + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2)); + + cpuid = kvm_get_supported_cpuid(); + + entry = kvm_get_supported_cpuid_index(1, 0); + entry->ecx &= ~X86_FEATURE_MWAIT; + set_cpuid(cpuid, entry); + + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + vcpu_set_cpuid(vcpu, cpuid); + + run = vcpu->run; + + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(vcpu); + + while (1) { + vcpu_run(vcpu); + + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + testcase = uc.args[1]; + break; + case UCALL_ABORT: + TEST_FAIL("%s at %s:%ld, testcase = %lx, vector = %ld", + (const char *)uc.args[0], __FILE__, + uc.args[1], uc.args[2], uc.args[3]); + goto done; + case UCALL_DONE: + goto done; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + goto done; + } + + disabled_quirks = 0; + if (testcase & MWAIT_QUIRK_DISABLED) + disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_FAULTS; + if (testcase & MISC_ENABLES_QUIRK_DISABLED) + disabled_quirks |= KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT; + vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, disabled_quirks); + + /* + * If the MISC_ENABLES quirk (KVM neglects to update CPUID to + * enable/disable MWAIT) is disabled, toggle the ENABLE_MWAIT + * bit in MISC_ENABLES accordingly. If the quirk is enabled, + * the only valid configuration is MWAIT disabled, as CPUID + * can't be manually changed after running the vCPU. + */ + if (!(testcase & MISC_ENABLES_QUIRK_DISABLED)) { + TEST_ASSERT(testcase & MWAIT_DISABLED, + "Can't toggle CPUID features after running vCPU"); + continue; + } + + vcpu_set_msr(vcpu, MSR_IA32_MISC_ENABLE, + (testcase & MWAIT_DISABLED) ? 0 : MSR_IA32_MISC_ENABLE_MWAIT); + } + +done: + kvm_vm_free(vm); + return 0; +} From 3de7203115af2f3a76ffdb0c90a89ad99f4c4e04 Mon Sep 17 00:00:00 2001 From: Jiang Jian Date: Wed, 22 Jun 2022 14:14:42 +0800 Subject: [PATCH 0623/1436] platform/chrome: wilco_ec: event: Fix typo in comment Drop the redundant word 'the'. Signed-off-by: Jiang Jian Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220622061442.18242-1-jiangjian@cdjrlc.com --- drivers/platform/chrome/wilco_ec/event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/chrome/wilco_ec/event.c b/drivers/platform/chrome/wilco_ec/event.c index 814518509739..32e400590be5 100644 --- a/drivers/platform/chrome/wilco_ec/event.c +++ b/drivers/platform/chrome/wilco_ec/event.c @@ -343,7 +343,7 @@ static __poll_t event_poll(struct file *filp, poll_table *wait) * * Removes the first event from the queue, places it in the passed buffer. * - * If there are no events in the the queue, then one of two things happens, + * If there are no events in the queue, then one of two things happens, * depending on if the file was opened in nonblocking mode: If in nonblocking * mode, then return -EAGAIN to say there's no data. If in blocking mode, then * block until an event is available. From fcd48a213f0ac45c2187b09e19d4849e14cb59f8 Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Mon, 13 Jun 2022 21:25:14 +0000 Subject: [PATCH 0624/1436] KVM: selftests: Remove dynamic memory allocation for stats header There's no need to allocate dynamic memory for the stats header since its size is known at compile time. Reviewed-by: David Matlack Reviewed-by: Peter Xu Signed-off-by: Ben Gardon Message-Id: <20220613212523.3436117-2-bgardon@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/kvm_binary_stats_test.c | 58 +++++++++---------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 3c2d06b61442..ac5c3d0181e3 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -26,56 +26,53 @@ static void stats_test(int stats_fd) int i; size_t size_desc; size_t size_data = 0; - struct kvm_stats_header *header; + struct kvm_stats_header header; char *id; struct kvm_stats_desc *stats_desc; u64 *stats_data; struct kvm_stats_desc *pdesc; /* Read kvm stats header */ - header = malloc(sizeof(*header)); - TEST_ASSERT(header, "Allocate memory for stats header"); - - ret = read(stats_fd, header, sizeof(*header)); - TEST_ASSERT(ret == sizeof(*header), "Read stats header"); - size_desc = sizeof(*stats_desc) + header->name_size; + ret = read(stats_fd, &header, sizeof(header)); + TEST_ASSERT(ret == sizeof(header), "Read stats header"); + size_desc = sizeof(*stats_desc) + header.name_size; /* Read kvm stats id string */ - id = malloc(header->name_size); + id = malloc(header.name_size); TEST_ASSERT(id, "Allocate memory for id string"); - ret = read(stats_fd, id, header->name_size); - TEST_ASSERT(ret == header->name_size, "Read id string"); + ret = read(stats_fd, id, header.name_size); + TEST_ASSERT(ret == header.name_size, "Read id string"); /* Check id string, that should start with "kvm" */ - TEST_ASSERT(!strncmp(id, "kvm", 3) && strlen(id) < header->name_size, + TEST_ASSERT(!strncmp(id, "kvm", 3) && strlen(id) < header.name_size, "Invalid KVM stats type, id: %s", id); /* Sanity check for other fields in header */ - if (header->num_desc == 0) { + if (header.num_desc == 0) { printf("No KVM stats defined!"); return; } /* Check overlap */ - TEST_ASSERT(header->desc_offset > 0 && header->data_offset > 0 - && header->desc_offset >= sizeof(*header) - && header->data_offset >= sizeof(*header), + TEST_ASSERT(header.desc_offset > 0 && header.data_offset > 0 + && header.desc_offset >= sizeof(header) + && header.data_offset >= sizeof(header), "Invalid offset fields in header"); - TEST_ASSERT(header->desc_offset > header->data_offset || - (header->desc_offset + size_desc * header->num_desc <= - header->data_offset), + TEST_ASSERT(header.desc_offset > header.data_offset || + (header.desc_offset + size_desc * header.num_desc <= + header.data_offset), "Descriptor block is overlapped with data block"); /* Allocate memory for stats descriptors */ - stats_desc = calloc(header->num_desc, size_desc); + stats_desc = calloc(header.num_desc, size_desc); TEST_ASSERT(stats_desc, "Allocate memory for stats descriptors"); /* Read kvm stats descriptors */ ret = pread(stats_fd, stats_desc, - size_desc * header->num_desc, header->desc_offset); - TEST_ASSERT(ret == size_desc * header->num_desc, + size_desc * header.num_desc, header.desc_offset); + TEST_ASSERT(ret == size_desc * header.num_desc, "Read KVM stats descriptors"); /* Sanity check for fields in descriptors */ - for (i = 0; i < header->num_desc; ++i) { + for (i = 0; i < header.num_desc; ++i) { pdesc = (void *)stats_desc + i * size_desc; /* Check type,unit,base boundaries */ TEST_ASSERT((pdesc->flags & KVM_STATS_TYPE_MASK) @@ -104,7 +101,7 @@ static void stats_test(int stats_fd) break; } /* Check name string */ - TEST_ASSERT(strlen(pdesc->name) < header->name_size, + TEST_ASSERT(strlen(pdesc->name) < header.name_size, "KVM stats name(%s) too long", pdesc->name); /* Check size field, which should not be zero */ TEST_ASSERT(pdesc->size, "KVM descriptor(%s) with size of 0", @@ -124,14 +121,14 @@ static void stats_test(int stats_fd) size_data += pdesc->size * sizeof(*stats_data); } /* Check overlap */ - TEST_ASSERT(header->data_offset >= header->desc_offset - || header->data_offset + size_data <= header->desc_offset, + TEST_ASSERT(header.data_offset >= header.desc_offset + || header.data_offset + size_data <= header.desc_offset, "Data block is overlapped with Descriptor block"); /* Check validity of all stats data size */ - TEST_ASSERT(size_data >= header->num_desc * sizeof(*stats_data), + TEST_ASSERT(size_data >= header.num_desc * sizeof(*stats_data), "Data size is not correct"); /* Check stats offset */ - for (i = 0; i < header->num_desc; ++i) { + for (i = 0; i < header.num_desc; ++i) { pdesc = (void *)stats_desc + i * size_desc; TEST_ASSERT(pdesc->offset < size_data, "Invalid offset (%u) for stats: %s", @@ -142,15 +139,15 @@ static void stats_test(int stats_fd) stats_data = malloc(size_data); TEST_ASSERT(stats_data, "Allocate memory for stats data"); /* Read kvm stats data as a bulk */ - ret = pread(stats_fd, stats_data, size_data, header->data_offset); + ret = pread(stats_fd, stats_data, size_data, header.data_offset); TEST_ASSERT(ret == size_data, "Read KVM stats data"); /* Read kvm stats data one by one */ size_data = 0; - for (i = 0; i < header->num_desc; ++i) { + for (i = 0; i < header.num_desc; ++i) { pdesc = (void *)stats_desc + i * size_desc; ret = pread(stats_fd, stats_data, pdesc->size * sizeof(*stats_data), - header->data_offset + size_data); + header.data_offset + size_data); TEST_ASSERT(ret == pdesc->size * sizeof(*stats_data), "Read data of KVM stats: %s", pdesc->name); size_data += pdesc->size * sizeof(*stats_data); @@ -159,7 +156,6 @@ static void stats_test(int stats_fd) free(stats_data); free(stats_desc); free(id); - free(header); } From 32faa0647cea46ffda9095c3a8c95b315e139f0f Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Mon, 13 Jun 2022 21:25:15 +0000 Subject: [PATCH 0625/1436] KVM: selftests: Read binary stats header in lib Move the code to read the binary stats header to the KVM selftests library. It will be re-used by other tests to check KVM behavior. No functional change intended. Reviewed-by: David Matlack Reviewed-by: Peter Xu Signed-off-by: Ben Gardon Message-Id: <20220613212523.3436117-3-bgardon@google.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/include/kvm_util_base.h | 8 ++++++++ tools/testing/selftests/kvm/kvm_binary_stats_test.c | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 7ebfc8c7de17..669fe4b400c2 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -308,6 +308,14 @@ static inline int vm_get_stats_fd(struct kvm_vm *vm) return fd; } +static inline void read_stats_header(int stats_fd, struct kvm_stats_header *header) +{ + ssize_t ret; + + ret = read(stats_fd, header, sizeof(*header)); + TEST_ASSERT(ret == sizeof(*header), "Read stats header"); +} + void vm_create_irqchip(struct kvm_vm *vm); void vm_set_user_memory_region(struct kvm_vm *vm, uint32_t slot, uint32_t flags, diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index ac5c3d0181e3..2a90b6276fcd 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -33,8 +33,8 @@ static void stats_test(int stats_fd) struct kvm_stats_desc *pdesc; /* Read kvm stats header */ - ret = read(stats_fd, &header, sizeof(header)); - TEST_ASSERT(ret == sizeof(header), "Read stats header"); + read_stats_header(stats_fd, &header); + size_desc = sizeof(*stats_desc) + header.name_size; /* Read kvm stats id string */ From 4d0a059415708ec0f221616f187853176d2fbebc Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Mon, 13 Jun 2022 21:25:16 +0000 Subject: [PATCH 0626/1436] KVM: selftests: Read binary stats desc in lib Move the code to read the binary stats descriptors to the KVM selftests library. It will be re-used by other tests to check KVM behavior. No functional change intended. Reviewed-by: David Matlack Reviewed-by: Peter Xu Signed-off-by: Ben Gardon Message-Id: <20220613212523.3436117-4-bgardon@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 25 ++++++++++++++ .../selftests/kvm/kvm_binary_stats_test.c | 16 +++------ tools/testing/selftests/kvm/lib/kvm_util.c | 33 +++++++++++++++++++ 3 files changed, 63 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 669fe4b400c2..8bce6df5fd40 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -316,6 +316,31 @@ static inline void read_stats_header(int stats_fd, struct kvm_stats_header *head TEST_ASSERT(ret == sizeof(*header), "Read stats header"); } +struct kvm_stats_desc *read_stats_descriptors(int stats_fd, + struct kvm_stats_header *header); + +static inline ssize_t get_stats_descriptor_size(struct kvm_stats_header *header) +{ + /* + * The base size of the descriptor is defined by KVM's ABI, but the + * size of the name field is variable, as far as KVM's ABI is + * concerned. For a given instance of KVM, the name field is the same + * size for all stats and is provided in the overall stats header. + */ + return sizeof(struct kvm_stats_desc) + header->name_size; +} + +static inline struct kvm_stats_desc *get_stats_descriptor(struct kvm_stats_desc *stats, + int index, + struct kvm_stats_header *header) +{ + /* + * Note, size_desc includes the size of the name field, which is + * variable. i.e. this is NOT equivalent to &stats_desc[i]. + */ + return (void *)stats + index * get_stats_descriptor_size(header); +} + void vm_create_irqchip(struct kvm_vm *vm); void vm_set_user_memory_region(struct kvm_vm *vm, uint32_t slot, uint32_t flags, diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 2a90b6276fcd..66cf6cdc638b 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -35,7 +35,7 @@ static void stats_test(int stats_fd) /* Read kvm stats header */ read_stats_header(stats_fd, &header); - size_desc = sizeof(*stats_desc) + header.name_size; + size_desc = get_stats_descriptor_size(&header); /* Read kvm stats id string */ id = malloc(header.name_size); @@ -62,18 +62,12 @@ static void stats_test(int stats_fd) header.data_offset), "Descriptor block is overlapped with data block"); - /* Allocate memory for stats descriptors */ - stats_desc = calloc(header.num_desc, size_desc); - TEST_ASSERT(stats_desc, "Allocate memory for stats descriptors"); /* Read kvm stats descriptors */ - ret = pread(stats_fd, stats_desc, - size_desc * header.num_desc, header.desc_offset); - TEST_ASSERT(ret == size_desc * header.num_desc, - "Read KVM stats descriptors"); + stats_desc = read_stats_descriptors(stats_fd, &header); /* Sanity check for fields in descriptors */ for (i = 0; i < header.num_desc; ++i) { - pdesc = (void *)stats_desc + i * size_desc; + pdesc = get_stats_descriptor(stats_desc, i, &header); /* Check type,unit,base boundaries */ TEST_ASSERT((pdesc->flags & KVM_STATS_TYPE_MASK) <= KVM_STATS_TYPE_MAX, "Unknown KVM stats type"); @@ -129,7 +123,7 @@ static void stats_test(int stats_fd) "Data size is not correct"); /* Check stats offset */ for (i = 0; i < header.num_desc; ++i) { - pdesc = (void *)stats_desc + i * size_desc; + pdesc = get_stats_descriptor(stats_desc, i, &header); TEST_ASSERT(pdesc->offset < size_data, "Invalid offset (%u) for stats: %s", pdesc->offset, pdesc->name); @@ -144,7 +138,7 @@ static void stats_test(int stats_fd) /* Read kvm stats data one by one */ size_data = 0; for (i = 0; i < header.num_desc; ++i) { - pdesc = (void *)stats_desc + i * size_desc; + pdesc = get_stats_descriptor(stats_desc, i, &header); ret = pread(stats_fd, stats_data, pdesc->size * sizeof(*stats_data), header.data_offset + size_data); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index f8c104dba258..64ef108cc270 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1850,3 +1850,36 @@ unsigned int vm_calc_num_guest_pages(enum vm_guest_mode mode, size_t size) n = DIV_ROUND_UP(size, vm_guest_mode_params[mode].page_size); return vm_adjust_num_guest_pages(mode, n); } + +/* + * Read binary stats descriptors + * + * Input Args: + * stats_fd - the file descriptor for the binary stats file from which to read + * header - the binary stats metadata header corresponding to the given FD + * + * Output Args: None + * + * Return: + * A pointer to a newly allocated series of stat descriptors. + * Caller is responsible for freeing the returned kvm_stats_desc. + * + * Read the stats descriptors from the binary stats interface. + */ +struct kvm_stats_desc *read_stats_descriptors(int stats_fd, + struct kvm_stats_header *header) +{ + struct kvm_stats_desc *stats_desc; + ssize_t desc_size, total_size, ret; + + desc_size = get_stats_descriptor_size(header); + total_size = header->num_desc * desc_size; + + stats_desc = calloc(header->num_desc, desc_size); + TEST_ASSERT(stats_desc, "Allocate memory for stats descriptors"); + + ret = pread(stats_fd, stats_desc, total_size, header->desc_offset); + TEST_ASSERT(ret == total_size, "Read KVM stats descriptors"); + + return stats_desc; +} From 143e7eea3d66737c73cc3aa3538123ea3bb1f640 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 13 Jun 2022 21:25:17 +0000 Subject: [PATCH 0627/1436] KVM: selftests: Clean up coding style in binary stats test Fix a variety of code style violations and/or inconsistencies in the binary stats test. The 80 char limit is a soft limit and can and should be ignored/violated if doing so improves the overall code readability. Specifically, provide consistent indentation and don't split expressions at arbitrary points just to honor the 80 char limit. Opportunistically expand/add comments to call out the more subtle aspects of the code. Signed-off-by: Sean Christopherson Reviewed-by: David Matlack Signed-off-by: Ben Gardon Message-Id: <20220613212523.3436117-5-bgardon@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/kvm_binary_stats_test.c | 79 +++++++++++-------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 66cf6cdc638b..a904873b2b86 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -40,27 +40,31 @@ static void stats_test(int stats_fd) /* Read kvm stats id string */ id = malloc(header.name_size); TEST_ASSERT(id, "Allocate memory for id string"); + ret = read(stats_fd, id, header.name_size); TEST_ASSERT(ret == header.name_size, "Read id string"); /* Check id string, that should start with "kvm" */ TEST_ASSERT(!strncmp(id, "kvm", 3) && strlen(id) < header.name_size, - "Invalid KVM stats type, id: %s", id); + "Invalid KVM stats type, id: %s", id); /* Sanity check for other fields in header */ if (header.num_desc == 0) { printf("No KVM stats defined!"); return; } - /* Check overlap */ - TEST_ASSERT(header.desc_offset > 0 && header.data_offset > 0 - && header.desc_offset >= sizeof(header) - && header.data_offset >= sizeof(header), - "Invalid offset fields in header"); + /* + * The descriptor and data offsets must be valid, they must not overlap + * the header, and the descriptor and data blocks must not overlap each + * other. Note, the data block is rechecked after its size is known. + */ + TEST_ASSERT(header.desc_offset && header.desc_offset >= sizeof(header) && + header.data_offset && header.data_offset >= sizeof(header), + "Invalid offset fields in header"); + TEST_ASSERT(header.desc_offset > header.data_offset || - (header.desc_offset + size_desc * header.num_desc <= - header.data_offset), - "Descriptor block is overlapped with data block"); + (header.desc_offset + size_desc * header.num_desc <= header.data_offset), + "Descriptor block is overlapped with data block"); /* Read kvm stats descriptors */ stats_desc = read_stats_descriptors(stats_fd, &header); @@ -68,14 +72,17 @@ static void stats_test(int stats_fd) /* Sanity check for fields in descriptors */ for (i = 0; i < header.num_desc; ++i) { pdesc = get_stats_descriptor(stats_desc, i, &header); + /* Check type,unit,base boundaries */ - TEST_ASSERT((pdesc->flags & KVM_STATS_TYPE_MASK) - <= KVM_STATS_TYPE_MAX, "Unknown KVM stats type"); - TEST_ASSERT((pdesc->flags & KVM_STATS_UNIT_MASK) - <= KVM_STATS_UNIT_MAX, "Unknown KVM stats unit"); - TEST_ASSERT((pdesc->flags & KVM_STATS_BASE_MASK) - <= KVM_STATS_BASE_MAX, "Unknown KVM stats base"); - /* Check exponent for stats unit + TEST_ASSERT((pdesc->flags & KVM_STATS_TYPE_MASK) <= KVM_STATS_TYPE_MAX, + "Unknown KVM stats type"); + TEST_ASSERT((pdesc->flags & KVM_STATS_UNIT_MASK) <= KVM_STATS_UNIT_MAX, + "Unknown KVM stats unit"); + TEST_ASSERT((pdesc->flags & KVM_STATS_BASE_MASK) <= KVM_STATS_BASE_MAX, + "Unknown KVM stats base"); + + /* + * Check exponent for stats unit * Exponent for counter should be greater than or equal to 0 * Exponent for unit bytes should be greater than or equal to 0 * Exponent for unit seconds should be less than or equal to 0 @@ -86,47 +93,51 @@ static void stats_test(int stats_fd) case KVM_STATS_UNIT_NONE: case KVM_STATS_UNIT_BYTES: case KVM_STATS_UNIT_CYCLES: - TEST_ASSERT(pdesc->exponent >= 0, - "Unsupported KVM stats unit"); + TEST_ASSERT(pdesc->exponent >= 0, "Unsupported KVM stats unit"); break; case KVM_STATS_UNIT_SECONDS: - TEST_ASSERT(pdesc->exponent <= 0, - "Unsupported KVM stats unit"); + TEST_ASSERT(pdesc->exponent <= 0, "Unsupported KVM stats unit"); break; } /* Check name string */ TEST_ASSERT(strlen(pdesc->name) < header.name_size, - "KVM stats name(%s) too long", pdesc->name); + "KVM stats name(%s) too long", pdesc->name); /* Check size field, which should not be zero */ - TEST_ASSERT(pdesc->size, "KVM descriptor(%s) with size of 0", - pdesc->name); + TEST_ASSERT(pdesc->size, + "KVM descriptor(%s) with size of 0", pdesc->name); /* Check bucket_size field */ switch (pdesc->flags & KVM_STATS_TYPE_MASK) { case KVM_STATS_TYPE_LINEAR_HIST: TEST_ASSERT(pdesc->bucket_size, - "Bucket size of Linear Histogram stats (%s) is zero", - pdesc->name); + "Bucket size of Linear Histogram stats (%s) is zero", + pdesc->name); break; default: TEST_ASSERT(!pdesc->bucket_size, - "Bucket size of stats (%s) is not zero", - pdesc->name); + "Bucket size of stats (%s) is not zero", + pdesc->name); } size_data += pdesc->size * sizeof(*stats_data); } - /* Check overlap */ - TEST_ASSERT(header.data_offset >= header.desc_offset - || header.data_offset + size_data <= header.desc_offset, - "Data block is overlapped with Descriptor block"); + + /* + * Now that the size of the data block is known, verify the data block + * doesn't overlap the descriptor block. + */ + TEST_ASSERT(header.data_offset >= header.desc_offset || + header.data_offset + size_data <= header.desc_offset, + "Data block is overlapped with Descriptor block"); + /* Check validity of all stats data size */ TEST_ASSERT(size_data >= header.num_desc * sizeof(*stats_data), - "Data size is not correct"); + "Data size is not correct"); + /* Check stats offset */ for (i = 0; i < header.num_desc; ++i) { pdesc = get_stats_descriptor(stats_desc, i, &header); TEST_ASSERT(pdesc->offset < size_data, - "Invalid offset (%u) for stats: %s", - pdesc->offset, pdesc->name); + "Invalid offset (%u) for stats: %s", + pdesc->offset, pdesc->name); } /* Allocate memory for stats data */ From ed6b53ec9090133cd744705a09811cf627f3e9cb Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Mon, 13 Jun 2022 21:25:18 +0000 Subject: [PATCH 0628/1436] KVM: selftests: Read binary stat data in lib Move the code to read the binary stats data to the KVM selftests library. It will be re-used by other tests to check KVM behavior. Also opportunistically remove an unnecessary calculation with "size_data" in stats_test. Reviewed-by: David Matlack Reviewed-by: Peter Xu Signed-off-by: Ben Gardon Message-Id: <20220613212523.3436117-6-bgardon@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 4 +++ .../selftests/kvm/kvm_binary_stats_test.c | 9 ++--- tools/testing/selftests/kvm/lib/kvm_util.c | 35 +++++++++++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 8bce6df5fd40..cec3af45e18d 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -341,6 +341,10 @@ static inline struct kvm_stats_desc *get_stats_descriptor(struct kvm_stats_desc return (void *)stats + index * get_stats_descriptor_size(header); } +void read_stat_data(int stats_fd, struct kvm_stats_header *header, + struct kvm_stats_desc *desc, uint64_t *data, + size_t max_elements); + void vm_create_irqchip(struct kvm_vm *vm); void vm_set_user_memory_region(struct kvm_vm *vm, uint32_t slot, uint32_t flags, diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index a904873b2b86..b01e8b0851e7 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -147,15 +147,10 @@ static void stats_test(int stats_fd) ret = pread(stats_fd, stats_data, size_data, header.data_offset); TEST_ASSERT(ret == size_data, "Read KVM stats data"); /* Read kvm stats data one by one */ - size_data = 0; for (i = 0; i < header.num_desc; ++i) { pdesc = get_stats_descriptor(stats_desc, i, &header); - ret = pread(stats_fd, stats_data, - pdesc->size * sizeof(*stats_data), - header.data_offset + size_data); - TEST_ASSERT(ret == pdesc->size * sizeof(*stats_data), - "Read data of KVM stats: %s", pdesc->name); - size_data += pdesc->size * sizeof(*stats_data); + read_stat_data(stats_fd, &header, pdesc, stats_data, + pdesc->size); } free(stats_data); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 64ef108cc270..e44eb510fcc1 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1883,3 +1883,38 @@ struct kvm_stats_desc *read_stats_descriptors(int stats_fd, return stats_desc; } + +/* + * Read stat data for a particular stat + * + * Input Args: + * stats_fd - the file descriptor for the binary stats file from which to read + * header - the binary stats metadata header corresponding to the given FD + * desc - the binary stat metadata for the particular stat to be read + * max_elements - the maximum number of 8-byte values to read into data + * + * Output Args: + * data - the buffer into which stat data should be read + * + * Read the data values of a specified stat from the binary stats interface. + */ +void read_stat_data(int stats_fd, struct kvm_stats_header *header, + struct kvm_stats_desc *desc, uint64_t *data, + size_t max_elements) +{ + size_t nr_elements = min_t(ssize_t, desc->size, max_elements); + size_t size = nr_elements * sizeof(*data); + ssize_t ret; + + TEST_ASSERT(desc->size, "No elements in stat '%s'", desc->name); + TEST_ASSERT(max_elements, "Zero elements requested for stat '%s'", desc->name); + + ret = pread(stats_fd, data, size, + header->data_offset + desc->offset); + + TEST_ASSERT(ret >= 0, "pread() failed on stat '%s', errno: %i (%s)", + desc->name, errno, strerror(errno)); + TEST_ASSERT(ret == size, + "pread() on stat '%s' read %ld bytes, wanted %lu bytes", + desc->name, size, ret); +} From 1c4dc57328bf218e999951824dce75c6125c4f3c Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Mon, 13 Jun 2022 21:25:20 +0000 Subject: [PATCH 0629/1436] KVM: x86: Fix errant brace in KVM capability handling The braces around the KVM_CAP_XSAVE2 block also surround the KVM_CAP_PMU_CAPABILITY block, likely the result of a merge issue. Simply move the curly brace back to where it belongs. Fixes: ba7bb663f5547 ("KVM: x86: Provide per VM capability for disabling PMU virtualization") Reviewed-by: David Matlack Reviewed-by: Peter Xu Signed-off-by: Ben Gardon Message-Id: <20220613212523.3436117-8-bgardon@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 9b9f9f65c548..c1b3b2ea8ee0 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4420,10 +4420,10 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) if (r < sizeof(struct kvm_xsave)) r = sizeof(struct kvm_xsave); break; + } case KVM_CAP_PMU_CAPABILITY: r = enable_pmu ? KVM_CAP_PMU_VALID_MASK : 0; break; - } case KVM_CAP_DISABLE_QUIRKS2: r = KVM_X86_VALID_QUIRKS; break; From 084cc29f8bbb034cf30a7ee07a816c115e0c28df Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Mon, 13 Jun 2022 21:25:21 +0000 Subject: [PATCH 0630/1436] KVM: x86/MMU: Allow NX huge pages to be disabled on a per-vm basis In some cases, the NX hugepage mitigation for iTLB multihit is not needed for all guests on a host. Allow disabling the mitigation on a per-VM basis to avoid the performance hit of NX hugepages on trusted workloads. In order to disable NX hugepages on a VM, ensure that the userspace actor has permission to reboot the system. Since disabling NX hugepages would allow a guest to crash the system, it is similar to reboot permissions. Ideally, KVM would require userspace to prove it has access to KVM's nx_huge_pages module param, e.g. so that userspace can opt out without needing full reboot permissions. But getting access to the module param file info is difficult because it is buried in layers of sysfs and module glue. Requiring CAP_SYS_BOOT is sufficient for all known use cases. Suggested-by: Jim Mattson Reviewed-by: David Matlack Reviewed-by: Peter Xu Signed-off-by: Ben Gardon Message-Id: <20220613212523.3436117-9-bgardon@google.com> Signed-off-by: Paolo Bonzini --- Documentation/virt/kvm/api.rst | 16 ++++++++++++++++ arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/mmu/mmu_internal.h | 7 ++++--- arch/x86/kvm/mmu/spte.c | 7 ++++--- arch/x86/kvm/mmu/spte.h | 3 ++- arch/x86/kvm/mmu/tdp_mmu.c | 2 +- arch/x86/kvm/x86.c | 30 ++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 1 + 8 files changed, 60 insertions(+), 8 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 320cb04f7bd9..bafaeedd455c 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -8206,6 +8206,22 @@ PV guests. The `KVM_PV_DUMP` command is available for the dump related UV data. Also the vcpu ioctl `KVM_S390_PV_CPU_COMMAND` is available and supports the `KVM_PV_DUMP_CPU` subcommand. +8.38 KVM_CAP_VM_DISABLE_NX_HUGE_PAGES +--------------------------- + +:Capability KVM_CAP_VM_DISABLE_NX_HUGE_PAGES +:Architectures: x86 +:Type: vm +:Parameters: arg[0] must be 0. +:Returns 0 on success, -EPERM if the userspace process does not + have CAP_SYS_BOOT, -EINVAL if args[0] is not 0 or any vCPUs have been + created. + +This capability disables the NX huge pages mitigation for iTLB MULTIHIT. + +The capability has no effect if the nx_huge_pages module parameter is not set. + +This capability may only be set before any vCPUs are created. 9. Known KVM API problems ========================= diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index e37727a74d0a..7e4c31b57a75 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1336,6 +1336,8 @@ struct kvm_arch { * the global KVM_MAX_VCPU_IDS may lead to significant memory waste. */ u32 max_vcpu_ids; + + bool disable_nx_huge_pages; }; struct kvm_vm_stat { diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index 5e1e3c8f8aaa..bb9d12ac0db3 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -155,9 +155,9 @@ void kvm_flush_remote_tlbs_with_address(struct kvm *kvm, unsigned int pte_list_count(struct kvm_rmap_head *rmap_head); extern int nx_huge_pages; -static inline bool is_nx_huge_page_enabled(void) +static inline bool is_nx_huge_page_enabled(struct kvm *kvm) { - return READ_ONCE(nx_huge_pages); + return READ_ONCE(nx_huge_pages) && !kvm->arch.disable_nx_huge_pages; } struct kvm_page_fault { @@ -256,7 +256,8 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, .user = err & PFERR_USER_MASK, .prefetch = prefetch, .is_tdp = likely(vcpu->arch.mmu->page_fault == kvm_tdp_page_fault), - .nx_huge_page_workaround_enabled = is_nx_huge_page_enabled(), + .nx_huge_page_workaround_enabled = + is_nx_huge_page_enabled(vcpu->kvm), .max_level = KVM_MAX_HUGEPAGE_LEVEL, .req_level = PG_LEVEL_4K, diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index 242e4828d7df..db294c1beea2 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -147,7 +147,7 @@ bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, spte |= spte_shadow_accessed_mask(spte); if (level > PG_LEVEL_4K && (pte_access & ACC_EXEC_MASK) && - is_nx_huge_page_enabled()) { + is_nx_huge_page_enabled(vcpu->kvm)) { pte_access &= ~ACC_EXEC_MASK; } @@ -246,7 +246,8 @@ static u64 make_spte_executable(u64 spte) * This is used during huge page splitting to build the SPTEs that make up the * new page table. */ -u64 make_huge_page_split_spte(u64 huge_spte, int huge_level, int index) +u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, int huge_level, + int index) { u64 child_spte; int child_level; @@ -274,7 +275,7 @@ u64 make_huge_page_split_spte(u64 huge_spte, int huge_level, int index) * When splitting to a 4K page, mark the page executable as the * NX hugepage mitigation no longer applies. */ - if (is_nx_huge_page_enabled()) + if (is_nx_huge_page_enabled(kvm)) child_spte = make_spte_executable(child_spte); } diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h index 121c5eaaec77..256f90587e8d 100644 --- a/arch/x86/kvm/mmu/spte.h +++ b/arch/x86/kvm/mmu/spte.h @@ -421,7 +421,8 @@ bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, unsigned int pte_access, gfn_t gfn, kvm_pfn_t pfn, u64 old_spte, bool prefetch, bool can_unsync, bool host_writable, u64 *new_spte); -u64 make_huge_page_split_spte(u64 huge_spte, int huge_level, int index); +u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, int huge_level, + int index); u64 make_nonleaf_spte(u64 *child_pt, bool ad_disabled); u64 make_mmio_spte(struct kvm_vcpu *vcpu, u64 gfn, unsigned int access); u64 mark_spte_for_access_track(u64 spte); diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 1ea40809ef1f..522e2532343b 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -1478,7 +1478,7 @@ static int tdp_mmu_split_huge_page(struct kvm *kvm, struct tdp_iter *iter, * not been linked in yet and thus is not reachable from any other CPU. */ for (i = 0; i < SPTE_ENT_PER_PAGE; i++) - sp->spt[i] = make_huge_page_split_spte(huge_spte, level, i); + sp->spt[i] = make_huge_page_split_spte(kvm, huge_spte, level, i); /* * Replace the huge spte with a pointer to the populated lower level diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c1b3b2ea8ee0..7ce0c6fe166d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4324,6 +4324,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_SYS_ATTRIBUTES: case KVM_CAP_VAPIC: case KVM_CAP_ENABLE_CAP: + case KVM_CAP_VM_DISABLE_NX_HUGE_PAGES: r = 1; break; case KVM_CAP_EXIT_HYPERCALL: @@ -6184,6 +6185,35 @@ split_irqchip_unlock: } mutex_unlock(&kvm->lock); break; + case KVM_CAP_VM_DISABLE_NX_HUGE_PAGES: + r = -EINVAL; + + /* + * Since the risk of disabling NX hugepages is a guest crashing + * the system, ensure the userspace process has permission to + * reboot the system. + * + * Note that unlike the reboot() syscall, the process must have + * this capability in the root namespace because exposing + * /dev/kvm into a container does not limit the scope of the + * iTLB multihit bug to that container. In other words, + * this must use capable(), not ns_capable(). + */ + if (!capable(CAP_SYS_BOOT)) { + r = -EPERM; + break; + } + + if (cap->args[0]) + break; + + mutex_lock(&kvm->lock); + if (!kvm->created_vcpus) { + kvm->arch.disable_nx_huge_pages = true; + r = 0; + } + mutex_unlock(&kvm->lock); + break; default: r = -EINVAL; break; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 7569b4ec199c..a36e78710382 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1166,6 +1166,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_S390_PROTECTED_DUMP 217 #define KVM_CAP_X86_TRIPLE_FAULT_EVENT 218 #define KVM_CAP_X86_NOTIFY_VMEXIT 219 +#define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220 #ifdef KVM_CAP_IRQ_ROUTING From 8448ec5993beee031376e36f77969cc0a07d8c6b Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Mon, 13 Jun 2022 21:25:19 +0000 Subject: [PATCH 0631/1436] KVM: selftests: Add NX huge pages test There's currently no test coverage of NX hugepages in KVM selftests, so add a basic test to ensure that the feature works as intended. The test creates a VM with a data slot backed with huge pages. The memory in the data slot is filled with op-codes for the return instruction. The guest then executes a series of accesses on the memory, some reads, some instruction fetches. After each operation, the guest exits and the test performs some checks on the backing page counts to ensure that NX page splitting an reclaim work as expected. Reviewed-by: David Matlack Signed-off-by: Ben Gardon Message-Id: <20220613212523.3436117-7-bgardon@google.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 10 + .../selftests/kvm/include/kvm_util_base.h | 11 + tools/testing/selftests/kvm/lib/kvm_util.c | 46 ++++ .../selftests/kvm/x86_64/nx_huge_pages_test.c | 229 ++++++++++++++++++ .../kvm/x86_64/nx_huge_pages_test.sh | 40 +++ 6 files changed, 337 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c create mode 100755 tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index f3c2f074b948..c478b4fefc57 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -29,6 +29,7 @@ /x86_64/mmio_warning_test /x86_64/mmu_role_test /x86_64/monitor_mwait_test +/x86_64/nx_huge_pages_test /x86_64/platform_info_test /x86_64/pmu_event_filter_test /x86_64/set_boot_cpu_id diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index ad1634e5659f..fa3e0687e9d5 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -70,6 +70,10 @@ LIBKVM_s390x += lib/s390x/ucall.c LIBKVM_riscv += lib/riscv/processor.c LIBKVM_riscv += lib/riscv/ucall.c +# Non-compiled test targets +TEST_PROGS_x86_64 += x86_64/nx_huge_pages_test.sh + +# Compiled test targets TEST_GEN_PROGS_x86_64 = x86_64/cpuid_test TEST_GEN_PROGS_x86_64 += x86_64/cr4_cpuid_sync_test TEST_GEN_PROGS_x86_64 += x86_64/get_msr_index_features @@ -135,6 +139,9 @@ TEST_GEN_PROGS_x86_64 += steal_time TEST_GEN_PROGS_x86_64 += kvm_binary_stats_test TEST_GEN_PROGS_x86_64 += system_counter_offset_test +# Compiled outputs used by test targets +TEST_GEN_PROGS_EXTENDED_x86_64 += x86_64/nx_huge_pages_test + TEST_GEN_PROGS_aarch64 += aarch64/arch_timer TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list @@ -174,7 +181,9 @@ TEST_GEN_PROGS_riscv += kvm_page_table_test TEST_GEN_PROGS_riscv += set_memory_region_test TEST_GEN_PROGS_riscv += kvm_binary_stats_test +TEST_PROGS += $(TEST_PROGS_$(UNAME_M)) TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) +TEST_GEN_PROGS_EXTENDED += $(TEST_GEN_PROGS_EXTENDED_$(UNAME_M)) LIBKVM += $(LIBKVM_$(UNAME_M)) INSTALL_HDR_PATH = $(top_srcdir)/usr @@ -221,6 +230,7 @@ $(LIBKVM_S_OBJ): $(OUTPUT)/%.o: %.S x := $(shell mkdir -p $(sort $(dir $(TEST_GEN_PROGS)))) $(TEST_GEN_PROGS): $(LIBKVM_OBJS) +$(TEST_GEN_PROGS_EXTENDED): $(LIBKVM_OBJS) cscope: include_paths = $(LINUX_TOOL_INCLUDE) $(LINUX_HDR_PATH) include lib .. cscope: diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index cec3af45e18d..c6c1d66136d6 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -345,6 +345,17 @@ void read_stat_data(int stats_fd, struct kvm_stats_header *header, struct kvm_stats_desc *desc, uint64_t *data, size_t max_elements); +void __vm_get_stat(struct kvm_vm *vm, const char *stat_name, uint64_t *data, + size_t max_elements); + +static inline uint64_t vm_get_stat(struct kvm_vm *vm, const char *stat_name) +{ + uint64_t data; + + __vm_get_stat(vm, stat_name, &data, 1); + return data; +} + void vm_create_irqchip(struct kvm_vm *vm); void vm_set_user_memory_region(struct kvm_vm *vm, uint32_t slot, uint32_t flags, diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index e44eb510fcc1..5a0fd368503f 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -1918,3 +1918,49 @@ void read_stat_data(int stats_fd, struct kvm_stats_header *header, "pread() on stat '%s' read %ld bytes, wanted %lu bytes", desc->name, size, ret); } + +/* + * Read the data of the named stat + * + * Input Args: + * vm - the VM for which the stat should be read + * stat_name - the name of the stat to read + * max_elements - the maximum number of 8-byte values to read into data + * + * Output Args: + * data - the buffer into which stat data should be read + * + * Read the data values of a specified stat from the binary stats interface. + */ +void __vm_get_stat(struct kvm_vm *vm, const char *stat_name, uint64_t *data, + size_t max_elements) +{ + struct kvm_stats_desc *stats_desc; + struct kvm_stats_header header; + struct kvm_stats_desc *desc; + size_t size_desc; + int stats_fd; + int i; + + stats_fd = vm_get_stats_fd(vm); + + read_stats_header(stats_fd, &header); + + stats_desc = read_stats_descriptors(stats_fd, &header); + + size_desc = get_stats_descriptor_size(&header); + + for (i = 0; i < header.num_desc; ++i) { + desc = (void *)stats_desc + (i * size_desc); + + if (strcmp(desc->name, stat_name)) + continue; + + read_stat_data(stats_fd, &header, desc, data, max_elements); + + break; + } + + free(stats_desc); + close(stats_fd); +} diff --git a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c new file mode 100644 index 000000000000..5fa61d225787 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * tools/testing/selftests/kvm/nx_huge_page_test.c + * + * Usage: to be run via nx_huge_page_test.sh, which does the necessary + * environment setup and teardown + * + * Copyright (C) 2022, Google LLC. + */ + +#define _GNU_SOURCE + +#include +#include +#include + +#include +#include "kvm_util.h" +#include "processor.h" + +#define HPAGE_SLOT 10 +#define HPAGE_GPA (4UL << 30) /* 4G prevents collision w/ slot 0 */ +#define HPAGE_GVA HPAGE_GPA /* GVA is arbitrary, so use GPA. */ +#define PAGES_PER_2MB_HUGE_PAGE 512 +#define HPAGE_SLOT_NPAGES (3 * PAGES_PER_2MB_HUGE_PAGE) + +/* + * Passed by nx_huge_pages_test.sh to provide an easy warning if this test is + * being run without it. + */ +#define MAGIC_TOKEN 887563923 + +/* + * x86 opcode for the return instruction. Used to call into, and then + * immediately return from, memory backed with hugepages. + */ +#define RETURN_OPCODE 0xC3 + +/* Call the specified memory address. */ +static void guest_do_CALL(uint64_t target) +{ + ((void (*)(void)) target)(); +} + +/* + * Exit the VM after each memory access so that the userspace component of the + * test can make assertions about the pages backing the VM. + * + * See the below for an explanation of how each access should affect the + * backing mappings. + */ +void guest_code(void) +{ + uint64_t hpage_1 = HPAGE_GVA; + uint64_t hpage_2 = hpage_1 + (PAGE_SIZE * 512); + uint64_t hpage_3 = hpage_2 + (PAGE_SIZE * 512); + + READ_ONCE(*(uint64_t *)hpage_1); + GUEST_SYNC(1); + + READ_ONCE(*(uint64_t *)hpage_2); + GUEST_SYNC(2); + + guest_do_CALL(hpage_1); + GUEST_SYNC(3); + + guest_do_CALL(hpage_3); + GUEST_SYNC(4); + + READ_ONCE(*(uint64_t *)hpage_1); + GUEST_SYNC(5); + + READ_ONCE(*(uint64_t *)hpage_3); + GUEST_SYNC(6); +} + +static void check_2m_page_count(struct kvm_vm *vm, int expected_pages_2m) +{ + int actual_pages_2m; + + actual_pages_2m = vm_get_stat(vm, "pages_2m"); + + TEST_ASSERT(actual_pages_2m == expected_pages_2m, + "Unexpected 2m page count. Expected %d, got %d", + expected_pages_2m, actual_pages_2m); +} + +static void check_split_count(struct kvm_vm *vm, int expected_splits) +{ + int actual_splits; + + actual_splits = vm_get_stat(vm, "nx_lpage_splits"); + + TEST_ASSERT(actual_splits == expected_splits, + "Unexpected NX huge page split count. Expected %d, got %d", + expected_splits, actual_splits); +} + +static void wait_for_reclaim(int reclaim_period_ms) +{ + long reclaim_wait_ms; + struct timespec ts; + + reclaim_wait_ms = reclaim_period_ms * 5; + ts.tv_sec = reclaim_wait_ms / 1000; + ts.tv_nsec = (reclaim_wait_ms - (ts.tv_sec * 1000)) * 1000000; + nanosleep(&ts, NULL); +} + +static void help(char *name) +{ + puts(""); + printf("usage: %s [-h] [-p period_ms] [-t token]\n", name); + puts(""); + printf(" -p: The NX reclaim period in miliseconds.\n"); + printf(" -t: The magic token to indicate environment setup is done.\n"); + puts(""); + exit(0); +} + +int main(int argc, char **argv) +{ + int reclaim_period_ms = 0, token = 0, opt; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + void *hva; + + while ((opt = getopt(argc, argv, "hp:t:")) != -1) { + switch (opt) { + case 'p': + reclaim_period_ms = atoi(optarg); + break; + case 't': + token = atoi(optarg); + break; + case 'h': + default: + help(argv[0]); + break; + } + } + + if (token != MAGIC_TOKEN) { + print_skip("This test must be run with the magic token %d.\n" + "This is done by nx_huge_pages_test.sh, which\n" + "also handles environment setup for the test.", + MAGIC_TOKEN); + exit(KSFT_SKIP); + } + + if (!reclaim_period_ms) { + print_skip("The NX reclaim period must be specified and non-zero"); + exit(KSFT_SKIP); + } + + vm = vm_create(1); + vcpu = vm_vcpu_add(vm, 0, guest_code); + + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS_HUGETLB, + HPAGE_GPA, HPAGE_SLOT, + HPAGE_SLOT_NPAGES, 0); + + virt_map(vm, HPAGE_GVA, HPAGE_GPA, HPAGE_SLOT_NPAGES); + + hva = addr_gpa2hva(vm, HPAGE_GPA); + memset(hva, RETURN_OPCODE, HPAGE_SLOT_NPAGES * PAGE_SIZE); + + check_2m_page_count(vm, 0); + check_split_count(vm, 0); + + /* + * The guest code will first read from the first hugepage, resulting + * in a huge page mapping being created. + */ + vcpu_run(vcpu); + check_2m_page_count(vm, 1); + check_split_count(vm, 0); + + /* + * Then the guest code will read from the second hugepage, resulting + * in another huge page mapping being created. + */ + vcpu_run(vcpu); + check_2m_page_count(vm, 2); + check_split_count(vm, 0); + + /* + * Next, the guest will execute from the first huge page, causing it + * to be remapped at 4k. + */ + vcpu_run(vcpu); + check_2m_page_count(vm, 1); + check_split_count(vm, 1); + + /* + * Executing from the third huge page (previously unaccessed) will + * cause part to be mapped at 4k. + */ + vcpu_run(vcpu); + check_2m_page_count(vm, 1); + check_split_count(vm, 2); + + /* Reading from the first huge page again should have no effect. */ + vcpu_run(vcpu); + check_2m_page_count(vm, 1); + check_split_count(vm, 2); + + /* Give recovery thread time to run. */ + wait_for_reclaim(reclaim_period_ms); + + /* + * Now that the reclaimer has run, all the split pages should be gone. + */ + check_2m_page_count(vm, 1); + check_split_count(vm, 0); + + /* + * The 4k mapping on hpage 3 should have been removed, so check that + * reading from it causes a huge page mapping to be installed. + */ + vcpu_run(vcpu); + check_2m_page_count(vm, 2); + check_split_count(vm, 0); + + kvm_vm_free(vm); + + return 0; +} + diff --git a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh new file mode 100755 index 000000000000..4e090a84f5f3 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-only */ +# +# Wrapper script which performs setup and cleanup for nx_huge_pages_test. +# Makes use of root privileges to set up huge pages and KVM module parameters. +# +# tools/testing/selftests/kvm/nx_huge_page_test.sh +# Copyright (C) 2022, Google LLC. + +set -e + +NX_HUGE_PAGES=$(cat /sys/module/kvm/parameters/nx_huge_pages) +NX_HUGE_PAGES_RECOVERY_RATIO=$(cat /sys/module/kvm/parameters/nx_huge_pages_recovery_ratio) +NX_HUGE_PAGES_RECOVERY_PERIOD=$(cat /sys/module/kvm/parameters/nx_huge_pages_recovery_period_ms) +HUGE_PAGES=$(cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages) + +set +e + +function sudo_echo () { + echo "$1" | sudo tee -a "$2" > /dev/null +} + +( + set -e + + sudo_echo 1 /sys/module/kvm/parameters/nx_huge_pages + sudo_echo 1 /sys/module/kvm/parameters/nx_huge_pages_recovery_ratio + sudo_echo 100 /sys/module/kvm/parameters/nx_huge_pages_recovery_period_ms + sudo_echo "$(( $HUGE_PAGES + 3 ))" /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages + + "$(dirname $0)"/nx_huge_pages_test -t 887563923 -p 100 +) +RET=$? + +sudo_echo "$NX_HUGE_PAGES" /sys/module/kvm/parameters/nx_huge_pages +sudo_echo "$NX_HUGE_PAGES_RECOVERY_RATIO" /sys/module/kvm/parameters/nx_huge_pages_recovery_ratio +sudo_echo "$NX_HUGE_PAGES_RECOVERY_PERIOD" /sys/module/kvm/parameters/nx_huge_pages_recovery_period_ms +sudo_echo "$HUGE_PAGES" /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages + +exit $RET From b774da3f2e5761cb85881ce62eb6dc97d15396c4 Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Mon, 13 Jun 2022 21:25:22 +0000 Subject: [PATCH 0632/1436] KVM: selftests: Test disabling NX hugepages on a VM Add an argument to the NX huge pages test to test disabling the feature on a VM using the new capability. Reviewed-by: David Matlack Signed-off-by: Ben Gardon Message-Id: <20220613212523.3436117-10-bgardon@google.com> [Handle failure of sudo or setcap more gracefully. - Paolo] Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 6 + .../selftests/kvm/x86_64/nx_huge_pages_test.c | 134 ++++++++++++------ .../kvm/x86_64/nx_huge_pages_test.sh | 21 ++- 3 files changed, 113 insertions(+), 48 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index c6c1d66136d6..fd2b52850b29 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -809,4 +809,10 @@ static inline void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) virt_arch_dump(stream, vm, indent); } + +static inline int __vm_disable_nx_huge_pages(struct kvm_vm *vm) +{ + return __vm_enable_cap(vm, KVM_CAP_VM_DISABLE_NX_HUGE_PAGES, 0); +} + #endif /* SELFTEST_KVM_UTIL_BASE_H */ diff --git a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c index 5fa61d225787..cc6421716400 100644 --- a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c +++ b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.c @@ -107,53 +107,34 @@ static void wait_for_reclaim(int reclaim_period_ms) nanosleep(&ts, NULL); } -static void help(char *name) +void run_test(int reclaim_period_ms, bool disable_nx_huge_pages, + bool reboot_permissions) { - puts(""); - printf("usage: %s [-h] [-p period_ms] [-t token]\n", name); - puts(""); - printf(" -p: The NX reclaim period in miliseconds.\n"); - printf(" -t: The magic token to indicate environment setup is done.\n"); - puts(""); - exit(0); -} - -int main(int argc, char **argv) -{ - int reclaim_period_ms = 0, token = 0, opt; struct kvm_vcpu *vcpu; struct kvm_vm *vm; void *hva; + int r; - while ((opt = getopt(argc, argv, "hp:t:")) != -1) { - switch (opt) { - case 'p': - reclaim_period_ms = atoi(optarg); - break; - case 't': - token = atoi(optarg); - break; - case 'h': - default: - help(argv[0]); - break; + vm = vm_create(1); + + if (disable_nx_huge_pages) { + /* + * Cannot run the test without NX huge pages if the kernel + * does not support it. + */ + if (!kvm_check_cap(KVM_CAP_VM_DISABLE_NX_HUGE_PAGES)) + return; + + r = __vm_disable_nx_huge_pages(vm); + if (reboot_permissions) { + TEST_ASSERT(!r, "Disabling NX huge pages should succeed if process has reboot permissions"); + } else { + TEST_ASSERT(r == -1 && errno == EPERM, + "This process should not have permission to disable NX huge pages"); + return; } } - if (token != MAGIC_TOKEN) { - print_skip("This test must be run with the magic token %d.\n" - "This is done by nx_huge_pages_test.sh, which\n" - "also handles environment setup for the test.", - MAGIC_TOKEN); - exit(KSFT_SKIP); - } - - if (!reclaim_period_ms) { - print_skip("The NX reclaim period must be specified and non-zero"); - exit(KSFT_SKIP); - } - - vm = vm_create(1); vcpu = vm_vcpu_add(vm, 0, guest_code); vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS_HUGETLB, @@ -187,31 +168,38 @@ int main(int argc, char **argv) /* * Next, the guest will execute from the first huge page, causing it * to be remapped at 4k. + * + * If NX huge pages are disabled, this should have no effect. */ vcpu_run(vcpu); - check_2m_page_count(vm, 1); - check_split_count(vm, 1); + check_2m_page_count(vm, disable_nx_huge_pages ? 2 : 1); + check_split_count(vm, disable_nx_huge_pages ? 0 : 1); /* * Executing from the third huge page (previously unaccessed) will * cause part to be mapped at 4k. + * + * If NX huge pages are disabled, it should be mapped at 2M. */ vcpu_run(vcpu); - check_2m_page_count(vm, 1); - check_split_count(vm, 2); + check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 1); + check_split_count(vm, disable_nx_huge_pages ? 0 : 2); /* Reading from the first huge page again should have no effect. */ vcpu_run(vcpu); - check_2m_page_count(vm, 1); - check_split_count(vm, 2); + check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 1); + check_split_count(vm, disable_nx_huge_pages ? 0 : 2); /* Give recovery thread time to run. */ wait_for_reclaim(reclaim_period_ms); /* * Now that the reclaimer has run, all the split pages should be gone. + * + * If NX huge pages are disabled, the relaimer will not run, so + * nothing should change from here on. */ - check_2m_page_count(vm, 1); + check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 1); check_split_count(vm, 0); /* @@ -219,10 +207,62 @@ int main(int argc, char **argv) * reading from it causes a huge page mapping to be installed. */ vcpu_run(vcpu); - check_2m_page_count(vm, 2); + check_2m_page_count(vm, disable_nx_huge_pages ? 3 : 2); check_split_count(vm, 0); kvm_vm_free(vm); +} + +static void help(char *name) +{ + puts(""); + printf("usage: %s [-h] [-p period_ms] [-t token]\n", name); + puts(""); + printf(" -p: The NX reclaim period in miliseconds.\n"); + printf(" -t: The magic token to indicate environment setup is done.\n"); + printf(" -r: The test has reboot permissions and can disable NX huge pages.\n"); + puts(""); + exit(0); +} + +int main(int argc, char **argv) +{ + int reclaim_period_ms = 0, token = 0, opt; + bool reboot_permissions = false; + + while ((opt = getopt(argc, argv, "hp:t:r")) != -1) { + switch (opt) { + case 'p': + reclaim_period_ms = atoi(optarg); + break; + case 't': + token = atoi(optarg); + break; + case 'r': + reboot_permissions = true; + break; + case 'h': + default: + help(argv[0]); + break; + } + } + + if (token != MAGIC_TOKEN) { + print_skip("This test must be run with the magic token %d.\n" + "This is done by nx_huge_pages_test.sh, which\n" + "also handles environment setup for the test.", + MAGIC_TOKEN); + exit(KSFT_SKIP); + } + + if (!reclaim_period_ms) { + print_skip("The NX reclaim period must be specified and non-zero"); + exit(KSFT_SKIP); + } + + run_test(reclaim_period_ms, false, reboot_permissions); + run_test(reclaim_period_ms, true, reboot_permissions); return 0; } diff --git a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh index 4e090a84f5f3..0560149e66ed 100755 --- a/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh +++ b/tools/testing/selftests/kvm/x86_64/nx_huge_pages_test.sh @@ -20,6 +20,10 @@ function sudo_echo () { echo "$1" | sudo tee -a "$2" > /dev/null } +NXECUTABLE="$(dirname $0)/nx_huge_pages_test" + +sudo_echo test /dev/null || exit 4 # KSFT_SKIP=4 + ( set -e @@ -28,7 +32,22 @@ function sudo_echo () { sudo_echo 100 /sys/module/kvm/parameters/nx_huge_pages_recovery_period_ms sudo_echo "$(( $HUGE_PAGES + 3 ))" /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages - "$(dirname $0)"/nx_huge_pages_test -t 887563923 -p 100 + # Test with reboot permissions + if [ $(whoami) == "root" ] || sudo setcap cap_sys_boot+ep $NXECUTABLE 2> /dev/null; then + echo Running test with CAP_SYS_BOOT enabled + $NXECUTABLE -t 887563923 -p 100 -r + test $(whoami) == "root" || sudo setcap cap_sys_boot-ep $NXECUTABLE + else + echo setcap failed, skipping nx_huge_pages_test with CAP_SYS_BOOT enabled + fi + + # Test without reboot permissions + if [ $(whoami) != "root" ] ; then + echo Running test with CAP_SYS_BOOT disabled + $NXECUTABLE -t 887563923 -p 100 + else + echo Running as root, skipping nx_huge_pages_test with CAP_SYS_BOOT disabled + fi ) RET=$? From 83f6e109f562063ab7a1f54d99bcab2858b09ead Mon Sep 17 00:00:00 2001 From: Ben Gardon Date: Mon, 13 Jun 2022 21:25:23 +0000 Subject: [PATCH 0633/1436] KVM: selftests: Cache binary stats metadata for duration of test In order to improve performance across multiple reads of VM stats, cache the stats metadata in the VM struct. Signed-off-by: Ben Gardon Message-Id: <20220613212523.3436117-11-bgardon@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/include/kvm_util_base.h | 5 +++ tools/testing/selftests/kvm/lib/kvm_util.c | 32 ++++++++++--------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index fd2b52850b29..b78e3c7a2566 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -84,6 +84,11 @@ struct kvm_vm { vm_vaddr_t idt; vm_vaddr_t handlers; uint32_t dirty_ring_size; + + /* Cache of information for binary stats interface */ + int stats_fd; + struct kvm_stats_header stats_header; + struct kvm_stats_desc *stats_desc; }; diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 5a0fd368503f..768f3bce0161 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -547,6 +547,12 @@ void kvm_vm_free(struct kvm_vm *vmp) if (vmp == NULL) return; + /* Free cached stats metadata and close FD */ + if (vmp->stats_fd) { + free(vmp->stats_desc); + close(vmp->stats_fd); + } + /* Free userspace_mem_regions. */ hash_for_each_safe(vmp->regions.slot_hash, ctr, node, region, slot_node) __vm_mem_region_delete(vmp, region, false); @@ -1935,32 +1941,28 @@ void read_stat_data(int stats_fd, struct kvm_stats_header *header, void __vm_get_stat(struct kvm_vm *vm, const char *stat_name, uint64_t *data, size_t max_elements) { - struct kvm_stats_desc *stats_desc; - struct kvm_stats_header header; struct kvm_stats_desc *desc; size_t size_desc; - int stats_fd; int i; - stats_fd = vm_get_stats_fd(vm); + if (!vm->stats_fd) { + vm->stats_fd = vm_get_stats_fd(vm); + read_stats_header(vm->stats_fd, &vm->stats_header); + vm->stats_desc = read_stats_descriptors(vm->stats_fd, + &vm->stats_header); + } - read_stats_header(stats_fd, &header); + size_desc = get_stats_descriptor_size(&vm->stats_header); - stats_desc = read_stats_descriptors(stats_fd, &header); - - size_desc = get_stats_descriptor_size(&header); - - for (i = 0; i < header.num_desc; ++i) { - desc = (void *)stats_desc + (i * size_desc); + for (i = 0; i < vm->stats_header.num_desc; ++i) { + desc = (void *)vm->stats_desc + (i * size_desc); if (strcmp(desc->name, stat_name)) continue; - read_stat_data(stats_fd, &header, desc, data, max_elements); + read_stat_data(vm->stats_fd, &vm->stats_header, desc, + data, max_elements); break; } - - free(stats_desc); - close(stats_fd); } From bb924ca69f71b4f54c8f07be28e2b76f5ad1d2ac Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:48 -0400 Subject: [PATCH 0634/1436] KVM: x86/mmu: Optimize MMU page cache lookup for all direct SPs Commit fb58a9c345f6 ("KVM: x86/mmu: Optimize MMU page cache lookup for fully direct MMUs") skipped the unsync checks and write flood clearing for full direct MMUs. We can extend this further to skip the checks for all direct shadow pages. Direct shadow pages in indirect MMUs (i.e. shadow paging) are used when shadowing a guest huge page with smaller pages. Such direct shadow pages, like their counterparts in fully direct MMUs, are never marked unsynced or have a non-zero write-flooding count. Checking sp->role.direct also generates better code than checking direct_map because, due to register pressure, direct_map has to get shoved onto the stack and then pulled back off. No functional change intended. Reviewed-by: Lai Jiangshan Reviewed-by: Sean Christopherson Reviewed-by: Peter Xu Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-2-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 27b2a5603496..c0afb4f1c8ae 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2000,7 +2000,6 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, int direct, unsigned int access) { - bool direct_mmu = vcpu->arch.mmu->root_role.direct; union kvm_mmu_page_role role; struct hlist_head *sp_list; unsigned quadrant; @@ -2060,7 +2059,8 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, continue; } - if (direct_mmu) + /* unsync and write-flooding only apply to indirect SPs. */ + if (sp->role.direct) goto trace_get_page; if (sp->unsync) { From 27a59d57f073f21f029df1517c2c0a1abea5b0ce Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:49 -0400 Subject: [PATCH 0635/1436] KVM: x86/mmu: Use a bool for direct The parameter "direct" can either be true or false, and all of the callers pass in a bool variable or true/false literal, so just use the type bool. No functional change intended. Reviewed-by: Lai Jiangshan Reviewed-by: Sean Christopherson Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-3-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index c0afb4f1c8ae..844b58ddb3bb 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1664,7 +1664,7 @@ static void drop_parent_pte(struct kvm_mmu_page *sp, mmu_spte_clear_no_track(parent_pte); } -static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, int direct) +static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, bool direct) { struct kvm_mmu_page *sp; @@ -1997,7 +1997,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gaddr, unsigned level, - int direct, + bool direct, unsigned int access) { union kvm_mmu_page_role role; From 86938ab6925b8fe174ca6abf397e6ea9d3c054a4 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:50 -0400 Subject: [PATCH 0636/1436] KVM: x86/mmu: Stop passing "direct" to mmu_alloc_root() The "direct" argument is vcpu->arch.mmu->root_role.direct, because unlike non-root page tables, it's impossible to have a direct root in an indirect MMU. So just use that. Suggested-by: Lai Jiangshan Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-4-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 844b58ddb3bb..2e30398fe59f 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3369,8 +3369,9 @@ static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn) } static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva, - u8 level, bool direct) + u8 level) { + bool direct = vcpu->arch.mmu->root_role.direct; struct kvm_mmu_page *sp; sp = kvm_mmu_get_page(vcpu, gfn, gva, level, direct, ACC_ALL); @@ -3396,7 +3397,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) root = kvm_tdp_mmu_get_vcpu_root_hpa(vcpu); mmu->root.hpa = root; } else if (shadow_root_level >= PT64_ROOT_4LEVEL) { - root = mmu_alloc_root(vcpu, 0, 0, shadow_root_level, true); + root = mmu_alloc_root(vcpu, 0, 0, shadow_root_level); mmu->root.hpa = root; } else if (shadow_root_level == PT32E_ROOT_LEVEL) { if (WARN_ON_ONCE(!mmu->pae_root)) { @@ -3408,7 +3409,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) WARN_ON_ONCE(IS_VALID_PAE_ROOT(mmu->pae_root[i])); root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), - i << 30, PT32_ROOT_LEVEL, true); + i << 30, PT32_ROOT_LEVEL); mmu->pae_root[i] = root | PT_PRESENT_MASK | shadow_me_value; } @@ -3532,7 +3533,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) */ if (mmu->cpu_role.base.level >= PT64_ROOT_4LEVEL) { root = mmu_alloc_root(vcpu, root_gfn, 0, - mmu->root_role.level, false); + mmu->root_role.level); mmu->root.hpa = root; goto set_root_pgd; } @@ -3578,7 +3579,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) } root = mmu_alloc_root(vcpu, root_gfn, i << 30, - PT32_ROOT_LEVEL, false); + PT32_ROOT_LEVEL); mmu->pae_root[i] = root | pm_mask; } From 2e65e842c57d72e9a573ba42bc2055b7f626ea1f Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:51 -0400 Subject: [PATCH 0637/1436] KVM: x86/mmu: Derive shadow MMU page role from parent Instead of computing the shadow page role from scratch for every new page, derive most of the information from the parent shadow page. This eliminates the dependency on the vCPU root role to allocate shadow page tables, and reduces the number of parameters to kvm_mmu_get_page(). Preemptively split out the role calculation to a separate function for use in a following commit. Note that when calculating the MMU root role, we can take @role.passthrough, @role.direct, and @role.access directly from @vcpu->arch.mmu->root_role. Only @role.level and @role.quadrant still must be overridden for PAE page directories, when shadowing 32-bit guest page tables with PAE page tables. No functional change intended. Reviewed-by: Peter Xu Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-5-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 114 +++++++++++++++++++-------------- arch/x86/kvm/mmu/paging_tmpl.h | 9 +-- 2 files changed, 71 insertions(+), 52 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 2e30398fe59f..fd1b479bf7fc 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1993,49 +1993,15 @@ static void clear_sp_write_flooding_count(u64 *spte) __clear_sp_write_flooding_count(sptep_to_sp(spte)); } -static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, - gfn_t gfn, - gva_t gaddr, - unsigned level, - bool direct, - unsigned int access) +static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn, + union kvm_mmu_page_role role) { - union kvm_mmu_page_role role; struct hlist_head *sp_list; - unsigned quadrant; struct kvm_mmu_page *sp; int ret; int collisions = 0; LIST_HEAD(invalid_list); - role = vcpu->arch.mmu->root_role; - role.level = level; - role.direct = direct; - role.access = access; - if (role.has_4_byte_gpte) { - /* - * If the guest has 4-byte PTEs then that means it's using 32-bit, - * 2-level, non-PAE paging. KVM shadows such guests with PAE paging - * (i.e. 8-byte PTEs). The difference in PTE size means that KVM must - * shadow each guest page table with multiple shadow page tables, which - * requires extra bookkeeping in the role. - * - * Specifically, to shadow the guest's page directory (which covers a - * 4GiB address space), KVM uses 4 PAE page directories, each mapping - * 1GiB of the address space. @role.quadrant encodes which quarter of - * the address space each maps. - * - * To shadow the guest's page tables (which each map a 4MiB region), KVM - * uses 2 PAE page tables, each mapping a 2MiB region. For these, - * @role.quadrant encodes which half of the region they map. - */ - quadrant = gaddr >> (PAGE_SHIFT + (SPTE_LEVEL_BITS * level)); - quadrant &= (1 << level) - 1; - role.quadrant = quadrant; - } - if (level <= vcpu->arch.mmu->cpu_role.base.level) - role.passthrough = 0; - sp_list = &vcpu->kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)]; for_each_valid_sp(vcpu->kvm, sp, sp_list) { if (sp->gfn != gfn) { @@ -2053,7 +2019,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, * Unsync pages must not be left as is, because the new * upper-level page will be write-protected. */ - if (level > PG_LEVEL_4K && sp->unsync) + if (role.level > PG_LEVEL_4K && sp->unsync) kvm_mmu_prepare_zap_page(vcpu->kvm, sp, &invalid_list); continue; @@ -2094,14 +2060,14 @@ trace_get_page: ++vcpu->kvm->stat.mmu_cache_miss; - sp = kvm_mmu_alloc_page(vcpu, direct); + sp = kvm_mmu_alloc_page(vcpu, role.direct); sp->gfn = gfn; sp->role = role; hlist_add_head(&sp->hash_link, sp_list); if (sp_has_gptes(sp)) { account_shadowed(vcpu->kvm, sp); - if (level == PG_LEVEL_4K && kvm_vcpu_write_protect_gfn(vcpu, gfn)) + if (role.level == PG_LEVEL_4K && kvm_vcpu_write_protect_gfn(vcpu, gfn)) kvm_flush_remote_tlbs_with_address(vcpu->kvm, gfn, 1); } trace_kvm_mmu_get_page(sp, true); @@ -2113,6 +2079,55 @@ out: return sp; } +static union kvm_mmu_page_role kvm_mmu_child_role(u64 *sptep, bool direct, unsigned int access) +{ + struct kvm_mmu_page *parent_sp = sptep_to_sp(sptep); + union kvm_mmu_page_role role; + + role = parent_sp->role; + role.level--; + role.access = access; + role.direct = direct; + role.passthrough = 0; + + /* + * If the guest has 4-byte PTEs then that means it's using 32-bit, + * 2-level, non-PAE paging. KVM shadows such guests with PAE paging + * (i.e. 8-byte PTEs). The difference in PTE size means that KVM must + * shadow each guest page table with multiple shadow page tables, which + * requires extra bookkeeping in the role. + * + * Specifically, to shadow the guest's page directory (which covers a + * 4GiB address space), KVM uses 4 PAE page directories, each mapping + * 1GiB of the address space. @role.quadrant encodes which quarter of + * the address space each maps. + * + * To shadow the guest's page tables (which each map a 4MiB region), KVM + * uses 2 PAE page tables, each mapping a 2MiB region. For these, + * @role.quadrant encodes which half of the region they map. + * + * Note, the 4 PAE page directories are pre-allocated and the quadrant + * assigned in mmu_alloc_root(). So only page tables need to be handled + * here. + */ + if (role.has_4_byte_gpte) { + WARN_ON_ONCE(role.level != PG_LEVEL_4K); + role.quadrant = (sptep - parent_sp->spt) % 2; + } + + return role; +} + +static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu, + u64 *sptep, gfn_t gfn, + bool direct, unsigned int access) +{ + union kvm_mmu_page_role role; + + role = kvm_mmu_child_role(sptep, direct, access); + return kvm_mmu_get_page(vcpu, gfn, role); +} + static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterator, struct kvm_vcpu *vcpu, hpa_t root, u64 addr) @@ -2964,8 +2979,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) if (is_shadow_present_pte(*it.sptep)) continue; - sp = kvm_mmu_get_page(vcpu, base_gfn, it.addr, - it.level - 1, true, ACC_ALL); + sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, true, ACC_ALL); link_shadow_page(vcpu, it.sptep, sp); if (fault->is_tdp && fault->huge_page_disallowed && @@ -3368,13 +3382,18 @@ static int mmu_check_root(struct kvm_vcpu *vcpu, gfn_t root_gfn) return ret; } -static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, gva_t gva, +static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, int quadrant, u8 level) { - bool direct = vcpu->arch.mmu->root_role.direct; + union kvm_mmu_page_role role = vcpu->arch.mmu->root_role; struct kvm_mmu_page *sp; - sp = kvm_mmu_get_page(vcpu, gfn, gva, level, direct, ACC_ALL); + role.level = level; + + if (role.has_4_byte_gpte) + role.quadrant = quadrant; + + sp = kvm_mmu_get_page(vcpu, gfn, role); ++sp->root_count; return __pa(sp->spt); @@ -3408,8 +3427,8 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) for (i = 0; i < 4; ++i) { WARN_ON_ONCE(IS_VALID_PAE_ROOT(mmu->pae_root[i])); - root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), - i << 30, PT32_ROOT_LEVEL); + root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), i, + PT32_ROOT_LEVEL); mmu->pae_root[i] = root | PT_PRESENT_MASK | shadow_me_value; } @@ -3578,8 +3597,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) root_gfn = pdptrs[i] >> PAGE_SHIFT; } - root = mmu_alloc_root(vcpu, root_gfn, i << 30, - PT32_ROOT_LEVEL); + root = mmu_alloc_root(vcpu, root_gfn, i, PT32_ROOT_LEVEL); mmu->pae_root[i] = root | pm_mask; } diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index e4655056e651..6ecdd7a41a82 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -654,8 +654,9 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, if (!is_shadow_present_pte(*it.sptep)) { table_gfn = gw->table_gfn[it.level - 2]; access = gw->pt_access[it.level - 2]; - sp = kvm_mmu_get_page(vcpu, table_gfn, fault->addr, - it.level-1, false, access); + sp = kvm_mmu_get_child_sp(vcpu, it.sptep, table_gfn, + false, access); + /* * We must synchronize the pagetable before linking it * because the guest doesn't need to flush tlb when @@ -711,8 +712,8 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, drop_large_spte(vcpu, it.sptep); if (!is_shadow_present_pte(*it.sptep)) { - sp = kvm_mmu_get_page(vcpu, base_gfn, fault->addr, - it.level - 1, true, direct_access); + sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, + true, direct_access); link_shadow_page(vcpu, it.sptep, sp); if (fault->huge_page_disallowed && fault->req_level >= it.level) From 7f49777550e55a7d6832cbb0873f48f91c175b9c Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:52 -0400 Subject: [PATCH 0638/1436] KVM: x86/mmu: Always pass 0 for @quadrant when gptes are 8 bytes The quadrant is only used when gptes are 4 bytes, but mmu_alloc_{direct,shadow}_roots() pass in a non-zero quadrant for PAE page directories regardless. Make this less confusing by only passing in a non-zero quadrant when it is actually necessary. Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-6-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index fd1b479bf7fc..f4e7978a6c6a 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -3389,9 +3389,10 @@ static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, int quadrant, struct kvm_mmu_page *sp; role.level = level; + role.quadrant = quadrant; - if (role.has_4_byte_gpte) - role.quadrant = quadrant; + WARN_ON_ONCE(quadrant && !role.has_4_byte_gpte); + WARN_ON_ONCE(role.direct && role.has_4_byte_gpte); sp = kvm_mmu_get_page(vcpu, gfn, role); ++sp->root_count; @@ -3427,7 +3428,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu) for (i = 0; i < 4; ++i) { WARN_ON_ONCE(IS_VALID_PAE_ROOT(mmu->pae_root[i])); - root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), i, + root = mmu_alloc_root(vcpu, i << (30 - PAGE_SHIFT), 0, PT32_ROOT_LEVEL); mmu->pae_root[i] = root | PT_PRESENT_MASK | shadow_me_value; @@ -3512,9 +3513,8 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) struct kvm_mmu *mmu = vcpu->arch.mmu; u64 pdptrs[4], pm_mask; gfn_t root_gfn, root_pgd; + int quadrant, i, r; hpa_t root; - unsigned i; - int r; root_pgd = mmu->get_guest_pgd(vcpu); root_gfn = root_pgd >> PAGE_SHIFT; @@ -3597,7 +3597,15 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu) root_gfn = pdptrs[i] >> PAGE_SHIFT; } - root = mmu_alloc_root(vcpu, root_gfn, i, PT32_ROOT_LEVEL); + /* + * If shadowing 32-bit non-PAE page tables, each PAE page + * directory maps one quarter of the guest's non-PAE page + * directory. Othwerise each PAE page direct shadows one guest + * PAE page directory so that quadrant should be 0. + */ + quadrant = (mmu->cpu_role.base.level == PT32_ROOT_LEVEL) ? i : 0; + + root = mmu_alloc_root(vcpu, root_gfn, quadrant, PT32_ROOT_LEVEL); mmu->pae_root[i] = root | pm_mask; } From 94c8136448c80496cbfe0922bcb379bcf62cb8ac Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:53 -0400 Subject: [PATCH 0639/1436] KVM: x86/mmu: Decompose kvm_mmu_get_page() into separate functions Decompose kvm_mmu_get_page() into separate helper functions to increase readability and prepare for allocating shadow pages without a vcpu pointer. Specifically, pull the guts of kvm_mmu_get_page() into 2 helper functions: kvm_mmu_find_shadow_page() - Walks the page hash checking for any existing mmu pages that match the given gfn and role. kvm_mmu_alloc_shadow_page() Allocates and initializes an entirely new kvm_mmu_page. This currently requries a vcpu pointer for allocation and looking up the memslot but that will be removed in a future commit. No functional change intended. Reviewed-by: Sean Christopherson Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-7-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 52 +++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index f4e7978a6c6a..a59fe860da29 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1993,16 +1993,16 @@ static void clear_sp_write_flooding_count(u64 *spte) __clear_sp_write_flooding_count(sptep_to_sp(spte)); } -static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn, - union kvm_mmu_page_role role) +static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm_vcpu *vcpu, + gfn_t gfn, + struct hlist_head *sp_list, + union kvm_mmu_page_role role) { - struct hlist_head *sp_list; struct kvm_mmu_page *sp; int ret; int collisions = 0; LIST_HEAD(invalid_list); - sp_list = &vcpu->kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)]; for_each_valid_sp(vcpu->kvm, sp, sp_list) { if (sp->gfn != gfn) { collisions++; @@ -2027,7 +2027,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn, /* unsync and write-flooding only apply to indirect SPs. */ if (sp->role.direct) - goto trace_get_page; + goto out; if (sp->unsync) { /* @@ -2053,14 +2053,26 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn, __clear_sp_write_flooding_count(sp); -trace_get_page: - trace_kvm_mmu_get_page(sp, false); goto out; } + sp = NULL; ++vcpu->kvm->stat.mmu_cache_miss; - sp = kvm_mmu_alloc_page(vcpu, role.direct); +out: + kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); + + if (collisions > vcpu->kvm->stat.max_mmu_page_hash_collisions) + vcpu->kvm->stat.max_mmu_page_hash_collisions = collisions; + return sp; +} + +static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm_vcpu *vcpu, + gfn_t gfn, + struct hlist_head *sp_list, + union kvm_mmu_page_role role) +{ + struct kvm_mmu_page *sp = kvm_mmu_alloc_page(vcpu, role.direct); sp->gfn = gfn; sp->role = role; @@ -2070,12 +2082,26 @@ trace_get_page: if (role.level == PG_LEVEL_4K && kvm_vcpu_write_protect_gfn(vcpu, gfn)) kvm_flush_remote_tlbs_with_address(vcpu->kvm, gfn, 1); } - trace_kvm_mmu_get_page(sp, true); -out: - kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); - if (collisions > vcpu->kvm->stat.max_mmu_page_hash_collisions) - vcpu->kvm->stat.max_mmu_page_hash_collisions = collisions; + return sp; +} + +static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn, + union kvm_mmu_page_role role) +{ + struct hlist_head *sp_list; + struct kvm_mmu_page *sp; + bool created = false; + + sp_list = &vcpu->kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)]; + + sp = kvm_mmu_find_shadow_page(vcpu, gfn, sp_list, role); + if (!sp) { + created = true; + sp = kvm_mmu_alloc_shadow_page(vcpu, gfn, sp_list, role); + } + + trace_kvm_mmu_get_page(sp, created); return sp; } From c306aec81ae1f40af42bf531065b66308ff72251 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:54 -0400 Subject: [PATCH 0640/1436] KVM: x86/mmu: Consolidate shadow page allocation and initialization Consolidate kvm_mmu_alloc_page() and kvm_mmu_alloc_shadow_page() under the latter so that all shadow page allocation and initialization happens in one place. No functional change intended. Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-8-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index a59fe860da29..8b84cdd8c6cd 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1664,27 +1664,6 @@ static void drop_parent_pte(struct kvm_mmu_page *sp, mmu_spte_clear_no_track(parent_pte); } -static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, bool direct) -{ - struct kvm_mmu_page *sp; - - sp = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache); - sp->spt = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_shadow_page_cache); - if (!direct) - sp->gfns = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_gfn_array_cache); - set_page_private(virt_to_page(sp->spt), (unsigned long)sp); - - /* - * active_mmu_pages must be a FIFO list, as kvm_zap_obsolete_pages() - * depends on valid pages being added to the head of the list. See - * comments in kvm_zap_obsolete_pages(). - */ - sp->mmu_valid_gen = vcpu->kvm->arch.mmu_valid_gen; - list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages); - kvm_mod_used_mmu_pages(vcpu->kvm, +1); - return sp; -} - static void mark_unsync(u64 *spte); static void kvm_mmu_mark_parents_unsync(struct kvm_mmu_page *sp) { @@ -2072,7 +2051,23 @@ static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm_vcpu *vcpu, struct hlist_head *sp_list, union kvm_mmu_page_role role) { - struct kvm_mmu_page *sp = kvm_mmu_alloc_page(vcpu, role.direct); + struct kvm_mmu_page *sp; + + sp = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache); + sp->spt = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_shadow_page_cache); + if (!role.direct) + sp->gfns = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_gfn_array_cache); + + set_page_private(virt_to_page(sp->spt), (unsigned long)sp); + + /* + * active_mmu_pages must be a FIFO list, as kvm_zap_obsolete_pages() + * depends on valid pages being added to the head of the list. See + * comments in kvm_zap_obsolete_pages(). + */ + sp->mmu_valid_gen = vcpu->kvm->arch.mmu_valid_gen; + list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages); + kvm_mod_used_mmu_pages(vcpu->kvm, +1); sp->gfn = gfn; sp->role = role; From 876546436db9775caee4cadf78edd2b5bf72ac84 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:55 -0400 Subject: [PATCH 0641/1436] KVM: x86/mmu: Rename shadow MMU functions that deal with shadow pages Rename 2 functions: kvm_mmu_get_page() -> kvm_mmu_get_shadow_page() kvm_mmu_free_page() -> kvm_mmu_free_shadow_page() This change makes it clear that these functions deal with shadow pages rather than struct pages. It also aligns these functions with the naming scheme for kvm_mmu_find_shadow_page() and kvm_mmu_alloc_shadow_page(). Prefer "shadow_page" over the shorter "sp" since these are core functions and the line lengths aren't terrible. No functional change intended. Reviewed-by: Sean Christopherson Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-9-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 8b84cdd8c6cd..bd45364bf465 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1626,7 +1626,7 @@ static inline void kvm_mod_used_mmu_pages(struct kvm *kvm, long nr) percpu_counter_add(&kvm_total_used_mmu_pages, nr); } -static void kvm_mmu_free_page(struct kvm_mmu_page *sp) +static void kvm_mmu_free_shadow_page(struct kvm_mmu_page *sp) { MMU_WARN_ON(!is_empty_shadow_page(sp->spt)); hlist_del(&sp->hash_link); @@ -2081,8 +2081,9 @@ static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm_vcpu *vcpu, return sp; } -static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu, gfn_t gfn, - union kvm_mmu_page_role role) +static struct kvm_mmu_page *kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, + gfn_t gfn, + union kvm_mmu_page_role role) { struct hlist_head *sp_list; struct kvm_mmu_page *sp; @@ -2146,7 +2147,7 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu, union kvm_mmu_page_role role; role = kvm_mmu_child_role(sptep, direct, access); - return kvm_mmu_get_page(vcpu, gfn, role); + return kvm_mmu_get_shadow_page(vcpu, gfn, role); } static void shadow_walk_init_using_root(struct kvm_shadow_walk_iterator *iterator, @@ -2422,7 +2423,7 @@ static void kvm_mmu_commit_zap_page(struct kvm *kvm, list_for_each_entry_safe(sp, nsp, invalid_list, link) { WARN_ON(!sp->role.invalid || sp->root_count); - kvm_mmu_free_page(sp); + kvm_mmu_free_shadow_page(sp); } } @@ -3415,7 +3416,7 @@ static hpa_t mmu_alloc_root(struct kvm_vcpu *vcpu, gfn_t gfn, int quadrant, WARN_ON_ONCE(quadrant && !role.has_4_byte_gpte); WARN_ON_ONCE(role.direct && role.has_4_byte_gpte); - sp = kvm_mmu_get_page(vcpu, gfn, role); + sp = kvm_mmu_get_shadow_page(vcpu, gfn, role); ++sp->root_count; return __pa(sp->spt); From be911771330a2ae0938d452fd89a8df085533134 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:56 -0400 Subject: [PATCH 0642/1436] KVM: x86/mmu: Move guest PT write-protection to account_shadowed() Move the code that write-protects newly-shadowed guest page tables into account_shadowed(). This avoids a extra gfn-to-memslot lookup and is a more logical place for this code to live. But most importantly, this reduces kvm_mmu_alloc_shadow_page()'s reliance on having a struct kvm_vcpu pointer, which will be necessary when creating new shadow pages during VM ioctls for eager page splitting. Note, it is safe to drop the role.level == PG_LEVEL_4K check since account_shadowed() returns early if role.level > PG_LEVEL_4K. No functional change intended. Reviewed-by: Sean Christopherson Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-10-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index bd45364bf465..2602c3642f23 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -766,6 +766,9 @@ static void account_shadowed(struct kvm *kvm, struct kvm_mmu_page *sp) KVM_PAGE_TRACK_WRITE); kvm_mmu_gfn_disallow_lpage(slot, gfn); + + if (kvm_mmu_slot_gfn_write_protect(kvm, slot, gfn, PG_LEVEL_4K)) + kvm_flush_remote_tlbs_with_address(kvm, gfn, 1); } void account_huge_nx_page(struct kvm *kvm, struct kvm_mmu_page *sp) @@ -2072,11 +2075,8 @@ static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm_vcpu *vcpu, sp->gfn = gfn; sp->role = role; hlist_add_head(&sp->hash_link, sp_list); - if (sp_has_gptes(sp)) { + if (sp_has_gptes(sp)) account_shadowed(vcpu->kvm, sp); - if (role.level == PG_LEVEL_4K && kvm_vcpu_write_protect_gfn(vcpu, gfn)) - kvm_flush_remote_tlbs_with_address(vcpu->kvm, gfn, 1); - } return sp; } From 2f8b1b539be37f6bbc4827dfe3320935976fefa4 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:57 -0400 Subject: [PATCH 0643/1436] KVM: x86/mmu: Pass memory caches to allocate SPs separately Refactor kvm_mmu_alloc_shadow_page() to receive the caches from which it will allocate the various pieces of memory for shadow pages as a parameter, rather than deriving them from the vcpu pointer. This will be useful in a future commit where shadow pages are allocated during VM ioctls for eager page splitting, and thus will use a different set of caches. Preemptively pull the caches out all the way to kvm_mmu_get_shadow_page() since eager page splitting will not be calling kvm_mmu_alloc_shadow_page() directly. No functional change intended. Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-11-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 2602c3642f23..fab417e7bf6c 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2049,17 +2049,25 @@ out: return sp; } +/* Caches used when allocating a new shadow page. */ +struct shadow_page_caches { + struct kvm_mmu_memory_cache *page_header_cache; + struct kvm_mmu_memory_cache *shadow_page_cache; + struct kvm_mmu_memory_cache *gfn_array_cache; +}; + static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm_vcpu *vcpu, + struct shadow_page_caches *caches, gfn_t gfn, struct hlist_head *sp_list, union kvm_mmu_page_role role) { struct kvm_mmu_page *sp; - sp = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_page_header_cache); - sp->spt = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_shadow_page_cache); + sp = kvm_mmu_memory_cache_alloc(caches->page_header_cache); + sp->spt = kvm_mmu_memory_cache_alloc(caches->shadow_page_cache); if (!role.direct) - sp->gfns = kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_gfn_array_cache); + sp->gfns = kvm_mmu_memory_cache_alloc(caches->gfn_array_cache); set_page_private(virt_to_page(sp->spt), (unsigned long)sp); @@ -2081,9 +2089,10 @@ static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm_vcpu *vcpu, return sp; } -static struct kvm_mmu_page *kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, - gfn_t gfn, - union kvm_mmu_page_role role) +static struct kvm_mmu_page *__kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, + struct shadow_page_caches *caches, + gfn_t gfn, + union kvm_mmu_page_role role) { struct hlist_head *sp_list; struct kvm_mmu_page *sp; @@ -2094,13 +2103,26 @@ static struct kvm_mmu_page *kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, sp = kvm_mmu_find_shadow_page(vcpu, gfn, sp_list, role); if (!sp) { created = true; - sp = kvm_mmu_alloc_shadow_page(vcpu, gfn, sp_list, role); + sp = kvm_mmu_alloc_shadow_page(vcpu, caches, gfn, sp_list, role); } trace_kvm_mmu_get_page(sp, created); return sp; } +static struct kvm_mmu_page *kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, + gfn_t gfn, + union kvm_mmu_page_role role) +{ + struct shadow_page_caches caches = { + .page_header_cache = &vcpu->arch.mmu_page_header_cache, + .shadow_page_cache = &vcpu->arch.mmu_shadow_page_cache, + .gfn_array_cache = &vcpu->arch.mmu_gfn_array_cache, + }; + + return __kvm_mmu_get_shadow_page(vcpu, &caches, gfn, role); +} + static union kvm_mmu_page_role kvm_mmu_child_role(u64 *sptep, bool direct, unsigned int access) { struct kvm_mmu_page *parent_sp = sptep_to_sp(sptep); From 336081fb3f26a3e819838317c011aee41d88e676 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:58 -0400 Subject: [PATCH 0644/1436] KVM: x86/mmu: Replace vcpu with kvm in kvm_mmu_alloc_shadow_page() The vcpu pointer in kvm_mmu_alloc_shadow_page() is only used to get the kvm pointer. So drop the vcpu pointer and just pass in the kvm pointer. No functional change intended. Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-12-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index fab417e7bf6c..c5a88e8d1b53 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2056,7 +2056,7 @@ struct shadow_page_caches { struct kvm_mmu_memory_cache *gfn_array_cache; }; -static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm_vcpu *vcpu, +static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm *kvm, struct shadow_page_caches *caches, gfn_t gfn, struct hlist_head *sp_list, @@ -2076,15 +2076,15 @@ static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm_vcpu *vcpu, * depends on valid pages being added to the head of the list. See * comments in kvm_zap_obsolete_pages(). */ - sp->mmu_valid_gen = vcpu->kvm->arch.mmu_valid_gen; - list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages); - kvm_mod_used_mmu_pages(vcpu->kvm, +1); + sp->mmu_valid_gen = kvm->arch.mmu_valid_gen; + list_add(&sp->link, &kvm->arch.active_mmu_pages); + kvm_mod_used_mmu_pages(kvm, +1); sp->gfn = gfn; sp->role = role; hlist_add_head(&sp->hash_link, sp_list); if (sp_has_gptes(sp)) - account_shadowed(vcpu->kvm, sp); + account_shadowed(kvm, sp); return sp; } @@ -2103,7 +2103,7 @@ static struct kvm_mmu_page *__kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, sp = kvm_mmu_find_shadow_page(vcpu, gfn, sp_list, role); if (!sp) { created = true; - sp = kvm_mmu_alloc_shadow_page(vcpu, caches, gfn, sp_list, role); + sp = kvm_mmu_alloc_shadow_page(vcpu->kvm, caches, gfn, sp_list, role); } trace_kvm_mmu_get_page(sp, created); From 3cc736b35799ab330225d89976fac36794e4bec0 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:26:59 -0400 Subject: [PATCH 0645/1436] KVM: x86/mmu: Pass kvm pointer separately from vcpu to kvm_mmu_find_shadow_page() Get the kvm pointer from the caller, rather than deriving it from vcpu->kvm, and plumb the kvm pointer all the way from kvm_mmu_get_shadow_page(). With this change in place, the vcpu pointer is only needed to sync indirect shadow pages. In other words, __kvm_mmu_get_shadow_page() can now be used to get *direct* shadow pages without a vcpu pointer. This enables eager page splitting, which needs to allocate direct shadow pages during VM ioctls. No functional change intended. Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-13-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index c5a88e8d1b53..88b3f3c2c8b1 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1975,7 +1975,8 @@ static void clear_sp_write_flooding_count(u64 *spte) __clear_sp_write_flooding_count(sptep_to_sp(spte)); } -static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm_vcpu *vcpu, +static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm *kvm, + struct kvm_vcpu *vcpu, gfn_t gfn, struct hlist_head *sp_list, union kvm_mmu_page_role role) @@ -1985,7 +1986,7 @@ static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm_vcpu *vcpu, int collisions = 0; LIST_HEAD(invalid_list); - for_each_valid_sp(vcpu->kvm, sp, sp_list) { + for_each_valid_sp(kvm, sp, sp_list) { if (sp->gfn != gfn) { collisions++; continue; @@ -2002,7 +2003,7 @@ static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm_vcpu *vcpu, * upper-level page will be write-protected. */ if (role.level > PG_LEVEL_4K && sp->unsync) - kvm_mmu_prepare_zap_page(vcpu->kvm, sp, + kvm_mmu_prepare_zap_page(kvm, sp, &invalid_list); continue; } @@ -2030,7 +2031,7 @@ static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm_vcpu *vcpu, WARN_ON(!list_empty(&invalid_list)); if (ret > 0) - kvm_flush_remote_tlbs(vcpu->kvm); + kvm_flush_remote_tlbs(kvm); } __clear_sp_write_flooding_count(sp); @@ -2039,13 +2040,13 @@ static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm_vcpu *vcpu, } sp = NULL; - ++vcpu->kvm->stat.mmu_cache_miss; + ++kvm->stat.mmu_cache_miss; out: - kvm_mmu_commit_zap_page(vcpu->kvm, &invalid_list); + kvm_mmu_commit_zap_page(kvm, &invalid_list); - if (collisions > vcpu->kvm->stat.max_mmu_page_hash_collisions) - vcpu->kvm->stat.max_mmu_page_hash_collisions = collisions; + if (collisions > kvm->stat.max_mmu_page_hash_collisions) + kvm->stat.max_mmu_page_hash_collisions = collisions; return sp; } @@ -2089,7 +2090,8 @@ static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm *kvm, return sp; } -static struct kvm_mmu_page *__kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, +static struct kvm_mmu_page *__kvm_mmu_get_shadow_page(struct kvm *kvm, + struct kvm_vcpu *vcpu, struct shadow_page_caches *caches, gfn_t gfn, union kvm_mmu_page_role role) @@ -2098,12 +2100,12 @@ static struct kvm_mmu_page *__kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp; bool created = false; - sp_list = &vcpu->kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)]; + sp_list = &kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)]; - sp = kvm_mmu_find_shadow_page(vcpu, gfn, sp_list, role); + sp = kvm_mmu_find_shadow_page(kvm, vcpu, gfn, sp_list, role); if (!sp) { created = true; - sp = kvm_mmu_alloc_shadow_page(vcpu->kvm, caches, gfn, sp_list, role); + sp = kvm_mmu_alloc_shadow_page(kvm, caches, gfn, sp_list, role); } trace_kvm_mmu_get_page(sp, created); @@ -2120,7 +2122,7 @@ static struct kvm_mmu_page *kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, .gfn_array_cache = &vcpu->arch.mmu_gfn_array_cache, }; - return __kvm_mmu_get_shadow_page(vcpu, &caches, gfn, role); + return __kvm_mmu_get_shadow_page(vcpu->kvm, vcpu, &caches, gfn, role); } static union kvm_mmu_page_role kvm_mmu_child_role(u64 *sptep, bool direct, unsigned int access) From cbd858b17e379f727c6bf1eaedde7b1a44e75b40 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:27:00 -0400 Subject: [PATCH 0646/1436] KVM: x86/mmu: Allow NULL @vcpu in kvm_mmu_find_shadow_page() Allow @vcpu to be NULL in kvm_mmu_find_shadow_page() (and its only caller __kvm_mmu_get_shadow_page()). @vcpu is only required to sync indirect shadow pages, so it's safe to pass in NULL when looking up direct shadow pages. This will be used for doing eager page splitting, which allocates direct shadow pages from the context of a VM ioctl without access to a vCPU pointer. Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-14-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 88b3f3c2c8b1..a7748c5a2385 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1975,6 +1975,12 @@ static void clear_sp_write_flooding_count(u64 *spte) __clear_sp_write_flooding_count(sptep_to_sp(spte)); } +/* + * The vCPU is required when finding indirect shadow pages; the shadow + * page may already exist and syncing it needs the vCPU pointer in + * order to read guest page tables. Direct shadow pages are never + * unsync, thus @vcpu can be NULL if @role.direct is true. + */ static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm *kvm, struct kvm_vcpu *vcpu, gfn_t gfn, @@ -2013,6 +2019,9 @@ static struct kvm_mmu_page *kvm_mmu_find_shadow_page(struct kvm *kvm, goto out; if (sp->unsync) { + if (KVM_BUG_ON(!vcpu, kvm)) + break; + /* * The page is good, but is stale. kvm_sync_page does * get the latest guest state, but (unlike mmu_unsync_children) @@ -2090,6 +2099,7 @@ static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm *kvm, return sp; } +/* Note, @vcpu may be NULL if @role.direct is true; see kvm_mmu_find_shadow_page. */ static struct kvm_mmu_page *__kvm_mmu_get_shadow_page(struct kvm *kvm, struct kvm_vcpu *vcpu, struct shadow_page_caches *caches, From 6ec6509eea39ee249550a398fd1790b26833675d Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:27:01 -0400 Subject: [PATCH 0647/1436] KVM: x86/mmu: Pass const memslot to rmap_add() Constify rmap_add()'s @slot parameter; it is simply passed on to gfn_to_rmap(), which takes a const memslot. No functional change intended. Reviewed-by: Ben Gardon Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-15-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index a7748c5a2385..45a4e85c0b2c 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1556,7 +1556,7 @@ static bool kvm_test_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, #define RMAP_RECYCLE_THRESHOLD 1000 -static void rmap_add(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot, +static void rmap_add(struct kvm_vcpu *vcpu, const struct kvm_memory_slot *slot, u64 *spte, gfn_t gfn) { struct kvm_mmu_page *sp; From 2ff9039a75a8c19fbbcef7fe74ea61a10e4639f3 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:27:02 -0400 Subject: [PATCH 0648/1436] KVM: x86/mmu: Decouple rmap_add() and link_shadow_page() from kvm_vcpu Allow adding new entries to the rmap and linking shadow pages without a struct kvm_vcpu pointer by moving the implementation of rmap_add() and link_shadow_page() into inner helper functions. No functional change intended. Reviewed-by: Ben Gardon Reviewed-by: Peter Xu Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-16-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 47 ++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 45a4e85c0b2c..a8cdbe2958d9 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -673,11 +673,6 @@ static void mmu_free_memory_caches(struct kvm_vcpu *vcpu) kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_header_cache); } -static struct pte_list_desc *mmu_alloc_pte_list_desc(struct kvm_vcpu *vcpu) -{ - return kvm_mmu_memory_cache_alloc(&vcpu->arch.mmu_pte_list_desc_cache); -} - static void mmu_free_pte_list_desc(struct pte_list_desc *pte_list_desc) { kmem_cache_free(pte_list_desc_cache, pte_list_desc); @@ -832,7 +827,7 @@ gfn_to_memslot_dirty_bitmap(struct kvm_vcpu *vcpu, gfn_t gfn, /* * Returns the number of pointers in the rmap chain, not counting the new one. */ -static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte, +static int pte_list_add(struct kvm_mmu_memory_cache *cache, u64 *spte, struct kvm_rmap_head *rmap_head) { struct pte_list_desc *desc; @@ -843,7 +838,7 @@ static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte, rmap_head->val = (unsigned long)spte; } else if (!(rmap_head->val & 1)) { rmap_printk("%p %llx 1->many\n", spte, *spte); - desc = mmu_alloc_pte_list_desc(vcpu); + desc = kvm_mmu_memory_cache_alloc(cache); desc->sptes[0] = (u64 *)rmap_head->val; desc->sptes[1] = spte; desc->spte_count = 2; @@ -855,7 +850,7 @@ static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte, while (desc->spte_count == PTE_LIST_EXT) { count += PTE_LIST_EXT; if (!desc->more) { - desc->more = mmu_alloc_pte_list_desc(vcpu); + desc->more = kvm_mmu_memory_cache_alloc(cache); desc = desc->more; desc->spte_count = 0; break; @@ -1556,8 +1551,10 @@ static bool kvm_test_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, #define RMAP_RECYCLE_THRESHOLD 1000 -static void rmap_add(struct kvm_vcpu *vcpu, const struct kvm_memory_slot *slot, - u64 *spte, gfn_t gfn) +static void __rmap_add(struct kvm *kvm, + struct kvm_mmu_memory_cache *cache, + const struct kvm_memory_slot *slot, + u64 *spte, gfn_t gfn) { struct kvm_mmu_page *sp; struct kvm_rmap_head *rmap_head; @@ -1566,15 +1563,23 @@ static void rmap_add(struct kvm_vcpu *vcpu, const struct kvm_memory_slot *slot, sp = sptep_to_sp(spte); kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn); rmap_head = gfn_to_rmap(gfn, sp->role.level, slot); - rmap_count = pte_list_add(vcpu, spte, rmap_head); + rmap_count = pte_list_add(cache, spte, rmap_head); if (rmap_count > RMAP_RECYCLE_THRESHOLD) { - kvm_unmap_rmapp(vcpu->kvm, rmap_head, NULL, gfn, sp->role.level, __pte(0)); + kvm_unmap_rmapp(kvm, rmap_head, NULL, gfn, sp->role.level, __pte(0)); kvm_flush_remote_tlbs_with_address( - vcpu->kvm, sp->gfn, KVM_PAGES_PER_HPAGE(sp->role.level)); + kvm, sp->gfn, KVM_PAGES_PER_HPAGE(sp->role.level)); } } +static void rmap_add(struct kvm_vcpu *vcpu, const struct kvm_memory_slot *slot, + u64 *spte, gfn_t gfn) +{ + struct kvm_mmu_memory_cache *cache = &vcpu->arch.mmu_pte_list_desc_cache; + + __rmap_add(vcpu->kvm, cache, slot, spte, gfn); +} + bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) { bool young = false; @@ -1645,13 +1650,13 @@ static unsigned kvm_page_table_hashfn(gfn_t gfn) return hash_64(gfn, KVM_MMU_HASH_SHIFT); } -static void mmu_page_add_parent_pte(struct kvm_vcpu *vcpu, +static void mmu_page_add_parent_pte(struct kvm_mmu_memory_cache *cache, struct kvm_mmu_page *sp, u64 *parent_pte) { if (!parent_pte) return; - pte_list_add(vcpu, parent_pte, &sp->parent_ptes); + pte_list_add(cache, parent_pte, &sp->parent_ptes); } static void mmu_page_remove_parent_pte(struct kvm_mmu_page *sp, @@ -2247,8 +2252,8 @@ static void shadow_walk_next(struct kvm_shadow_walk_iterator *iterator) __shadow_walk_next(iterator, *iterator->sptep); } -static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep, - struct kvm_mmu_page *sp) +static void __link_shadow_page(struct kvm_mmu_memory_cache *cache, u64 *sptep, + struct kvm_mmu_page *sp) { u64 spte; @@ -2258,12 +2263,18 @@ static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep, mmu_spte_set(sptep, spte); - mmu_page_add_parent_pte(vcpu, sp, sptep); + mmu_page_add_parent_pte(cache, sp, sptep); if (sp->unsync_children || sp->unsync) mark_unsync(sptep); } +static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep, + struct kvm_mmu_page *sp) +{ + __link_shadow_page(&vcpu->arch.mmu_pte_list_desc_cache, sptep, sp); +} + static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned direct_access) { From 81cb4657e9f0d931216fc22966ddf68a5151a206 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:27:03 -0400 Subject: [PATCH 0649/1436] KVM: x86/mmu: Update page stats in __rmap_add() Update the page stats in __rmap_add() rather than at the call site. This will avoid having to manually update page stats when splitting huge pages in a subsequent commit. No functional change intended. Reviewed-by: Ben Gardon Reviewed-by: Peter Xu Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-17-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index a8cdbe2958d9..7cca28d89a85 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1562,6 +1562,8 @@ static void __rmap_add(struct kvm *kvm, sp = sptep_to_sp(spte); kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn); + kvm_update_page_stats(kvm, sp->role.level, 1); + rmap_head = gfn_to_rmap(gfn, sp->role.level, slot); rmap_count = pte_list_add(cache, spte, rmap_head); @@ -2783,7 +2785,6 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot, if (!was_rmapped) { WARN_ON_ONCE(ret == RET_PF_SPURIOUS); - kvm_update_page_stats(vcpu->kvm, level, 1); rmap_add(vcpu, slot, sptep, gfn); } From 6a97575d5cffb71aa9a95d33f0ca03c8a4bb3b2b Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:27:04 -0400 Subject: [PATCH 0650/1436] KVM: x86/mmu: Cache the access bits of shadowed translations Splitting huge pages requires allocating/finding shadow pages to replace the huge page. Shadow pages are keyed, in part, off the guest access permissions they are shadowing. For fully direct MMUs, there is no shadowing so the access bits in the shadow page role are always ACC_ALL. But during shadow paging, the guest can enforce whatever access permissions it wants. In particular, eager page splitting needs to know the permissions to use for the subpages, but KVM cannot retrieve them from the guest page tables because eager page splitting does not have a vCPU. Fortunately, the guest access permissions are easy to cache whenever page faults or FNAME(sync_page) update the shadow page tables; this is an extension of the existing cache of the shadowed GFNs in the gfns array of the shadow page. The access bits only take up 3 bits, which leaves 61 bits left over for gfns, which is more than enough. Now that the gfns array caches more information than just GFNs, rename it to shadowed_translation. While here, preemptively fix up the WARN_ON() that detects gfn mismatches in direct SPs. The WARN_ON() was paired with a pr_err_ratelimited(), which means that users could sometimes see the WARN without the accompanying error message. Fix this by outputting the error message as part of the WARN splat, and opportunistically make them WARN_ONCE() because if these ever fire, they are all but guaranteed to fire a lot and will bring down the kernel. Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-18-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/mmu/mmu.c | 85 +++++++++++++++++++++++---------- arch/x86/kvm/mmu/mmu_internal.h | 17 ++++++- arch/x86/kvm/mmu/paging_tmpl.h | 9 +++- 4 files changed, 84 insertions(+), 29 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 7e4c31b57a75..64efe8c90c31 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -713,7 +713,7 @@ struct kvm_vcpu_arch { struct kvm_mmu_memory_cache mmu_pte_list_desc_cache; struct kvm_mmu_memory_cache mmu_shadow_page_cache; - struct kvm_mmu_memory_cache mmu_gfn_array_cache; + struct kvm_mmu_memory_cache mmu_shadowed_info_cache; struct kvm_mmu_memory_cache mmu_page_header_cache; /* diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 7cca28d89a85..13a059ad5dc7 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -656,7 +656,7 @@ static int mmu_topup_memory_caches(struct kvm_vcpu *vcpu, bool maybe_indirect) if (r) return r; if (maybe_indirect) { - r = kvm_mmu_topup_memory_cache(&vcpu->arch.mmu_gfn_array_cache, + r = kvm_mmu_topup_memory_cache(&vcpu->arch.mmu_shadowed_info_cache, PT64_ROOT_MAX_LEVEL); if (r) return r; @@ -669,7 +669,7 @@ static void mmu_free_memory_caches(struct kvm_vcpu *vcpu) { kvm_mmu_free_memory_cache(&vcpu->arch.mmu_pte_list_desc_cache); kvm_mmu_free_memory_cache(&vcpu->arch.mmu_shadow_page_cache); - kvm_mmu_free_memory_cache(&vcpu->arch.mmu_gfn_array_cache); + kvm_mmu_free_memory_cache(&vcpu->arch.mmu_shadowed_info_cache); kvm_mmu_free_memory_cache(&vcpu->arch.mmu_page_header_cache); } @@ -678,34 +678,68 @@ static void mmu_free_pte_list_desc(struct pte_list_desc *pte_list_desc) kmem_cache_free(pte_list_desc_cache, pte_list_desc); } +static bool sp_has_gptes(struct kvm_mmu_page *sp); + static gfn_t kvm_mmu_page_get_gfn(struct kvm_mmu_page *sp, int index) { if (sp->role.passthrough) return sp->gfn; if (!sp->role.direct) - return sp->gfns[index]; + return sp->shadowed_translation[index] >> PAGE_SHIFT; return sp->gfn + (index << ((sp->role.level - 1) * SPTE_LEVEL_BITS)); } -static void kvm_mmu_page_set_gfn(struct kvm_mmu_page *sp, int index, gfn_t gfn) +/* + * For leaf SPTEs, fetch the *guest* access permissions being shadowed. Note + * that the SPTE itself may have a more constrained access permissions that + * what the guest enforces. For example, a guest may create an executable + * huge PTE but KVM may disallow execution to mitigate iTLB multihit. + */ +static u32 kvm_mmu_page_get_access(struct kvm_mmu_page *sp, int index) { - if (sp->role.passthrough) { - WARN_ON_ONCE(gfn != sp->gfn); + if (sp_has_gptes(sp)) + return sp->shadowed_translation[index] & ACC_ALL; + + /* + * For direct MMUs (e.g. TDP or non-paging guests) or passthrough SPs, + * KVM is not shadowing any guest page tables, so the "guest access + * permissions" are just ACC_ALL. + * + * For direct SPs in indirect MMUs (shadow paging), i.e. when KVM + * is shadowing a guest huge page with small pages, the guest access + * permissions being shadowed are the access permissions of the huge + * page. + * + * In both cases, sp->role.access contains the correct access bits. + */ + return sp->role.access; +} + +static void kvm_mmu_page_set_translation(struct kvm_mmu_page *sp, int index, gfn_t gfn, u32 access) +{ + if (sp_has_gptes(sp)) { + sp->shadowed_translation[index] = (gfn << PAGE_SHIFT) | access; return; } - if (!sp->role.direct) { - sp->gfns[index] = gfn; - return; - } + WARN_ONCE(access != kvm_mmu_page_get_access(sp, index), + "access mismatch under %s page %llx (expected %u, got %u)\n", + sp->role.passthrough ? "passthrough" : "direct", + sp->gfn, kvm_mmu_page_get_access(sp, index), access); - if (WARN_ON(gfn != kvm_mmu_page_get_gfn(sp, index))) - pr_err_ratelimited("gfn mismatch under direct page %llx " - "(expected %llx, got %llx)\n", - sp->gfn, - kvm_mmu_page_get_gfn(sp, index), gfn); + WARN_ONCE(gfn != kvm_mmu_page_get_gfn(sp, index), + "gfn mismatch under %s page %llx (expected %llx, got %llx)\n", + sp->role.passthrough ? "passthrough" : "direct", + sp->gfn, kvm_mmu_page_get_gfn(sp, index), gfn); +} + +static void kvm_mmu_page_set_access(struct kvm_mmu_page *sp, int index, u32 access) +{ + gfn_t gfn = kvm_mmu_page_get_gfn(sp, index); + + kvm_mmu_page_set_translation(sp, index, gfn, access); } /* @@ -1554,14 +1588,14 @@ static bool kvm_test_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, static void __rmap_add(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, const struct kvm_memory_slot *slot, - u64 *spte, gfn_t gfn) + u64 *spte, gfn_t gfn, u32 access) { struct kvm_mmu_page *sp; struct kvm_rmap_head *rmap_head; int rmap_count; sp = sptep_to_sp(spte); - kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn); + kvm_mmu_page_set_translation(sp, spte - sp->spt, gfn, access); kvm_update_page_stats(kvm, sp->role.level, 1); rmap_head = gfn_to_rmap(gfn, sp->role.level, slot); @@ -1575,11 +1609,11 @@ static void __rmap_add(struct kvm *kvm, } static void rmap_add(struct kvm_vcpu *vcpu, const struct kvm_memory_slot *slot, - u64 *spte, gfn_t gfn) + u64 *spte, gfn_t gfn, u32 access) { struct kvm_mmu_memory_cache *cache = &vcpu->arch.mmu_pte_list_desc_cache; - __rmap_add(vcpu->kvm, cache, slot, spte, gfn); + __rmap_add(vcpu->kvm, cache, slot, spte, gfn, access); } bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) @@ -1643,7 +1677,7 @@ static void kvm_mmu_free_shadow_page(struct kvm_mmu_page *sp) list_del(&sp->link); free_page((unsigned long)sp->spt); if (!sp->role.direct) - free_page((unsigned long)sp->gfns); + free_page((unsigned long)sp->shadowed_translation); kmem_cache_free(mmu_page_header_cache, sp); } @@ -2070,7 +2104,7 @@ out: struct shadow_page_caches { struct kvm_mmu_memory_cache *page_header_cache; struct kvm_mmu_memory_cache *shadow_page_cache; - struct kvm_mmu_memory_cache *gfn_array_cache; + struct kvm_mmu_memory_cache *shadowed_info_cache; }; static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm *kvm, @@ -2084,7 +2118,7 @@ static struct kvm_mmu_page *kvm_mmu_alloc_shadow_page(struct kvm *kvm, sp = kvm_mmu_memory_cache_alloc(caches->page_header_cache); sp->spt = kvm_mmu_memory_cache_alloc(caches->shadow_page_cache); if (!role.direct) - sp->gfns = kvm_mmu_memory_cache_alloc(caches->gfn_array_cache); + sp->shadowed_translation = kvm_mmu_memory_cache_alloc(caches->shadowed_info_cache); set_page_private(virt_to_page(sp->spt), (unsigned long)sp); @@ -2136,7 +2170,7 @@ static struct kvm_mmu_page *kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, struct shadow_page_caches caches = { .page_header_cache = &vcpu->arch.mmu_page_header_cache, .shadow_page_cache = &vcpu->arch.mmu_shadow_page_cache, - .gfn_array_cache = &vcpu->arch.mmu_gfn_array_cache, + .shadowed_info_cache = &vcpu->arch.mmu_shadowed_info_cache, }; return __kvm_mmu_get_shadow_page(vcpu->kvm, vcpu, &caches, gfn, role); @@ -2785,7 +2819,10 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot, if (!was_rmapped) { WARN_ON_ONCE(ret == RET_PF_SPURIOUS); - rmap_add(vcpu, slot, sptep, gfn); + rmap_add(vcpu, slot, sptep, gfn, pte_access); + } else { + /* Already rmapped but the pte_access bits may have changed. */ + kvm_mmu_page_set_access(sp, sptep - sp->spt, pte_access); } return ret; diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index bb9d12ac0db3..ae2d660e2dab 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -67,8 +67,21 @@ struct kvm_mmu_page { gfn_t gfn; u64 *spt; - /* hold the gfn of each spte inside spt */ - gfn_t *gfns; + + /* + * Stores the result of the guest translation being shadowed by each + * SPTE. KVM shadows two types of guest translations: nGPA -> GPA + * (shadow EPT/NPT) and GVA -> GPA (traditional shadow paging). In both + * cases the result of the translation is a GPA and a set of access + * constraints. + * + * The GFN is stored in the upper bits (PAGE_SHIFT) and the shadowed + * access permissions are stored in the lower bits. Note, for + * convenience and uniformity across guests, the access permissions are + * stored in KVM format (e.g. ACC_EXEC_MASK) not the raw guest format. + */ + u64 *shadowed_translation; + /* Currently serving as active root */ union { int root_count; diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 6ecdd7a41a82..24f292f3f93f 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -985,7 +985,8 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, } /* - * Using the cached information from sp->gfns is safe because: + * Using the information in sp->shadowed_translation (kvm_mmu_page_get_gfn()) is + * safe because: * - The spte has a reference to the struct page, so the pfn for a given gfn * can't change unless all sptes pointing to it are nuked first. * @@ -1067,12 +1068,16 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp) * "present" bit, as all other paging modes will create a * read-only SPTE if pte_access is zero. */ - if ((!pte_access && !shadow_present_mask) || gfn != sp->gfns[i]) { + if ((!pte_access && !shadow_present_mask) || + gfn != kvm_mmu_page_get_gfn(sp, i)) { drop_spte(vcpu->kvm, &sp->spt[i]); flush = true; continue; } + /* Update the shadowed access bits in case they changed. */ + kvm_mmu_page_set_access(sp, i, pte_access); + sptep = &sp->spt[i]; spte = *sptep; host_writable = spte & shadow_host_writable_mask; From 47855da0555a46eb4f98f5e5cae98525daf83ff9 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:27:05 -0400 Subject: [PATCH 0651/1436] KVM: x86/mmu: Extend make_huge_page_split_spte() for the shadow MMU Currently make_huge_page_split_spte() assumes execute permissions can be granted to any 4K SPTE when splitting huge pages. This is true for the TDP MMU but is not necessarily true for the shadow MMU, since KVM may be shadowing a non-executable huge page. To fix this, pass in the role of the child shadow page where the huge page will be split and derive the execution permission from that. This is correct because huge pages are always split with direct shadow page and thus the shadow page role contains the correct access permissions. No functional change intended. Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-19-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/spte.c | 15 +++++++-------- arch/x86/kvm/mmu/spte.h | 4 ++-- arch/x86/kvm/mmu/tdp_mmu.c | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index db294c1beea2..fb1f17504138 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -246,11 +246,10 @@ static u64 make_spte_executable(u64 spte) * This is used during huge page splitting to build the SPTEs that make up the * new page table. */ -u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, int huge_level, +u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, union kvm_mmu_page_role role, int index) { u64 child_spte; - int child_level; if (WARN_ON_ONCE(!is_shadow_present_pte(huge_spte))) return 0; @@ -259,23 +258,23 @@ u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, int huge_level, return 0; child_spte = huge_spte; - child_level = huge_level - 1; /* * The child_spte already has the base address of the huge page being * split. So we just have to OR in the offset to the page at the next * lower level for the given index. */ - child_spte |= (index * KVM_PAGES_PER_HPAGE(child_level)) << PAGE_SHIFT; + child_spte |= (index * KVM_PAGES_PER_HPAGE(role.level)) << PAGE_SHIFT; - if (child_level == PG_LEVEL_4K) { + if (role.level == PG_LEVEL_4K) { child_spte &= ~PT_PAGE_SIZE_MASK; /* - * When splitting to a 4K page, mark the page executable as the - * NX hugepage mitigation no longer applies. + * When splitting to a 4K page where execution is allowed, mark + * the page executable as the NX hugepage mitigation no longer + * applies. */ - if (is_nx_huge_page_enabled(kvm)) + if ((role.access & ACC_EXEC_MASK) && is_nx_huge_page_enabled(kvm)) child_spte = make_spte_executable(child_spte); } diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h index 256f90587e8d..b5c855f5514f 100644 --- a/arch/x86/kvm/mmu/spte.h +++ b/arch/x86/kvm/mmu/spte.h @@ -421,8 +421,8 @@ bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, unsigned int pte_access, gfn_t gfn, kvm_pfn_t pfn, u64 old_spte, bool prefetch, bool can_unsync, bool host_writable, u64 *new_spte); -u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, int huge_level, - int index); +u64 make_huge_page_split_spte(struct kvm *kvm, u64 huge_spte, + union kvm_mmu_page_role role, int index); u64 make_nonleaf_spte(u64 *child_pt, bool ad_disabled); u64 make_mmio_spte(struct kvm_vcpu *vcpu, u64 gfn, unsigned int access); u64 mark_spte_for_access_track(u64 spte); diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 522e2532343b..f3a430d64975 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -1478,7 +1478,7 @@ static int tdp_mmu_split_huge_page(struct kvm *kvm, struct tdp_iter *iter, * not been linked in yet and thus is not reachable from any other CPU. */ for (i = 0; i < SPTE_ENT_PER_PAGE; i++) - sp->spt[i] = make_huge_page_split_spte(kvm, huge_spte, level, i); + sp->spt[i] = make_huge_page_split_spte(kvm, huge_spte, sp->role, i); /* * Replace the huge spte with a pointer to the populated lower level From 20d49186c0302015c229e23c7e63855cbacc8032 Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:27:06 -0400 Subject: [PATCH 0652/1436] KVM: x86/mmu: Zap collapsible SPTEs in shadow MMU at all possible levels Currently KVM only zaps collapsible 4KiB SPTEs in the shadow MMU. This is fine for now since KVM never creates intermediate huge pages during dirty logging. In other words, KVM always replaces 1GiB pages directly with 4KiB pages, so there is no reason to look for collapsible 2MiB pages. However, this will stop being true once the shadow MMU participates in eager page splitting. During eager page splitting, each 1GiB is first split into 2MiB pages and then those are split into 4KiB pages. The intermediate 2MiB pages may be left behind if an error condition causes eager page splitting to bail early. No functional change intended. Reviewed-by: Peter Xu Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-20-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 13a059ad5dc7..7fdbb9060e9d 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -6154,18 +6154,24 @@ restart: return need_tlb_flush; } +static void kvm_rmap_zap_collapsible_sptes(struct kvm *kvm, + const struct kvm_memory_slot *slot) +{ + /* + * Note, use KVM_MAX_HUGEPAGE_LEVEL - 1 since there's no need to zap + * pages that are already mapped at the maximum hugepage level. + */ + if (slot_handle_level(kvm, slot, kvm_mmu_zap_collapsible_spte, + PG_LEVEL_4K, KVM_MAX_HUGEPAGE_LEVEL - 1, true)) + kvm_arch_flush_remote_tlbs_memslot(kvm, slot); +} + void kvm_mmu_zap_collapsible_sptes(struct kvm *kvm, const struct kvm_memory_slot *slot) { if (kvm_memslots_have_rmaps(kvm)) { write_lock(&kvm->mmu_lock); - /* - * Zap only 4k SPTEs since the legacy MMU only supports dirty - * logging at a 4k granularity and never creates collapsible - * 2m SPTEs during dirty logging. - */ - if (slot_handle_level_4k(kvm, slot, kvm_mmu_zap_collapsible_spte, true)) - kvm_arch_flush_remote_tlbs_memslot(kvm, slot); + kvm_rmap_zap_collapsible_sptes(kvm, slot); write_unlock(&kvm->mmu_lock); } From 0cd8dc739833080aa0813cbd94d907a93e3a14c3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Jun 2022 15:27:07 -0400 Subject: [PATCH 0653/1436] KVM: x86/mmu: pull call to drop_large_spte() into __link_shadow_page() Before allocating a child shadow page table, all callers check whether the parent already points to a huge page and, if so, they drop that SPTE. This is done by drop_large_spte(). However, dropping the large SPTE is really only necessary before the sp is installed. While the sp is returned by kvm_mmu_get_child_sp(), installing it happens later in __link_shadow_page(). Move the call there instead of having it in each and every caller. To ensure that the shadow page is not linked twice if it was present, do _not_ opportunistically make kvm_mmu_get_child_sp() idempotent: instead, return an error value if the shadow page already existed. This is a bit more verbose, but clearer than NULL. Finally, now that the drop_large_spte() name is not taken anymore, remove the two underscores in front of __drop_large_spte(). Reviewed-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 43 +++++++++++++++++----------------- arch/x86/kvm/mmu/paging_tmpl.h | 31 +++++++++++------------- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 7fdbb9060e9d..192cb7dc4471 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1135,26 +1135,16 @@ static void drop_spte(struct kvm *kvm, u64 *sptep) rmap_remove(kvm, sptep); } - -static bool __drop_large_spte(struct kvm *kvm, u64 *sptep) +static void drop_large_spte(struct kvm *kvm, u64 *sptep) { - if (is_large_pte(*sptep)) { - WARN_ON(sptep_to_sp(sptep)->role.level == PG_LEVEL_4K); - drop_spte(kvm, sptep); - return true; - } + struct kvm_mmu_page *sp; - return false; -} + sp = sptep_to_sp(sptep); + WARN_ON(sp->role.level == PG_LEVEL_4K); -static void drop_large_spte(struct kvm_vcpu *vcpu, u64 *sptep) -{ - if (__drop_large_spte(vcpu->kvm, sptep)) { - struct kvm_mmu_page *sp = sptep_to_sp(sptep); - - kvm_flush_remote_tlbs_with_address(vcpu->kvm, sp->gfn, + drop_spte(kvm, sptep); + kvm_flush_remote_tlbs_with_address(kvm, sp->gfn, KVM_PAGES_PER_HPAGE(sp->role.level)); - } } /* @@ -2221,6 +2211,9 @@ static struct kvm_mmu_page *kvm_mmu_get_child_sp(struct kvm_vcpu *vcpu, { union kvm_mmu_page_role role; + if (is_shadow_present_pte(*sptep) && !is_large_pte(*sptep)) + return ERR_PTR(-EEXIST); + role = kvm_mmu_child_role(sptep, direct, access); return kvm_mmu_get_shadow_page(vcpu, gfn, role); } @@ -2288,13 +2281,21 @@ static void shadow_walk_next(struct kvm_shadow_walk_iterator *iterator) __shadow_walk_next(iterator, *iterator->sptep); } -static void __link_shadow_page(struct kvm_mmu_memory_cache *cache, u64 *sptep, +static void __link_shadow_page(struct kvm *kvm, + struct kvm_mmu_memory_cache *cache, u64 *sptep, struct kvm_mmu_page *sp) { u64 spte; BUILD_BUG_ON(VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK); + /* + * If an SPTE is present already, it must be a leaf and therefore + * a large one. Drop it and flush the TLB before installing sp. + */ + if (is_shadow_present_pte(*sptep)) + drop_large_spte(kvm, sptep); + spte = make_nonleaf_spte(sp->spt, sp_ad_disabled(sp)); mmu_spte_set(sptep, spte); @@ -2308,7 +2309,7 @@ static void __link_shadow_page(struct kvm_mmu_memory_cache *cache, u64 *sptep, static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep, struct kvm_mmu_page *sp) { - __link_shadow_page(&vcpu->arch.mmu_pte_list_desc_cache, sptep, sp); + __link_shadow_page(vcpu->kvm, &vcpu->arch.mmu_pte_list_desc_cache, sptep, sp); } static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep, @@ -3080,11 +3081,9 @@ static int __direct_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) if (it.level == fault->goal_level) break; - drop_large_spte(vcpu, it.sptep); - if (is_shadow_present_pte(*it.sptep)) - continue; - sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, true, ACC_ALL); + if (sp == ERR_PTR(-EEXIST)) + continue; link_shadow_page(vcpu, it.sptep, sp); if (fault->is_tdp && fault->huge_page_disallowed && diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 24f292f3f93f..2448fa8d8438 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -648,15 +648,13 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, gfn_t table_gfn; clear_sp_write_flooding_count(it.sptep); - drop_large_spte(vcpu, it.sptep); - sp = NULL; - if (!is_shadow_present_pte(*it.sptep)) { - table_gfn = gw->table_gfn[it.level - 2]; - access = gw->pt_access[it.level - 2]; - sp = kvm_mmu_get_child_sp(vcpu, it.sptep, table_gfn, - false, access); + table_gfn = gw->table_gfn[it.level - 2]; + access = gw->pt_access[it.level - 2]; + sp = kvm_mmu_get_child_sp(vcpu, it.sptep, table_gfn, + false, access); + if (sp != ERR_PTR(-EEXIST)) { /* * We must synchronize the pagetable before linking it * because the guest doesn't need to flush tlb when @@ -685,7 +683,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, if (FNAME(gpte_changed)(vcpu, gw, it.level - 1)) goto out_gpte_changed; - if (sp) + if (sp != ERR_PTR(-EEXIST)) link_shadow_page(vcpu, it.sptep, sp); } @@ -709,16 +707,15 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault, validate_direct_spte(vcpu, it.sptep, direct_access); - drop_large_spte(vcpu, it.sptep); + sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, + true, direct_access); + if (sp == ERR_PTR(-EEXIST)) + continue; - if (!is_shadow_present_pte(*it.sptep)) { - sp = kvm_mmu_get_child_sp(vcpu, it.sptep, base_gfn, - true, direct_access); - link_shadow_page(vcpu, it.sptep, sp); - if (fault->huge_page_disallowed && - fault->req_level >= it.level) - account_huge_nx_page(vcpu->kvm, sp); - } + link_shadow_page(vcpu, it.sptep, sp); + if (fault->huge_page_disallowed && + fault->req_level >= it.level) + account_huge_nx_page(vcpu->kvm, sp); } if (WARN_ON_ONCE(it.level != fault->goal_level)) From 837f66c71207542283831d0762c5dca3db5b397a Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:27:08 -0400 Subject: [PATCH 0654/1436] KVM: Allow for different capacities in kvm_mmu_memory_cache structs Allow the capacity of the kvm_mmu_memory_cache struct to be chosen at declaration time rather than being fixed for all declarations. This will be used in a follow-up commit to declare an cache in x86 with a capacity of 512+ objects without having to increase the capacity of all caches in KVM. This change requires each cache now specify its capacity at runtime, since the cache struct itself no longer has a fixed capacity known at compile time. To protect against someone accidentally defining a kvm_mmu_memory_cache struct directly (without the extra storage), this commit includes a WARN_ON() in kvm_mmu_topup_memory_cache(). In order to support different capacities, this commit changes the objects pointer array to be dynamically allocated the first time the cache is topped-up. While here, opportunistically clean up the stack-allocated kvm_mmu_memory_cache structs in riscv and arm64 to use designated initializers. No functional change intended. Reviewed-by: Marc Zyngier Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-22-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- arch/arm64/kvm/mmu.c | 2 +- arch/riscv/kvm/mmu.c | 5 +---- include/linux/kvm_host.h | 1 + include/linux/kvm_types.h | 6 +++++- virt/kvm/kvm_main.c | 33 ++++++++++++++++++++++++++++++--- 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index f5651a05b6a8..87f1cd0df36e 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -786,7 +786,7 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa, { phys_addr_t addr; int ret = 0; - struct kvm_mmu_memory_cache cache = { 0, __GFP_ZERO, NULL, }; + struct kvm_mmu_memory_cache cache = { .gfp_zero = __GFP_ZERO }; struct kvm_pgtable *pgt = kvm->arch.mmu.pgt; enum kvm_pgtable_prot prot = KVM_PGTABLE_PROT_DEVICE | KVM_PGTABLE_PROT_R | diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c index 1c00695ebee7..081f8d2b9cf3 100644 --- a/arch/riscv/kvm/mmu.c +++ b/arch/riscv/kvm/mmu.c @@ -350,10 +350,7 @@ static int gstage_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa, int ret = 0; unsigned long pfn; phys_addr_t addr, end; - struct kvm_mmu_memory_cache pcache; - - memset(&pcache, 0, sizeof(pcache)); - pcache.gfp_zero = __GFP_ZERO; + struct kvm_mmu_memory_cache pcache = { .gfp_zero = __GFP_ZERO }; end = (gpa + size + PAGE_SIZE - 1) & PAGE_MASK; pfn = __phys_to_pfn(hpa); diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index a2bbdf3ab086..3554e48406e4 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1356,6 +1356,7 @@ void kvm_flush_remote_tlbs(struct kvm *kvm); #ifdef KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE int kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int min); +int __kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int capacity, int min); int kvm_mmu_memory_cache_nr_free_objects(struct kvm_mmu_memory_cache *mc); void kvm_mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc); void *kvm_mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc); diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index f328a01db4fe..4d933518060f 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h @@ -85,12 +85,16 @@ struct gfn_to_pfn_cache { * MMU flows is problematic, as is triggering reclaim, I/O, etc... while * holding MMU locks. Note, these caches act more like prefetch buffers than * classical caches, i.e. objects are not returned to the cache on being freed. + * + * The @capacity field and @objects array are lazily initialized when the cache + * is topped up (__kvm_mmu_topup_memory_cache()). */ struct kvm_mmu_memory_cache { int nobjs; gfp_t gfp_zero; struct kmem_cache *kmem_cache; - void *objects[KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE]; + int capacity; + void **objects; }; #endif diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 5b8ae83e09d7..45188d11812c 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -396,14 +396,31 @@ static inline void *mmu_memory_cache_alloc_obj(struct kvm_mmu_memory_cache *mc, return (void *)__get_free_page(gfp_flags); } -int kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int min) +int __kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int capacity, int min) { + gfp_t gfp = GFP_KERNEL_ACCOUNT; void *obj; if (mc->nobjs >= min) return 0; - while (mc->nobjs < ARRAY_SIZE(mc->objects)) { - obj = mmu_memory_cache_alloc_obj(mc, GFP_KERNEL_ACCOUNT); + + if (unlikely(!mc->objects)) { + if (WARN_ON_ONCE(!capacity)) + return -EIO; + + mc->objects = kvmalloc_array(sizeof(void *), capacity, gfp); + if (!mc->objects) + return -ENOMEM; + + mc->capacity = capacity; + } + + /* It is illegal to request a different capacity across topups. */ + if (WARN_ON_ONCE(mc->capacity != capacity)) + return -EIO; + + while (mc->nobjs < mc->capacity) { + obj = mmu_memory_cache_alloc_obj(mc, gfp); if (!obj) return mc->nobjs >= min ? 0 : -ENOMEM; mc->objects[mc->nobjs++] = obj; @@ -411,6 +428,11 @@ int kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int min) return 0; } +int kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int min) +{ + return __kvm_mmu_topup_memory_cache(mc, KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE, min); +} + int kvm_mmu_memory_cache_nr_free_objects(struct kvm_mmu_memory_cache *mc) { return mc->nobjs; @@ -424,6 +446,11 @@ void kvm_mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc) else free_page((unsigned long)mc->objects[--mc->nobjs]); } + + kvfree(mc->objects); + + mc->objects = NULL; + mc->capacity = 0; } void *kvm_mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc) From ada51a9de7375ef8933fcaa1af9cb61a7fe0ceef Mon Sep 17 00:00:00 2001 From: David Matlack Date: Wed, 22 Jun 2022 15:27:09 -0400 Subject: [PATCH 0655/1436] KVM: x86/mmu: Extend Eager Page Splitting to nested MMUs Add support for Eager Page Splitting pages that are mapped by nested MMUs. Walk through the rmap first splitting all 1GiB pages to 2MiB pages, and then splitting all 2MiB pages to 4KiB pages. Note, Eager Page Splitting is limited to nested MMUs as a policy rather than due to any technical reason (the sp->role.guest_mode check could just be deleted and Eager Page Splitting would work correctly for all shadow MMU pages). There is really no reason to support Eager Page Splitting for tdp_mmu=N, since such support will eventually be phased out, and there is no current use case supporting Eager Page Splitting on hosts where TDP is either disabled or unavailable in hardware. Furthermore, future improvements to nested MMU scalability may diverge the code from the legacy shadow paging implementation. These improvements will be simpler to make if Eager Page Splitting does not have to worry about legacy shadow paging. Splitting huge pages mapped by nested MMUs requires dealing with some extra complexity beyond that of the TDP MMU: (1) The shadow MMU has a limit on the number of shadow pages that are allowed to be allocated. So, as a policy, Eager Page Splitting refuses to split if there are KVM_MIN_FREE_MMU_PAGES or fewer pages available. (2) Splitting a huge page may end up re-using an existing lower level shadow page tables. This is unlike the TDP MMU which always allocates new shadow page tables when splitting. (3) When installing the lower level SPTEs, they must be added to the rmap which may require allocating additional pte_list_desc structs. Case (2) is especially interesting since it may require a TLB flush, unlike the TDP MMU which can fully split huge pages without any TLB flushes. Specifically, an existing lower level page table may point to even lower level page tables that are not fully populated, effectively unmapping a portion of the huge page, which requires a flush. As of this commit, a flush is always done always after dropping the huge page and before installing the lower level page table. This TLB flush could instead be delayed until the MMU lock is about to be dropped, which would batch flushes for multiple splits. However these flushes should be rare in practice (a huge page must be aliased in multiple SPTEs and have been split for NX Huge Pages in only some of them). Flushing immediately is simpler to plumb and also reduces the chances of tripping over a CPU bug (e.g. see iTLB multihit). [ This commit is based off of the original implementation of Eager Page Splitting from Peter in Google's kernel from 2016. ] Suggested-by: Peter Feiner Signed-off-by: David Matlack Message-Id: <20220516232138.1783324-23-dmatlack@google.com> Signed-off-by: Paolo Bonzini --- .../admin-guide/kernel-parameters.txt | 3 +- arch/x86/include/asm/kvm_host.h | 22 ++ arch/x86/kvm/mmu/mmu.c | 259 +++++++++++++++++- 3 files changed, 275 insertions(+), 9 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 97c16aa2f53f..329f0f274e2b 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2418,8 +2418,7 @@ the KVM_CLEAR_DIRTY ioctl, and only for the pages being cleared. - Eager page splitting currently only supports splitting - huge pages mapped by the TDP MMU. + Eager page splitting is only supported when kvm.tdp_mmu=Y. Default is Y (on). diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 64efe8c90c31..665667d61caf 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1338,6 +1338,28 @@ struct kvm_arch { u32 max_vcpu_ids; bool disable_nx_huge_pages; + + /* + * Memory caches used to allocate shadow pages when performing eager + * page splitting. No need for a shadowed_info_cache since eager page + * splitting only allocates direct shadow pages. + * + * Protected by kvm->slots_lock. + */ + struct kvm_mmu_memory_cache split_shadow_page_cache; + struct kvm_mmu_memory_cache split_page_header_cache; + + /* + * Memory cache used to allocate pte_list_desc structs while splitting + * huge pages. In the worst case, to split one huge page, 512 + * pte_list_desc structs are needed to add each lower level leaf sptep + * to the rmap plus 1 to extend the parent_ptes rmap of the lower level + * page table. + * + * Protected by kvm->slots_lock. + */ +#define SPLIT_DESC_CACHE_MIN_NR_OBJECTS (SPTE_ENT_PER_PAGE + 1) + struct kvm_mmu_memory_cache split_desc_cache; }; struct kvm_vm_stat { diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 192cb7dc4471..9bfe339bf67f 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -5942,9 +5942,25 @@ int kvm_mmu_init_vm(struct kvm *kvm) node->track_write = kvm_mmu_pte_write; node->track_flush_slot = kvm_mmu_invalidate_zap_pages_in_memslot; kvm_page_track_register_notifier(kvm, node); + + kvm->arch.split_page_header_cache.kmem_cache = mmu_page_header_cache; + kvm->arch.split_page_header_cache.gfp_zero = __GFP_ZERO; + + kvm->arch.split_shadow_page_cache.gfp_zero = __GFP_ZERO; + + kvm->arch.split_desc_cache.kmem_cache = pte_list_desc_cache; + kvm->arch.split_desc_cache.gfp_zero = __GFP_ZERO; + return 0; } +static void mmu_free_vm_memory_caches(struct kvm *kvm) +{ + kvm_mmu_free_memory_cache(&kvm->arch.split_desc_cache); + kvm_mmu_free_memory_cache(&kvm->arch.split_page_header_cache); + kvm_mmu_free_memory_cache(&kvm->arch.split_shadow_page_cache); +} + void kvm_mmu_uninit_vm(struct kvm *kvm) { struct kvm_page_track_notifier_node *node = &kvm->arch.mmu_sp_tracker; @@ -5952,6 +5968,8 @@ void kvm_mmu_uninit_vm(struct kvm *kvm) kvm_page_track_unregister_notifier(kvm, node); kvm_mmu_uninit_tdp_mmu(kvm); + + mmu_free_vm_memory_caches(kvm); } static bool __kvm_zap_rmaps(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) @@ -6073,15 +6091,235 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm, kvm_arch_flush_remote_tlbs_memslot(kvm, memslot); } +static inline bool need_topup(struct kvm_mmu_memory_cache *cache, int min) +{ + return kvm_mmu_memory_cache_nr_free_objects(cache) < min; +} + +static bool need_topup_split_caches_or_resched(struct kvm *kvm) +{ + if (need_resched() || rwlock_needbreak(&kvm->mmu_lock)) + return true; + + /* + * In the worst case, SPLIT_DESC_CACHE_MIN_NR_OBJECTS descriptors are needed + * to split a single huge page. Calculating how many are actually needed + * is possible but not worth the complexity. + */ + return need_topup(&kvm->arch.split_desc_cache, SPLIT_DESC_CACHE_MIN_NR_OBJECTS) || + need_topup(&kvm->arch.split_page_header_cache, 1) || + need_topup(&kvm->arch.split_shadow_page_cache, 1); +} + +static int topup_split_caches(struct kvm *kvm) +{ + int r; + + lockdep_assert_held(&kvm->slots_lock); + + /* + * Setting capacity == min would cause KVM to drop mmu_lock even if + * just one object was consumed from the cache, so make capacity + * larger than min. + */ + r = __kvm_mmu_topup_memory_cache(&kvm->arch.split_desc_cache, + 2 * SPLIT_DESC_CACHE_MIN_NR_OBJECTS, + SPLIT_DESC_CACHE_MIN_NR_OBJECTS); + if (r) + return r; + + r = kvm_mmu_topup_memory_cache(&kvm->arch.split_page_header_cache, 1); + if (r) + return r; + + return kvm_mmu_topup_memory_cache(&kvm->arch.split_shadow_page_cache, 1); +} + +static struct kvm_mmu_page *shadow_mmu_get_sp_for_split(struct kvm *kvm, u64 *huge_sptep) +{ + struct kvm_mmu_page *huge_sp = sptep_to_sp(huge_sptep); + struct shadow_page_caches caches = {}; + union kvm_mmu_page_role role; + unsigned int access; + gfn_t gfn; + + gfn = kvm_mmu_page_get_gfn(huge_sp, huge_sptep - huge_sp->spt); + access = kvm_mmu_page_get_access(huge_sp, huge_sptep - huge_sp->spt); + + /* + * Note, huge page splitting always uses direct shadow pages, regardless + * of whether the huge page itself is mapped by a direct or indirect + * shadow page, since the huge page region itself is being directly + * mapped with smaller pages. + */ + role = kvm_mmu_child_role(huge_sptep, /*direct=*/true, access); + + /* Direct SPs do not require a shadowed_info_cache. */ + caches.page_header_cache = &kvm->arch.split_page_header_cache; + caches.shadow_page_cache = &kvm->arch.split_shadow_page_cache; + + /* Safe to pass NULL for vCPU since requesting a direct SP. */ + return __kvm_mmu_get_shadow_page(kvm, NULL, &caches, gfn, role); +} + +static void shadow_mmu_split_huge_page(struct kvm *kvm, + const struct kvm_memory_slot *slot, + u64 *huge_sptep) + +{ + struct kvm_mmu_memory_cache *cache = &kvm->arch.split_desc_cache; + u64 huge_spte = READ_ONCE(*huge_sptep); + struct kvm_mmu_page *sp; + u64 *sptep, spte; + gfn_t gfn; + int index; + + sp = shadow_mmu_get_sp_for_split(kvm, huge_sptep); + + for (index = 0; index < SPTE_ENT_PER_PAGE; index++) { + sptep = &sp->spt[index]; + gfn = kvm_mmu_page_get_gfn(sp, index); + + /* + * The SP may already have populated SPTEs, e.g. if this huge + * page is aliased by multiple sptes with the same access + * permissions. These entries are guaranteed to map the same + * gfn-to-pfn translation since the SP is direct, so no need to + * modify them. + * + * If a given SPTE points to a lower level page table, installing + * such SPTEs would effectively unmap a potion of the huge page. + * This is not an issue because __link_shadow_page() flushes the TLB + * when the passed sp replaces a large SPTE. + */ + if (is_shadow_present_pte(*sptep)) + continue; + + spte = make_huge_page_split_spte(kvm, huge_spte, sp->role, index); + mmu_spte_set(sptep, spte); + __rmap_add(kvm, cache, slot, sptep, gfn, sp->role.access); + } + + __link_shadow_page(kvm, cache, huge_sptep, sp); +} + +static int shadow_mmu_try_split_huge_page(struct kvm *kvm, + const struct kvm_memory_slot *slot, + u64 *huge_sptep) +{ + struct kvm_mmu_page *huge_sp = sptep_to_sp(huge_sptep); + int level, r = 0; + gfn_t gfn; + u64 spte; + + /* Grab information for the tracepoint before dropping the MMU lock. */ + gfn = kvm_mmu_page_get_gfn(huge_sp, huge_sptep - huge_sp->spt); + level = huge_sp->role.level; + spte = *huge_sptep; + + if (kvm_mmu_available_pages(kvm) <= KVM_MIN_FREE_MMU_PAGES) { + r = -ENOSPC; + goto out; + } + + if (need_topup_split_caches_or_resched(kvm)) { + write_unlock(&kvm->mmu_lock); + cond_resched(); + /* + * If the topup succeeds, return -EAGAIN to indicate that the + * rmap iterator should be restarted because the MMU lock was + * dropped. + */ + r = topup_split_caches(kvm) ?: -EAGAIN; + write_lock(&kvm->mmu_lock); + goto out; + } + + shadow_mmu_split_huge_page(kvm, slot, huge_sptep); + +out: + trace_kvm_mmu_split_huge_page(gfn, spte, level, r); + return r; +} + +static bool shadow_mmu_try_split_huge_pages(struct kvm *kvm, + struct kvm_rmap_head *rmap_head, + const struct kvm_memory_slot *slot) +{ + struct rmap_iterator iter; + struct kvm_mmu_page *sp; + u64 *huge_sptep; + int r; + +restart: + for_each_rmap_spte(rmap_head, &iter, huge_sptep) { + sp = sptep_to_sp(huge_sptep); + + /* TDP MMU is enabled, so rmap only contains nested MMU SPs. */ + if (WARN_ON_ONCE(!sp->role.guest_mode)) + continue; + + /* The rmaps should never contain non-leaf SPTEs. */ + if (WARN_ON_ONCE(!is_large_pte(*huge_sptep))) + continue; + + /* SPs with level >PG_LEVEL_4K should never by unsync. */ + if (WARN_ON_ONCE(sp->unsync)) + continue; + + /* Don't bother splitting huge pages on invalid SPs. */ + if (sp->role.invalid) + continue; + + r = shadow_mmu_try_split_huge_page(kvm, slot, huge_sptep); + + /* + * The split succeeded or needs to be retried because the MMU + * lock was dropped. Either way, restart the iterator to get it + * back into a consistent state. + */ + if (!r || r == -EAGAIN) + goto restart; + + /* The split failed and shouldn't be retried (e.g. -ENOMEM). */ + break; + } + + return false; +} + +static void kvm_shadow_mmu_try_split_huge_pages(struct kvm *kvm, + const struct kvm_memory_slot *slot, + gfn_t start, gfn_t end, + int target_level) +{ + int level; + + /* + * Split huge pages starting with KVM_MAX_HUGEPAGE_LEVEL and working + * down to the target level. This ensures pages are recursively split + * all the way to the target level. There's no need to split pages + * already at the target level. + */ + for (level = KVM_MAX_HUGEPAGE_LEVEL; level > target_level; level--) { + slot_handle_level_range(kvm, slot, shadow_mmu_try_split_huge_pages, + level, level, start, end - 1, true, false); + } +} + /* Must be called with the mmu_lock held in write-mode. */ void kvm_mmu_try_split_huge_pages(struct kvm *kvm, const struct kvm_memory_slot *memslot, u64 start, u64 end, int target_level) { - if (is_tdp_mmu_enabled(kvm)) - kvm_tdp_mmu_try_split_huge_pages(kvm, memslot, start, end, - target_level, false); + if (!is_tdp_mmu_enabled(kvm)) + return; + + if (kvm_memslots_have_rmaps(kvm)) + kvm_shadow_mmu_try_split_huge_pages(kvm, memslot, start, end, target_level); + + kvm_tdp_mmu_try_split_huge_pages(kvm, memslot, start, end, target_level, false); /* * A TLB flush is unnecessary at this point for the same resons as in @@ -6096,12 +6334,19 @@ void kvm_mmu_slot_try_split_huge_pages(struct kvm *kvm, u64 start = memslot->base_gfn; u64 end = start + memslot->npages; - if (is_tdp_mmu_enabled(kvm)) { - read_lock(&kvm->mmu_lock); - kvm_tdp_mmu_try_split_huge_pages(kvm, memslot, start, end, target_level, true); - read_unlock(&kvm->mmu_lock); + if (!is_tdp_mmu_enabled(kvm)) + return; + + if (kvm_memslots_have_rmaps(kvm)) { + write_lock(&kvm->mmu_lock); + kvm_shadow_mmu_try_split_huge_pages(kvm, memslot, start, end, target_level); + write_unlock(&kvm->mmu_lock); } + read_lock(&kvm->mmu_lock); + kvm_tdp_mmu_try_split_huge_pages(kvm, memslot, start, end, target_level, true); + read_unlock(&kvm->mmu_lock); + /* * No TLB flush is necessary here. KVM will flush TLBs after * write-protecting and/or clearing dirty on the newly split SPTEs to From 951ceb94ede39acbebf34481ec87fe2c46b91e0f Mon Sep 17 00:00:00 2001 From: Jue Wang Date: Fri, 10 Jun 2022 10:11:27 -0700 Subject: [PATCH 0656/1436] KVM: x86: Make APIC_VERSION capture only the magic 0x14UL. Refactor APIC_VERSION so that the maximum number of LVT entries is inserted at runtime rather than compile time. This will be used in a subsequent commit to expose the LVT CMCI Register to VMs that support Corrected Machine Check error counting/signaling (IA32_MCG_CAP.MCG_CMCI_P=1). Suggested-by: Sean Christopherson Signed-off-by: Jue Wang Signed-off-by: Paolo Bonzini Message-Id: <20220610171134.772566-2-juew@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 43c42a580295..828af02be350 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -54,7 +54,7 @@ #define PRIo64 "o" /* 14 is the version for Xeon and Pentium 8.4.8*/ -#define APIC_VERSION (0x14UL | ((KVM_APIC_LVT_NUM - 1) << 16)) +#define APIC_VERSION 0x14UL #define LAPIC_MMIO_LENGTH (1 << 12) /* followed define is not in apicdef.h */ #define MAX_APIC_VECTOR 256 @@ -402,7 +402,7 @@ static inline int apic_lvt_nmi_mode(u32 lvt_val) void kvm_apic_set_version(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - u32 v = APIC_VERSION; + u32 v = APIC_VERSION | ((KVM_APIC_LVT_NUM - 1) << 16); if (!lapic_in_kernel(vcpu)) return; From 1d8c681fb6ed459128ab9d5e36adb7ec06a26aea Mon Sep 17 00:00:00 2001 From: Jue Wang Date: Fri, 10 Jun 2022 10:11:28 -0700 Subject: [PATCH 0657/1436] KVM: x86: Fill apic_lvt_mask with enums / explicit entries. This patch defines a lapic_lvt_entry enum used as explicit indices to the apic_lvt_mask array. In later patches a LVT_CMCI will be added to implement the Corrected Machine Check Interrupt signaling. Suggested-by: Sean Christopherson Signed-off-by: Jue Wang Signed-off-by: Paolo Bonzini Message-Id: <20220610171134.772566-3-juew@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 19 ++++++++++--------- arch/x86/kvm/lapic.h | 12 +++++++++++- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 828af02be350..fe295c718fd9 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -402,7 +402,7 @@ static inline int apic_lvt_nmi_mode(u32 lvt_val) void kvm_apic_set_version(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - u32 v = APIC_VERSION | ((KVM_APIC_LVT_NUM - 1) << 16); + u32 v = APIC_VERSION | ((KVM_APIC_MAX_NR_LVT_ENTRIES - 1) << 16); if (!lapic_in_kernel(vcpu)) return; @@ -420,12 +420,13 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu) kvm_lapic_set_reg(apic, APIC_LVR, v); } -static const unsigned int apic_lvt_mask[KVM_APIC_LVT_NUM] = { - LVT_MASK , /* part LVTT mask, timer mode mask added at runtime */ - LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ - LVT_MASK | APIC_MODE_MASK, /* LVTPC */ - LINT_MASK, LINT_MASK, /* LVT0-1 */ - LVT_MASK /* LVTERR */ +static const unsigned int apic_lvt_mask[KVM_APIC_MAX_NR_LVT_ENTRIES] = { + [LVT_TIMER] = LVT_MASK, /* timer mode mask added at runtime */ + [LVT_THERMAL_MONITOR] = LVT_MASK | APIC_MODE_MASK, + [LVT_PERFORMANCE_COUNTER] = LVT_MASK | APIC_MODE_MASK, + [LVT_LINT0] = LINT_MASK, + [LVT_LINT1] = LINT_MASK, + [LVT_ERROR] = LVT_MASK }; static int find_highest_vector(void *bitmap) @@ -2091,7 +2092,7 @@ static int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) int i; u32 lvt_val; - for (i = 0; i < KVM_APIC_LVT_NUM; i++) { + for (i = 0; i < KVM_APIC_MAX_NR_LVT_ENTRIES; i++) { lvt_val = kvm_lapic_get_reg(apic, APIC_LVTT + 0x10 * i); kvm_lapic_set_reg(apic, APIC_LVTT + 0x10 * i, @@ -2409,7 +2410,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) kvm_apic_set_xapic_id(apic, vcpu->vcpu_id); kvm_apic_set_version(apic->vcpu); - for (i = 0; i < KVM_APIC_LVT_NUM; i++) + for (i = 0; i < KVM_APIC_MAX_NR_LVT_ENTRIES; i++) kvm_lapic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); apic_update_lvtt(apic); if (kvm_vcpu_is_reset_bsp(vcpu) && diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 6207b64b1281..af26777fb0ea 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -10,7 +10,6 @@ #define KVM_APIC_INIT 0 #define KVM_APIC_SIPI 1 -#define KVM_APIC_LVT_NUM 6 #define APIC_SHORT_MASK 0xc0000 #define APIC_DEST_NOSHORT 0x0 @@ -29,6 +28,17 @@ enum lapic_mode { LAPIC_MODE_X2APIC = MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE, }; +enum lapic_lvt_entry { + LVT_TIMER, + LVT_THERMAL_MONITOR, + LVT_PERFORMANCE_COUNTER, + LVT_LINT0, + LVT_LINT1, + LVT_ERROR, + + KVM_APIC_MAX_NR_LVT_ENTRIES, +}; + struct kvm_timer { struct hrtimer timer; s64 period; /* unit: ns */ From 0378739401cfc2fd2a50a2a337a4f394e8493008 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 22 Jun 2022 15:27:10 -0400 Subject: [PATCH 0658/1436] KVM: x86/mmu: Avoid unnecessary flush on eager page split The TLB flush before installing the newly-populated lower level page table is unnecessary if the lower-level page table maps the huge page identically. KVM knows it is if it did not reuse an existing shadow page table, tell drop_large_spte() to skip the flush in that case. Extracted from a patch by David Matlack. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 9bfe339bf67f..bd74a287b54a 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1135,7 +1135,7 @@ static void drop_spte(struct kvm *kvm, u64 *sptep) rmap_remove(kvm, sptep); } -static void drop_large_spte(struct kvm *kvm, u64 *sptep) +static void drop_large_spte(struct kvm *kvm, u64 *sptep, bool flush) { struct kvm_mmu_page *sp; @@ -1143,7 +1143,9 @@ static void drop_large_spte(struct kvm *kvm, u64 *sptep) WARN_ON(sp->role.level == PG_LEVEL_4K); drop_spte(kvm, sptep); - kvm_flush_remote_tlbs_with_address(kvm, sp->gfn, + + if (flush) + kvm_flush_remote_tlbs_with_address(kvm, sp->gfn, KVM_PAGES_PER_HPAGE(sp->role.level)); } @@ -2283,7 +2285,7 @@ static void shadow_walk_next(struct kvm_shadow_walk_iterator *iterator) static void __link_shadow_page(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, u64 *sptep, - struct kvm_mmu_page *sp) + struct kvm_mmu_page *sp, bool flush) { u64 spte; @@ -2291,10 +2293,11 @@ static void __link_shadow_page(struct kvm *kvm, /* * If an SPTE is present already, it must be a leaf and therefore - * a large one. Drop it and flush the TLB before installing sp. + * a large one. Drop it, and flush the TLB if needed, before + * installing sp. */ if (is_shadow_present_pte(*sptep)) - drop_large_spte(kvm, sptep); + drop_large_spte(kvm, sptep, flush); spte = make_nonleaf_spte(sp->spt, sp_ad_disabled(sp)); @@ -2309,7 +2312,7 @@ static void __link_shadow_page(struct kvm *kvm, static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep, struct kvm_mmu_page *sp) { - __link_shadow_page(vcpu->kvm, &vcpu->arch.mmu_pte_list_desc_cache, sptep, sp); + __link_shadow_page(vcpu->kvm, &vcpu->arch.mmu_pte_list_desc_cache, sptep, sp, true); } static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep, @@ -6170,6 +6173,7 @@ static void shadow_mmu_split_huge_page(struct kvm *kvm, struct kvm_mmu_memory_cache *cache = &kvm->arch.split_desc_cache; u64 huge_spte = READ_ONCE(*huge_sptep); struct kvm_mmu_page *sp; + bool flush = false; u64 *sptep, spte; gfn_t gfn; int index; @@ -6187,20 +6191,24 @@ static void shadow_mmu_split_huge_page(struct kvm *kvm, * gfn-to-pfn translation since the SP is direct, so no need to * modify them. * - * If a given SPTE points to a lower level page table, installing - * such SPTEs would effectively unmap a potion of the huge page. - * This is not an issue because __link_shadow_page() flushes the TLB - * when the passed sp replaces a large SPTE. + * However, if a given SPTE points to a lower level page table, + * that lower level page table may only be partially populated. + * Installing such SPTEs would effectively unmap a potion of the + * huge page. Unmapping guest memory always requires a TLB flush + * since a subsequent operation on the unmapped regions would + * fail to detect the need to flush. */ - if (is_shadow_present_pte(*sptep)) + if (is_shadow_present_pte(*sptep)) { + flush |= !is_last_spte(*sptep, sp->role.level); continue; + } spte = make_huge_page_split_spte(kvm, huge_spte, sp->role, index); mmu_spte_set(sptep, spte); __rmap_add(kvm, cache, slot, sptep, gfn, sp->role.access); } - __link_shadow_page(kvm, cache, huge_sptep, sp); + __link_shadow_page(kvm, cache, huge_sptep, sp, flush); } static int shadow_mmu_try_split_huge_page(struct kvm *kvm, From 987f625e0799c9666ce0a0e18c2d0c001db96fad Mon Sep 17 00:00:00 2001 From: Jue Wang Date: Fri, 10 Jun 2022 10:11:29 -0700 Subject: [PATCH 0659/1436] KVM: x86: Add APIC_LVTx() macro. An APIC_LVTx macro is introduced to calcualte the APIC_LVTx register offset based on the index in the lapic_lvt_entry enum. Later patches will extend the APIC_LVTx macro to support the APIC_LVTCMCI register in order to implement Corrected Machine Check Interrupt signaling. Suggested-by: Sean Christopherson Signed-off-by: Jue Wang Signed-off-by: Paolo Bonzini Message-Id: <20220610171134.772566-4-juew@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 7 +++---- arch/x86/kvm/lapic.h | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index fe295c718fd9..30eb9b7fbe71 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2093,9 +2093,8 @@ static int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) u32 lvt_val; for (i = 0; i < KVM_APIC_MAX_NR_LVT_ENTRIES; i++) { - lvt_val = kvm_lapic_get_reg(apic, - APIC_LVTT + 0x10 * i); - kvm_lapic_set_reg(apic, APIC_LVTT + 0x10 * i, + lvt_val = kvm_lapic_get_reg(apic, APIC_LVTx(i)); + kvm_lapic_set_reg(apic, APIC_LVTx(i), lvt_val | APIC_LVT_MASKED); } apic_update_lvtt(apic); @@ -2411,7 +2410,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) kvm_apic_set_version(apic->vcpu); for (i = 0; i < KVM_APIC_MAX_NR_LVT_ENTRIES; i++) - kvm_lapic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); + kvm_lapic_set_reg(apic, APIC_LVTx(i), APIC_LVT_MASKED); apic_update_lvtt(apic); if (kvm_vcpu_is_reset_bsp(vcpu) && kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_LINT0_REENABLED)) diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index af26777fb0ea..08843c21084d 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -39,6 +39,8 @@ enum lapic_lvt_entry { KVM_APIC_MAX_NR_LVT_ENTRIES, }; +#define APIC_LVTx(x) (APIC_LVTT + 0x10 * (x)) + struct kvm_timer { struct hrtimer timer; s64 period; /* unit: ns */ From 4b903561ec499eef233bf690076cd71b1f8604cf Mon Sep 17 00:00:00 2001 From: Jue Wang Date: Fri, 10 Jun 2022 10:11:30 -0700 Subject: [PATCH 0660/1436] KVM: x86: Add Corrected Machine Check Interrupt (CMCI) emulation to lapic. This patch calculates the number of lvt entries as part of KVM_X86_MCE_SETUP conditioned on the presence of MCG_CMCI_P bit in MCG_CAP and stores result in kvm_lapic. It translats from APIC_LVTx register to index in lapic_lvt_entry enum. It extends the APIC_LVTx macro as well as other lapic write/reset handling etc to support Corrected Machine Check Interrupt. Signed-off-by: Jue Wang Signed-off-by: Paolo Bonzini Message-Id: <20220610171134.772566-5-juew@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 49 ++++++++++++++++++++++++++++++-------------- arch/x86/kvm/lapic.h | 4 +++- arch/x86/kvm/x86.c | 2 ++ 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 30eb9b7fbe71..f03facc2ee3e 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -399,14 +400,21 @@ static inline int apic_lvt_nmi_mode(u32 lvt_val) return (lvt_val & (APIC_MODE_MASK | APIC_LVT_MASKED)) == APIC_DM_NMI; } +static inline bool kvm_lapic_lvt_supported(struct kvm_lapic *apic, int lvt_index) +{ + return apic->nr_lvt_entries > lvt_index; +} + void kvm_apic_set_version(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; - u32 v = APIC_VERSION | ((KVM_APIC_MAX_NR_LVT_ENTRIES - 1) << 16); + u32 v = 0; if (!lapic_in_kernel(vcpu)) return; + v = APIC_VERSION | ((apic->nr_lvt_entries - 1) << 16); + /* * KVM emulates 82093AA datasheet (with in-kernel IOAPIC implementation) * which doesn't have EOI register; Some buggy OSes (e.g. Windows with @@ -426,7 +434,8 @@ static const unsigned int apic_lvt_mask[KVM_APIC_MAX_NR_LVT_ENTRIES] = { [LVT_PERFORMANCE_COUNTER] = LVT_MASK | APIC_MODE_MASK, [LVT_LINT0] = LINT_MASK, [LVT_LINT1] = LINT_MASK, - [LVT_ERROR] = LVT_MASK + [LVT_ERROR] = LVT_MASK, + [LVT_CMCI] = LVT_MASK | APIC_MODE_MASK }; static int find_highest_vector(void *bitmap) @@ -1436,6 +1445,9 @@ static int kvm_lapic_reg_read(struct kvm_lapic *apic, u32 offset, int len, APIC_REG_MASK(APIC_TMCCT) | APIC_REG_MASK(APIC_TDCR); + if (kvm_lapic_lvt_supported(apic, LVT_CMCI)) + valid_reg_mask |= APIC_REG_MASK(APIC_LVTCMCI); + /* * ARBPRI and ICR2 are not valid in x2APIC mode. WARN if KVM reads ICR * in x2APIC mode as it's an 8-byte register in x2APIC and needs to be @@ -2044,6 +2056,16 @@ static void kvm_lapic_xapic_id_updated(struct kvm_lapic *apic) kvm_set_apicv_inhibit(apic->vcpu->kvm, APICV_INHIBIT_REASON_APIC_ID_MODIFIED); } +static int get_lvt_index(u32 reg) +{ + if (reg == APIC_LVTCMCI) + return LVT_CMCI; + if (reg < APIC_LVTT || reg > APIC_LVTERR) + return -1; + return array_index_nospec( + (reg - APIC_LVTT) >> 4, KVM_APIC_MAX_NR_LVT_ENTRIES); +} + static int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) { int ret = 0; @@ -2090,12 +2112,10 @@ static int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) apic_set_spiv(apic, val & mask); if (!(val & APIC_SPIV_APIC_ENABLED)) { int i; - u32 lvt_val; - for (i = 0; i < KVM_APIC_MAX_NR_LVT_ENTRIES; i++) { - lvt_val = kvm_lapic_get_reg(apic, APIC_LVTx(i)); + for (i = 0; i < apic->nr_lvt_entries; i++) { kvm_lapic_set_reg(apic, APIC_LVTx(i), - lvt_val | APIC_LVT_MASKED); + kvm_lapic_get_reg(apic, APIC_LVTx(i)) | APIC_LVT_MASKED); } apic_update_lvtt(apic); atomic_set(&apic->lapic_timer.pending, 0); @@ -2124,16 +2144,15 @@ static int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) case APIC_LVTTHMR: case APIC_LVTPC: case APIC_LVT1: - case APIC_LVTERR: { - /* TODO: Check vector */ - size_t size; - u32 index; - + case APIC_LVTERR: + case APIC_LVTCMCI: { + u32 index = get_lvt_index(reg); + if (!kvm_lapic_lvt_supported(apic, index)) { + ret = 1; + break; + } if (!kvm_apic_sw_enabled(apic)) val |= APIC_LVT_MASKED; - size = ARRAY_SIZE(apic_lvt_mask); - index = array_index_nospec( - (reg - APIC_LVTT) >> 4, size); val &= apic_lvt_mask[index]; kvm_lapic_set_reg(apic, reg, val); break; @@ -2409,7 +2428,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event) kvm_apic_set_xapic_id(apic, vcpu->vcpu_id); kvm_apic_set_version(apic->vcpu); - for (i = 0; i < KVM_APIC_MAX_NR_LVT_ENTRIES; i++) + for (i = 0; i < apic->nr_lvt_entries; i++) kvm_lapic_set_reg(apic, APIC_LVTx(i), APIC_LVT_MASKED); apic_update_lvtt(apic); if (kvm_vcpu_is_reset_bsp(vcpu) && diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 08843c21084d..762bf6163798 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -35,11 +35,12 @@ enum lapic_lvt_entry { LVT_LINT0, LVT_LINT1, LVT_ERROR, + LVT_CMCI, KVM_APIC_MAX_NR_LVT_ENTRIES, }; -#define APIC_LVTx(x) (APIC_LVTT + 0x10 * (x)) +#define APIC_LVTx(x) ((x) == LVT_CMCI ? APIC_LVTCMCI : APIC_LVTT + 0x10 * (x)) struct kvm_timer { struct hrtimer timer; @@ -78,6 +79,7 @@ struct kvm_lapic { struct gfn_to_hva_cache vapic_cache; unsigned long pending_events; unsigned int sipi_vector; + int nr_lvt_entries; }; struct dest_map; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 7ce0c6fe166d..6d6d6c6413ba 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4845,6 +4845,8 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu, /* Init IA32_MCi_CTL to all 1s */ for (bank = 0; bank < bank_num; bank++) vcpu->arch.mce_banks[bank*4] = ~(u64)0; + vcpu->arch.apic->nr_lvt_entries = + KVM_APIC_MAX_NR_LVT_ENTRIES - !(mcg_cap & MCG_CMCI_P); static_call(kvm_x86_setup_mce)(vcpu); out: From 087acc4e1847993a66f43128e40be0ab2244c98f Mon Sep 17 00:00:00 2001 From: Jue Wang Date: Fri, 10 Jun 2022 10:11:31 -0700 Subject: [PATCH 0661/1436] KVM: x86: Use kcalloc to allocate the mce_banks array. This patch updates the allocation of mce_banks with the array allocation API (kcalloc) as a precedent for the later mci_ctl2_banks to implement per-bank control of Corrected Machine Check Interrupt (CMCI). Suggested-by: Sean Christopherson Signed-off-by: Jue Wang Signed-off-by: Paolo Bonzini Message-Id: <20220610171134.772566-6-juew@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6d6d6c6413ba..3c6eb6837b96 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -11447,7 +11447,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) goto fail_free_lapic; vcpu->arch.pio_data = page_address(page); - vcpu->arch.mce_banks = kzalloc(KVM_MAX_MCE_BANKS * sizeof(u64) * 4, + vcpu->arch.mce_banks = kcalloc(KVM_MAX_MCE_BANKS * 4, sizeof(u64), GFP_KERNEL_ACCOUNT); if (!vcpu->arch.mce_banks) goto fail_free_pio_data; From 281b52780b57821abc434c0413107d3075881a1f Mon Sep 17 00:00:00 2001 From: Jue Wang Date: Fri, 10 Jun 2022 10:11:32 -0700 Subject: [PATCH 0662/1436] KVM: x86: Add emulation for MSR_IA32_MCx_CTL2 MSRs. This patch adds the emulation of IA32_MCi_CTL2 registers to KVM. A separate mci_ctl2_banks array is used to keep the existing mce_banks register layout intact. In Machine Check Architecture, in addition to MCG_CMCI_P, bit 30 of the per-bank register IA32_MCi_CTL2 controls whether Corrected Machine Check error reporting is enabled. Signed-off-by: Jue Wang Signed-off-by: Paolo Bonzini Message-Id: <20220610171134.772566-7-juew@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/x86.c | 126 ++++++++++++++++++++++---------- 2 files changed, 90 insertions(+), 37 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 665667d61caf..88a3026ee163 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -826,6 +826,7 @@ struct kvm_vcpu_arch { u64 mcg_ctl; u64 mcg_ext_ctl; u64 *mce_banks; + u64 *mci_ctl2_banks; /* Cache MMIO info */ u64 mmio_gva; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3c6eb6837b96..f743e4ef2009 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3191,6 +3191,16 @@ static void kvmclock_sync_fn(struct work_struct *work) KVMCLOCK_SYNC_PERIOD); } +/* These helpers are safe iff @msr is known to be an MCx bank MSR. */ +static bool is_mci_control_msr(u32 msr) +{ + return (msr & 3) == 0; +} +static bool is_mci_status_msr(u32 msr) +{ + return (msr & 3) == 1; +} + /* * On AMD, HWCR[McStatusWrEn] controls whether setting MCi_STATUS results in #GP. */ @@ -3209,6 +3219,7 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) unsigned bank_num = mcg_cap & 0xff; u32 msr = msr_info->index; u64 data = msr_info->data; + u32 offset, last_msr; switch (msr) { case MSR_IA32_MCG_STATUS: @@ -3222,35 +3233,53 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 1; vcpu->arch.mcg_ctl = data; break; - default: - if (msr >= MSR_IA32_MC0_CTL && - msr < MSR_IA32_MCx_CTL(bank_num)) { - u32 offset = array_index_nospec( - msr - MSR_IA32_MC0_CTL, - MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL); + case MSR_IA32_MC0_CTL2 ... MSR_IA32_MCx_CTL2(KVM_MAX_MCE_BANKS) - 1: + last_msr = MSR_IA32_MCx_CTL2(bank_num) - 1; + if (msr > last_msr) + return 1; - /* only 0 or all 1s can be written to IA32_MCi_CTL - * some Linux kernels though clear bit 10 in bank 4 to - * workaround a BIOS/GART TBL issue on AMD K8s, ignore - * this to avoid an uncatched #GP in the guest. + if (!(mcg_cap & MCG_CMCI_P) && (data || !msr_info->host_initiated)) + return 1; + /* An attempt to write a 1 to a reserved bit raises #GP */ + if (data & ~(MCI_CTL2_CMCI_EN | MCI_CTL2_CMCI_THRESHOLD_MASK)) + return 1; + offset = array_index_nospec(msr - MSR_IA32_MC0_CTL2, + last_msr + 1 - MSR_IA32_MC0_CTL2); + vcpu->arch.mci_ctl2_banks[offset] = data; + break; + case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: + last_msr = MSR_IA32_MCx_CTL(bank_num) - 1; + if (msr > last_msr) + return 1; + + /* + * Only 0 or all 1s can be written to IA32_MCi_CTL, all other + * values are architecturally undefined. But, some Linux + * kernels clear bit 10 in bank 4 to workaround a BIOS/GART TLB + * issue on AMD K8s, allow bit 10 to be clear when setting all + * other bits in order to avoid an uncaught #GP in the guest. * * UNIXWARE clears bit 0 of MC1_CTL to ignore * correctable, single-bit ECC data errors. - */ - if ((offset & 0x3) == 0 && - data != 0 && (data | (1 << 10) | 1) != ~(u64)0) - return -1; + */ + if (is_mci_control_msr(msr) && + data != 0 && (data | (1 << 10) | 1) != ~(u64)0) + return 1; - /* MCi_STATUS */ - if (!msr_info->host_initiated && - (offset & 0x3) == 1 && data != 0) { - if (!can_set_mci_status(vcpu)) - return -1; - } + /* + * All CPUs allow writing 0 to MCi_STATUS MSRs to clear the MSR. + * AMD-based CPUs allow non-zero values, but if and only if + * HWCR[McStatusWrEn] is set. + */ + if (!msr_info->host_initiated && is_mci_status_msr(msr) && + data != 0 && !can_set_mci_status(vcpu)) + return 1; - vcpu->arch.mce_banks[offset] = data; - break; - } + offset = array_index_nospec(msr - MSR_IA32_MC0_CTL, + last_msr + 1 - MSR_IA32_MC0_CTL); + vcpu->arch.mce_banks[offset] = data; + break; + default: return 1; } return 0; @@ -3534,7 +3563,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 1; } break; - case 0x200 ... 0x2ff: + case 0x200 ... MSR_IA32_MC0_CTL2 - 1: + case MSR_IA32_MCx_CTL2(KVM_MAX_MCE_BANKS) ... 0x2ff: return kvm_mtrr_set_msr(vcpu, msr, data); case MSR_IA32_APICBASE: return kvm_set_apic_base(vcpu, msr_info); @@ -3704,6 +3734,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_IA32_MCG_CTL: case MSR_IA32_MCG_STATUS: case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: + case MSR_IA32_MC0_CTL2 ... MSR_IA32_MCx_CTL2(KVM_MAX_MCE_BANKS) - 1: return set_msr_mce(vcpu, msr_info); case MSR_K7_PERFCTR0 ... MSR_K7_PERFCTR3: @@ -3819,6 +3850,7 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) u64 data; u64 mcg_cap = vcpu->arch.mcg_cap; unsigned bank_num = mcg_cap & 0xff; + u32 offset, last_msr; switch (msr) { case MSR_IA32_P5_MC_ADDR: @@ -3836,16 +3868,27 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) case MSR_IA32_MCG_STATUS: data = vcpu->arch.mcg_status; break; - default: - if (msr >= MSR_IA32_MC0_CTL && - msr < MSR_IA32_MCx_CTL(bank_num)) { - u32 offset = array_index_nospec( - msr - MSR_IA32_MC0_CTL, - MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL); + case MSR_IA32_MC0_CTL2 ... MSR_IA32_MCx_CTL2(KVM_MAX_MCE_BANKS) - 1: + last_msr = MSR_IA32_MCx_CTL2(bank_num) - 1; + if (msr > last_msr) + return 1; - data = vcpu->arch.mce_banks[offset]; - break; - } + if (!(mcg_cap & MCG_CMCI_P) && !host) + return 1; + offset = array_index_nospec(msr - MSR_IA32_MC0_CTL2, + last_msr + 1 - MSR_IA32_MC0_CTL2); + data = vcpu->arch.mci_ctl2_banks[offset]; + break; + case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: + last_msr = MSR_IA32_MCx_CTL(bank_num) - 1; + if (msr > last_msr) + return 1; + + offset = array_index_nospec(msr - MSR_IA32_MC0_CTL, + last_msr + 1 - MSR_IA32_MC0_CTL); + data = vcpu->arch.mce_banks[offset]; + break; + default: return 1; } *pdata = data; @@ -3949,7 +3992,8 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) break; } case MSR_MTRRcap: - case 0x200 ... 0x2ff: + case 0x200 ... MSR_IA32_MC0_CTL2 - 1: + case MSR_IA32_MCx_CTL2(KVM_MAX_MCE_BANKS) ... 0x2ff: return kvm_mtrr_get_msr(vcpu, msr_info->index, &msr_info->data); case 0xcd: /* fsb frequency */ msr_info->data = 3; @@ -4065,6 +4109,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) case MSR_IA32_MCG_CTL: case MSR_IA32_MCG_STATUS: case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: + case MSR_IA32_MC0_CTL2 ... MSR_IA32_MCx_CTL2(KVM_MAX_MCE_BANKS) - 1: return get_msr_mce(vcpu, msr_info->index, &msr_info->data, msr_info->host_initiated); case MSR_IA32_XSS: @@ -4842,9 +4887,12 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu, /* Init IA32_MCG_CTL to all 1s */ if (mcg_cap & MCG_CTL_P) vcpu->arch.mcg_ctl = ~(u64)0; - /* Init IA32_MCi_CTL to all 1s */ - for (bank = 0; bank < bank_num; bank++) + /* Init IA32_MCi_CTL to all 1s, IA32_MCi_CTL2 to all 0s */ + for (bank = 0; bank < bank_num; bank++) { vcpu->arch.mce_banks[bank*4] = ~(u64)0; + if (mcg_cap & MCG_CMCI_P) + vcpu->arch.mci_ctl2_banks[bank] = 0; + } vcpu->arch.apic->nr_lvt_entries = KVM_APIC_MAX_NR_LVT_ENTRIES - !(mcg_cap & MCG_CMCI_P); @@ -11449,7 +11497,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) vcpu->arch.mce_banks = kcalloc(KVM_MAX_MCE_BANKS * 4, sizeof(u64), GFP_KERNEL_ACCOUNT); - if (!vcpu->arch.mce_banks) + vcpu->arch.mci_ctl2_banks = kcalloc(KVM_MAX_MCE_BANKS, sizeof(u64), + GFP_KERNEL_ACCOUNT); + if (!vcpu->arch.mce_banks || !vcpu->arch.mci_ctl2_banks) goto fail_free_pio_data; vcpu->arch.mcg_cap = KVM_MAX_MCE_BANKS; @@ -11503,6 +11553,7 @@ free_wbinvd_dirty_mask: free_cpumask_var(vcpu->arch.wbinvd_dirty_mask); fail_free_mce_banks: kfree(vcpu->arch.mce_banks); + kfree(vcpu->arch.mci_ctl2_banks); fail_free_pio_data: free_page((unsigned long)vcpu->arch.pio_data); fail_free_lapic: @@ -11548,6 +11599,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) kvm_hv_vcpu_uninit(vcpu); kvm_pmu_destroy(vcpu); kfree(vcpu->arch.mce_banks); + kfree(vcpu->arch.mci_ctl2_banks); kvm_free_lapic(vcpu); idx = srcu_read_lock(&vcpu->kvm->srcu); kvm_mmu_destroy(vcpu); From aebc3ca19063d68b76bcaaca81558d4f180c61b0 Mon Sep 17 00:00:00 2001 From: Jue Wang Date: Fri, 10 Jun 2022 10:11:33 -0700 Subject: [PATCH 0663/1436] KVM: x86: Enable CMCI capability by default and handle injected UCNA errors This patch enables MCG_CMCI_P by default in kvm_mce_cap_supported. It reuses ioctl KVM_X86_SET_MCE to implement injection of UnCorrectable No Action required (UCNA) errors, signaled via Corrected Machine Check Interrupt (CMCI). Neither of the CMCI and UCNA emulations depends on hardware. Signed-off-by: Jue Wang Signed-off-by: Paolo Bonzini Message-Id: <20220610171134.772566-8-juew@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 1 + arch/x86/kvm/x86.c | 43 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 4002f6cc179d..c30115b9cb33 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8299,6 +8299,7 @@ static __init int hardware_setup(void) } kvm_caps.supported_mce_cap |= MCG_LMCE_P; + kvm_caps.supported_mce_cap |= MCG_CMCI_P; if (pt_mode != PT_MODE_SYSTEM && pt_mode != PT_MODE_HOST_GUEST) return -EINVAL; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f743e4ef2009..031678eff28e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4901,6 +4901,42 @@ out: return r; } +/* + * Validate this is an UCNA (uncorrectable no action) error by checking the + * MCG_STATUS and MCi_STATUS registers: + * - none of the bits for Machine Check Exceptions are set + * - both the VAL (valid) and UC (uncorrectable) bits are set + * MCI_STATUS_PCC - Processor Context Corrupted + * MCI_STATUS_S - Signaled as a Machine Check Exception + * MCI_STATUS_AR - Software recoverable Action Required + */ +static bool is_ucna(struct kvm_x86_mce *mce) +{ + return !mce->mcg_status && + !(mce->status & (MCI_STATUS_PCC | MCI_STATUS_S | MCI_STATUS_AR)) && + (mce->status & MCI_STATUS_VAL) && + (mce->status & MCI_STATUS_UC); +} + +static int kvm_vcpu_x86_set_ucna(struct kvm_vcpu *vcpu, struct kvm_x86_mce *mce, u64* banks) +{ + u64 mcg_cap = vcpu->arch.mcg_cap; + + banks[1] = mce->status; + banks[2] = mce->addr; + banks[3] = mce->misc; + vcpu->arch.mcg_status = mce->mcg_status; + + if (!(mcg_cap & MCG_CMCI_P) || + !(vcpu->arch.mci_ctl2_banks[mce->bank] & MCI_CTL2_CMCI_EN)) + return 0; + + if (lapic_in_kernel(vcpu)) + kvm_apic_local_deliver(vcpu->arch.apic, APIC_LVTCMCI); + + return 0; +} + static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu, struct kvm_x86_mce *mce) { @@ -4910,6 +4946,12 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu, if (mce->bank >= bank_num || !(mce->status & MCI_STATUS_VAL)) return -EINVAL; + + banks += array_index_nospec(4 * mce->bank, 4 * bank_num); + + if (is_ucna(mce)) + return kvm_vcpu_x86_set_ucna(vcpu, mce, banks); + /* * if IA32_MCG_CTL is not all 1s, the uncorrected error * reporting is disabled @@ -4917,7 +4959,6 @@ static int kvm_vcpu_ioctl_x86_set_mce(struct kvm_vcpu *vcpu, if ((mce->status & MCI_STATUS_UC) && (mcg_cap & MCG_CTL_P) && vcpu->arch.mcg_ctl != ~(u64)0) return 0; - banks += 4 * mce->bank; /* * if IA32_MCi_CTL is not all 1s, the uncorrected error * reporting is disabled for the bank From eede2065cacce2e04110bc6e45e9dc8e843c571b Mon Sep 17 00:00:00 2001 From: Jue Wang Date: Fri, 10 Jun 2022 10:11:34 -0700 Subject: [PATCH 0664/1436] KVM: selftests: Add a self test for CMCI and UCNA emulations. This patch add a self test that verifies user space can inject UnCorrectable No Action required (UCNA) memory errors to the guest. It also verifies that incorrectly configured MSRs for Corrected Machine Check Interrupt (CMCI) emulation will result in #GP. Signed-off-by: Jue Wang Signed-off-by: Paolo Bonzini Message-Id: <20220610171134.772566-9-juew@google.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/include/x86_64/apic.h | 1 + .../selftests/kvm/include/x86_64/mce.h | 25 ++ .../kvm/x86_64/ucna_injection_test.c | 316 ++++++++++++++++++ 5 files changed, 344 insertions(+) create mode 100644 tools/testing/selftests/kvm/include/x86_64/mce.h create mode 100644 tools/testing/selftests/kvm/x86_64/ucna_injection_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index c478b4fefc57..f44ebf401310 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -43,6 +43,7 @@ /x86_64/sync_regs_test /x86_64/tsc_msrs_test /x86_64/tsc_scaling_sync +/x86_64/ucna_injection_test /x86_64/userspace_io_test /x86_64/userspace_msr_exit_test /x86_64/vmx_apic_access_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index fa3e0687e9d5..4d6753aadfa0 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -101,6 +101,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/svm_int_ctl_test TEST_GEN_PROGS_x86_64 += x86_64/svm_nested_soft_inject_test TEST_GEN_PROGS_x86_64 += x86_64/tsc_scaling_sync TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test +TEST_GEN_PROGS_x86_64 += x86_64/ucna_injection_test TEST_GEN_PROGS_x86_64 += x86_64/userspace_io_test TEST_GEN_PROGS_x86_64 += x86_64/userspace_msr_exit_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_apic_access_test diff --git a/tools/testing/selftests/kvm/include/x86_64/apic.h b/tools/testing/selftests/kvm/include/x86_64/apic.h index ac88557dcc9a..bed316fdecd5 100644 --- a/tools/testing/selftests/kvm/include/x86_64/apic.h +++ b/tools/testing/selftests/kvm/include/x86_64/apic.h @@ -35,6 +35,7 @@ #define APIC_SPIV_APIC_ENABLED (1 << 8) #define APIC_IRR 0x200 #define APIC_ICR 0x300 +#define APIC_LVTCMCI 0x2f0 #define APIC_DEST_SELF 0x40000 #define APIC_DEST_ALLINC 0x80000 #define APIC_DEST_ALLBUT 0xC0000 diff --git a/tools/testing/selftests/kvm/include/x86_64/mce.h b/tools/testing/selftests/kvm/include/x86_64/mce.h new file mode 100644 index 000000000000..6119321f3f5d --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86_64/mce.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * tools/testing/selftests/kvm/include/x86_64/mce.h + * + * Copyright (C) 2022, Google LLC. + */ + +#ifndef SELFTEST_KVM_MCE_H +#define SELFTEST_KVM_MCE_H + +#define MCG_CTL_P BIT_ULL(8) /* MCG_CTL register available */ +#define MCG_SER_P BIT_ULL(24) /* MCA recovery/new status bits */ +#define MCG_LMCE_P BIT_ULL(27) /* Local machine check supported */ +#define MCG_CMCI_P BIT_ULL(10) /* CMCI supported */ +#define KVM_MAX_MCE_BANKS 32 +#define MCG_CAP_BANKS_MASK 0xff /* Bit 0-7 of the MCG_CAP register are #banks */ +#define MCI_STATUS_VAL (1ULL << 63) /* valid error */ +#define MCI_STATUS_UC (1ULL << 61) /* uncorrected error */ +#define MCI_STATUS_EN (1ULL << 60) /* error enabled */ +#define MCI_STATUS_MISCV (1ULL << 59) /* misc error reg. valid */ +#define MCI_STATUS_ADDRV (1ULL << 58) /* addr reg. valid */ +#define MCM_ADDR_PHYS 2 /* physical address */ +#define MCI_CTL2_CMCI_EN BIT_ULL(30) + +#endif /* SELFTEST_KVM_MCE_H */ diff --git a/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c b/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c new file mode 100644 index 000000000000..a897c7fd8abe --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/ucna_injection_test.c @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ucna_injection_test + * + * Copyright (C) 2022, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + * Test that user space can inject UnCorrectable No Action required (UCNA) + * memory errors to the guest. + * + * The test starts one vCPU with the MCG_CMCI_P enabled. It verifies that + * proper UCNA errors can be injected to a vCPU with MCG_CMCI_P and + * corresponding per-bank control register (MCI_CTL2) bit enabled. + * The test also checks that the UCNA errors get recorded in the + * Machine Check bank registers no matter the error signal interrupts get + * delivered into the guest or not. + * + */ + +#define _GNU_SOURCE /* for program_invocation_short_name */ +#include +#include +#include +#include + +#include "kvm_util_base.h" +#include "kvm_util.h" +#include "mce.h" +#include "processor.h" +#include "test_util.h" +#include "apic.h" + +#define SYNC_FIRST_UCNA 9 +#define SYNC_SECOND_UCNA 10 +#define SYNC_GP 11 +#define FIRST_UCNA_ADDR 0xdeadbeef +#define SECOND_UCNA_ADDR 0xcafeb0ba + +/* + * Vector for the CMCI interrupt. + * Value is arbitrary. Any value in 0x20-0xFF should work: + * https://wiki.osdev.org/Interrupt_Vector_Table + */ +#define CMCI_VECTOR 0xa9 + +#define UCNA_BANK 0x7 // IMC0 bank + +#define MCI_CTL2_RESERVED_BIT BIT_ULL(29) + +static uint64_t supported_mcg_caps; + +/* + * Record states about the injected UCNA. + * The variables started with the 'i_' prefixes are recorded in interrupt + * handler. Variables without the 'i_' prefixes are recorded in guest main + * execution thread. + */ +static volatile uint64_t i_ucna_rcvd; +static volatile uint64_t i_ucna_addr; +static volatile uint64_t ucna_addr; +static volatile uint64_t ucna_addr2; + +struct thread_params { + struct kvm_vcpu *vcpu; + uint64_t *p_i_ucna_rcvd; + uint64_t *p_i_ucna_addr; + uint64_t *p_ucna_addr; + uint64_t *p_ucna_addr2; +}; + +static void verify_apic_base_addr(void) +{ + uint64_t msr = rdmsr(MSR_IA32_APICBASE); + uint64_t base = GET_APIC_BASE(msr); + + GUEST_ASSERT(base == APIC_DEFAULT_GPA); +} + +static void ucna_injection_guest_code(void) +{ + uint64_t ctl2; + verify_apic_base_addr(); + xapic_enable(); + + /* Sets up the interrupt vector and enables per-bank CMCI sigaling. */ + xapic_write_reg(APIC_LVTCMCI, CMCI_VECTOR | APIC_DM_FIXED); + ctl2 = rdmsr(MSR_IA32_MCx_CTL2(UCNA_BANK)); + wrmsr(MSR_IA32_MCx_CTL2(UCNA_BANK), ctl2 | MCI_CTL2_CMCI_EN); + + /* Enables interrupt in guest. */ + asm volatile("sti"); + + /* Let user space inject the first UCNA */ + GUEST_SYNC(SYNC_FIRST_UCNA); + + ucna_addr = rdmsr(MSR_IA32_MCx_ADDR(UCNA_BANK)); + + /* Disables the per-bank CMCI signaling. */ + ctl2 = rdmsr(MSR_IA32_MCx_CTL2(UCNA_BANK)); + wrmsr(MSR_IA32_MCx_CTL2(UCNA_BANK), ctl2 & ~MCI_CTL2_CMCI_EN); + + /* Let the user space inject the second UCNA */ + GUEST_SYNC(SYNC_SECOND_UCNA); + + ucna_addr2 = rdmsr(MSR_IA32_MCx_ADDR(UCNA_BANK)); + GUEST_DONE(); +} + +static void cmci_disabled_guest_code(void) +{ + uint64_t ctl2 = rdmsr(MSR_IA32_MCx_CTL2(UCNA_BANK)); + wrmsr(MSR_IA32_MCx_CTL2(UCNA_BANK), ctl2 | MCI_CTL2_CMCI_EN); + + GUEST_DONE(); +} + +static void cmci_enabled_guest_code(void) +{ + uint64_t ctl2 = rdmsr(MSR_IA32_MCx_CTL2(UCNA_BANK)); + wrmsr(MSR_IA32_MCx_CTL2(UCNA_BANK), ctl2 | MCI_CTL2_RESERVED_BIT); + + GUEST_DONE(); +} + +static void guest_cmci_handler(struct ex_regs *regs) +{ + i_ucna_rcvd++; + i_ucna_addr = rdmsr(MSR_IA32_MCx_ADDR(UCNA_BANK)); + xapic_write_reg(APIC_EOI, 0); +} + +static void guest_gp_handler(struct ex_regs *regs) +{ + GUEST_SYNC(SYNC_GP); +} + +static void run_vcpu_expect_gp(struct kvm_vcpu *vcpu) +{ + unsigned int exit_reason; + struct ucall uc; + + vcpu_run(vcpu); + + exit_reason = vcpu->run->exit_reason; + TEST_ASSERT(exit_reason == KVM_EXIT_IO, + "exited with unexpected exit reason %u-%s, expected KVM_EXIT_IO", + exit_reason, exit_reason_str(exit_reason)); + TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_SYNC, + "Expect UCALL_SYNC\n"); + TEST_ASSERT(uc.args[1] == SYNC_GP, "#GP is expected."); + printf("vCPU received GP in guest.\n"); +} + +static void inject_ucna(struct kvm_vcpu *vcpu, uint64_t addr) { + /* + * A UCNA error is indicated with VAL=1, UC=1, PCC=0, S=0 and AR=0 in + * the IA32_MCi_STATUS register. + * MSCOD=1 (BIT[16] - MscodDataRdErr). + * MCACOD=0x0090 (Memory controller error format, channel 0) + */ + uint64_t status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN | + MCI_STATUS_MISCV | MCI_STATUS_ADDRV | 0x10090; + struct kvm_x86_mce mce = {}; + mce.status = status; + mce.mcg_status = 0; + /* + * MCM_ADDR_PHYS indicates the reported address is a physical address. + * Lowest 6 bits is the recoverable address LSB, i.e., the injected MCE + * is at 4KB granularity. + */ + mce.misc = (MCM_ADDR_PHYS << 6) | 0xc; + mce.addr = addr; + mce.bank = UCNA_BANK; + + vcpu_ioctl(vcpu, KVM_X86_SET_MCE, &mce); +} + +static void *run_ucna_injection(void *arg) +{ + struct thread_params *params = (struct thread_params *)arg; + struct ucall uc; + int old; + int r; + unsigned int exit_reason; + + r = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old); + TEST_ASSERT(r == 0, + "pthread_setcanceltype failed with errno=%d", + r); + + vcpu_run(params->vcpu); + + exit_reason = params->vcpu->run->exit_reason; + TEST_ASSERT(exit_reason == KVM_EXIT_IO, + "unexpected exit reason %u-%s, expected KVM_EXIT_IO", + exit_reason, exit_reason_str(exit_reason)); + TEST_ASSERT(get_ucall(params->vcpu, &uc) == UCALL_SYNC, + "Expect UCALL_SYNC\n"); + TEST_ASSERT(uc.args[1] == SYNC_FIRST_UCNA, "Injecting first UCNA."); + + printf("Injecting first UCNA at %#x.\n", FIRST_UCNA_ADDR); + + inject_ucna(params->vcpu, FIRST_UCNA_ADDR); + vcpu_run(params->vcpu); + + exit_reason = params->vcpu->run->exit_reason; + TEST_ASSERT(exit_reason == KVM_EXIT_IO, + "unexpected exit reason %u-%s, expected KVM_EXIT_IO", + exit_reason, exit_reason_str(exit_reason)); + TEST_ASSERT(get_ucall(params->vcpu, &uc) == UCALL_SYNC, + "Expect UCALL_SYNC\n"); + TEST_ASSERT(uc.args[1] == SYNC_SECOND_UCNA, "Injecting second UCNA."); + + printf("Injecting second UCNA at %#x.\n", SECOND_UCNA_ADDR); + + inject_ucna(params->vcpu, SECOND_UCNA_ADDR); + vcpu_run(params->vcpu); + + exit_reason = params->vcpu->run->exit_reason; + TEST_ASSERT(exit_reason == KVM_EXIT_IO, + "unexpected exit reason %u-%s, expected KVM_EXIT_IO", + exit_reason, exit_reason_str(exit_reason)); + if (get_ucall(params->vcpu, &uc) == UCALL_ABORT) { + TEST_ASSERT(false, "vCPU assertion failure: %s.\n", + (const char *)uc.args[0]); + } + + return NULL; +} + +static void test_ucna_injection(struct kvm_vcpu *vcpu, struct thread_params *params) +{ + struct kvm_vm *vm = vcpu->vm; + params->vcpu = vcpu; + params->p_i_ucna_rcvd = (uint64_t *)addr_gva2hva(vm, (uint64_t)&i_ucna_rcvd); + params->p_i_ucna_addr = (uint64_t *)addr_gva2hva(vm, (uint64_t)&i_ucna_addr); + params->p_ucna_addr = (uint64_t *)addr_gva2hva(vm, (uint64_t)&ucna_addr); + params->p_ucna_addr2 = (uint64_t *)addr_gva2hva(vm, (uint64_t)&ucna_addr2); + + run_ucna_injection(params); + + TEST_ASSERT(*params->p_i_ucna_rcvd == 1, "Only first UCNA get signaled."); + TEST_ASSERT(*params->p_i_ucna_addr == FIRST_UCNA_ADDR, + "Only first UCNA reported addr get recorded via interrupt."); + TEST_ASSERT(*params->p_ucna_addr == FIRST_UCNA_ADDR, + "First injected UCNAs should get exposed via registers."); + TEST_ASSERT(*params->p_ucna_addr2 == SECOND_UCNA_ADDR, + "Second injected UCNAs should get exposed via registers."); + + printf("Test successful.\n" + "UCNA CMCI interrupts received: %ld\n" + "Last UCNA address received via CMCI: %lx\n" + "First UCNA address in vCPU thread: %lx\n" + "Second UCNA address in vCPU thread: %lx\n", + *params->p_i_ucna_rcvd, *params->p_i_ucna_addr, + *params->p_ucna_addr, *params->p_ucna_addr2); +} + +static void setup_mce_cap(struct kvm_vcpu *vcpu, bool enable_cmci_p) +{ + uint64_t mcg_caps = MCG_CTL_P | MCG_SER_P | MCG_LMCE_P | KVM_MAX_MCE_BANKS; + if (enable_cmci_p) + mcg_caps |= MCG_CMCI_P; + + mcg_caps &= supported_mcg_caps | MCG_CAP_BANKS_MASK; + vcpu_ioctl(vcpu, KVM_X86_SETUP_MCE, &mcg_caps); +} + +static struct kvm_vcpu *create_vcpu_with_mce_cap(struct kvm_vm *vm, uint32_t vcpuid, + bool enable_cmci_p, void *guest_code) +{ + struct kvm_vcpu *vcpu = vm_vcpu_add(vm, vcpuid, guest_code); + setup_mce_cap(vcpu, enable_cmci_p); + return vcpu; +} + +int main(int argc, char *argv[]) +{ + struct thread_params params; + struct kvm_vm *vm; + struct kvm_vcpu *ucna_vcpu; + struct kvm_vcpu *cmcidis_vcpu; + struct kvm_vcpu *cmci_vcpu; + + kvm_check_cap(KVM_CAP_MCE); + + vm = __vm_create(VM_MODE_DEFAULT, 3, 0); + + kvm_ioctl(vm->kvm_fd, KVM_X86_GET_MCE_CAP_SUPPORTED, + &supported_mcg_caps); + + if (!(supported_mcg_caps & MCG_CMCI_P)) { + print_skip("MCG_CMCI_P is not supported"); + exit(KSFT_SKIP); + } + + ucna_vcpu = create_vcpu_with_mce_cap(vm, 0, true, ucna_injection_guest_code); + cmcidis_vcpu = create_vcpu_with_mce_cap(vm, 1, false, cmci_disabled_guest_code); + cmci_vcpu = create_vcpu_with_mce_cap(vm, 2, true, cmci_enabled_guest_code); + + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(ucna_vcpu); + vcpu_init_descriptor_tables(cmcidis_vcpu); + vcpu_init_descriptor_tables(cmci_vcpu); + vm_install_exception_handler(vm, CMCI_VECTOR, guest_cmci_handler); + vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); + + virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); + + test_ucna_injection(ucna_vcpu, ¶ms); + run_vcpu_expect_gp(cmcidis_vcpu); + run_vcpu_expect_gp(cmci_vcpu); + + kvm_vm_free(vm); +} From 4b88b1a518b337de1252b8180519ca4c00015c9e Mon Sep 17 00:00:00 2001 From: Zeng Guang Date: Thu, 23 Jun 2022 17:45:11 +0800 Subject: [PATCH 0665/1436] KVM: selftests: Enhance handling WRMSR ICR register in x2APIC mode Hardware would directly write x2APIC ICR register instead of software emulation in some circumstances, e.g when Intel IPI virtualization is enabled. This behavior requires normal reserved bits checking to ensure them input as zero, otherwise it will cause #GP. So we need mask out those reserved bits from the data written to vICR register. Remove Delivery Status bit emulation in test case as this flag is invalid and not needed in x2APIC mode. KVM may ignore clearing it during interrupt dispatch which will lead to fake test failure. Opportunistically correct vector number for test sending IPI to non-existent vCPUs. Signed-off-by: Zeng Guang Message-Id: <20220623094511.26066-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/x86_64/xapic_state_test.c | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c index 5c5dc7bbb4e2..87531623064f 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c @@ -71,13 +71,27 @@ static void ____test_icr(struct xapic_vcpu *x, uint64_t val) vcpu_ioctl(vcpu, KVM_GET_LAPIC, &xapic); icr = (u64)(*((u32 *)&xapic.regs[APIC_ICR])) | (u64)(*((u32 *)&xapic.regs[APIC_ICR2])) << 32; - if (!x->is_x2apic) + if (!x->is_x2apic) { val &= (-1u | (0xffull << (32 + 24))); - ASSERT_EQ(icr, val & ~APIC_ICR_BUSY); + ASSERT_EQ(icr, val & ~APIC_ICR_BUSY); + } else { + ASSERT_EQ(icr & ~APIC_ICR_BUSY, val & ~APIC_ICR_BUSY); + } } +#define X2APIC_RSVED_BITS_MASK (GENMASK_ULL(31,20) | \ + GENMASK_ULL(17,16) | \ + GENMASK_ULL(13,13)) + static void __test_icr(struct xapic_vcpu *x, uint64_t val) { + if (x->is_x2apic) { + /* Hardware writing vICR register requires reserved bits 31:20, + * 17:16 and 13 kept as zero to avoid #GP exception. Data value + * written to vICR should mask out those bits above. + */ + val &= ~X2APIC_RSVED_BITS_MASK; + } ____test_icr(x, val | APIC_ICR_BUSY); ____test_icr(x, val & ~(u64)APIC_ICR_BUSY); } @@ -102,7 +116,7 @@ static void test_icr(struct xapic_vcpu *x) icr = APIC_INT_ASSERT | 0xff; for (i = vcpu->id + 1; i < 0xff; i++) { for (j = 0; j < 8; j++) - __test_icr(x, i << (32 + 24) | APIC_INT_ASSERT | (j << 8)); + __test_icr(x, i << (32 + 24) | icr | (j << 8)); } /* And again with a shorthand destination for all types of IPIs. */ From a725a29d52ef8cbc4904449672d35964f1392217 Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Wed, 22 Jun 2022 21:38:55 -0700 Subject: [PATCH 0666/1436] staging: r8188eu: Make rtw_signal_stat_timer_hdl a static function Make rtw_signal_stat_timer_hdl a static function instead of a global function. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/20220623043855.407208-1-marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index cc91638a085d..6564e82ddd66 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -24,7 +24,7 @@ static u8 rtw_rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -void rtw_signal_stat_timer_hdl(struct timer_list *t); +static void rtw_signal_stat_timer_hdl(struct timer_list *t); void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) { @@ -1794,7 +1794,7 @@ _recv_entry_drop: return ret; } -void rtw_signal_stat_timer_hdl(struct timer_list *t) +static void rtw_signal_stat_timer_hdl(struct timer_list *t) { struct adapter *adapter = from_timer(adapter, t, recvpriv.signal_stat_timer); struct recv_priv *recvpriv = &adapter->recvpriv; From 21cdd6a0e8441461e549f0c25af9696c6c4de22c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 24 Jun 2022 10:22:20 +0300 Subject: [PATCH 0667/1436] usb: musb: mpfs: Fix error codes in probe() These error paths return success but they need to return a negative error code. Fixes: 7a96b6ea90a4 ("usb: musb: Add support for PolarFire SoC's musb controller") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YrVmLEc/FOEzNdzj@kili Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/mpfs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/musb/mpfs.c b/drivers/usb/musb/mpfs.c index 99666ef8af06..a69ca338eace 100644 --- a/drivers/usb/musb/mpfs.c +++ b/drivers/usb/musb/mpfs.c @@ -181,8 +181,10 @@ static int mpfs_probe(struct platform_device *pdev) glue->clk = clk; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) + if (!pdata) { + ret = -ENOMEM; goto err_clk_disable; + } pdata->config = &mpfs_musb_hdrc_config; pdata->platform_ops = &mpfs_ops; @@ -197,6 +199,7 @@ static int mpfs_probe(struct platform_device *pdev) if (IS_ERR(glue->phy)) { dev_err(dev, "failed to register usb-phy %ld\n", PTR_ERR(glue->phy)); + ret = PTR_ERR(glue->phy); goto err_clk_disable; } From db638c6500abaffb8f7770b2a69c40d003d54ae1 Mon Sep 17 00:00:00 2001 From: Amelie Delaunay Date: Wed, 22 Jun 2022 18:07:17 +0200 Subject: [PATCH 0668/1436] usb: dwc2: gadget: remove D+ pull-up while no vbus with usb-role-switch When using usb-role-switch, D+ pull-up is set as soon as DTCL_SFTDISCON is cleared, whatever the vbus valid signal state is. The pull-up should not be set when vbus isn't present (this is determined by the drd controller). This patch ensures that B-Session (so Peripheral role + vbus valid signal) is valid before clearing the DCTL_SFTDISCON bit when role switch is used. Keep original behavior when usb-role-switch isn't used. Acked-by: Minas Harutyunyan Signed-off-by: Amelie Delaunay Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220622160717.314580-1-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/gadget.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index fe2a58c75861..8b15742d9e8a 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3594,7 +3594,8 @@ void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) { /* remove the soft-disconnect and let's go */ - dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); + if (!hsotg->role_sw || (dwc2_readl(hsotg, GOTGCTL) & GOTGCTL_BSESVLD)) + dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON); } /** From 2958d494b7577037a257461bae0bfe723f192910 Mon Sep 17 00:00:00 2001 From: Jiang Jian Date: Wed, 22 Jun 2022 18:35:58 +0800 Subject: [PATCH 0669/1436] usb: dwc2: drop unexpected word "the" in the comments there is an unexpected word "the" in the comments that need to be dropped file: ./drivers/usb/dwc2/hcd.c line: 1002 * even and the current frame number is even the the transfer changed to: * even and the current frame number is even the transfer Signed-off-by: Jiang Jian Link: https://lore.kernel.org/r/20220622103558.6647-1-jiangjian@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 2c9613d0d395..aaf7b9fc4d34 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -1000,7 +1000,7 @@ static void dwc2_hc_set_even_odd_frame(struct dwc2_hsotg *hsotg, /* * Try to figure out if we're an even or odd frame. If we set - * even and the current frame number is even the the transfer + * even and the current frame number is even the transfer * will happen immediately. Similar if both are odd. If one is * even and the other is odd then the transfer will happen when * the frame number ticks. From d46b4343e13246ab1d2b057b972657886e2a5f14 Mon Sep 17 00:00:00 2001 From: Jiang Jian Date: Wed, 22 Jun 2022 18:30:03 +0800 Subject: [PATCH 0670/1436] usb: max-3421: drop unexpected word "the" in the comments there is an unexpected word "the" in the comments that need to be dropped file: ./drivers/usb/host/max3421-hcd.c line: 315 * reasonable overview of how control transfers use the the IN/OUT changed to: * reasonable overview of how control transfers use the IN/OUT Signed-off-by: Jiang Jian Link: https://lore.kernel.org/r/20220622103003.5420-1-jiangjian@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/max3421-hcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 502a3ac5e35b..352e3ac2b377 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -312,7 +312,7 @@ static const int hrsl_to_error[] = { /* * See https://www.beyondlogic.org/usbnutshell/usb4.shtml#Control for a - * reasonable overview of how control transfers use the the IN/OUT + * reasonable overview of how control transfers use the IN/OUT * tokens. */ #define MAX3421_HXFR_BULK_IN(ep) (0x00 | (ep)) /* bulk or interrupt */ From 508aeb54e4f0225f4ff3da9b7ec8ac44ce30aad8 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 23 Jun 2022 09:08:08 +0800 Subject: [PATCH 0671/1436] usb: gadget: u_ether: Remove duplicated include in u_ether.c Fix following includecheck warning: ./drivers/usb/gadget/function/u_ether.c: linux/etherdevice.h is included more than once. Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20220623010808.9816-1-yang.lee@linux.alibaba.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/u_ether.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index f51694f29de9..7887def05dc2 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "u_ether.h" From 4de5c54f8c806621ab055eeb240877d75d53b208 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 24 Jun 2022 11:45:45 -0400 Subject: [PATCH 0672/1436] KVM: nVMX: clean up posted interrupt descriptor try_cmpxchg Rely on try_cmpxchg64 for re-reading the PID on failure, using READ_ONCE only right before the first iteration. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/posted_intr.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/vmx/posted_intr.c b/arch/x86/kvm/vmx/posted_intr.c index 73f60aa480fe..1b56c5e5c9fb 100644 --- a/arch/x86/kvm/vmx/posted_intr.c +++ b/arch/x86/kvm/vmx/posted_intr.c @@ -34,7 +34,7 @@ static inline struct pi_desc *vcpu_to_pi_desc(struct kvm_vcpu *vcpu) return &(to_vmx(vcpu)->pi_desc); } -static int pi_try_set_control(struct pi_desc *pi_desc, u64 old, u64 new) +static int pi_try_set_control(struct pi_desc *pi_desc, u64 *pold, u64 new) { /* * PID.ON can be set at any time by a different vCPU or by hardware, @@ -42,7 +42,7 @@ static int pi_try_set_control(struct pi_desc *pi_desc, u64 old, u64 new) * update must be retried with a fresh snapshot an ON change causes * the cmpxchg to fail. */ - if (!try_cmpxchg64(&pi_desc->control, &old, new)) + if (!try_cmpxchg64(&pi_desc->control, pold, new)) return -EBUSY; return 0; @@ -96,8 +96,9 @@ void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu) if (!x2apic_mode) dest = (dest << 8) & 0xFF00; + old.control = READ_ONCE(pi_desc->control); do { - old.control = new.control = READ_ONCE(pi_desc->control); + new.control = old.control; /* * Clear SN (as above) and refresh the destination APIC ID to @@ -111,7 +112,7 @@ void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu) * descriptor was modified on "put" to use the wakeup vector. */ new.nv = POSTED_INTR_VECTOR; - } while (pi_try_set_control(pi_desc, old.control, new.control)); + } while (pi_try_set_control(pi_desc, &old.control, new.control)); local_irq_restore(flags); @@ -156,12 +157,12 @@ static void pi_enable_wakeup_handler(struct kvm_vcpu *vcpu) WARN(pi_desc->sn, "PI descriptor SN field set before blocking"); + old.control = READ_ONCE(pi_desc->control); do { - old.control = new.control = READ_ONCE(pi_desc->control); - /* set 'NV' to 'wakeup vector' */ + new.control = old.control; new.nv = POSTED_INTR_WAKEUP_VECTOR; - } while (pi_try_set_control(pi_desc, old.control, new.control)); + } while (pi_try_set_control(pi_desc, &old.control, new.control)); /* * Send a wakeup IPI to this CPU if an interrupt may have been posted From e36de87d34a7f2f26b2e2129c6dc18a0024663eb Mon Sep 17 00:00:00 2001 From: Vineeth Pillai Date: Mon, 23 May 2022 15:03:27 -0400 Subject: [PATCH 0673/1436] KVM: debugfs: expose pid of vcpu threads Add a new debugfs file to expose the pid of each vcpu threads. This is very helpful for userland tools to get the vcpu pids without worrying about thread naming conventions of the VMM. Signed-off-by: Vineeth Pillai (Google) Message-Id: <20220523190327.2658-1-vineeth@bitbyteword.org> Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 2 ++ virt/kvm/kvm_main.c | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 3554e48406e4..3b40f8d68fbb 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1435,6 +1435,8 @@ int kvm_arch_pm_notifier(struct kvm *kvm, unsigned long state); #ifdef __KVM_HAVE_ARCH_VCPU_DEBUGFS void kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry); +#else +static inline void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) {} #endif int kvm_arch_hardware_enable(void); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 45188d11812c..da263c370d00 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -3822,9 +3822,18 @@ static int create_vcpu_fd(struct kvm_vcpu *vcpu) return anon_inode_getfd(name, &kvm_vcpu_fops, vcpu, O_RDWR | O_CLOEXEC); } +#ifdef __KVM_HAVE_ARCH_VCPU_DEBUGFS +static int vcpu_get_pid(void *data, u64 *val) +{ + struct kvm_vcpu *vcpu = (struct kvm_vcpu *) data; + *val = pid_nr(rcu_access_pointer(vcpu->pid)); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(vcpu_get_pid_fops, vcpu_get_pid, NULL, "%llu\n"); + static void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) { -#ifdef __KVM_HAVE_ARCH_VCPU_DEBUGFS struct dentry *debugfs_dentry; char dir_name[ITOA_MAX_LEN * 2]; @@ -3834,10 +3843,12 @@ static void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) snprintf(dir_name, sizeof(dir_name), "vcpu%d", vcpu->vcpu_id); debugfs_dentry = debugfs_create_dir(dir_name, vcpu->kvm->debugfs_dentry); + debugfs_create_file("pid", 0444, debugfs_dentry, vcpu, + &vcpu_get_pid_fops); kvm_arch_create_vcpu_debugfs(vcpu, debugfs_dentry); -#endif } +#endif /* * Creates some virtual cpus. Good luck creating more than one. From aae99a7c9ab371b2cb402eebf62d4e70258f8a6d Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:26:53 -0500 Subject: [PATCH 0674/1436] x86/cpufeatures: Introduce x2AVIC CPUID bit Introduce a new feature bit for virtualized x2APIC (x2AVIC) in CPUID_Fn8000000A_EDX [SVM Revision and Feature Identification]. Reviewed-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Reviewed-by: Paolo Bonzini Message-Id: <20220519102709.24125-2-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/cpufeatures.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 393f2bbb5e3a..6466a58b9cff 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -345,6 +345,7 @@ #define X86_FEATURE_AVIC (15*32+13) /* Virtual Interrupt Controller */ #define X86_FEATURE_V_VMSAVE_VMLOAD (15*32+15) /* Virtual VMSAVE VMLOAD */ #define X86_FEATURE_VGIF (15*32+16) /* Virtual GIF */ +#define X86_FEATURE_X2AVIC (15*32+18) /* Virtual x2apic */ #define X86_FEATURE_V_SPEC_CTRL (15*32+20) /* Virtual SPEC_CTRL */ #define X86_FEATURE_SVME_ADDR_CHK (15*32+28) /* "" SVME addr check */ From bf348f667ed36c0799dd6d10adb7be9cdfea48c3 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:26:54 -0500 Subject: [PATCH 0675/1436] KVM: x86: lapic: Rename [GET/SET]_APIC_DEST_FIELD to [GET/SET]_XAPIC_DEST_FIELD To signify that the macros only support 8-bit xAPIC destination ID. Suggested-by: Maxim Levitsky Reviewed-by: Maxim Levitsky Reviewed-by: Pankaj Gupta Signed-off-by: Suravee Suthikulpanit Reviewed-by: Paolo Bonzini Message-Id: <20220519102709.24125-3-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/hyperv/hv_apic.c | 2 +- arch/x86/include/asm/apicdef.h | 4 ++-- arch/x86/kernel/apic/apic.c | 2 +- arch/x86/kernel/apic/ipi.c | 2 +- arch/x86/kvm/lapic.c | 2 +- arch/x86/kvm/svm/avic.c | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/hyperv/hv_apic.c b/arch/x86/hyperv/hv_apic.c index db2d92fb44da..fb8b2c088681 100644 --- a/arch/x86/hyperv/hv_apic.c +++ b/arch/x86/hyperv/hv_apic.c @@ -46,7 +46,7 @@ static void hv_apic_icr_write(u32 low, u32 id) { u64 reg_val; - reg_val = SET_APIC_DEST_FIELD(id); + reg_val = SET_XAPIC_DEST_FIELD(id); reg_val = reg_val << 32; reg_val |= low; diff --git a/arch/x86/include/asm/apicdef.h b/arch/x86/include/asm/apicdef.h index 92035eb3afee..68d213e83fcc 100644 --- a/arch/x86/include/asm/apicdef.h +++ b/arch/x86/include/asm/apicdef.h @@ -89,8 +89,8 @@ #define APIC_DM_EXTINT 0x00700 #define APIC_VECTOR_MASK 0x000FF #define APIC_ICR2 0x310 -#define GET_APIC_DEST_FIELD(x) (((x) >> 24) & 0xFF) -#define SET_APIC_DEST_FIELD(x) ((x) << 24) +#define GET_XAPIC_DEST_FIELD(x) (((x) >> 24) & 0xFF) +#define SET_XAPIC_DEST_FIELD(x) ((x) << 24) #define APIC_LVTT 0x320 #define APIC_LVTTHMR 0x330 #define APIC_LVTPC 0x340 diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index 189d3a5e471a..a4347605ab00 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -275,7 +275,7 @@ void native_apic_icr_write(u32 low, u32 id) unsigned long flags; local_irq_save(flags); - apic_write(APIC_ICR2, SET_APIC_DEST_FIELD(id)); + apic_write(APIC_ICR2, SET_XAPIC_DEST_FIELD(id)); apic_write(APIC_ICR, low); local_irq_restore(flags); } diff --git a/arch/x86/kernel/apic/ipi.c b/arch/x86/kernel/apic/ipi.c index d1fb874fbe64..2a6509e8c840 100644 --- a/arch/x86/kernel/apic/ipi.c +++ b/arch/x86/kernel/apic/ipi.c @@ -99,7 +99,7 @@ sendmask: static inline int __prepare_ICR2(unsigned int mask) { - return SET_APIC_DEST_FIELD(mask); + return SET_XAPIC_DEST_FIELD(mask); } static inline void __xapic_wait_icr_idle(void) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index f03facc2ee3e..6f31cc0548f0 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1326,7 +1326,7 @@ void kvm_apic_send_ipi(struct kvm_lapic *apic, u32 icr_low, u32 icr_high) if (apic_x2apic_mode(apic)) irq.dest_id = icr_high; else - irq.dest_id = GET_APIC_DEST_FIELD(icr_high); + irq.dest_id = GET_XAPIC_DEST_FIELD(icr_high); trace_kvm_apic_ipi(icr_low, irq.dest_id); diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index d1bc5820ea46..37016feb5ac4 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -303,7 +303,7 @@ static int avic_kick_target_vcpus_fast(struct kvm *kvm, struct kvm_lapic *source if (apic_x2apic_mode(source)) dest = icrh; else - dest = GET_APIC_DEST_FIELD(icrh); + dest = GET_XAPIC_DEST_FIELD(icrh); if (dest_mode == APIC_DEST_PHYSICAL) { /* broadcast destination, use slow path */ @@ -397,7 +397,7 @@ static void avic_kick_target_vcpus(struct kvm *kvm, struct kvm_lapic *source, */ kvm_for_each_vcpu(i, vcpu, kvm) { if (kvm_apic_match_dest(vcpu, source, icrl & APIC_SHORT_MASK, - GET_APIC_DEST_FIELD(icrh), + GET_XAPIC_DEST_FIELD(icrh), icrl & APIC_DEST_MASK)) { vcpu->arch.apic->irr_pending = true; svm_complete_interrupt_delivery(vcpu, From 4bdec12aa8d6d0fd7f1ac6740c456bf726e53c0b Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:26:55 -0500 Subject: [PATCH 0676/1436] KVM: SVM: Detect X2APIC virtualization (x2AVIC) support Add CPUID check for the x2APIC virtualization (x2AVIC) feature. If available, the SVM driver can support both AVIC and x2AVIC modes when load the kvm_amd driver with avic=1. The operating mode will be determined at runtime depending on the guest APIC mode. Reviewed-by: Maxim Levitsky Reviewed-by: Pankaj Gupta Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-4-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/svm.h | 3 +++ arch/x86/kvm/svm/avic.c | 45 ++++++++++++++++++++++++++++++++++++++ arch/x86/kvm/svm/svm.c | 15 ++----------- arch/x86/kvm/svm/svm.h | 9 ++++++++ 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index 1b07fba11704..1d4d30cd84c2 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -195,6 +195,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area { #define AVIC_ENABLE_SHIFT 31 #define AVIC_ENABLE_MASK (1 << AVIC_ENABLE_SHIFT) +#define X2APIC_MODE_SHIFT 30 +#define X2APIC_MODE_MASK (1 << X2APIC_MODE_SHIFT) + #define LBR_CTL_ENABLE_MASK BIT_ULL(0) #define VIRTUAL_VMLOAD_VMSAVE_ENABLE_MASK BIT_ULL(1) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 37016feb5ac4..509163833cbc 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -40,6 +40,9 @@ #define AVIC_GATAG_TO_VMID(x) ((x >> AVIC_VCPU_ID_BITS) & AVIC_VM_ID_MASK) #define AVIC_GATAG_TO_VCPUID(x) (x & AVIC_VCPU_ID_MASK) +static bool force_avic; +module_param_unsafe(force_avic, bool, 0444); + /* Note: * This hash table is used to map VM_ID to a struct kvm_svm, * when handling AMD IOMMU GALOG notification to schedule in @@ -50,6 +53,7 @@ static DEFINE_HASHTABLE(svm_vm_data_hash, SVM_VM_DATA_HASH_BITS); static u32 next_vm_id = 0; static bool next_vm_id_wrapped = 0; static DEFINE_SPINLOCK(svm_vm_data_hash_lock); +enum avic_modes avic_mode; /* * This is a wrapper of struct amd_iommu_ir_data. @@ -1058,3 +1062,44 @@ void avic_vcpu_unblocking(struct kvm_vcpu *vcpu) avic_vcpu_load(vcpu, vcpu->cpu); } + +/* + * Note: + * - The module param avic enable both xAPIC and x2APIC mode. + * - Hypervisor can support both xAVIC and x2AVIC in the same guest. + * - The mode can be switched at run-time. + */ +bool avic_hardware_setup(struct kvm_x86_ops *x86_ops) +{ + if (!npt_enabled) + return false; + + if (boot_cpu_has(X86_FEATURE_AVIC)) { + avic_mode = AVIC_MODE_X1; + pr_info("AVIC enabled\n"); + } else if (force_avic) { + /* + * Some older systems does not advertise AVIC support. + * See Revision Guide for specific AMD processor for more detail. + */ + avic_mode = AVIC_MODE_X1; + pr_warn("AVIC is not supported in CPUID but force enabled"); + pr_warn("Your system might crash and burn"); + } + + /* AVIC is a prerequisite for x2AVIC. */ + if (boot_cpu_has(X86_FEATURE_X2AVIC)) { + if (avic_mode == AVIC_MODE_X1) { + avic_mode = AVIC_MODE_X2; + pr_info("x2AVIC enabled\n"); + } else { + pr_warn(FW_BUG "Cannot support x2AVIC due to AVIC is disabled"); + pr_warn(FW_BUG "Try enable AVIC using force_avic option"); + } + } + + if (avic_mode != AVIC_MODE_NONE) + amd_iommu_register_ga_log_notifier(&avic_ga_log_notifier); + + return !!avic_mode; +} diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 136298cfb3fb..e45568aea060 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -188,9 +188,6 @@ module_param(tsc_scaling, int, 0444); static bool avic; module_param(avic, bool, 0444); -static bool force_avic; -module_param_unsafe(force_avic, bool, 0444); - bool __read_mostly dump_invalid_vmcb; module_param(dump_invalid_vmcb, bool, 0644); @@ -5016,17 +5013,9 @@ static __init int svm_hardware_setup(void) nrips = false; } - enable_apicv = avic = avic && npt_enabled && (boot_cpu_has(X86_FEATURE_AVIC) || force_avic); + enable_apicv = avic = avic && avic_hardware_setup(&svm_x86_ops); - if (enable_apicv) { - if (!boot_cpu_has(X86_FEATURE_AVIC)) { - pr_warn("AVIC is not supported in CPUID but force enabled"); - pr_warn("Your system might crash and burn"); - } else - pr_info("AVIC enabled\n"); - - amd_iommu_register_ga_log_notifier(&avic_ga_log_notifier); - } else { + if (!enable_apicv) { svm_x86_ops.vcpu_blocking = NULL; svm_x86_ops.vcpu_unblocking = NULL; svm_x86_ops.vcpu_get_apicv_inhibit_reasons = NULL; diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index d51de3c9264a..6d6390f785c5 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -36,6 +36,14 @@ extern bool npt_enabled; extern int vgif; extern bool intercept_smi; +enum avic_modes { + AVIC_MODE_NONE = 0, + AVIC_MODE_X1, + AVIC_MODE_X2, +}; + +extern enum avic_modes avic_mode; + /* * Clean bits in VMCB. * VMCB_ALL_CLEAN_MASK might also need to @@ -607,6 +615,7 @@ extern struct kvm_x86_nested_ops svm_nested_ops; /* avic.c */ +bool avic_hardware_setup(struct kvm_x86_ops *ops); int avic_ga_log_notifier(u32 ga_tag); void avic_vm_destroy(struct kvm *kvm); int avic_vm_init(struct kvm *kvm); From d2fe6bf5b881205ae99e858ed9b7ba1ebdb9c029 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:26:56 -0500 Subject: [PATCH 0677/1436] KVM: SVM: Update max number of vCPUs supported for x2AVIC mode xAVIC and x2AVIC modes can support diffferent number of vcpus. Update existing logics to support each mode accordingly. Also, modify the maximum physical APIC ID for AVIC to 255 to reflect the actual value supported by the architecture. Reviewed-by: Maxim Levitsky Reviewed-by: Pankaj Gupta Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-5-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/svm.h | 12 +++++++++--- arch/x86/kvm/svm/avic.c | 8 +++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index 1d4d30cd84c2..ed4b83d7f09e 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -258,10 +258,16 @@ enum avic_ipi_failure_cause { /* - * 0xff is broadcast, so the max index allowed for physical APIC ID - * table is 0xfe. APIC IDs above 0xff are reserved. + * For AVIC, the max index allowed for physical APIC ID + * table is 0xff (255). */ -#define AVIC_MAX_PHYSICAL_ID_COUNT 0xff +#define AVIC_MAX_PHYSICAL_ID 0XFEULL + +/* + * For x2AVIC, the max index allowed for physical APIC ID + * table is 0x1ff (511). + */ +#define X2AVIC_MAX_PHYSICAL_ID 0x1FFUL #define AVIC_HPA_MASK ~((0xFFFULL << 52) | 0xFFF) #define VMCB_AVIC_APIC_BAR_MASK 0xFFFFFFFFFF000ULL diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 509163833cbc..15dc6ca2c498 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -179,7 +179,7 @@ void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb) vmcb->control.avic_backing_page = bpa & AVIC_HPA_MASK; vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK; vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK; - vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID_COUNT; + vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID; vmcb->control.avic_vapic_bar = APIC_DEFAULT_PHYS_BASE & VMCB_AVIC_APIC_BAR_MASK; if (kvm_apicv_activated(svm->vcpu.kvm)) @@ -194,7 +194,8 @@ static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu, u64 *avic_physical_id_table; struct kvm_svm *kvm_svm = to_kvm_svm(vcpu->kvm); - if (index >= AVIC_MAX_PHYSICAL_ID_COUNT) + if ((avic_mode == AVIC_MODE_X1 && index > AVIC_MAX_PHYSICAL_ID) || + (avic_mode == AVIC_MODE_X2 && index > X2AVIC_MAX_PHYSICAL_ID)) return NULL; avic_physical_id_table = page_address(kvm_svm->avic_physical_id_table_page); @@ -241,7 +242,8 @@ static int avic_init_backing_page(struct kvm_vcpu *vcpu) int id = vcpu->vcpu_id; struct vcpu_svm *svm = to_svm(vcpu); - if (id >= AVIC_MAX_PHYSICAL_ID_COUNT) + if ((avic_mode == AVIC_MODE_X1 && id > AVIC_MAX_PHYSICAL_ID) || + (avic_mode == AVIC_MODE_X2 && id > X2AVIC_MAX_PHYSICAL_ID)) return -EINVAL; if (!vcpu->arch.apic->regs) From c514d3a348ac4358215fdfb9ed17d4c01dd39731 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:26:57 -0500 Subject: [PATCH 0678/1436] KVM: SVM: Update avic_kick_target_vcpus to support 32-bit APIC ID In x2APIC mode, ICRH contains 32-bit destination APIC ID. So, update the avic_kick_target_vcpus() accordingly. Reviewed-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-6-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/avic.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 15dc6ca2c498..8b8a221cd635 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -402,9 +402,15 @@ static void avic_kick_target_vcpus(struct kvm *kvm, struct kvm_lapic *source, * since entered the guest will have processed pending IRQs at VMRUN. */ kvm_for_each_vcpu(i, vcpu, kvm) { + u32 dest; + + if (apic_x2apic_mode(vcpu->arch.apic)) + dest = icrh; + else + dest = GET_XAPIC_DEST_FIELD(icrh); + if (kvm_apic_match_dest(vcpu, source, icrl & APIC_SHORT_MASK, - GET_XAPIC_DEST_FIELD(icrh), - icrl & APIC_DEST_MASK)) { + dest, icrl & APIC_DEST_MASK)) { vcpu->arch.apic->irr_pending = true; svm_complete_interrupt_delivery(vcpu, icrl & APIC_MODE_MASK, From ab1b1dc131cd7da4c66758e711c0f69da3633561 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:26:58 -0500 Subject: [PATCH 0679/1436] KVM: SVM: Do not support updating APIC ID when in x2APIC mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In X2APIC mode, the Logical Destination Register is read-only, which provides a fixed mapping between the logical and physical APIC IDs. Therefore, there is no Logical APIC ID table in X2AVIC and the processor uses the X2APIC ID in the backing page to create a vCPU’s logical ID. In addition, KVM does not support updating APIC ID in x2APIC mode, which means AVIC does not need to handle this case. Therefore, check x2APIC mode when handling physical and logical APIC ID update, and when invalidating logical APIC ID table. Reviewed-by: Maxim Levitsky Suggested-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-7-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/avic.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 8b8a221cd635..cc4da232040c 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -526,8 +526,13 @@ static void avic_invalidate_logical_id_entry(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); bool flat = svm->dfr_reg == APIC_DFR_FLAT; - u32 *entry = avic_get_logical_id_entry(vcpu, svm->ldr_reg, flat); + u32 *entry; + /* Note: x2AVIC does not use logical APIC ID table */ + if (apic_x2apic_mode(vcpu->arch.apic)) + return; + + entry = avic_get_logical_id_entry(vcpu, svm->ldr_reg, flat); if (entry) clear_bit(AVIC_LOGICAL_ID_ENTRY_VALID_BIT, (unsigned long *)entry); } @@ -539,6 +544,10 @@ static int avic_handle_ldr_update(struct kvm_vcpu *vcpu) u32 ldr = kvm_lapic_get_reg(vcpu->arch.apic, APIC_LDR); u32 id = kvm_xapic_id(vcpu->arch.apic); + /* AVIC does not support LDR update for x2APIC */ + if (apic_x2apic_mode(vcpu->arch.apic)) + return 0; + if (ldr == svm->ldr_reg) return 0; From 5c127c85472c0c4c9d1f88e2807adcab9335d97c Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:26:59 -0500 Subject: [PATCH 0680/1436] KVM: SVM: Adding support for configuring x2APIC MSRs interception When enabling x2APIC virtualization (x2AVIC), the interception of x2APIC MSRs must be disabled to let the hardware virtualize guest MSR accesses. Current implementation keeps track of list of MSR interception state in the svm_direct_access_msrs array. Therefore, extends the array to include x2APIC MSRs. Reviewed-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-8-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/svm.c | 25 +++++++++++++++++++++++++ arch/x86/kvm/svm/svm.h | 4 ++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index e45568aea060..382edac728c7 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -100,6 +100,31 @@ static const struct svm_direct_access_msrs { { .index = MSR_IA32_CR_PAT, .always = false }, { .index = MSR_AMD64_SEV_ES_GHCB, .always = true }, { .index = MSR_TSC_AUX, .always = false }, + { .index = (APIC_BASE_MSR + APIC_ID), .always = false }, + { .index = (APIC_BASE_MSR + APIC_LVR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_TASKPRI), .always = false }, + { .index = (APIC_BASE_MSR + APIC_ARBPRI), .always = false }, + { .index = (APIC_BASE_MSR + APIC_PROCPRI), .always = false }, + { .index = (APIC_BASE_MSR + APIC_EOI), .always = false }, + { .index = (APIC_BASE_MSR + APIC_RRR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_LDR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_DFR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_SPIV), .always = false }, + { .index = (APIC_BASE_MSR + APIC_ISR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_TMR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_IRR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_ESR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_ICR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_ICR2), .always = false }, + { .index = (APIC_BASE_MSR + APIC_LVTT), .always = false }, + { .index = (APIC_BASE_MSR + APIC_LVTTHMR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_LVTPC), .always = false }, + { .index = (APIC_BASE_MSR + APIC_LVT0), .always = false }, + { .index = (APIC_BASE_MSR + APIC_LVT1), .always = false }, + { .index = (APIC_BASE_MSR + APIC_LVTERR), .always = false }, + { .index = (APIC_BASE_MSR + APIC_TMICT), .always = false }, + { .index = (APIC_BASE_MSR + APIC_TMCCT), .always = false }, + { .index = (APIC_BASE_MSR + APIC_TDCR), .always = false }, { .index = MSR_INVALID, .always = false }, }; diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 6d6390f785c5..172c2a37e60e 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -29,8 +29,8 @@ #define IOPM_SIZE PAGE_SIZE * 3 #define MSRPM_SIZE PAGE_SIZE * 2 -#define MAX_DIRECT_ACCESS_MSRS 21 -#define MSRPM_OFFSETS 16 +#define MAX_DIRECT_ACCESS_MSRS 46 +#define MSRPM_OFFSETS 32 extern u32 msrpm_offsets[MSRPM_OFFSETS] __read_mostly; extern bool npt_enabled; extern int vgif; From 8fc9c7a3079e2d2e72dfb2f4e9bb2b1fc67f0ee6 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:27:00 -0500 Subject: [PATCH 0681/1436] KVM: x86: Deactivate APICv on vCPU with APIC disabled APICv should be deactivated on vCPU that has APIC disabled. Therefore, call kvm_vcpu_update_apicv() when changing APIC mode, and add additional check for APIC disable mode when determine APICV activation, Suggested-by: Maxim Levitsky Reviewed-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-9-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 4 +++- arch/x86/kvm/x86.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 6f31cc0548f0..6ff17d5a2ae3 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2371,8 +2371,10 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) if (((old_value ^ value) & X2APIC_ENABLE) && (value & X2APIC_ENABLE)) kvm_apic_set_x2apic_id(apic, vcpu->vcpu_id); - if ((old_value ^ value) & (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)) + if ((old_value ^ value) & (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)) { + kvm_vcpu_update_apicv(vcpu); static_call_cond(kvm_x86_set_virtual_apic_mode)(vcpu); + } apic->base_address = apic->vcpu->arch.apic_base & MSR_IA32_APICBASE_BASE; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 031678eff28e..47981e97d686 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -10065,7 +10065,9 @@ void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu) down_read(&vcpu->kvm->arch.apicv_update_lock); preempt_disable(); - activate = kvm_vcpu_apicv_activated(vcpu); + /* Do not activate APICV when APIC is disabled */ + activate = kvm_vcpu_apicv_activated(vcpu) && + (kvm_get_apic_mode(vcpu) != LAPIC_MODE_DISABLED); if (apic->apicv_active == activate) goto out; From 05c4fe8c1bd94c6f59a8b82cbd535b1aea55945f Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:27:01 -0500 Subject: [PATCH 0682/1436] KVM: SVM: Refresh AVIC configuration when changing APIC mode AMD AVIC can support xAPIC and x2APIC virtualization, which requires changing x2APIC bit VMCB and MSR intercepton for x2APIC MSRs. Therefore, call avic_refresh_apicv_exec_ctrl() to refresh configuration accordingly. Reviewed-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-10-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/avic.c | 12 ++++++++++++ arch/x86/kvm/svm/svm.c | 1 + arch/x86/kvm/svm/svm.h | 2 ++ 3 files changed, 15 insertions(+) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index cc4da232040c..eb7060d3327b 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -675,6 +675,18 @@ void avic_apicv_post_state_restore(struct kvm_vcpu *vcpu) avic_handle_ldr_update(vcpu); } +void avic_set_virtual_apic_mode(struct kvm_vcpu *vcpu) +{ + if (!lapic_in_kernel(vcpu) || avic_mode == AVIC_MODE_NONE) + return; + + if (kvm_get_apic_mode(vcpu) == LAPIC_MODE_INVALID) { + WARN_ONCE(true, "Invalid local APIC state (vcpu_id=%d)", vcpu->vcpu_id); + return; + } + avic_refresh_apicv_exec_ctrl(vcpu); +} + static int avic_set_pi_irte_mode(struct kvm_vcpu *vcpu, bool activate) { int ret = 0; diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 382edac728c7..67ba0d3a7f62 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4793,6 +4793,7 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { .enable_nmi_window = svm_enable_nmi_window, .enable_irq_window = svm_enable_irq_window, .update_cr8_intercept = svm_update_cr8_intercept, + .set_virtual_apic_mode = avic_set_virtual_apic_mode, .refresh_apicv_exec_ctrl = avic_refresh_apicv_exec_ctrl, .check_apicv_inhibit_reasons = avic_check_apicv_inhibit_reasons, .apicv_post_state_restore = avic_apicv_post_state_restore, diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 172c2a37e60e..6d89842853cf 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -634,6 +634,8 @@ void avic_vcpu_blocking(struct kvm_vcpu *vcpu); void avic_vcpu_unblocking(struct kvm_vcpu *vcpu); void avic_ring_doorbell(struct kvm_vcpu *vcpu); unsigned long avic_vcpu_get_apicv_inhibit_reasons(struct kvm_vcpu *vcpu); +void avic_set_virtual_apic_mode(struct kvm_vcpu *vcpu); + /* sev.c */ From 7a8f7c1f3434afc94b6895eff713e0fcea01e3b4 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 19 May 2022 05:27:02 -0500 Subject: [PATCH 0683/1436] KVM: x86: nSVM: always intercept x2apic msrs As a preparation for x2avic, this patch ensures that x2apic msrs are always intercepted for the nested guest. Reviewed-by: Suravee Suthikulpanit Tested-by: Suravee Suthikulpanit Signed-off-by: Maxim Levitsky Message-Id: <20220519102709.24125-11-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/nested.c | 5 +++++ arch/x86/kvm/svm/svm.h | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 83bae1f2eeb8..adf4120b05d9 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -230,6 +230,11 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm) break; p = msrpm_offsets[i]; + + /* x2apic msrs are intercepted always for the nested guest */ + if (is_x2apic_msrpm_offset(p)) + continue; + offset = svm->nested.ctl.msrpm_base_pa + (p * 4); if (kvm_vcpu_read_guest(&svm->vcpu, offset, &value, 4)) diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 6d89842853cf..288a1384aa0f 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -521,6 +521,15 @@ static inline bool nested_npt_enabled(struct vcpu_svm *svm) return svm->nested.ctl.nested_ctl & SVM_NESTED_CTL_NP_ENABLE; } +static inline bool is_x2apic_msrpm_offset(u32 offset) +{ + /* 4 msrs per u8, and 4 u8 in u32 */ + u32 msr = offset * 16; + + return (msr >= APIC_BASE_MSR) && + (msr < (APIC_BASE_MSR + 0x100)); +} + /* svm.c */ #define MSR_INVALID 0xffffffffU From 4d1d7942e36add0aa741a62d0c8e3aba2d5b3ab1 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:27:03 -0500 Subject: [PATCH 0684/1436] KVM: SVM: Introduce logic to (de)activate x2AVIC mode Introduce logic to (de)activate AVIC, which also allows switching between AVIC to x2AVIC mode at runtime. When an AVIC-enabled guest switches from APIC to x2APIC mode, the SVM driver needs to perform the following steps: 1. Set the x2APIC mode bit for AVIC in VMCB along with the maximum APIC ID support for each mode accodingly. 2. Disable x2APIC MSRs interception in order to allow the hardware to virtualize x2APIC MSRs accesses. Reported-by: kernel test robot Reviewed-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-12-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/svm.h | 1 + arch/x86/kvm/svm/avic.c | 39 +++++++++++++++++++++++++++++++++----- arch/x86/kvm/svm/svm.c | 18 ++++++++++++++++++ arch/x86/kvm/svm/svm.h | 1 + 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index ed4b83d7f09e..0361626841bc 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -256,6 +256,7 @@ enum avic_ipi_failure_cause { AVIC_IPI_FAILURE_INVALID_BACKING_PAGE, }; +#define AVIC_PHYSICAL_MAX_INDEX_MASK GENMASK_ULL(9, 0) /* * For AVIC, the max index allowed for physical APIC ID diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index eb7060d3327b..c7db96428b19 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -63,6 +63,36 @@ struct amd_svm_iommu_ir { void *data; /* Storing pointer to struct amd_ir_data */ }; +static void avic_activate_vmcb(struct vcpu_svm *svm) +{ + struct vmcb *vmcb = svm->vmcb01.ptr; + + vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK); + vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK; + + vmcb->control.int_ctl |= AVIC_ENABLE_MASK; + if (apic_x2apic_mode(svm->vcpu.arch.apic)) { + vmcb->control.int_ctl |= X2APIC_MODE_MASK; + vmcb->control.avic_physical_id |= X2AVIC_MAX_PHYSICAL_ID; + /* Disabling MSR intercept for x2APIC registers */ + svm_set_x2apic_msr_interception(svm, false); + } else { + vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID; + /* Enabling MSR intercept for x2APIC registers */ + svm_set_x2apic_msr_interception(svm, true); + } +} + +static void avic_deactivate_vmcb(struct vcpu_svm *svm) +{ + struct vmcb *vmcb = svm->vmcb01.ptr; + + vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK); + vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK; + + /* Enabling MSR intercept for x2APIC registers */ + svm_set_x2apic_msr_interception(svm, true); +} /* Note: * This function is called from IOMMU driver to notify @@ -179,13 +209,12 @@ void avic_init_vmcb(struct vcpu_svm *svm, struct vmcb *vmcb) vmcb->control.avic_backing_page = bpa & AVIC_HPA_MASK; vmcb->control.avic_logical_id = lpa & AVIC_HPA_MASK; vmcb->control.avic_physical_id = ppa & AVIC_HPA_MASK; - vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID; vmcb->control.avic_vapic_bar = APIC_DEFAULT_PHYS_BASE & VMCB_AVIC_APIC_BAR_MASK; if (kvm_apicv_activated(svm->vcpu.kvm)) - vmcb->control.int_ctl |= AVIC_ENABLE_MASK; + avic_activate_vmcb(svm); else - vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK; + avic_deactivate_vmcb(svm); } static u64 *avic_get_physical_id_entry(struct kvm_vcpu *vcpu, @@ -1049,9 +1078,9 @@ void avic_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu) * accordingly before re-activating. */ avic_apicv_post_state_restore(vcpu); - vmcb->control.int_ctl |= AVIC_ENABLE_MASK; + avic_activate_vmcb(svm); } else { - vmcb->control.int_ctl &= ~AVIC_ENABLE_MASK; + avic_deactivate_vmcb(svm); } vmcb_mark_dirty(vmcb, VMCB_AVIC); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 67ba0d3a7f62..491e4d549e2f 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -805,6 +805,24 @@ void svm_vcpu_init_msrpm(struct kvm_vcpu *vcpu, u32 *msrpm) } } +void svm_set_x2apic_msr_interception(struct vcpu_svm *svm, bool intercept) +{ + int i; + + if (avic_mode != AVIC_MODE_X2 || + !apic_x2apic_mode(svm->vcpu.arch.apic)) + return; + + for (i = 0; i < MAX_DIRECT_ACCESS_MSRS; i++) { + int index = direct_access_msrs[i].index; + + if ((index < APIC_BASE_MSR) || + (index > APIC_BASE_MSR + 0xff)) + continue; + set_msr_interception(&svm->vcpu, svm->msrpm, index, + !intercept, !intercept); + } +} void svm_vcpu_free_msrpm(u32 *msrpm) { diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index 288a1384aa0f..ccaae7d160cd 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -555,6 +555,7 @@ void svm_set_gif(struct vcpu_svm *svm, bool value); int svm_invoke_exit_handler(struct kvm_vcpu *vcpu, u64 exit_code); void set_msr_interception(struct kvm_vcpu *vcpu, u32 *msrpm, u32 msr, int read, int write); +void svm_set_x2apic_msr_interception(struct vcpu_svm *svm, bool disable); void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode, int trig_mode, int vec); From c0caeee65af3944b7b8abbf566e7cc1fae15c775 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:27:04 -0500 Subject: [PATCH 0685/1436] KVM: SVM: Do not throw warning when calling avic_vcpu_load on a running vcpu Originalliy, this WARN_ON is designed to detect when calling avic_vcpu_load() on an already running vcpu in AVIC mode (i.e. the AVIC is_running bit is set). However, for x2AVIC, the vCPU can switch from xAPIC to x2APIC mode while in running state, in which the avic_vcpu_load() will be called from svm_refresh_apicv_exec_ctrl(). Therefore, remove this warning since it is no longer appropriate. Reviewed-by: Maxim Levitsky Reviewed-by: Pankaj Gupta Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-13-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/avic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index c7db96428b19..fcff249e73cd 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -1030,7 +1030,6 @@ void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu) return; entry = READ_ONCE(*(svm->avic_physical_id_cache)); - WARN_ON(entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK); entry &= ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK; entry |= (h_physical_id & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK); From 0e311d33bfbef86da130674e8528cc23e6acfe16 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:27:05 -0500 Subject: [PATCH 0686/1436] KVM: SVM: Introduce hybrid-AVIC mode Currently, AVIC is inhibited when booting a VM w/ x2APIC support. because AVIC cannot virtualize x2APIC MSR register accesses. However, the AVIC doorbell can be used to accelerate interrupt injection into a running vCPU, while all guest accesses to x2APIC MSRs will be intercepted and emulated by KVM. With hybrid-AVIC support, the APICV_INHIBIT_REASON_X2APIC is no longer enforced. Suggested-by: Maxim Levitsky Reviewed-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-14-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm_host.h | 5 ----- arch/x86/kvm/svm/avic.c | 13 +++++++++++-- arch/x86/kvm/svm/svm.c | 9 --------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 88a3026ee163..de5a149d0971 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1129,11 +1129,6 @@ enum kvm_apicv_inhibit { */ APICV_INHIBIT_REASON_PIT_REINJ, - /* - * AVIC is inhibited because the guest has x2apic in its CPUID. - */ - APICV_INHIBIT_REASON_X2APIC, - /* * AVIC is disabled because SEV doesn't support it. */ diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index fcff249e73cd..a8db5d2532bc 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -71,12 +71,22 @@ static void avic_activate_vmcb(struct vcpu_svm *svm) vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK; vmcb->control.int_ctl |= AVIC_ENABLE_MASK; - if (apic_x2apic_mode(svm->vcpu.arch.apic)) { + + /* Note: + * KVM can support hybrid-AVIC mode, where KVM emulates x2APIC + * MSR accesses, while interrupt injection to a running vCPU + * can be achieved using AVIC doorbell. The AVIC hardware still + * accelerate MMIO accesses, but this does not cause any harm + * as the guest is not supposed to access xAPIC mmio when uses x2APIC. + */ + if (apic_x2apic_mode(svm->vcpu.arch.apic) && + avic_mode == AVIC_MODE_X2) { vmcb->control.int_ctl |= X2APIC_MODE_MASK; vmcb->control.avic_physical_id |= X2AVIC_MAX_PHYSICAL_ID; /* Disabling MSR intercept for x2APIC registers */ svm_set_x2apic_msr_interception(svm, false); } else { + /* For xAVIC and hybrid-xAVIC modes */ vmcb->control.avic_physical_id |= AVIC_MAX_PHYSICAL_ID; /* Enabling MSR intercept for x2APIC registers */ svm_set_x2apic_msr_interception(svm, true); @@ -968,7 +978,6 @@ bool avic_check_apicv_inhibit_reasons(enum kvm_apicv_inhibit reason) BIT(APICV_INHIBIT_REASON_NESTED) | BIT(APICV_INHIBIT_REASON_IRQWIN) | BIT(APICV_INHIBIT_REASON_PIT_REINJ) | - BIT(APICV_INHIBIT_REASON_X2APIC) | BIT(APICV_INHIBIT_REASON_BLOCKIRQ) | BIT(APICV_INHIBIT_REASON_SEV) | BIT(APICV_INHIBIT_REASON_APIC_ID_MODIFIED) | diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 491e4d549e2f..bb0457c1e41c 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4160,7 +4160,6 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); struct kvm_cpuid_entry2 *best; - struct kvm *kvm = vcpu->kvm; vcpu->arch.xsaves_enabled = guest_cpuid_has(vcpu, X86_FEATURE_XSAVE) && boot_cpu_has(X86_FEATURE_XSAVE) && @@ -4192,14 +4191,6 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) vcpu->arch.reserved_gpa_bits &= ~(1UL << (best->ebx & 0x3f)); } - if (kvm_vcpu_apicv_active(vcpu)) { - /* - * AVIC does not work with an x2APIC mode guest. If the X2APIC feature - * is exposed to the guest, disable AVIC. - */ - if (guest_cpuid_has(vcpu, X86_FEATURE_X2APIC)) - kvm_set_apicv_inhibit(kvm, APICV_INHIBIT_REASON_X2APIC); - } init_vmcb_after_set_cpuid(vcpu); } From f8d8ac215919cf40d3b358846ed8e8e3a3683131 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:27:06 -0500 Subject: [PATCH 0687/1436] KVM: x86: Warning APICv inconsistency only when vcpu APIC mode is valid When launching a VM with x2APIC and specify more than 255 vCPUs, the guest kernel can disable x2APIC (e.g. specify nox2apic kernel option). The VM fallbacks to xAPIC mode, and disable the vCPU ID 255 and greater. In this case, APICV is deactivated for the disabled vCPUs. However, the current APICv consistency warning does not account for this case, which results in a warning. Therefore, modify warning logic to report only when vCPU APIC mode is valid. Reviewed-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-15-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 47981e97d686..acd7ce1dcb9f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -10477,7 +10477,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) * per-VM state, and responsing vCPUs must wait for the update * to complete before servicing KVM_REQ_APICV_UPDATE. */ - WARN_ON_ONCE(kvm_vcpu_apicv_activated(vcpu) != kvm_vcpu_apicv_active(vcpu)); + WARN_ON_ONCE((kvm_vcpu_apicv_activated(vcpu) != kvm_vcpu_apicv_active(vcpu)) && + (kvm_get_apic_mode(vcpu) != LAPIC_MODE_DISABLED)); exit_fastpath = static_call(kvm_x86_vcpu_run)(vcpu); if (likely(exit_fastpath != EXIT_FASTPATH_REENTER_GUEST)) From 8c9e639da435874fb845c4d296ce55664071ea7a Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:27:07 -0500 Subject: [PATCH 0688/1436] KVM: SVM: Use target APIC ID to complete x2AVIC IRQs when possible For x2AVIC, the index from incomplete IPI #vmexit info is invalid for logical cluster mode. Only ICRH/ICRL values can be used to determine the IPI destination APIC ID. Since QEMU defines guest physical APIC ID to be the same as vCPU ID, it can be used to quickly identify the target vCPU to deliver IPI, and avoid the overhead from searching through all vCPUs to match the target vCPU. Reviewed-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-16-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/avic.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index a8db5d2532bc..229de5fe665d 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -390,9 +390,7 @@ static int avic_kick_target_vcpus_fast(struct kvm *kvm, struct kvm_lapic *source logid_index = cluster + __ffs(bitmap); - if (apic_x2apic_mode(source)) { - l1_physical_id = logid_index; - } else { + if (!apic_x2apic_mode(source)) { u32 *avic_logical_id_table = page_address(kvm_svm->avic_logical_id_table_page); @@ -407,6 +405,23 @@ static int avic_kick_target_vcpus_fast(struct kvm *kvm, struct kvm_lapic *source l1_physical_id = logid_entry & AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK; + } else { + /* + * For x2APIC logical mode, cannot leverage the index. + * Instead, calculate physical ID from logical ID in ICRH. + */ + int cluster = (icrh & 0xffff0000) >> 16; + int apic = ffs(icrh & 0xffff) - 1; + + /* + * If the x2APIC logical ID sub-field (i.e. icrh[15:0]) + * contains anything but a single bit, we cannot use the + * fast path, because it is limited to a single vCPU. + */ + if (apic < 0 || icrh != (1 << apic)) + return -EINVAL; + + l1_physical_id = (cluster << 4) + apic; } } From 39b6b8c35cf37970e07e9081c0e7d1083930b2f7 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Thu, 19 May 2022 05:27:08 -0500 Subject: [PATCH 0689/1436] KVM: SVM: Add AVIC doorbell tracepoint Add a tracepoint to track number of doorbells being sent to signal a running vCPU to process IRQ after being injected. Reviewed-by: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220519102709.24125-17-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/avic.c | 4 +++- arch/x86/kvm/trace.h | 18 ++++++++++++++++++ arch/x86/kvm/x86.c | 1 + 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 229de5fe665d..f18c852b6900 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -324,8 +324,10 @@ void avic_ring_doorbell(struct kvm_vcpu *vcpu) */ int cpu = READ_ONCE(vcpu->cpu); - if (cpu != get_cpu()) + if (cpu != get_cpu()) { wrmsrl(MSR_AMD64_SVM_AVIC_DOORBELL, kvm_cpu_get_apicid(cpu)); + trace_kvm_avic_doorbell(vcpu->vcpu_id, kvm_cpu_get_apicid(cpu)); + } put_cpu(); } diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index fd28dd40b813..bc85622e28b2 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -1490,6 +1490,24 @@ TRACE_EVENT(kvm_avic_kick_vcpu_slowpath, __entry->icrh, __entry->icrl, __entry->index) ); +TRACE_EVENT(kvm_avic_doorbell, + TP_PROTO(u32 vcpuid, u32 apicid), + TP_ARGS(vcpuid, apicid), + + TP_STRUCT__entry( + __field(u32, vcpuid) + __field(u32, apicid) + ), + + TP_fast_assign( + __entry->vcpuid = vcpuid; + __entry->apicid = apicid; + ), + + TP_printk("vcpuid=%u, apicid=%u", + __entry->vcpuid, __entry->apicid) +); + TRACE_EVENT(kvm_hv_timer_state, TP_PROTO(unsigned int vcpu_id, unsigned int hv_timer_in_use), TP_ARGS(vcpu_id, hv_timer_in_use), diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index acd7ce1dcb9f..d88600e41ff8 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -13328,6 +13328,7 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_unaccelerated_access); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_incomplete_ipi); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_ga_log); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_kick_vcpu_slowpath); +EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_avic_doorbell); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_apicv_accept_irq); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_vmgexit_enter); EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_vmgexit_exit); From 091abbf578f926e763adc0f577baeb7f405b4bdc Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 19 May 2022 05:27:09 -0500 Subject: [PATCH 0690/1436] KVM: x86: nSVM: optimize svm_set_x2apic_msr_interception - Avoid toggling the x2apic msr interception if it is already up to date. - Avoid touching L0 msr bitmap when AVIC is inhibited on entry to the guest mode, because in this case the guest usually uses its own msr bitmap. Later on VM exit, the 1st optimization will allow KVM to skip touching the L0 msr bitmap as well. Reviewed-by: Suravee Suthikulpanit Tested-by: Suravee Suthikulpanit Signed-off-by: Maxim Levitsky Message-Id: <20220519102709.24125-18-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/avic.c | 8 ++++++++ arch/x86/kvm/svm/svm.c | 7 +++++++ arch/x86/kvm/svm/svm.h | 2 ++ 3 files changed, 17 insertions(+) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index f18c852b6900..6919dee69f18 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -100,6 +100,14 @@ static void avic_deactivate_vmcb(struct vcpu_svm *svm) vmcb->control.int_ctl &= ~(AVIC_ENABLE_MASK | X2APIC_MODE_MASK); vmcb->control.avic_physical_id &= ~AVIC_PHYSICAL_MAX_INDEX_MASK; + /* + * If running nested and the guest uses its own MSR bitmap, there + * is no need to update L0's msr bitmap + */ + if (is_guest_mode(&svm->vcpu) && + vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_MSR_PROT)) + return; + /* Enabling MSR intercept for x2APIC registers */ svm_set_x2apic_msr_interception(svm, true); } diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index bb0457c1e41c..37ce061dfc76 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -809,6 +809,9 @@ void svm_set_x2apic_msr_interception(struct vcpu_svm *svm, bool intercept) { int i; + if (intercept == svm->x2avic_msrs_intercepted) + return; + if (avic_mode != AVIC_MODE_X2 || !apic_x2apic_mode(svm->vcpu.arch.apic)) return; @@ -822,6 +825,8 @@ void svm_set_x2apic_msr_interception(struct vcpu_svm *svm, bool intercept) set_msr_interception(&svm->vcpu, svm->msrpm, index, !intercept, !intercept); } + + svm->x2avic_msrs_intercepted = intercept; } void svm_vcpu_free_msrpm(u32 *msrpm) @@ -1393,6 +1398,8 @@ static int svm_vcpu_create(struct kvm_vcpu *vcpu) goto error_free_vmsa_page; } + svm->x2avic_msrs_intercepted = true; + svm->vmcb01.ptr = page_address(vmcb01_page); svm->vmcb01.pa = __sme_set(page_to_pfn(vmcb01_page) << PAGE_SHIFT); svm_switch_vmcb(svm, &svm->vmcb01); diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h index ccaae7d160cd..558ca1296d36 100644 --- a/arch/x86/kvm/svm/svm.h +++ b/arch/x86/kvm/svm/svm.h @@ -276,6 +276,8 @@ struct vcpu_svm { struct vcpu_sev_es_state sev_es; bool guest_state_loaded; + + bool x2avic_msrs_intercepted; }; struct svm_cpu_data { From 7a6177d6f344941410faa51f3e46ef242c54b406 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 15 Jun 2022 13:32:29 -0400 Subject: [PATCH 0691/1436] KVM: x86: complete fast IN directly with complete_emulator_pio_in() Use complete_emulator_pio_in() directly when completing fast PIO, there's no need to bounce through emulator_pio_in(): the comment about ECX changing doesn't apply to fast PIO, which isn't used for string I/O. No functional change intended. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d88600e41ff8..d66a873f4427 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8871,11 +8871,7 @@ static int complete_fast_pio_in(struct kvm_vcpu *vcpu) /* For size less than 4 we merge, else we zero extend */ val = (vcpu->arch.pio.size < 4) ? kvm_rax_read(vcpu) : 0; - /* - * Since vcpu->arch.pio.count == 1 let emulator_pio_in perform - * the copy and tracing - */ - emulator_pio_in(vcpu, vcpu->arch.pio.size, vcpu->arch.pio.port, &val, 1); + complete_emulator_pio_in(vcpu, &val); kvm_rax_write(vcpu, val); return kvm_skip_emulated_instruction(vcpu); From 0f87ac234d98c68e4b2bfde6a8bcdeef3d3f54b7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Oct 2021 06:50:06 -0400 Subject: [PATCH 0692/1436] KVM: x86: inline kernel_pio into its sole caller The caller of kernel_pio already has arguments for most of what kernel_pio fishes out of vcpu->arch.pio. This is the first step towards ensuring that vcpu->arch.pio.* is only used when exiting to userspace. No functional change intended. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 38 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d66a873f4427..524a96d26399 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -7575,37 +7575,31 @@ emul_write: return emulator_write_emulated(ctxt, addr, new, bytes, exception); } -static int kernel_pio(struct kvm_vcpu *vcpu, void *pd) -{ - int r = 0, i; - - for (i = 0; i < vcpu->arch.pio.count; i++) { - if (vcpu->arch.pio.in) - r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, vcpu->arch.pio.port, - vcpu->arch.pio.size, pd); - else - r = kvm_io_bus_write(vcpu, KVM_PIO_BUS, - vcpu->arch.pio.port, vcpu->arch.pio.size, - pd); - if (r) - break; - pd += vcpu->arch.pio.size; - } - return r; -} - static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size, unsigned short port, unsigned int count, bool in) { + void *data = vcpu->arch.pio_data; + unsigned i; + int r; + vcpu->arch.pio.port = port; vcpu->arch.pio.in = in; - vcpu->arch.pio.count = count; + vcpu->arch.pio.count = count; vcpu->arch.pio.size = size; - if (!kernel_pio(vcpu, vcpu->arch.pio_data)) - return 1; + for (i = 0; i < count; i++) { + if (in) + r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, port, size, data); + else + r = kvm_io_bus_write(vcpu, KVM_PIO_BUS, port, size, data); + if (r) + goto userspace_io; + data += size; + } + return 1; +userspace_io: vcpu->run->exit_reason = KVM_EXIT_IO; vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; vcpu->run->io.size = size; From 35ab3b77a0ae76246dd2666d4f8190c824392fb4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 15 Jun 2022 11:05:06 -0400 Subject: [PATCH 0693/1436] KVM: x86: drop PIO from unregistered devices KVM protects the device list with SRCU, and therefore different calls to kvm_io_bus_read()/kvm_io_bus_write() can very well see different incarnations of kvm->buses. If userspace unregisters a device while vCPUs are running there is no well-defined result. This patch applies a safe fallback by returning early from emulator_pio_in_out(). This corresponds to returning zeroes from IN, and dropping the writes on the floor for OUT. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 524a96d26399..5a56d39bd81f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -7593,8 +7593,19 @@ static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size, r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, port, size, data); else r = kvm_io_bus_write(vcpu, KVM_PIO_BUS, port, size, data); - if (r) - goto userspace_io; + + if (r) { + if (i == 0) + goto userspace_io; + + /* + * Userspace must have unregistered the device while PIO + * was running. Drop writes / read as 0 (the buffer + * was zeroed in __emulator_pio_in). + */ + break; + } + data += size; } return 1; @@ -7606,7 +7617,6 @@ userspace_io: vcpu->run->io.data_offset = KVM_PIO_PAGE_OFFSET * PAGE_SIZE; vcpu->run->io.count = count; vcpu->run->io.port = port; - return 0; } From 30d583fd4e1ecafa8642f9f74e102876b4aeb733 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Oct 2021 08:07:19 -0400 Subject: [PATCH 0694/1436] KVM: x86: move all vcpu->arch.pio* setup in emulator_pio_in_out() For now, this is basically an excuse to add back the void* argument to the function, while removing some knowledge of vcpu->arch.pio* from its callers. The WARN that vcpu->arch.pio.count is zero is also extended to OUT operations. The vcpu->arch.pio* fields still need to be filled even when the PIO is handled in-kernel as __emulator_pio_in() is always followed by complete_emulator_pio_in(). But after fixing that, it will be possible to to only populate the vcpu->arch.pio* fields on userspace exits. No functional change intended. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/trace.h | 2 +- arch/x86/kvm/x86.c | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h index bc85622e28b2..2120d7c060a9 100644 --- a/arch/x86/kvm/trace.h +++ b/arch/x86/kvm/trace.h @@ -154,7 +154,7 @@ TRACE_EVENT(kvm_xen_hypercall, TRACE_EVENT(kvm_pio, TP_PROTO(unsigned int rw, unsigned int port, unsigned int size, - unsigned int count, void *data), + unsigned int count, const void *data), TP_ARGS(rw, port, size, count, data), TP_STRUCT__entry( diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5a56d39bd81f..368d0d4d56ff 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -7576,17 +7576,25 @@ emul_write: } static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size, - unsigned short port, + unsigned short port, void *data, unsigned int count, bool in) { - void *data = vcpu->arch.pio_data; unsigned i; int r; + WARN_ON_ONCE(vcpu->arch.pio.count); vcpu->arch.pio.port = port; vcpu->arch.pio.in = in; vcpu->arch.pio.count = count; vcpu->arch.pio.size = size; + if (in) { + /* The buffer is only used in complete_emulator_pio_in(). */ + WARN_ON(data); + memset(vcpu->arch.pio_data, 0, size * count); + } else { + memcpy(vcpu->arch.pio_data, data, size * count); + } + data = vcpu->arch.pio_data; for (i = 0; i < count; i++) { if (in) @@ -7623,9 +7631,7 @@ userspace_io: static int __emulator_pio_in(struct kvm_vcpu *vcpu, int size, unsigned short port, unsigned int count) { - WARN_ON(vcpu->arch.pio.count); - memset(vcpu->arch.pio_data, 0, size * count); - return emulator_pio_in_out(vcpu, size, port, count, true); + return emulator_pio_in_out(vcpu, size, port, NULL, count, true); } static void complete_emulator_pio_in(struct kvm_vcpu *vcpu, void *val) @@ -7674,9 +7680,8 @@ static int emulator_pio_out(struct kvm_vcpu *vcpu, int size, { int ret; - memcpy(vcpu->arch.pio_data, val, size * count); - trace_kvm_pio(KVM_PIO_OUT, port, size, count, vcpu->arch.pio_data); - ret = emulator_pio_in_out(vcpu, size, port, count, false); + trace_kvm_pio(KVM_PIO_OUT, port, size, count, val); + ret = emulator_pio_in_out(vcpu, size, port, (void *)val, count, false); if (ret) vcpu->arch.pio.count = 0; From 0c05e10bce5217657bcdaa9787c9ea94e6b384b2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 15 Jun 2022 10:24:01 -0400 Subject: [PATCH 0695/1436] KVM: x86: wean in-kernel PIO from vcpu->arch.pio* Make emulator_pio_in_out operate directly on the provided buffer as long as PIO is handled inside KVM. For input operations, this means that, in the case of in-kernel PIO, __emulator_pio_in() does not have to be always followed by complete_emulator_pio_in(). This affects emulator_pio_in() and kvm_sev_es_ins(); for the latter, that is why the call moves from advance_sev_es_emulated_ins() to complete_sev_es_emulated_ins(). For output, it means that vcpu->pio.count is never set unnecessarily and there is no need to clear it; but also vcpu->pio.size must not be used in kvm_sev_es_outs(), because it will not be updated for in-kernel OUT. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 73 ++++++++++++++++++++-------------------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 368d0d4d56ff..716ae5c92687 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -7583,19 +7583,6 @@ static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size, int r; WARN_ON_ONCE(vcpu->arch.pio.count); - vcpu->arch.pio.port = port; - vcpu->arch.pio.in = in; - vcpu->arch.pio.count = count; - vcpu->arch.pio.size = size; - if (in) { - /* The buffer is only used in complete_emulator_pio_in(). */ - WARN_ON(data); - memset(vcpu->arch.pio_data, 0, size * count); - } else { - memcpy(vcpu->arch.pio_data, data, size * count); - } - data = vcpu->arch.pio_data; - for (i = 0; i < count; i++) { if (in) r = kvm_io_bus_read(vcpu, KVM_PIO_BUS, port, size, data); @@ -7608,9 +7595,10 @@ static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size, /* * Userspace must have unregistered the device while PIO - * was running. Drop writes / read as 0 (the buffer - * was zeroed in __emulator_pio_in). + * was running. Drop writes / read as 0. */ + if (in) + memset(data, 0, size * (count - i)); break; } @@ -7619,6 +7607,16 @@ static int emulator_pio_in_out(struct kvm_vcpu *vcpu, int size, return 1; userspace_io: + vcpu->arch.pio.port = port; + vcpu->arch.pio.in = in; + vcpu->arch.pio.count = count; + vcpu->arch.pio.size = size; + + if (in) + memset(vcpu->arch.pio_data, 0, size * count); + else + memcpy(vcpu->arch.pio_data, data, size * count); + vcpu->run->exit_reason = KVM_EXIT_IO; vcpu->run->io.direction = in ? KVM_EXIT_IO_IN : KVM_EXIT_IO_OUT; vcpu->run->io.size = size; @@ -7629,15 +7627,19 @@ userspace_io: } static int __emulator_pio_in(struct kvm_vcpu *vcpu, int size, - unsigned short port, unsigned int count) + unsigned short port, void *val, unsigned int count) { - return emulator_pio_in_out(vcpu, size, port, NULL, count, true); + int r = emulator_pio_in_out(vcpu, size, port, val, count, true); + if (r) + trace_kvm_pio(KVM_PIO_IN, port, size, count, val); + + return r; } static void complete_emulator_pio_in(struct kvm_vcpu *vcpu, void *val) { int size = vcpu->arch.pio.size; - unsigned count = vcpu->arch.pio.count; + unsigned int count = vcpu->arch.pio.count; memcpy(val, vcpu->arch.pio_data, size * count); trace_kvm_pio(KVM_PIO_IN, vcpu->arch.pio.port, size, count, vcpu->arch.pio_data); vcpu->arch.pio.count = 0; @@ -7654,16 +7656,11 @@ static int emulator_pio_in(struct kvm_vcpu *vcpu, int size, * shenanigans as KVM doesn't support modifying the rep count, * and the emulator ensures @count doesn't overflow the buffer. */ - } else { - int r = __emulator_pio_in(vcpu, size, port, count); - if (!r) - return r; - - /* Results already available, fall through. */ + complete_emulator_pio_in(vcpu, val); + return 1; } - complete_emulator_pio_in(vcpu, val); - return 1; + return __emulator_pio_in(vcpu, size, port, val, count); } static int emulator_pio_in_emulated(struct x86_emulate_ctxt *ctxt, @@ -7678,14 +7675,8 @@ static int emulator_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port, const void *val, unsigned int count) { - int ret; - trace_kvm_pio(KVM_PIO_OUT, port, size, count, val); - ret = emulator_pio_in_out(vcpu, size, port, (void *)val, count, false); - if (ret) - vcpu->arch.pio.count = 0; - - return ret; + return emulator_pio_in_out(vcpu, size, port, (void *)val, count, false); } static int emulator_pio_out_emulated(struct x86_emulate_ctxt *ctxt, @@ -13245,7 +13236,7 @@ static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size, /* memcpy done already by emulator_pio_out. */ vcpu->arch.sev_pio_count -= count; - vcpu->arch.sev_pio_data += count * vcpu->arch.pio.size; + vcpu->arch.sev_pio_data += count * size; if (!ret) break; @@ -13261,20 +13252,20 @@ static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size, static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size, unsigned int port); -static void advance_sev_es_emulated_ins(struct kvm_vcpu *vcpu) +static void advance_sev_es_emulated_ins(struct kvm_vcpu *vcpu, unsigned count, int size) { - unsigned count = vcpu->arch.pio.count; - complete_emulator_pio_in(vcpu, vcpu->arch.sev_pio_data); vcpu->arch.sev_pio_count -= count; - vcpu->arch.sev_pio_data += count * vcpu->arch.pio.size; + vcpu->arch.sev_pio_data += count * size; } static int complete_sev_es_emulated_ins(struct kvm_vcpu *vcpu) { + unsigned count = vcpu->arch.pio.count; int size = vcpu->arch.pio.size; int port = vcpu->arch.pio.port; - advance_sev_es_emulated_ins(vcpu); + complete_emulator_pio_in(vcpu, vcpu->arch.sev_pio_data); + advance_sev_es_emulated_ins(vcpu, count, size); if (vcpu->arch.sev_pio_count) return kvm_sev_es_ins(vcpu, size, port); return 1; @@ -13286,11 +13277,11 @@ static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size, for (;;) { unsigned int count = min_t(unsigned int, PAGE_SIZE / size, vcpu->arch.sev_pio_count); - if (!__emulator_pio_in(vcpu, size, port, count)) + if (!__emulator_pio_in(vcpu, size, port, vcpu->arch.sev_pio_data, count)) break; /* Emulation done by the kernel. */ - advance_sev_es_emulated_ins(vcpu); + advance_sev_es_emulated_ins(vcpu, count, size); if (!vcpu->arch.sev_pio_count) return 1; } From dc7a4bfde507ffe1d8bef49aba1322f1d20c2cb3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Oct 2021 08:01:36 -0400 Subject: [PATCH 0696/1436] KVM: x86: wean fast IN from emulator_pio_in Use __emulator_pio_in() directly for fast PIO instead of bouncing through emulator_pio_in() now that __emulator_pio_in() fills "val" when handling in-kernel PIO. vcpu->arch.pio.count is guaranteed to be '0', so this a pure nop. emulator_pio_in_emulated is now the last caller of emulator_pio_in. No functional change intended. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 716ae5c92687..b824ffc63b17 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -8886,7 +8886,7 @@ static int kvm_fast_pio_in(struct kvm_vcpu *vcpu, int size, /* For size less than 4 we merge, else we zero extend */ val = (size < 4) ? kvm_rax_read(vcpu) : 0; - ret = emulator_pio_in(vcpu, size, port, &val, 1); + ret = __emulator_pio_in(vcpu, size, port, &val, 1); if (ret) { kvm_rax_write(vcpu, val); return ret; From f35cee4adb54af59129193d528706b390befb5f4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Oct 2021 08:19:48 -0400 Subject: [PATCH 0697/1436] KVM: x86: de-underscorify __emulator_pio_in Now all callers except emulator_pio_in_emulated are using __emulator_pio_in/complete_emulator_pio_in explicitly. Move the "either copy the result or attempt PIO" logic in emulator_pio_in_emulated, and rename __emulator_pio_in to just emulator_pio_in. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b824ffc63b17..1a017a5a680b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -7626,8 +7626,8 @@ userspace_io: return 0; } -static int __emulator_pio_in(struct kvm_vcpu *vcpu, int size, - unsigned short port, void *val, unsigned int count) +static int emulator_pio_in(struct kvm_vcpu *vcpu, int size, + unsigned short port, void *val, unsigned int count) { int r = emulator_pio_in_out(vcpu, size, port, val, count, true); if (r) @@ -7645,9 +7645,11 @@ static void complete_emulator_pio_in(struct kvm_vcpu *vcpu, void *val) vcpu->arch.pio.count = 0; } -static int emulator_pio_in(struct kvm_vcpu *vcpu, int size, - unsigned short port, void *val, unsigned int count) +static int emulator_pio_in_emulated(struct x86_emulate_ctxt *ctxt, + int size, unsigned short port, void *val, + unsigned int count) { + struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); if (vcpu->arch.pio.count) { /* * Complete a previous iteration that required userspace I/O. @@ -7660,15 +7662,7 @@ static int emulator_pio_in(struct kvm_vcpu *vcpu, int size, return 1; } - return __emulator_pio_in(vcpu, size, port, val, count); -} - -static int emulator_pio_in_emulated(struct x86_emulate_ctxt *ctxt, - int size, unsigned short port, void *val, - unsigned int count) -{ - return emulator_pio_in(emul_to_vcpu(ctxt), size, port, val, count); - + return emulator_pio_in(vcpu, size, port, val, count); } static int emulator_pio_out(struct kvm_vcpu *vcpu, int size, @@ -8886,7 +8880,7 @@ static int kvm_fast_pio_in(struct kvm_vcpu *vcpu, int size, /* For size less than 4 we merge, else we zero extend */ val = (size < 4) ? kvm_rax_read(vcpu) : 0; - ret = __emulator_pio_in(vcpu, size, port, &val, 1); + ret = emulator_pio_in(vcpu, size, port, &val, 1); if (ret) { kvm_rax_write(vcpu, val); return ret; @@ -13277,7 +13271,7 @@ static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size, for (;;) { unsigned int count = min_t(unsigned int, PAGE_SIZE / size, vcpu->arch.sev_pio_count); - if (!__emulator_pio_in(vcpu, size, port, vcpu->arch.sev_pio_data, count)) + if (!emulator_pio_in(vcpu, size, port, vcpu->arch.sev_pio_data, count)) break; /* Emulation done by the kernel. */ From db209369d48eab1e2c724d90c606752d398ae334 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Oct 2021 08:47:56 -0400 Subject: [PATCH 0698/1436] KVM: SEV-ES: reuse advance_sev_es_emulated_ins for OUT too complete_emulator_pio_in() only has to be called by complete_sev_es_emulated_ins() now; therefore, all that the function does now is adjust sev_pio_count and sev_pio_data. Which is the same for both IN and OUT. No functional change intended. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1a017a5a680b..567d13405445 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -13206,6 +13206,12 @@ int kvm_sev_es_mmio_read(struct kvm_vcpu *vcpu, gpa_t gpa, unsigned int bytes, } EXPORT_SYMBOL_GPL(kvm_sev_es_mmio_read); +static void advance_sev_es_emulated_pio(struct kvm_vcpu *vcpu, unsigned count, int size) +{ + vcpu->arch.sev_pio_count -= count; + vcpu->arch.sev_pio_data += count * size; +} + static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size, unsigned int port); @@ -13229,8 +13235,7 @@ static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size, int ret = emulator_pio_out(vcpu, size, port, vcpu->arch.sev_pio_data, count); /* memcpy done already by emulator_pio_out. */ - vcpu->arch.sev_pio_count -= count; - vcpu->arch.sev_pio_data += count * size; + advance_sev_es_emulated_pio(vcpu, count, size); if (!ret) break; @@ -13246,12 +13251,6 @@ static int kvm_sev_es_outs(struct kvm_vcpu *vcpu, unsigned int size, static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size, unsigned int port); -static void advance_sev_es_emulated_ins(struct kvm_vcpu *vcpu, unsigned count, int size) -{ - vcpu->arch.sev_pio_count -= count; - vcpu->arch.sev_pio_data += count * size; -} - static int complete_sev_es_emulated_ins(struct kvm_vcpu *vcpu) { unsigned count = vcpu->arch.pio.count; @@ -13259,7 +13258,7 @@ static int complete_sev_es_emulated_ins(struct kvm_vcpu *vcpu) int port = vcpu->arch.pio.port; complete_emulator_pio_in(vcpu, vcpu->arch.sev_pio_data); - advance_sev_es_emulated_ins(vcpu, count, size); + advance_sev_es_emulated_pio(vcpu, count, size); if (vcpu->arch.sev_pio_count) return kvm_sev_es_ins(vcpu, size, port); return 1; @@ -13275,7 +13274,7 @@ static int kvm_sev_es_ins(struct kvm_vcpu *vcpu, unsigned int size, break; /* Emulation done by the kernel. */ - advance_sev_es_emulated_ins(vcpu, count, size); + advance_sev_es_emulated_pio(vcpu, count, size); if (!vcpu->arch.sev_pio_count) return 1; } From 72ae5822b81a6686c4b4d526ccdd7b7f5f0f9b97 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 24 Jun 2022 17:18:07 +0000 Subject: [PATCH 0699/1436] KVM: x86/mmu: Use "unsigned int", not "u32", for SPTEs' @access info Use an "unsigned int" for @access parameters instead of a "u32", mostly to be consistent throughout KVM, but also because "u32" is misleading. @access can actually squeeze into a u8, i.e. doesn't need 32 bits, but is as an "unsigned int" because sp->role.access is an unsigned int. No functional change intended. Link: https://lore.kernel.org/all/YqyZxEfxXLsHGoZ%2F@google.com Cc: David Matlack Signed-off-by: Sean Christopherson Message-Id: <20220624171808.2845941-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index bd74a287b54a..d5554cd61492 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -717,7 +717,8 @@ static u32 kvm_mmu_page_get_access(struct kvm_mmu_page *sp, int index) return sp->role.access; } -static void kvm_mmu_page_set_translation(struct kvm_mmu_page *sp, int index, gfn_t gfn, u32 access) +static void kvm_mmu_page_set_translation(struct kvm_mmu_page *sp, int index, + gfn_t gfn, unsigned int access) { if (sp_has_gptes(sp)) { sp->shadowed_translation[index] = (gfn << PAGE_SHIFT) | access; @@ -735,7 +736,8 @@ static void kvm_mmu_page_set_translation(struct kvm_mmu_page *sp, int index, gfn sp->gfn, kvm_mmu_page_get_gfn(sp, index), gfn); } -static void kvm_mmu_page_set_access(struct kvm_mmu_page *sp, int index, u32 access) +static void kvm_mmu_page_set_access(struct kvm_mmu_page *sp, int index, + unsigned int access) { gfn_t gfn = kvm_mmu_page_get_gfn(sp, index); @@ -1580,7 +1582,7 @@ static bool kvm_test_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, static void __rmap_add(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, const struct kvm_memory_slot *slot, - u64 *spte, gfn_t gfn, u32 access) + u64 *spte, gfn_t gfn, unsigned int access) { struct kvm_mmu_page *sp; struct kvm_rmap_head *rmap_head; @@ -1601,7 +1603,7 @@ static void __rmap_add(struct kvm *kvm, } static void rmap_add(struct kvm_vcpu *vcpu, const struct kvm_memory_slot *slot, - u64 *spte, gfn_t gfn, u32 access) + u64 *spte, gfn_t gfn, unsigned int access) { struct kvm_mmu_memory_cache *cache = &vcpu->arch.mmu_pte_list_desc_cache; From b9b71f43683ae9d76b0989249607bbe8c9eb6c5c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 24 Jun 2022 17:18:08 +0000 Subject: [PATCH 0700/1436] KVM: x86/mmu: Buffer nested MMU split_desc_cache only by default capacity Buffer split_desc_cache, the cache used to allcoate rmap list entries, only by the default cache capacity (currently 40), not by doubling the minimum (513). Aliasing L2 GPAs to L1 GPAs is uncommon, thus eager page splitting is unlikely to need 500+ entries. And because each object is a non-trivial 128 bytes (see struct pte_list_desc), those extra ~500 entries means KVM is in all likelihood wasting ~64kb of memory per VM. Link: https://lore.kernel.org/all/YrTDcrsn0%2F+alpzf@google.com Cc: David Matlack Signed-off-by: Sean Christopherson Message-Id: <20220624171808.2845941-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index d5554cd61492..f7fa4c31b7c5 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -6118,17 +6118,25 @@ static bool need_topup_split_caches_or_resched(struct kvm *kvm) static int topup_split_caches(struct kvm *kvm) { + /* + * Allocating rmap list entries when splitting huge pages for nested + * MMUs is uncommon as KVM needs to allocate if and only if there is + * more than one rmap entry for a gfn, i.e. requires an L1 gfn to be + * aliased by multiple L2 gfns. Aliasing gfns when using TDP is very + * atypical for VMMs; a few gfns are often aliased during boot, e.g. + * when remapping firmware, but aliasing rarely occurs post-boot). If + * there is only one rmap entry, rmap->val points directly at that one + * entry and doesn't need to allocate a list. Buffer the cache by the + * default capacity so that KVM doesn't have to topup the cache if it + * encounters an aliased gfn or two. + */ + const int capacity = SPLIT_DESC_CACHE_MIN_NR_OBJECTS + + KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE; int r; lockdep_assert_held(&kvm->slots_lock); - /* - * Setting capacity == min would cause KVM to drop mmu_lock even if - * just one object was consumed from the cache, so make capacity - * larger than min. - */ - r = __kvm_mmu_topup_memory_cache(&kvm->arch.split_desc_cache, - 2 * SPLIT_DESC_CACHE_MIN_NR_OBJECTS, + r = __kvm_mmu_topup_memory_cache(&kvm->arch.split_desc_cache, capacity, SPLIT_DESC_CACHE_MIN_NR_OBJECTS); if (r) return r; From 1024a6e0c004248b7041709741f92cfb76f59df8 Mon Sep 17 00:00:00 2001 From: Gayatri Kammela Date: Tue, 14 Jun 2022 17:27:51 -0700 Subject: [PATCH 0701/1436] platform/x86: intel/pmc: Add Alder Lake N support to PMC core driver Add Alder Lake N (ADL-N) to the list of the platforms that Intel's PMC core driver supports. Alder Lake N reuses all the TigerLake PCH IPs. Cc: Srinivas Pandruvada Cc: Andy Shevchenko Cc: David E. Box Signed-off-by: Gayatri Kammela Reviewed-by: Rajneesh Bhardwaj Link: https://lore.kernel.org/r/20220615002751.3371730-1-gayatri.kammela@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/pmc/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c index 40183bda7894..a1fe1e0dcf4a 100644 --- a/drivers/platform/x86/intel/pmc/core.c +++ b/drivers/platform/x86/intel/pmc/core.c @@ -1911,6 +1911,7 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = { X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L, &icl_reg_map), X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, &tgl_reg_map), X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &tgl_reg_map), + X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, &tgl_reg_map), X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, &adl_reg_map), X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, &tgl_reg_map), {} From d7e64c6d9c60f8c72d46c82af185336eaa2a1989 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 15 Jun 2022 11:11:07 +0300 Subject: [PATCH 0702/1436] platform/mellanox: nvsw-sn2201: fix error code in nvsw_sn2201_create_static_devices() This should return PTR_ERR() instead of IS_ERR(). Also "dev->client" has been set to NULL by this point so it returns 0/success so preserve the error code earlier. Fixes: 662f24826f95 ("platform/mellanox: Add support for new SN2201 system") Signed-off-by: Dan Carpenter Acked-by: Michael Shych Link: https://lore.kernel.org/r/YqmUGwmPK7cPolk/@kili Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/mellanox/nvsw-sn2201.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/platform/mellanox/nvsw-sn2201.c b/drivers/platform/mellanox/nvsw-sn2201.c index 2923daf63b75..7b9c107c17ce 100644 --- a/drivers/platform/mellanox/nvsw-sn2201.c +++ b/drivers/platform/mellanox/nvsw-sn2201.c @@ -890,6 +890,7 @@ nvsw_sn2201_create_static_devices(struct nvsw_sn2201 *nvsw_sn2201, int size) { struct mlxreg_hotplug_device *dev = devs; + int ret; int i; /* Create I2C static devices. */ @@ -901,6 +902,7 @@ nvsw_sn2201_create_static_devices(struct nvsw_sn2201 *nvsw_sn2201, dev->nr, dev->brdinfo->addr); dev->adapter = NULL; + ret = PTR_ERR(dev->client); goto fail_create_static_devices; } } @@ -914,7 +916,7 @@ fail_create_static_devices: dev->client = NULL; dev->adapter = NULL; } - return IS_ERR(dev->client); + return ret; } static void nvsw_sn2201_destroy_static_devices(struct nvsw_sn2201 *nvsw_sn2201, From 3c40a71c03b6b4478ac7d517a8dff30617a0cdc8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 Jun 2022 01:49:50 +0300 Subject: [PATCH 0703/1436] platform/x86: thinkpad_acpi: Sort headers for better maintenance It's quite hard to understand in that zillions of headers that are included if any specific one is already listed. Sort headers for better maintenance. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220616224951.66660-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 58 +++++++++++++++------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index e23a5398ea3e..c128038118dc 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -34,46 +34,50 @@ * thanks to Chris Wright */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include +#include +#include #include -#include +#include #include #include +#include #include -#include -#include -#include #include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include -#include +#include #include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include + #include #include + #include + +#include +#include +#include + #include "dual_accel_detect.h" /* ThinkPad CMOS commands */ From 664607f54594d939bb9dda2a29db2b8e926b4e3f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 17 Jun 2022 01:49:51 +0300 Subject: [PATCH 0704/1436] platform/x86: thinkpad_acpi: Replace custom str_on_off() etc Replace enabled(), onoff() and other similar places by str_*() helpers. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220616224951.66660-2-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 55 +++++++++++----------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index c128038118dc..c54c318bf9f6 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -262,8 +263,6 @@ enum tpacpi_hkey_event_t { #define TPACPI_DBG_BRGHT 0x0020 #define TPACPI_DBG_MIXER 0x0040 -#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") -#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") #define strlencmp(a, b) (strncmp((a), (b), strlen(b))) @@ -1317,9 +1316,7 @@ static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, struct seq_file * return status; } - seq_printf(m, "status:\t\t%s\n", - (status == TPACPI_RFK_RADIO_ON) ? - "enabled" : "disabled"); + seq_printf(m, "status:\t\t%s\n", str_enabled_disabled(status == TPACPI_RFK_RADIO_ON)); seq_printf(m, "commands:\tenable, disable\n"); } @@ -1346,8 +1343,7 @@ static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) if (status != -1) { tpacpi_disclose_usertask("procfs", "attempt to %s %s\n", - (status == TPACPI_RFK_RADIO_ON) ? - "enable" : "disable", + str_enable_disable(status == TPACPI_RFK_RADIO_ON), tpacpi_rfkill_names[id]); res = (tpacpi_rfkill_switches[id]->ops->set_status)(status); tpacpi_rfk_update_swstate(tpacpi_rfkill_switches[id]); @@ -3504,8 +3500,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { tp_features.hotkey_wlsw = 1; radiosw_state = !!status; - pr_info("radio switch found; radios are %s\n", - enabled(status, 0)); + pr_info("radio switch found; radios are %s\n", str_enabled_disabled(status & BIT(0))); } tabletsw_state = hotkey_init_tablet_mode(); @@ -4165,7 +4160,7 @@ static int hotkey_read(struct seq_file *m) if (res) return res; - seq_printf(m, "status:\t\t%s\n", enabled(status, 0)); + seq_printf(m, "status:\t\t%s\n", str_enabled_disabled(status & BIT(0))); if (hotkey_all_mask) { seq_printf(m, "mask:\t\t0x%08x\n", hotkey_user_mask); seq_printf(m, "commands:\tenable, disable, reset, \n"); @@ -4298,9 +4293,8 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state) { int status; - vdbg_printk(TPACPI_DBG_RFKILL, - "will attempt to %s bluetooth\n", - (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); + vdbg_printk(TPACPI_DBG_RFKILL, "will attempt to %s bluetooth\n", + str_enable_disable(state == TPACPI_RFK_RADIO_ON)); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_bluetoothemul) { @@ -4664,9 +4658,8 @@ static int wan_set_status(enum tpacpi_rfkill_state state) { int status; - vdbg_printk(TPACPI_DBG_RFKILL, - "will attempt to %s wwan\n", - (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); + vdbg_printk(TPACPI_DBG_RFKILL, "will attempt to %s wwan\n", + str_enable_disable(state == TPACPI_RFK_RADIO_ON)); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_wwanemul) { @@ -4842,9 +4835,8 @@ static int uwb_set_status(enum tpacpi_rfkill_state state) { int status; - vdbg_printk(TPACPI_DBG_RFKILL, - "will attempt to %s UWB\n", - (state == TPACPI_RFK_RADIO_ON) ? "enable" : "disable"); + vdbg_printk(TPACPI_DBG_RFKILL, "will attempt to %s UWB\n", + str_enable_disable(state == TPACPI_RFK_RADIO_ON)); #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES if (dbg_uwbemul) { @@ -5198,11 +5190,11 @@ static int video_read(struct seq_file *m) return autosw; seq_printf(m, "status:\t\tsupported\n"); - seq_printf(m, "lcd:\t\t%s\n", enabled(status, 0)); - seq_printf(m, "crt:\t\t%s\n", enabled(status, 1)); + seq_printf(m, "lcd:\t\t%s\n", str_enabled_disabled(status & BIT(0))); + seq_printf(m, "crt:\t\t%s\n", str_enabled_disabled(status & BIT(1))); if (video_supported == TPACPI_VIDEO_NEW) - seq_printf(m, "dvi:\t\t%s\n", enabled(status, 3)); - seq_printf(m, "auto:\t\t%s\n", enabled(autosw, 0)); + seq_printf(m, "dvi:\t\t%s\n", str_enabled_disabled(status & BIT(3))); + seq_printf(m, "auto:\t\t%s\n", str_enabled_disabled(autosw & BIT(0))); seq_printf(m, "commands:\tlcd_enable, lcd_disable\n"); seq_printf(m, "commands:\tcrt_enable, crt_disable\n"); if (video_supported == TPACPI_VIDEO_NEW) @@ -5633,7 +5625,7 @@ static int light_read(struct seq_file *m) status = light_get_status(); if (status < 0) return status; - seq_printf(m, "status:\t\t%s\n", onoff(status, 0)); + seq_printf(m, "status:\t\t%s\n", str_on_off(status & BIT(0))); seq_printf(m, "commands:\ton, off\n"); } @@ -6089,9 +6081,7 @@ static int __init led_init(struct ibm_init_struct *iibm) return 0; } -#define str_led_status(s) \ - ((s) == TPACPI_LED_OFF ? "off" : \ - ((s) == TPACPI_LED_ON ? "on" : "blinking")) +#define str_led_status(s) ((s) >= TPACPI_LED_BLINK ? "blinking" : str_on_off(s)) static int led_read(struct seq_file *m) { @@ -6108,8 +6098,7 @@ static int led_read(struct seq_file *m) status = led_get_status(i); if (status < 0) return -EIO; - seq_printf(m, "%d:\t\t%s\n", - i, str_led_status(status)); + seq_printf(m, "%d:\t\t%s\n", i, str_led_status(status)); } } @@ -7831,8 +7820,7 @@ static int volume_read(struct seq_file *m) seq_printf(m, "level:\t\t%d\n", status & TP_EC_AUDIO_LVL_MSK); - seq_printf(m, "mute:\t\t%s\n", - onoff(status, TP_EC_AUDIO_MUTESW)); + seq_printf(m, "mute:\t\t%s\n", str_on_off(status & BIT(TP_EC_AUDIO_MUTESW))); if (volume_control_allowed) { seq_printf(m, "commands:\tunmute, mute\n"); @@ -9061,7 +9049,7 @@ static int fan_read(struct seq_file *m) seq_printf(m, "status:\t\t%s\n" "level:\t\t%d\n", - (status != 0) ? "enabled" : "disabled", status); + str_enabled_disabled(status), status); break; case TPACPI_FAN_RD_TPEC: @@ -9070,8 +9058,7 @@ static int fan_read(struct seq_file *m) if (rc) return rc; - seq_printf(m, "status:\t\t%s\n", - (status != 0) ? "enabled" : "disabled"); + seq_printf(m, "status:\t\t%s\n", str_enabled_disabled(status)); rc = fan_get_speed(&speed); if (rc < 0) From 349da8ee726a19c5034145199985bbf78a1e933d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 20 Jun 2022 16:56:26 +0200 Subject: [PATCH 0705/1436] platform/x86: acer_wmi: Cleanup Kconfig selects ACER_WMI already depends on ACPI_WMI which depends on ACPI so the "depends on ACPI" is unnecessary. And since ACER_WMI already depends on ACPI adding an "if ACPI" to the ACPI_VIDEO select is nonsense. While at it also group all the selects together. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220620145628.5882-1-hdegoede@redhat.com --- drivers/platform/x86/Kconfig | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index e7f10287a894..f01f75589627 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -177,17 +177,15 @@ config ACER_WIRELESS config ACER_WMI tristate "Acer WMI Laptop Extras" - depends on ACPI - select LEDS_CLASS - select NEW_LEDS depends on BACKLIGHT_CLASS_DEVICE depends on SERIO_I8042 depends on INPUT depends on RFKILL || RFKILL = n depends on ACPI_WMI + select ACPI_VIDEO select INPUT_SPARSEKMAP - # Acer WMI depends on ACPI_VIDEO when ACPI is enabled - select ACPI_VIDEO if ACPI + select LEDS_CLASS + select NEW_LEDS help This is a driver for newer Acer (and Wistron) laptops. It adds wireless radio and bluetooth control, and on some laptops, From 44fc1060a62d4810e2ce8f961232c34dad006ec8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 20 Jun 2022 16:56:27 +0200 Subject: [PATCH 0706/1436] platform/x86: Kconfig: Remove unnecessary "if X86" drivers/platform/x86/Kconfig is wrapped in one big if X86_PLATFORM_DEVICES .. endif and X86_PLATFORM_DEVICES already has a "depends on X86" so the "if X86" in drivers/platform/Kconfig is not necessary and except for MIPS none of the other includes there has such an if. So let's remove it. While at it also move the x86/Kconfig include to the end of the file for alphabetical sorting. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220620145628.5882-2-hdegoede@redhat.com --- drivers/platform/Kconfig | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 18fc6a08569e..b437847b6237 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig @@ -1,7 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only -if X86 -source "drivers/platform/x86/Kconfig" -endif if MIPS source "drivers/platform/mips/Kconfig" endif @@ -15,3 +12,5 @@ source "drivers/platform/mellanox/Kconfig" source "drivers/platform/olpc/Kconfig" source "drivers/platform/surface/Kconfig" + +source "drivers/platform/x86/Kconfig" From 63a00f04bff91d22f1668e4f530514c995232ebc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 20 Jun 2022 16:56:28 +0200 Subject: [PATCH 0707/1436] platform/x86/dell: Kconfig: Remove unnecessary "depends on X86_PLATFORM_DEVICES" platform/x86/dell/Kconfig is only sourced if X86_PLATFORM_DEVICES is set, so it does not need to depend on it. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220620145628.5882-3-hdegoede@redhat.com --- drivers/platform/x86/dell/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig index fe224a54f24c..25421e061c47 100644 --- a/drivers/platform/x86/dell/Kconfig +++ b/drivers/platform/x86/dell/Kconfig @@ -5,7 +5,6 @@ menuconfig X86_PLATFORM_DRIVERS_DELL bool "Dell X86 Platform Specific Device Drivers" - depends on X86_PLATFORM_DEVICES help Say Y here to get to see options for device drivers for various Dell x86 platforms, including vendor-specific laptop extension drivers. From f0da93cbaf7af868e34d611d555f4067b748ecdf Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 21 Jun 2022 15:55:11 +0200 Subject: [PATCH 0708/1436] platform/x86: thinkpad_acpi: Fix a memory leak of EFCH MMIO resource Unlike release_mem_region(), a call to release_resource() does not free the resource, so it has to be freed explicitly to avoid a memory leak. Signed-off-by: Jean Delvare Fixes: 455cd867b85b ("platform/x86: thinkpad_acpi: Add a s2idle resume quirk for a number of laptops") Cc: Mario Limonciello Cc: Henrique de Moraes Holschuh Cc: Hans de Goede Cc: Mark Gross Reviewed-by: Mario Limonciello Link: https://lore.kernel.org/r/20220621155511.5b266395@endymion.delvare Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index c54c318bf9f6..17d503e65a54 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -4529,6 +4529,7 @@ static void thinkpad_acpi_amd_s2idle_restore(void) iounmap(addr); cleanup_resource: release_resource(res); + kfree(res); } static struct acpi_s2idle_dev_ops thinkpad_acpi_s2idle_dev_ops = { From 71eac0c07c7b26063bf5ee14a082e05421688552 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 24 Jun 2022 15:54:53 +0200 Subject: [PATCH 0709/1436] Staging: rtl8192e: Use struct_size Using struct_size is encouraged because it is safer than using sizeof and calculations by hand. Signed-off-by: Felix Schlepper Link: https://lore.kernel.org/r/54ea62a2b7628d3bdd5aa52df82c3e91704a2127.1656078068.git.f3sch.git@outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib_tx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c index 37715afb0210..f2ef32e943ae 100644 --- a/drivers/staging/rtl8192e/rtllib_tx.c +++ b/drivers/staging/rtl8192e/rtllib_tx.c @@ -205,8 +205,7 @@ static struct rtllib_txb *rtllib_alloc_txb(int nr_frags, int txb_size, struct rtllib_txb *txb; int i; - txb = kmalloc(sizeof(struct rtllib_txb) + (sizeof(u8 *) * nr_frags), - gfp_mask); + txb = kmalloc(struct_size(txb, fragments, nr_frags), gfp_mask); if (!txb) return NULL; From 9fdc63fe40faaffeecaf3f1425dd1b27892f96fc Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 24 Jun 2022 15:54:54 +0200 Subject: [PATCH 0710/1436] Staging: rtl8192e: Using kzalloc and delete memset By using kzalloc, we can delete a memset. The practical difference is that using kzalloc() will zero out the txb->fragments[] array. The original code worked fine, but zeroing everything seems nicer. Signed-off-by: Felix Schlepper Link: https://lore.kernel.org/r/9727fe31c675f2f3052ca2fa586d137dd856ac91.1656078068.git.f3sch.git@outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib_tx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c index f2ef32e943ae..1307cf55741a 100644 --- a/drivers/staging/rtl8192e/rtllib_tx.c +++ b/drivers/staging/rtl8192e/rtllib_tx.c @@ -205,11 +205,10 @@ static struct rtllib_txb *rtllib_alloc_txb(int nr_frags, int txb_size, struct rtllib_txb *txb; int i; - txb = kmalloc(struct_size(txb, fragments, nr_frags), gfp_mask); + txb = kzalloc(struct_size(txb, fragments, nr_frags), gfp_mask); if (!txb) return NULL; - memset(txb, 0, sizeof(struct rtllib_txb)); txb->nr_frags = nr_frags; txb->frag_size = cpu_to_le16(txb_size); From acde2522fa1aaa9aea58fb4c7dca596e8c0b5d57 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 24 Jun 2022 15:54:55 +0200 Subject: [PATCH 0711/1436] Staging: rtl8192e: Cleaning up error handling Moved error handling to one common block. This removes double checking if all txb->fragments[] were initialized. The original code worked fine, but this is cleaner. Signed-off-by: Felix Schlepper Link: https://lore.kernel.org/r/13b32131cd00a1f0b8793657a24ada71240a8350.1656078068.git.f3sch.git@outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib_tx.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/staging/rtl8192e/rtllib_tx.c b/drivers/staging/rtl8192e/rtllib_tx.c index 1307cf55741a..42f81b23a144 100644 --- a/drivers/staging/rtl8192e/rtllib_tx.c +++ b/drivers/staging/rtl8192e/rtllib_tx.c @@ -214,19 +214,19 @@ static struct rtllib_txb *rtllib_alloc_txb(int nr_frags, int txb_size, for (i = 0; i < nr_frags; i++) { txb->fragments[i] = dev_alloc_skb(txb_size); - if (unlikely(!txb->fragments[i])) { - i--; - break; - } + if (unlikely(!txb->fragments[i])) + goto err_free; memset(txb->fragments[i]->cb, 0, sizeof(txb->fragments[i]->cb)); } - if (unlikely(i != nr_frags)) { - while (i >= 0) - dev_kfree_skb_any(txb->fragments[i--]); - kfree(txb); - return NULL; - } + return txb; + +err_free: + while (--i >= 0) + dev_kfree_skb_any(txb->fragments[i]); + kfree(txb); + + return NULL; } static int rtllib_classify(struct sk_buff *skb, u8 bIsAmsdu) From f6c99d86246ad4a9013caf7914138368e80f7b93 Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Fri, 24 Jun 2022 18:39:02 +0200 Subject: [PATCH 0712/1436] staging: vchiq_arm: Add missing memory barrier comments One of points on the TODO list was to comment the memory barriers. This patch addresses the missing ones in order to help reviewers. Link: https://github.com/raspberrypi/linux/pull/5066 Signed-off-by: Phil Elwell Signed-off-by: Stefan Wahren Link: https://lore.kernel.org/r/20220624163902.6913-1-stefan.wahren@i2se.com Signed-off-by: Greg Kroah-Hartman --- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 4 ++++ .../vc04_services/interface/vchiq_arm/vchiq_core.c | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 3bcb893d14a1..dc33490ba7fb 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -602,6 +602,10 @@ static struct vchiq_arm_state *vchiq_platform_get_arm_state(struct vchiq_state * void remote_event_signal(struct remote_event *event) { + /* + * Ensure that all writes to shared data structures have completed + * before signalling the peer. + */ wmb(); event->fired = 1; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 7b9c100eb74d..45ed30bfdbf5 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -528,6 +528,7 @@ remote_event_wait(wait_queue_head_t *wq, struct remote_event *event) return 0; } event->armed = 0; + /* Ensure that the peer sees that we are not waiting (armed == 0). */ wmb(); } @@ -650,6 +651,7 @@ request_poll(struct vchiq_state *state, struct vchiq_service *service, skip_service: state->poll_needed = 1; + /* Ensure the slot handler thread sees the poll_needed flag. */ wmb(); /* ... and ensure the slot handler runs. */ @@ -1156,6 +1158,7 @@ queue_message_sync(struct vchiq_state *state, struct vchiq_service *service, remote_event_wait(&state->sync_release_event, &local->sync_release); + /* Ensure that reads don't overtake the remote_event_wait. */ rmb(); header = (struct vchiq_header *)SLOT_DATA_FROM_INDEX(state, @@ -1959,6 +1962,7 @@ slot_handler_func(void *v) DEBUG_TRACE(SLOT_HANDLER_LINE); remote_event_wait(&state->trigger_event, &local->trigger); + /* Ensure that reads don't overtake the remote_event_wait. */ rmb(); DEBUG_TRACE(SLOT_HANDLER_LINE); @@ -2021,6 +2025,7 @@ sync_func(void *v) remote_event_wait(&state->sync_trigger_event, &local->sync_trigger); + /* Ensure that reads don't overtake the remote_event_wait. */ rmb(); msgid = header->msgid; @@ -3081,6 +3086,10 @@ enum vchiq_status vchiq_bulk_transfer(struct vchiq_instance *instance, unsigned if (vchiq_prepare_bulk_data(instance, bulk, offset, uoffset, size, dir)) goto unlock_error_exit; + /* + * Ensure that the bulk data record is visible to the peer + * before proceeding. + */ wmb(); vchiq_log_info(vchiq_core_log_level, "%d: bt (%d->%d) %cx %x@%pad %pK", From b78137d00a66f69c51e291e06d3e4ec6d1223acd Mon Sep 17 00:00:00 2001 From: Chang Yu Date: Fri, 24 Jun 2022 07:45:26 -0700 Subject: [PATCH 0713/1436] staging: r8188eu: core/rtw_recv.c: clean up nested if statements Combine two nested if statements into a single one to fix indentation issue and improve readability, as suggested by checkpatch.pl Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Chang Yu Link: https://lore.kernel.org/r/20220624144526.437322-1-marcus.yu.56@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 6564e82ddd66..020bc212532f 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -166,10 +166,8 @@ int rtw_free_recvframe(struct recv_frame *precvframe, struct __queue *pfree_recv list_add_tail(&precvframe->list, get_list_head(pfree_recv_queue)); - if (padapter) { - if (pfree_recv_queue == &precvpriv->free_recv_queue) - precvpriv->free_recvframe_cnt++; - } + if (padapter && (pfree_recv_queue == &precvpriv->free_recv_queue)) + precvpriv->free_recvframe_cnt++; spin_unlock_bh(&pfree_recv_queue->lock); From 80394da44b7be8f5e474b048aed6ceaf0082c2b4 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sun, 26 Jun 2022 20:06:03 +0200 Subject: [PATCH 0714/1436] staging: r8188eu: remove rtw_usleep_os Remove the rtw_usleep_os helper function. There are only two callers, both of which call rtw_usleep_os(100). This is equivalent to msleep(1). Tested-by: Philipp Hortmann # Edimax N150 Tested-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220626180603.287054-1-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_pwrctrl.c | 2 +- drivers/staging/r8188eu/hal/rtl8188e_hal_init.c | 2 +- drivers/staging/r8188eu/include/osdep_service.h | 2 -- drivers/staging/r8188eu/os_dep/osdep_service.c | 8 -------- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_pwrctrl.c b/drivers/staging/r8188eu/core/rtw_pwrctrl.c index 45e85b593665..cf9020a73933 100644 --- a/drivers/staging/r8188eu/core/rtw_pwrctrl.c +++ b/drivers/staging/r8188eu/core/rtw_pwrctrl.c @@ -273,7 +273,7 @@ static s32 LPS_RF_ON_check(struct adapter *padapter, u32 delay_ms) err = -1; break; } - rtw_usleep_os(100); + msleep(1); } return err; diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index 5549e7be334a..5b65313e0b9d 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -243,7 +243,7 @@ static int efuse_read_phymap_from_txpktbuf( if (reg) break; - rtw_usleep_os(100); + msleep(1); } while (time_before(jiffies, timeout)); /* data from EEPROM needs to be in LE */ diff --git a/drivers/staging/r8188eu/include/osdep_service.h b/drivers/staging/r8188eu/include/osdep_service.h index 1d97d5be46d5..72990a1cdc66 100644 --- a/drivers/staging/r8188eu/include/osdep_service.h +++ b/drivers/staging/r8188eu/include/osdep_service.h @@ -76,8 +76,6 @@ void *rtw_malloc2d(int h, int w, int size); spin_lock_init(&((q)->lock)); \ } while (0) -void rtw_usleep_os(int us); - static inline unsigned char _cancel_timer_ex(struct timer_list *ptimer) { return del_timer_sync(ptimer); diff --git a/drivers/staging/r8188eu/os_dep/osdep_service.c b/drivers/staging/r8188eu/os_dep/osdep_service.c index 812acd59be79..3504a0a9ba87 100644 --- a/drivers/staging/r8188eu/os_dep/osdep_service.c +++ b/drivers/staging/r8188eu/os_dep/osdep_service.c @@ -42,14 +42,6 @@ Otherwise, there will be racing condition. Caller must check if the list is empty before calling rtw_list_delete */ -void rtw_usleep_os(int us) -{ - if (1 < (us / 1000)) - msleep(1); - else - msleep((us / 1000) + 1); -} - static const struct device_type wlan_type = { .name = "wlan", }; From 1b0a54b3e83f67cade6e510f43804ac7ab4c0bb9 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sun, 26 Jun 2022 20:09:59 +0200 Subject: [PATCH 0715/1436] staging: r8188eu: merge two led structs The led layer uses struct led_priv and struct LED_871x to store state info. Merge the two structs. Move LED_871x's components into led_priv. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220626181000.287225-1-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_led.c | 27 ++++++++++------------- drivers/staging/r8188eu/include/rtw_led.h | 9 +++----- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_led.c b/drivers/staging/r8188eu/core/rtw_led.c index 25989acf5259..d5c6c5e29621 100644 --- a/drivers/staging/r8188eu/core/rtw_led.c +++ b/drivers/staging/r8188eu/core/rtw_led.c @@ -16,7 +16,7 @@ (l)->CurrLedState == LED_BLINK_WPS_STOP || \ (l)->bLedWPSBlinkInProgress) -static void ResetLedStatus(struct LED_871x *pLed) +static void ResetLedStatus(struct led_priv *pLed) { pLed->CurrLedState = RTW_LED_OFF; /* Current LED state. */ pLed->bLedOn = false; /* true if LED is ON, false if LED is OFF. */ @@ -32,7 +32,7 @@ static void ResetLedStatus(struct LED_871x *pLed) pLed->bLedScanBlinkInProgress = false; } -static void SwLedOn(struct adapter *padapter, struct LED_871x *pLed) +static void SwLedOn(struct adapter *padapter, struct led_priv *pLed) { u8 LedCfg; int res; @@ -48,7 +48,7 @@ static void SwLedOn(struct adapter *padapter, struct LED_871x *pLed) pLed->bLedOn = true; } -static void SwLedOff(struct adapter *padapter, struct LED_871x *pLed) +static void SwLedOff(struct adapter *padapter, struct led_priv *pLed) { u8 LedCfg; int res; @@ -75,7 +75,7 @@ exit: static void blink_work(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); - struct LED_871x *pLed = container_of(dwork, struct LED_871x, blink_work); + struct led_priv *pLed = container_of(dwork, struct led_priv, blink_work); struct adapter *padapter = pLed->padapter; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -182,35 +182,32 @@ static void blink_work(struct work_struct *work) void rtl8188eu_InitSwLeds(struct adapter *padapter) { struct led_priv *pledpriv = &padapter->ledpriv; - struct LED_871x *pLed = &pledpriv->SwLed0; - pLed->padapter = padapter; - ResetLedStatus(pLed); - INIT_DELAYED_WORK(&pLed->blink_work, blink_work); + pledpriv->padapter = padapter; + ResetLedStatus(pledpriv); + INIT_DELAYED_WORK(&pledpriv->blink_work, blink_work); } void rtl8188eu_DeInitSwLeds(struct adapter *padapter) { struct led_priv *ledpriv = &padapter->ledpriv; - struct LED_871x *pLed = &ledpriv->SwLed0; - cancel_delayed_work_sync(&pLed->blink_work); - ResetLedStatus(pLed); - SwLedOff(padapter, pLed); + cancel_delayed_work_sync(&ledpriv->blink_work); + ResetLedStatus(ledpriv); + SwLedOff(padapter, ledpriv); } void rtw_led_control(struct adapter *padapter, enum LED_CTL_MODE LedAction) { - struct led_priv *ledpriv = &padapter->ledpriv; + struct led_priv *pLed = &padapter->ledpriv; struct registry_priv *registry_par; - struct LED_871x *pLed = &ledpriv->SwLed0; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped) || (!padapter->hw_init_completed)) return; - if (!ledpriv->bRegUseLed) + if (!pLed->bRegUseLed) return; registry_par = &padapter->registrypriv; diff --git a/drivers/staging/r8188eu/include/rtw_led.h b/drivers/staging/r8188eu/include/rtw_led.h index 2c14cb23d9ad..d6b0c1c2f9a2 100644 --- a/drivers/staging/r8188eu/include/rtw_led.h +++ b/drivers/staging/r8188eu/include/rtw_led.h @@ -37,9 +37,11 @@ enum LED_STATE_871x { LED_BLINK_RUNTOP = 13, /* Customized for RunTop */ }; -struct LED_871x { +struct led_priv { struct adapter *padapter; + bool bRegUseLed; + enum LED_STATE_871x CurrLedState; /* Current LED state. */ enum LED_STATE_871x BlinkingLedState; /* Next state for blinking, * either RTW_LED_ON or RTW_LED_OFF are. */ @@ -58,11 +60,6 @@ struct LED_871x { struct delayed_work blink_work; }; -struct led_priv{ - struct LED_871x SwLed0; - bool bRegUseLed; -}; - void rtl8188eu_InitSwLeds(struct adapter *padapter); void rtl8188eu_DeInitSwLeds(struct adapter *padapter); From df8d0a55047b57074ac69db795a9775b3abe364e Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 27 Jun 2022 10:53:54 +0200 Subject: [PATCH 0716/1436] staging: r8188eu: make power sequences static Simplify the handling of "power sequences". At the moment, this is rather complicated: The hal layer calls HalPwrSeqCmdParsing. This function takes a pointer to a power sequence. The sequences themselves are defined as global variables in a separate file. There's an alias for each sequence, the callers of HalPwrSeqCmdParsing use these aliases instead of the sequences themselves. There's no point in passing the sequences around. We can move the sequences into the same file as the HalPwrSeqCmdParsing function where they are used. Callers of HalPwrSeqCmdParsing can refer to a sequence by using a numeric define rather than a pointer to the sequence. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220627085354.28849-1-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/Makefile | 1 - drivers/staging/r8188eu/hal/Hal8188EPwrSeq.c | 45 --------------- drivers/staging/r8188eu/hal/HalPwrSeqCmd.c | 57 ++++++++++++++++++- drivers/staging/r8188eu/hal/usb_halinit.c | 8 +-- .../staging/r8188eu/include/Hal8188EPwrSeq.h | 13 ----- .../staging/r8188eu/include/HalPwrSeqCmd.h | 8 ++- .../staging/r8188eu/include/rtl8188e_hal.h | 5 -- 7 files changed, 67 insertions(+), 70 deletions(-) delete mode 100644 drivers/staging/r8188eu/hal/Hal8188EPwrSeq.c delete mode 100644 drivers/staging/r8188eu/include/Hal8188EPwrSeq.h diff --git a/drivers/staging/r8188eu/Makefile b/drivers/staging/r8188eu/Makefile index 1d7982b618ba..eea16eb7caa0 100644 --- a/drivers/staging/r8188eu/Makefile +++ b/drivers/staging/r8188eu/Makefile @@ -5,7 +5,6 @@ r8188eu-y = \ hal/HalHWImg8188E_RF.o \ hal/HalPhyRf_8188e.o \ hal/HalPwrSeqCmd.o \ - hal/Hal8188EPwrSeq.o \ hal/Hal8188ERateAdaptive.o \ hal/hal_intf.o \ hal/hal_com.o \ diff --git a/drivers/staging/r8188eu/hal/Hal8188EPwrSeq.c b/drivers/staging/r8188eu/hal/Hal8188EPwrSeq.c deleted file mode 100644 index 6505e1fcb070..000000000000 --- a/drivers/staging/r8188eu/hal/Hal8188EPwrSeq.c +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Copyright(c) 2007 - 2011 Realtek Corporation. */ - -#include "../include/Hal8188EPwrSeq.h" -#include "../include/rtl8188e_hal.h" - -struct wl_pwr_cfg rtl8188E_power_on_flow[] = { - { 0x0006, PWR_CMD_POLLING, BIT(1), BIT(1) }, - { 0x0002, PWR_CMD_WRITE, BIT(0) | BIT(1), 0 }, /* reset BB */ - { 0x0026, PWR_CMD_WRITE, BIT(7), BIT(7) }, /* schmitt trigger */ - { 0x0005, PWR_CMD_WRITE, BIT(7), 0 }, /* disable HWPDN (control by DRV)*/ - { 0x0005, PWR_CMD_WRITE, BIT(4) | BIT(3), 0 }, /* disable WL suspend*/ - { 0x0005, PWR_CMD_WRITE, BIT(0), BIT(0) }, - { 0x0005, PWR_CMD_POLLING, BIT(0), 0 }, - { 0x0023, PWR_CMD_WRITE, BIT(4), 0 }, - { 0xFFFF, PWR_CMD_END, 0, 0 }, -}; - -struct wl_pwr_cfg rtl8188E_card_disable_flow[] = { - { 0x001F, PWR_CMD_WRITE, 0xFF, 0 }, /* turn off RF */ - { 0x0023, PWR_CMD_WRITE, BIT(4), BIT(4) }, /* LDO Sleep mode */ - { 0x0005, PWR_CMD_WRITE, BIT(1), BIT(1) }, /* turn off MAC by HW state machine */ - { 0x0005, PWR_CMD_POLLING, BIT(1), 0 }, - { 0x0026, PWR_CMD_WRITE, BIT(7), BIT(7) }, /* schmitt trigger */ - { 0x0005, PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3) }, /* enable WL suspend */ - { 0x0007, PWR_CMD_WRITE, 0xFF, 0 }, /* enable bandgap mbias in suspend */ - { 0x0041, PWR_CMD_WRITE, BIT(4), 0 }, /* Clear SIC_EN register */ - { 0xfe10, PWR_CMD_WRITE, BIT(4), BIT(4) }, /* Set USB suspend enable local register */ - { 0xFFFF, PWR_CMD_END, 0, 0 }, -}; - -/* This is used by driver for LPSRadioOff Procedure, not for FW LPS Step */ -struct wl_pwr_cfg rtl8188E_enter_lps_flow[] = { - { 0x0522, PWR_CMD_WRITE, 0xFF, 0x7F },/* Tx Pause */ - { 0x05F8, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */ - { 0x05F9, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */ - { 0x05FA, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */ - { 0x05FB, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */ - { 0x0002, PWR_CMD_WRITE, BIT(0), 0 }, /* CCK and OFDM are disabled, clocks are gated */ - { 0x0002, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US }, - { 0x0100, PWR_CMD_WRITE, 0xFF, 0x3F }, /* Reset MAC TRX */ - { 0x0101, PWR_CMD_WRITE, BIT(1), 0 }, /* check if removed later */ - { 0x0553, PWR_CMD_WRITE, BIT(5), BIT(5) }, /* Respond TxOK to scheduler */ - { 0xFFFF, PWR_CMD_END, 0, 0 }, -}; diff --git a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c index 4a4563b900b3..b5f6d41464db 100644 --- a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c +++ b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c @@ -3,9 +3,50 @@ #include "../include/HalPwrSeqCmd.h" -u8 HalPwrSeqCmdParsing(struct adapter *padapter, struct wl_pwr_cfg pwrseqcmd[]) +static struct wl_pwr_cfg rtl8188E_power_on_flow[] = { + { 0x0006, PWR_CMD_POLLING, BIT(1), BIT(1) }, + { 0x0002, PWR_CMD_WRITE, BIT(0) | BIT(1), 0 }, /* reset BB */ + { 0x0026, PWR_CMD_WRITE, BIT(7), BIT(7) }, /* schmitt trigger */ + { 0x0005, PWR_CMD_WRITE, BIT(7), 0 }, /* disable HWPDN (control by DRV)*/ + { 0x0005, PWR_CMD_WRITE, BIT(4) | BIT(3), 0 }, /* disable WL suspend*/ + { 0x0005, PWR_CMD_WRITE, BIT(0), BIT(0) }, + { 0x0005, PWR_CMD_POLLING, BIT(0), 0 }, + { 0x0023, PWR_CMD_WRITE, BIT(4), 0 }, + { 0xFFFF, PWR_CMD_END, 0, 0 }, +}; + +static struct wl_pwr_cfg rtl8188E_card_disable_flow[] = { + { 0x001F, PWR_CMD_WRITE, 0xFF, 0 }, /* turn off RF */ + { 0x0023, PWR_CMD_WRITE, BIT(4), BIT(4) }, /* LDO Sleep mode */ + { 0x0005, PWR_CMD_WRITE, BIT(1), BIT(1) }, /* turn off MAC by HW state machine */ + { 0x0005, PWR_CMD_POLLING, BIT(1), 0 }, + { 0x0026, PWR_CMD_WRITE, BIT(7), BIT(7) }, /* schmitt trigger */ + { 0x0005, PWR_CMD_WRITE, BIT(3) | BIT(4), BIT(3) }, /* enable WL suspend */ + { 0x0007, PWR_CMD_WRITE, 0xFF, 0 }, /* enable bandgap mbias in suspend */ + { 0x0041, PWR_CMD_WRITE, BIT(4), 0 }, /* Clear SIC_EN register */ + { 0xfe10, PWR_CMD_WRITE, BIT(4), BIT(4) }, /* Set USB suspend enable local register */ + { 0xFFFF, PWR_CMD_END, 0, 0 }, +}; + +/* This is used by driver for LPSRadioOff Procedure, not for FW LPS Step */ +static struct wl_pwr_cfg rtl8188E_enter_lps_flow[] = { + { 0x0522, PWR_CMD_WRITE, 0xFF, 0x7F },/* Tx Pause */ + { 0x05F8, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */ + { 0x05F9, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */ + { 0x05FA, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */ + { 0x05FB, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */ + { 0x0002, PWR_CMD_WRITE, BIT(0), 0 }, /* CCK and OFDM are disabled, clocks are gated */ + { 0x0002, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US }, + { 0x0100, PWR_CMD_WRITE, 0xFF, 0x3F }, /* Reset MAC TRX */ + { 0x0101, PWR_CMD_WRITE, BIT(1), 0 }, /* check if removed later */ + { 0x0553, PWR_CMD_WRITE, BIT(5), BIT(5) }, /* Respond TxOK to scheduler */ + { 0xFFFF, PWR_CMD_END, 0, 0 }, +}; + +u8 HalPwrSeqCmdParsing(struct adapter *padapter, enum r8188eu_pwr_seq seq) { struct wl_pwr_cfg pwrcfgcmd = {0}; + struct wl_pwr_cfg *pwrseqcmd; u8 poll_bit = false; u32 aryidx = 0; u8 value = 0; @@ -14,6 +55,20 @@ u8 HalPwrSeqCmdParsing(struct adapter *padapter, struct wl_pwr_cfg pwrseqcmd[]) u32 max_poll_count = 5000; int res; + switch (seq) { + case PWR_ON_FLOW: + pwrseqcmd = rtl8188E_power_on_flow; + break; + case DISABLE_FLOW: + pwrseqcmd = rtl8188E_card_disable_flow; + break; + case LPS_ENTER_FLOW: + pwrseqcmd = rtl8188E_enter_lps_flow; + break; + default: + return false; + }; + do { pwrcfgcmd = pwrseqcmd[aryidx]; diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index cb9b4bcc536a..bb3045111147 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -11,7 +11,7 @@ #include "../include/rtw_iol.h" #include "../include/usb_ops.h" #include "../include/usb_osintf.h" -#include "../include/Hal8188EPwrSeq.h" +#include "../include/HalPwrSeqCmd.h" static void _ConfigNormalChipOutEP_8188E(struct adapter *adapt, u8 NumOutPipe) { @@ -59,7 +59,7 @@ u32 rtl8188eu_InitPowerOn(struct adapter *adapt) if (haldata->bMacPwrCtrlOn) return _SUCCESS; - if (!HalPwrSeqCmdParsing(adapt, Rtl8188E_NIC_PWR_ON_FLOW)) + if (!HalPwrSeqCmdParsing(adapt, PWR_ON_FLOW)) return _FAIL; /* Enable MAC DMA/WMAC/SCHEDULE/SEC block */ @@ -798,7 +798,7 @@ static void CardDisableRTL8188EU(struct adapter *Adapter) rtw_write8(Adapter, REG_CR, 0x0); /* Run LPS WL RFOFF flow */ - HalPwrSeqCmdParsing(Adapter, Rtl8188E_NIC_LPS_ENTER_FLOW); + HalPwrSeqCmdParsing(Adapter, LPS_ENTER_FLOW); /* 2. 0x1F[7:0] = 0 turn off RF */ @@ -828,7 +828,7 @@ static void CardDisableRTL8188EU(struct adapter *Adapter) rtw_write8(Adapter, REG_32K_CTRL, val8 & (~BIT(0))); /* Card disable power action flow */ - HalPwrSeqCmdParsing(Adapter, Rtl8188E_NIC_DISABLE_FLOW); + HalPwrSeqCmdParsing(Adapter, DISABLE_FLOW); /* Reset MCU IO Wrapper */ res = rtw_read8(Adapter, REG_RSV_CTRL + 1, &val8); diff --git a/drivers/staging/r8188eu/include/Hal8188EPwrSeq.h b/drivers/staging/r8188eu/include/Hal8188EPwrSeq.h deleted file mode 100644 index e4c5b5d23cb4..000000000000 --- a/drivers/staging/r8188eu/include/Hal8188EPwrSeq.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* Copyright(c) 2007 - 2011 Realtek Corporation. */ - -#ifndef __HAL8188EPWRSEQ_H__ -#define __HAL8188EPWRSEQ_H__ - -#include "HalPwrSeqCmd.h" - -extern struct wl_pwr_cfg rtl8188E_power_on_flow[]; -extern struct wl_pwr_cfg rtl8188E_card_disable_flow[]; -extern struct wl_pwr_cfg rtl8188E_enter_lps_flow[]; - -#endif /* __HAL8188EPWRSEQ_H__ */ diff --git a/drivers/staging/r8188eu/include/HalPwrSeqCmd.h b/drivers/staging/r8188eu/include/HalPwrSeqCmd.h index 49c02cce569e..869f54d99e57 100644 --- a/drivers/staging/r8188eu/include/HalPwrSeqCmd.h +++ b/drivers/staging/r8188eu/include/HalPwrSeqCmd.h @@ -53,7 +53,13 @@ struct wl_pwr_cfg { #define GET_PWR_CFG_MASK(__PWR_CMD) __PWR_CMD.msk #define GET_PWR_CFG_VALUE(__PWR_CMD) __PWR_CMD.value +enum r8188eu_pwr_seq { + PWR_ON_FLOW, + DISABLE_FLOW, + LPS_ENTER_FLOW, +}; + /* Prototype of protected function. */ -u8 HalPwrSeqCmdParsing(struct adapter *padapter, struct wl_pwr_cfg PwrCfgCmd[]); +u8 HalPwrSeqCmdParsing(struct adapter *padapter, enum r8188eu_pwr_seq seq); #endif diff --git a/drivers/staging/r8188eu/include/rtl8188e_hal.h b/drivers/staging/r8188eu/include/rtl8188e_hal.h index d2a069d4e1cc..5cd62b216720 100644 --- a/drivers/staging/r8188eu/include/rtl8188e_hal.h +++ b/drivers/staging/r8188eu/include/rtl8188e_hal.h @@ -26,11 +26,6 @@ #include "odm_RegConfig8188E.h" #include "odm_RTL8188E.h" -/* RTL8188E Power Configuration CMDs for USB/SDIO interfaces */ -#define Rtl8188E_NIC_PWR_ON_FLOW rtl8188E_power_on_flow -#define Rtl8188E_NIC_DISABLE_FLOW rtl8188E_card_disable_flow -#define Rtl8188E_NIC_LPS_ENTER_FLOW rtl8188E_enter_lps_flow - #define DRVINFO_SZ 4 /* unit is 8bytes */ #define PageNum_128(_Len) (u32)(((_Len)>>7) + ((_Len) & 0x7F ? 1 : 0)) From 58301e1c15db89c0edc6a122c8f6fb5af271954b Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Tue, 14 Jun 2022 15:46:58 +0700 Subject: [PATCH 0717/1436] Documentation: samsung-s3c24xx: Add blank line after SPDX directive After merging spdx tree for linux-next testing, Stephen Rothwell reported htmldocs warning: Documentation/arm/samsung-s3c24xx/cpufreq.rst:2: WARNING: Explicit markup ends without a blank line; unexpected unindent. It is due to missing blank line separator between SPDX directive and page title. Add the blank line to fix the warning. Link: https://lore.kernel.org/linux-next/20220614164506.6afd65a6@canb.auug.org.au/ Fixes: b7bc1c9e5b04da ("treewide: Replace GPLv2 boilerplate/reference with SPDX - gpl-2.0_147.RULE") Cc: Jonathan Corbet Cc: Allison Randal Cc: Greg Kroah-Hartman Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Reported-by: Stephen Rothwell Signed-off-by: Bagas Sanjaya Signed-off-by: Greg Kroah-Hartman --- Documentation/arm/samsung-s3c24xx/cpufreq.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/arm/samsung-s3c24xx/cpufreq.rst b/Documentation/arm/samsung-s3c24xx/cpufreq.rst index ed19ce1a4629..cd22697cf606 100644 --- a/Documentation/arm/samsung-s3c24xx/cpufreq.rst +++ b/Documentation/arm/samsung-s3c24xx/cpufreq.rst @@ -1,4 +1,5 @@ .. SPDX-License-Identifier: GPL-2.0-only + ======================= S3C24XX CPUfreq support ======================= From 6569689e78299ff91002960a163012b576f2b21a Mon Sep 17 00:00:00 2001 From: Xuezhi Zhang Date: Fri, 24 Jun 2022 20:12:38 +0800 Subject: [PATCH 0718/1436] usb: core: sysfs: convert sysfs snprintf to sysfs_emit Fix up all sysfs show entries to use sysfs_emit Signed-off-by: Xuezhi Zhang Link: https://lore.kernel.org/r/20220624121238.134256-1-zhangxuezhi1@coolpad.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/sysfs.c | 79 ++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index fa2e49d432ff..631574718d8a 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -35,7 +35,7 @@ static ssize_t field##_show(struct device *dev, \ return -EINTR; \ actconfig = udev->actconfig; \ if (actconfig) \ - rc = sprintf(buf, format_string, \ + rc = sysfs_emit(buf, format_string, \ actconfig->desc.field); \ usb_unlock_device(udev); \ return rc; \ @@ -61,7 +61,7 @@ static ssize_t bMaxPower_show(struct device *dev, return -EINTR; actconfig = udev->actconfig; if (actconfig) - rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); + rc = sysfs_emit(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); usb_unlock_device(udev); return rc; } @@ -80,7 +80,7 @@ static ssize_t configuration_show(struct device *dev, return -EINTR; actconfig = udev->actconfig; if (actconfig && actconfig->string) - rc = sprintf(buf, "%s\n", actconfig->string); + rc = sysfs_emit(buf, "%s\n", actconfig->string); usb_unlock_device(udev); return rc; } @@ -114,7 +114,7 @@ static ssize_t devspec_show(struct device *dev, struct device_attribute *attr, { struct device_node *of_node = dev->of_node; - return sprintf(buf, "%pOF\n", of_node); + return sysfs_emit(buf, "%pOF\n", of_node); } static DEVICE_ATTR_RO(devspec); #endif @@ -131,7 +131,7 @@ static ssize_t name##_show(struct device *dev, \ retval = usb_lock_device_interruptible(udev); \ if (retval < 0) \ return -EINTR; \ - retval = sprintf(buf, "%s\n", udev->name); \ + retval = sysfs_emit(buf, "%s\n", udev->name); \ usb_unlock_device(udev); \ return retval; \ } \ @@ -175,7 +175,7 @@ static ssize_t speed_show(struct device *dev, struct device_attribute *attr, default: speed = "unknown"; } - return sprintf(buf, "%s\n", speed); + return sysfs_emit(buf, "%s\n", speed); } static DEVICE_ATTR_RO(speed); @@ -185,7 +185,7 @@ static ssize_t rx_lanes_show(struct device *dev, struct device_attribute *attr, struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->rx_lanes); + return sysfs_emit(buf, "%d\n", udev->rx_lanes); } static DEVICE_ATTR_RO(rx_lanes); @@ -195,7 +195,7 @@ static ssize_t tx_lanes_show(struct device *dev, struct device_attribute *attr, struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->tx_lanes); + return sysfs_emit(buf, "%d\n", udev->tx_lanes); } static DEVICE_ATTR_RO(tx_lanes); @@ -205,7 +205,7 @@ static ssize_t busnum_show(struct device *dev, struct device_attribute *attr, struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->bus->busnum); + return sysfs_emit(buf, "%d\n", udev->bus->busnum); } static DEVICE_ATTR_RO(busnum); @@ -215,7 +215,7 @@ static ssize_t devnum_show(struct device *dev, struct device_attribute *attr, struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->devnum); + return sysfs_emit(buf, "%d\n", udev->devnum); } static DEVICE_ATTR_RO(devnum); @@ -225,7 +225,7 @@ static ssize_t devpath_show(struct device *dev, struct device_attribute *attr, struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "%s\n", udev->devpath); + return sysfs_emit(buf, "%s\n", udev->devpath); } static DEVICE_ATTR_RO(devpath); @@ -237,7 +237,7 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, udev = to_usb_device(dev); bcdUSB = le16_to_cpu(udev->descriptor.bcdUSB); - return sprintf(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff); + return sysfs_emit(buf, "%2x.%02x\n", bcdUSB >> 8, bcdUSB & 0xff); } static DEVICE_ATTR_RO(version); @@ -247,7 +247,7 @@ static ssize_t maxchild_show(struct device *dev, struct device_attribute *attr, struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->maxchild); + return sysfs_emit(buf, "%d\n", udev->maxchild); } static DEVICE_ATTR_RO(maxchild); @@ -257,7 +257,7 @@ static ssize_t quirks_show(struct device *dev, struct device_attribute *attr, struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "0x%x\n", udev->quirks); + return sysfs_emit(buf, "0x%x\n", udev->quirks); } static DEVICE_ATTR_RO(quirks); @@ -267,7 +267,7 @@ static ssize_t avoid_reset_quirk_show(struct device *dev, struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET)); + return sysfs_emit(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET)); } static ssize_t avoid_reset_quirk_store(struct device *dev, @@ -297,7 +297,7 @@ static ssize_t urbnum_show(struct device *dev, struct device_attribute *attr, struct usb_device *udev; udev = to_usb_device(dev); - return sprintf(buf, "%d\n", atomic_read(&udev->urbnum)); + return sysfs_emit(buf, "%d\n", atomic_read(&udev->urbnum)); } static DEVICE_ATTR_RO(urbnum); @@ -305,8 +305,8 @@ static ssize_t ltm_capable_show(struct device *dev, struct device_attribute *attr, char *buf) { if (usb_device_supports_ltm(to_usb_device(dev))) - return sprintf(buf, "%s\n", "yes"); - return sprintf(buf, "%s\n", "no"); + return sysfs_emit(buf, "%s\n", "yes"); + return sysfs_emit(buf, "%s\n", "no"); } static DEVICE_ATTR_RO(ltm_capable); @@ -317,7 +317,7 @@ static ssize_t persist_show(struct device *dev, struct device_attribute *attr, { struct usb_device *udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->persist_enabled); + return sysfs_emit(buf, "%d\n", udev->persist_enabled); } static ssize_t persist_store(struct device *dev, struct device_attribute *attr, @@ -372,7 +372,7 @@ static ssize_t connected_duration_show(struct device *dev, { struct usb_device *udev = to_usb_device(dev); - return sprintf(buf, "%u\n", + return sysfs_emit(buf, "%u\n", jiffies_to_msecs(jiffies - udev->connect_time)); } static DEVICE_ATTR_RO(connected_duration); @@ -394,14 +394,14 @@ static ssize_t active_duration_show(struct device *dev, duration = jiffies_to_msecs(jiffies + udev->active_duration); else duration = jiffies_to_msecs(udev->active_duration); - return sprintf(buf, "%u\n", duration); + return sysfs_emit(buf, "%u\n", duration); } static DEVICE_ATTR_RO(active_duration); static ssize_t autosuspend_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", dev->power.autosuspend_delay / 1000); + return sysfs_emit(buf, "%d\n", dev->power.autosuspend_delay / 1000); } static ssize_t autosuspend_store(struct device *dev, @@ -442,7 +442,7 @@ static ssize_t level_show(struct device *dev, struct device_attribute *attr, warn_level(); if (udev->state != USB_STATE_SUSPENDED && !udev->dev.power.runtime_auto) p = on_string; - return sprintf(buf, "%s\n", p); + return sysfs_emit(buf, "%s\n", p); } static ssize_t level_store(struct device *dev, struct device_attribute *attr, @@ -490,7 +490,7 @@ static ssize_t usb2_hardware_lpm_show(struct device *dev, else p = "disabled"; - return sprintf(buf, "%s\n", p); + return sysfs_emit(buf, "%s\n", p); } static ssize_t usb2_hardware_lpm_store(struct device *dev, @@ -529,7 +529,7 @@ static ssize_t usb2_lpm_l1_timeout_show(struct device *dev, char *buf) { struct usb_device *udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->l1_params.timeout); + return sysfs_emit(buf, "%d\n", udev->l1_params.timeout); } static ssize_t usb2_lpm_l1_timeout_store(struct device *dev, @@ -552,7 +552,7 @@ static ssize_t usb2_lpm_besl_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *udev = to_usb_device(dev); - return sprintf(buf, "%d\n", udev->l1_params.besl); + return sysfs_emit(buf, "%d\n", udev->l1_params.besl); } static ssize_t usb2_lpm_besl_store(struct device *dev, @@ -589,7 +589,7 @@ static ssize_t usb3_hardware_lpm_u1_show(struct device *dev, usb_unlock_device(udev); - return sprintf(buf, "%s\n", p); + return sysfs_emit(buf, "%s\n", p); } static DEVICE_ATTR_RO(usb3_hardware_lpm_u1); @@ -611,7 +611,7 @@ static ssize_t usb3_hardware_lpm_u2_show(struct device *dev, usb_unlock_device(udev); - return sprintf(buf, "%s\n", p); + return sysfs_emit(buf, "%s\n", p); } static DEVICE_ATTR_RO(usb3_hardware_lpm_u2); @@ -694,7 +694,7 @@ field##_show(struct device *dev, struct device_attribute *attr, \ struct usb_device *udev; \ \ udev = to_usb_device(dev); \ - return sprintf(buf, format_string, \ + return sysfs_emit(buf, format_string, \ le16_to_cpu(udev->descriptor.field)); \ } \ static DEVICE_ATTR_RO(field) @@ -711,7 +711,7 @@ field##_show(struct device *dev, struct device_attribute *attr, \ struct usb_device *udev; \ \ udev = to_usb_device(dev); \ - return sprintf(buf, format_string, udev->descriptor.field); \ + return sysfs_emit(buf, format_string, udev->descriptor.field); \ } \ static DEVICE_ATTR_RO(field) @@ -727,7 +727,7 @@ static ssize_t authorized_show(struct device *dev, struct device_attribute *attr, char *buf) { struct usb_device *usb_dev = to_usb_device(dev); - return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized); + return sysfs_emit(buf, "%u\n", usb_dev->authorized); } /* @@ -918,7 +918,7 @@ static ssize_t authorized_default_show(struct device *dev, struct usb_hcd *hcd; hcd = bus_to_hcd(usb_bus); - return snprintf(buf, PAGE_SIZE, "%u\n", hcd->dev_policy); + return sysfs_emit(buf, "%u\n", hcd->dev_policy); } static ssize_t authorized_default_store(struct device *dev, @@ -957,7 +957,7 @@ static ssize_t interface_authorized_default_show(struct device *dev, struct usb_device *usb_dev = to_usb_device(dev); struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus); - return sprintf(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd)); + return sysfs_emit(buf, "%u\n", !!HCD_INTF_AUTHORIZED(hcd)); } /* @@ -1066,7 +1066,7 @@ iad_##field##_show(struct device *dev, struct device_attribute *attr, \ { \ struct usb_interface *intf = to_usb_interface(dev); \ \ - return sprintf(buf, format_string, \ + return sysfs_emit(buf, format_string, \ intf->intf_assoc->field); \ } \ static DEVICE_ATTR_RO(iad_##field) @@ -1085,7 +1085,7 @@ field##_show(struct device *dev, struct device_attribute *attr, \ { \ struct usb_interface *intf = to_usb_interface(dev); \ \ - return sprintf(buf, format_string, \ + return sysfs_emit(buf, format_string, \ intf->cur_altsetting->desc.field); \ } \ static DEVICE_ATTR_RO(field) @@ -1107,7 +1107,7 @@ static ssize_t interface_show(struct device *dev, struct device_attribute *attr, string = READ_ONCE(intf->cur_altsetting->string); if (!string) return 0; - return sprintf(buf, "%s\n", string); + return sysfs_emit(buf, "%s\n", string); } static DEVICE_ATTR_RO(interface); @@ -1122,7 +1122,8 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, udev = interface_to_usbdev(intf); alt = READ_ONCE(intf->cur_altsetting); - return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" + return sysfs_emit(buf, + "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" "ic%02Xisc%02Xip%02Xin%02X\n", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), @@ -1150,7 +1151,7 @@ static ssize_t supports_autosuspend_show(struct device *dev, s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend); device_unlock(dev); - return sprintf(buf, "%u\n", s); + return sysfs_emit(buf, "%u\n", s); } static DEVICE_ATTR_RO(supports_autosuspend); @@ -1163,7 +1164,7 @@ static ssize_t interface_authorized_show(struct device *dev, { struct usb_interface *intf = to_usb_interface(dev); - return sprintf(buf, "%u\n", intf->authorized); + return sysfs_emit(buf, "%u\n", intf->authorized); } /* From b2c510ffe29f20a5f6ff31ae28d32ffa494b8cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Thu, 23 Jun 2022 15:36:59 -0400 Subject: [PATCH 0719/1436] dt-bindings: usb: mtk-xhci: Allow wakeup interrupt-names to be optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing "minItems: 1" to the interrupt-names property to allow the second interrupt-names, "wakeup", to be optional. Fixes: fe8e488058c4 ("dt-bindings: usb: mtk-xhci: add wakeup interrupt") Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: Krzysztof Kozlowski Acked-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220623193702.817996-2-nfraprado@collabora.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index 892718459d25..63cbc2b62d18 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -57,6 +57,7 @@ properties: - description: optional, wakeup interrupt used to support runtime PM interrupt-names: + minItems: 1 items: - const: host - const: wakeup From ebc4969ae125e65fdb563f66f4bfa7aec95f7eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Thu, 23 Jun 2022 15:37:00 -0400 Subject: [PATCH 0720/1436] dt-bindings: usb: mtk-xhci: Make all clocks required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All of the clocks listed in the binding are always wired to the XHCI controller hardware blocks on all SoCs. The reason some clocks were made optional in the binding was to account for the fact that depending on the SoC, some of the clocks might be fixed (ie not controlled by software). Given that the devicetree should represent the hardware, make all clocks required in the binding. Subsequent patches will make the DTS changes to specify fixed-clocks for the clocks that aren't controllable. Signed-off-by: Nícolas F. R. A. Prado Link: https://lore.kernel.org/r/20220623193702.817996-3-nfraprado@collabora.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index 63cbc2b62d18..1444d18ef9bc 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -67,7 +67,6 @@ properties: maxItems: 1 clocks: - minItems: 1 items: - description: Controller clock used by normal mode - description: Reference clock used by low power mode etc @@ -76,9 +75,8 @@ properties: - description: controller clock clock-names: - minItems: 1 items: - - const: sys_ck # required, the following ones are optional + - const: sys_ck - const: ref_ck - const: mcu_ck - const: dma_ck From 1ccd59066246188a0ecb5ba816e223294d73aa26 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 23 Jun 2022 13:59:14 +0200 Subject: [PATCH 0721/1436] platform/x86: ideapad-laptop: Add allow_v4_dytc module parameter Add an allow_v4_dytc module parameter to allow users to easily test if DYTC version 4 platform-profiles work on their laptop. Fixes: 599482c58ebd ("platform/x86: ideapad-laptop: Add platform support for Ideapad 5 Pro 16ACH6-82L5") Link: https://bugzilla.kernel.org/show_bug.cgi?id=213297 Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220623115914.103001-1-hdegoede@redhat.com --- drivers/platform/x86/ideapad-laptop.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 3ccb7b71dfb1..71f4b59eed4b 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -152,6 +152,10 @@ static bool no_bt_rfkill; module_param(no_bt_rfkill, bool, 0444); MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth."); +static bool allow_v4_dytc; +module_param(allow_v4_dytc, bool, 0444); +MODULE_PARM_DESC(allow_v4_dytc, "Enable DYTC version 4 platform-profile support."); + /* * ACPI Helpers */ @@ -901,13 +905,16 @@ static int ideapad_dytc_profile_init(struct ideapad_private *priv) dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF; - if (dytc_version < 5) { - if (dytc_version < 4 || !dmi_check_system(ideapad_dytc_v4_allow_table)) { - dev_info(&priv->platform_device->dev, - "DYTC_VERSION is less than 4 or is not allowed: %d\n", - dytc_version); - return -ENODEV; - } + if (dytc_version < 4) { + dev_info(&priv->platform_device->dev, "DYTC_VERSION < 4 is not supported\n"); + return -ENODEV; + } + + if (dytc_version < 5 && + !(allow_v4_dytc || dmi_check_system(ideapad_dytc_v4_allow_table))) { + dev_info(&priv->platform_device->dev, + "DYTC_VERSION 4 support may not work. Pass ideapad_laptop.allow_v4_dytc=Y on the kernel commandline to enable\n"); + return -ENODEV; } priv->dytc = kzalloc(sizeof(*priv->dytc), GFP_KERNEL); From 7dbd3af50aad93a1e97c0d2a7b544a64e0a0a6b0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 27 Jun 2022 15:08:50 +0200 Subject: [PATCH 0722/1436] platform/x86: ideapad-laptop: Add Ideapad 5 15ITL05 to ideapad_dytc_v4_allow_table[] The Ideapad 5 15ITL05 uses DYTC version 4 for platform-profile control. This has been tested successfully with the ideapad-laptop DYTC version 5 code; Add the Ideapad 5 15ITL05 to the ideapad_dytc_v4_allow_table[]. Fixes: 599482c58ebd ("platform/x86: ideapad-laptop: Add platform support for Ideapad 5 Pro 16ACH6-82L5") Link: https://bugzilla.kernel.org/show_bug.cgi?id=213297 Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220627130850.313537-1-hdegoede@redhat.com --- drivers/platform/x86/ideapad-laptop.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 71f4b59eed4b..abd0c81d62c4 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -875,12 +875,18 @@ static void dytc_profile_refresh(struct ideapad_private *priv) static const struct dmi_system_id ideapad_dytc_v4_allow_table[] = { { /* Ideapad 5 Pro 16ACH6 */ - .ident = "LENOVO 82L5", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), DMI_MATCH(DMI_PRODUCT_NAME, "82L5") } }, + { + /* Ideapad 5 15ITL05 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "IdeaPad 5 15ITL05") + } + }, {} }; From 5f8954e099b8ae96e7de1bb95950e00c85bedd40 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 27 Jun 2022 16:35:59 +0200 Subject: [PATCH 0723/1436] Revert "mwifiex: fix sleep in atomic context bugs caused by dev_coredumpv" This reverts commit a52ed4866d2b90dd5e4ae9dabd453f3ed8fa3cbc as it causes build problems in linux-next. It needs to be reintroduced in a way that can allow the api to evolve and not require a "flag day" to catch all users. Link: https://lore.kernel.org/r/20220623160723.7a44b573@canb.auug.org.au Cc: Duoming Zhou Cc: Brian Norris Cc: Johannes Berg Reported-by: Stephen Rothwell Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/mwifiex/init.c | 9 ++++----- drivers/net/wireless/marvell/mwifiex/main.h | 3 +-- drivers/net/wireless/marvell/mwifiex/sta_event.c | 6 +++--- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/init.c b/drivers/net/wireless/marvell/mwifiex/init.c index fca3ab948f6c..88c72d1827a0 100644 --- a/drivers/net/wireless/marvell/mwifiex/init.c +++ b/drivers/net/wireless/marvell/mwifiex/init.c @@ -63,10 +63,9 @@ static void wakeup_timer_fn(struct timer_list *t) adapter->if_ops.card_reset(adapter); } -static void fw_dump_work(struct work_struct *work) +static void fw_dump_timer_fn(struct timer_list *t) { - struct mwifiex_adapter *adapter = - container_of(work, struct mwifiex_adapter, devdump_work.work); + struct mwifiex_adapter *adapter = from_timer(adapter, t, devdump_timer); mwifiex_upload_device_dump(adapter); } @@ -322,7 +321,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->active_scan_triggered = false; timer_setup(&adapter->wakeup_timer, wakeup_timer_fn, 0); adapter->devdump_len = 0; - INIT_DELAYED_WORK(&adapter->devdump_work, fw_dump_work); + timer_setup(&adapter->devdump_timer, fw_dump_timer_fn, 0); } /* @@ -401,7 +400,7 @@ static void mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter) { del_timer(&adapter->wakeup_timer); - cancel_delayed_work_sync(&adapter->devdump_work); + del_timer_sync(&adapter->devdump_timer); mwifiex_cancel_all_pending_cmd(adapter); wake_up_interruptible(&adapter->cmd_wait_q.wait); wake_up_interruptible(&adapter->hs_activate_wait_q); diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 5d8646f16162..332dd1c8db35 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -49,7 +49,6 @@ #include #include #include -#include #include "decl.h" #include "ioctl.h" @@ -1056,7 +1055,7 @@ struct mwifiex_adapter { /* Device dump data/length */ void *devdump_data; int devdump_len; - struct delayed_work devdump_work; + struct timer_list devdump_timer; bool ignore_btcoex_events; }; diff --git a/drivers/net/wireless/marvell/mwifiex/sta_event.c b/drivers/net/wireless/marvell/mwifiex/sta_event.c index 4d93386494c5..7d42c5d2dbf6 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_event.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_event.c @@ -623,8 +623,8 @@ mwifiex_fw_dump_info_event(struct mwifiex_private *priv, * transmission event get lost, in this cornel case, * user would still get partial of the dump. */ - schedule_delayed_work(&adapter->devdump_work, - msecs_to_jiffies(MWIFIEX_TIMER_10S)); + mod_timer(&adapter->devdump_timer, + jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S)); } /* Overflow check */ @@ -643,7 +643,7 @@ mwifiex_fw_dump_info_event(struct mwifiex_private *priv, return; upload_dump: - cancel_delayed_work_sync(&adapter->devdump_work); + del_timer_sync(&adapter->devdump_timer); mwifiex_upload_device_dump(adapter); } From 38a523a2946d3a0961d141d477a1ee2b1f3bdbb1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 27 Jun 2022 16:36:57 +0200 Subject: [PATCH 0724/1436] Revert "devcoredump: remove the useless gfp_t parameter in dev_coredumpv and dev_coredumpm" This reverts commit 77515ebaf01920e2db49e04672ef669a7c2907f2 as it causes build problems in linux-next. It needs to be reintroduced in a way that can allow the api to evolve and not require a "flag day" to catch all users. Link: https://lore.kernel.org/r/20220623160723.7a44b573@canb.auug.org.au Cc: Duoming Zhou Cc: Brian Norris Cc: Johannes Berg Reported-by: Stephen Rothwell Signed-off-by: Greg Kroah-Hartman --- drivers/base/devcoredump.c | 16 ++++++++++------ drivers/bluetooth/btmrvl_sdio.c | 2 +- drivers/bluetooth/hci_qca.c | 2 +- drivers/gpu/drm/etnaviv/etnaviv_dump.c | 2 +- drivers/gpu/drm/msm/disp/msm_disp_snapshot.c | 4 ++-- drivers/gpu/drm/msm/msm_gpu.c | 4 ++-- drivers/media/platform/qcom/venus/core.c | 2 +- drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c | 2 +- drivers/net/wireless/ath/ath10k/coredump.c | 2 +- .../net/wireless/ath/wil6210/wil_crash_dump.c | 2 +- .../wireless/broadcom/brcm80211/brcmfmac/debug.c | 2 +- drivers/net/wireless/intel/iwlwifi/fw/dbg.c | 6 ++++-- drivers/net/wireless/marvell/mwifiex/main.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 3 ++- drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 3 ++- drivers/net/wireless/realtek/rtw88/main.c | 2 +- drivers/net/wireless/realtek/rtw89/ser.c | 2 +- drivers/remoteproc/qcom_q6v5_mss.c | 2 +- drivers/remoteproc/remoteproc_coredump.c | 8 ++++---- include/drm/drm_print.h | 2 +- include/linux/devcoredump.h | 13 +++++++------ sound/soc/intel/avs/apl.c | 2 +- sound/soc/intel/avs/skl.c | 2 +- sound/soc/intel/catpt/dsp.c | 2 +- 24 files changed, 50 insertions(+), 40 deletions(-) diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 8535f0bd5dfb..f4d794d6bb85 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -173,13 +173,15 @@ static void devcd_freev(void *data) * @dev: the struct device for the crashed device * @data: vmalloc data containing the device coredump * @datalen: length of the data + * @gfp: allocation flags * * This function takes ownership of the vmalloc'ed data and will free * it when it is no longer used. See dev_coredumpm() for more information. */ -void dev_coredumpv(struct device *dev, void *data, size_t datalen) +void dev_coredumpv(struct device *dev, void *data, size_t datalen, + gfp_t gfp) { - dev_coredumpm(dev, NULL, data, datalen, devcd_readv, devcd_freev); + dev_coredumpm(dev, NULL, data, datalen, gfp, devcd_readv, devcd_freev); } EXPORT_SYMBOL_GPL(dev_coredumpv); @@ -234,6 +236,7 @@ static ssize_t devcd_read_from_sgtable(char *buffer, loff_t offset, * @owner: the module that contains the read/free functions, use %THIS_MODULE * @data: data cookie for the @read/@free functions * @datalen: length of the data + * @gfp: allocation flags * @read: function to read from the given buffer * @free: function to free the given buffer * @@ -243,7 +246,7 @@ static ssize_t devcd_read_from_sgtable(char *buffer, loff_t offset, * function will be called to free the data. */ void dev_coredumpm(struct device *dev, struct module *owner, - void *data, size_t datalen, + void *data, size_t datalen, gfp_t gfp, ssize_t (*read)(char *buffer, loff_t offset, size_t count, void *data, size_t datalen), void (*free)(void *data)) @@ -265,7 +268,7 @@ void dev_coredumpm(struct device *dev, struct module *owner, if (!try_module_get(owner)) goto free; - devcd = kzalloc(sizeof(*devcd), GFP_KERNEL); + devcd = kzalloc(sizeof(*devcd), gfp); if (!devcd) goto put_module; @@ -315,6 +318,7 @@ EXPORT_SYMBOL_GPL(dev_coredumpm); * @dev: the struct device for the crashed device * @table: the dump data * @datalen: length of the data + * @gfp: allocation flags * * Creates a new device coredump for the given device. If a previous one hasn't * been read yet, the new coredump is discarded. The data lifetime is determined @@ -322,9 +326,9 @@ EXPORT_SYMBOL_GPL(dev_coredumpm); * it will free the data. */ void dev_coredumpsg(struct device *dev, struct scatterlist *table, - size_t datalen) + size_t datalen, gfp_t gfp) { - dev_coredumpm(dev, NULL, table, datalen, devcd_read_from_sgtable, + dev_coredumpm(dev, NULL, table, datalen, gfp, devcd_read_from_sgtable, devcd_free_sgtable); } EXPORT_SYMBOL_GPL(dev_coredumpsg); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 9b9728719db2..b8ef66f89fc1 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1515,7 +1515,7 @@ done: /* fw_dump_data will be free in device coredump release function * after 5 min */ - dev_coredumpv(&card->func->dev, fw_dump_data, fw_dump_len); + dev_coredumpv(&card->func->dev, fw_dump_data, fw_dump_len, GFP_KERNEL); BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump end"); } diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 2e4074211ae9..eab34e24d944 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -1120,7 +1120,7 @@ static void qca_controller_memdump(struct work_struct *work) qca_memdump->ram_dump_size); memdump_buf = qca_memdump->memdump_buf_head; dev_coredumpv(&hu->serdev->dev, memdump_buf, - qca_memdump->received_dump); + qca_memdump->received_dump, GFP_KERNEL); cancel_delayed_work(&qca->ctrl_memdump_timeout); kfree(qca->qca_memdump); qca->qca_memdump = NULL; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_dump.c b/drivers/gpu/drm/etnaviv/etnaviv_dump.c index 519fcb234b3e..f418e0b75772 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_dump.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_dump.c @@ -225,5 +225,5 @@ void etnaviv_core_dump(struct etnaviv_gem_submit *submit) etnaviv_core_dump_header(&iter, ETDUMP_BUF_END, iter.data); - dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start); + dev_coredumpv(gpu->dev, iter.start, iter.data - iter.start, GFP_KERNEL); } diff --git a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c index f057d294c30b..e75b97127c0d 100644 --- a/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c +++ b/drivers/gpu/drm/msm/disp/msm_disp_snapshot.c @@ -74,8 +74,8 @@ static void _msm_disp_snapshot_work(struct kthread_work *work) * If there is a codedump pending for the device, the dev_coredumpm() * will also free new coredump state. */ - dev_coredumpm(disp_state->dev, THIS_MODULE, disp_state, 0, - disp_devcoredump_read, msm_disp_state_free); + dev_coredumpm(disp_state->dev, THIS_MODULE, disp_state, 0, GFP_KERNEL, + disp_devcoredump_read, msm_disp_state_free); } void msm_disp_snapshot_state(struct drm_device *drm_dev) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 30576ced0a0a..eb8a6663f309 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -317,8 +317,8 @@ static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, gpu->crashstate = state; /* FIXME: Release the crashstate if this errors out? */ - dev_coredumpm(gpu->dev->dev, THIS_MODULE, gpu, 0, - msm_gpu_devcoredump_read, msm_gpu_devcoredump_free); + dev_coredumpm(gpu->dev->dev, THIS_MODULE, gpu, 0, GFP_KERNEL, + msm_gpu_devcoredump_read, msm_gpu_devcoredump_free); } #else static void msm_gpu_crashstate_capture(struct msm_gpu *gpu, diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index db84dfb3fb11..877eca125803 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -49,7 +49,7 @@ static void venus_coredump(struct venus_core *core) memcpy(data, mem_va, mem_size); memunmap(mem_va); - dev_coredumpv(dev, data, mem_size); + dev_coredumpv(dev, data, mem_size, GFP_KERNEL); } static void venus_event_notify(struct venus_core *core, u32 event) diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c index fa520ab7c960..c991b30bc9f0 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-dump.c @@ -281,5 +281,5 @@ void mcp251xfd_dump(const struct mcp251xfd_priv *priv) mcp251xfd_dump_end(priv, &iter); dev_coredumpv(&priv->spi->dev, iter.start, - iter.data - iter.start); + iter.data - iter.start, GFP_KERNEL); } diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index dc9237069921..fe6b6f97a916 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -1607,7 +1607,7 @@ int ath10k_coredump_submit(struct ath10k *ar) return -ENODATA; } - dev_coredumpv(ar->dev, dump, le32_to_cpu(dump->len)); + dev_coredumpv(ar->dev, dump, le32_to_cpu(dump->len), GFP_KERNEL); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c index 79299609dd62..89c12cb2aaab 100644 --- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c +++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c @@ -117,6 +117,6 @@ void wil_fw_core_dump(struct wil6210_priv *wil) /* fw_dump_data will be free in device coredump release function * after 5 min */ - dev_coredumpv(wil_to_dev(wil), fw_dump_data, fw_dump_size); + dev_coredumpv(wil_to_dev(wil), fw_dump_data, fw_dump_size, GFP_KERNEL); wil_info(wil, "fw core dumped, size %d bytes\n", fw_dump_size); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c index 87f3652ef3bd..eecf8a38d94a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c @@ -37,7 +37,7 @@ int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data, return err; } - dev_coredumpv(bus->dev, dump, len + ramsize); + dev_coredumpv(bus->dev, dump, len + ramsize, GFP_KERNEL); return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index f2f7cf494a8c..abf49022edbe 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -2601,7 +2601,8 @@ static void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt, fw_error_dump.trans_ptr->data, fw_error_dump.trans_ptr->len, fw_error_dump.fwrt_len); - dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len); + dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len, + GFP_KERNEL); } vfree(fw_error_dump.fwrt_ptr); vfree(fw_error_dump.trans_ptr); @@ -2646,7 +2647,8 @@ static void iwl_fw_error_ini_dump(struct iwl_fw_runtime *fwrt, entry->data, entry->size, offs); offs += entry->size; } - dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len); + dev_coredumpsg(fwrt->trans->dev, sg_dump_data, file_len, + GFP_KERNEL); } iwl_dump_ini_list_free(&dump_list); } diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 26fef0ab1b0d..ace7371c4773 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -1115,7 +1115,8 @@ void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter) */ mwifiex_dbg(adapter, MSG, "== mwifiex dump information to /sys/class/devcoredump start\n"); - dev_coredumpv(adapter->dev, adapter->devdump_data, adapter->devdump_len); + dev_coredumpv(adapter->dev, adapter->devdump_data, adapter->devdump_len, + GFP_KERNEL); mwifiex_dbg(adapter, MSG, "== mwifiex dump information to /sys/class/devcoredump end\n"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 5336fe8c668d..bd687f7de628 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -2421,5 +2421,6 @@ void mt7615_coredump_work(struct work_struct *work) dev_kfree_skb(skb); } - dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ); + dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, + GFP_KERNEL); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index cac284f95ce0..a630ddbf19e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -1630,7 +1630,8 @@ void mt7921_coredump_work(struct work_struct *work) } if (dump) - dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ); + dev_coredumpv(dev->mt76.dev, dump, MT76_CONNAC_COREDUMP_SZ, + GFP_KERNEL); mt7921_reset(&dev->mt76); } diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index a276544cecdd..efabd5b1bf5b 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -414,7 +414,7 @@ static void rtw_fwcd_dump(struct rtw_dev *rtwdev) * framework. Note that a new dump will be discarded if a previous one * hasn't been released yet. */ - dev_coredumpv(rtwdev->dev, desc->data, desc->size); + dev_coredumpv(rtwdev->dev, desc->data, desc->size, GFP_KERNEL); } static void rtw_fwcd_free(struct rtw_dev *rtwdev, bool free_self) diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index d28fe01ad729..9e95ed972710 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -127,7 +127,7 @@ static void rtw89_ser_cd_send(struct rtw89_dev *rtwdev, * will be discarded if a previous one hasn't been released by * framework yet. */ - dev_coredumpv(rtwdev->dev, buf, sizeof(*buf)); + dev_coredumpv(rtwdev->dev, buf, sizeof(*buf), GFP_KERNEL); } static void rtw89_ser_cd_free(struct rtw89_dev *rtwdev, diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index 813d87faef6c..af217de75e4d 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -597,7 +597,7 @@ static void q6v5_dump_mba_logs(struct q6v5 *qproc) data = vmalloc(MBA_LOG_SIZE); if (data) { memcpy(data, mba_region, MBA_LOG_SIZE); - dev_coredumpv(&rproc->dev, data, MBA_LOG_SIZE); + dev_coredumpv(&rproc->dev, data, MBA_LOG_SIZE, GFP_KERNEL); } memunmap(mba_region); } diff --git a/drivers/remoteproc/remoteproc_coredump.c b/drivers/remoteproc/remoteproc_coredump.c index cd55c2abd227..4b093420d98a 100644 --- a/drivers/remoteproc/remoteproc_coredump.c +++ b/drivers/remoteproc/remoteproc_coredump.c @@ -309,7 +309,7 @@ void rproc_coredump(struct rproc *rproc) phdr += elf_size_of_phdr(class); } if (dump_conf == RPROC_COREDUMP_ENABLED) { - dev_coredumpv(&rproc->dev, data, data_size); + dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL); return; } @@ -318,7 +318,7 @@ void rproc_coredump(struct rproc *rproc) dump_state.header = data; init_completion(&dump_state.dump_done); - dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, + dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, GFP_KERNEL, rproc_coredump_read, rproc_coredump_free); /* @@ -449,7 +449,7 @@ void rproc_coredump_using_sections(struct rproc *rproc) } if (dump_conf == RPROC_COREDUMP_ENABLED) { - dev_coredumpv(&rproc->dev, data, data_size); + dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL); return; } @@ -458,7 +458,7 @@ void rproc_coredump_using_sections(struct rproc *rproc) dump_state.header = data; init_completion(&dump_state.dump_done); - dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, + dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, GFP_KERNEL, rproc_coredump_read, rproc_coredump_free); /* Wait until the dump is read and free is called. Data is freed diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index b41850366bcc..22fabdeed297 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -162,7 +162,7 @@ struct drm_print_iterator { * void makecoredump(...) * { * ... - * dev_coredumpm(dev, THIS_MODULE, data, 0, + * dev_coredumpm(dev, THIS_MODULE, data, 0, GFP_KERNEL, * coredump_read, ...) * } * diff --git a/include/linux/devcoredump.h b/include/linux/devcoredump.h index c7d840d824c3..c008169ed2c6 100644 --- a/include/linux/devcoredump.h +++ b/include/linux/devcoredump.h @@ -52,26 +52,27 @@ static inline void _devcd_free_sgtable(struct scatterlist *table) #ifdef CONFIG_DEV_COREDUMP -void dev_coredumpv(struct device *dev, void *data, size_t datalen); +void dev_coredumpv(struct device *dev, void *data, size_t datalen, + gfp_t gfp); void dev_coredumpm(struct device *dev, struct module *owner, - void *data, size_t datalen, + void *data, size_t datalen, gfp_t gfp, ssize_t (*read)(char *buffer, loff_t offset, size_t count, void *data, size_t datalen), void (*free)(void *data)); void dev_coredumpsg(struct device *dev, struct scatterlist *table, - size_t datalen); + size_t datalen, gfp_t gfp); #else static inline void dev_coredumpv(struct device *dev, void *data, - size_t datalen) + size_t datalen, gfp_t gfp) { vfree(data); } static inline void dev_coredumpm(struct device *dev, struct module *owner, - void *data, size_t datalen, + void *data, size_t datalen, gfp_t gfp, ssize_t (*read)(char *buffer, loff_t offset, size_t count, void *data, size_t datalen), void (*free)(void *data)) @@ -80,7 +81,7 @@ dev_coredumpm(struct device *dev, struct module *owner, } static inline void dev_coredumpsg(struct device *dev, struct scatterlist *table, - size_t datalen) + size_t datalen, gfp_t gfp) { _devcd_free_sgtable(table); } diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c index 1ff57f1a483d..b8e2b23c9f64 100644 --- a/sound/soc/intel/avs/apl.c +++ b/sound/soc/intel/avs/apl.c @@ -164,7 +164,7 @@ static int apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) } while (offset < msg->ext.coredump.stack_dump_size); exit: - dev_coredumpv(adev->dev, dump, dump_size); + dev_coredumpv(adev->dev, dump, dump_size, GFP_KERNEL); return 0; } diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c index 3413162768dc..bda5ec7510fe 100644 --- a/sound/soc/intel/avs/skl.c +++ b/sound/soc/intel/avs/skl.c @@ -88,7 +88,7 @@ static int skl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) return -ENOMEM; memcpy_fromio(dump, avs_sram_addr(adev, AVS_FW_REGS_WINDOW), AVS_FW_REGS_SIZE); - dev_coredumpv(adev->dev, dump, AVS_FW_REGS_SIZE); + dev_coredumpv(adev->dev, dump, AVS_FW_REGS_SIZE, GFP_KERNEL); return 0; } diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c index d2afe9ff1e3a..346bec000306 100644 --- a/sound/soc/intel/catpt/dsp.c +++ b/sound/soc/intel/catpt/dsp.c @@ -539,7 +539,7 @@ int catpt_coredump(struct catpt_dev *cdev) pos += CATPT_DMA_REGS_SIZE; } - dev_coredumpv(cdev->dev, dump, dump_size); + dev_coredumpv(cdev->dev, dump, dump_size, GFP_KERNEL); return 0; } From 31c779f293b343577690c01369a5019ca6ec5de9 Mon Sep 17 00:00:00 2001 From: Yangxi Xiang Date: Mon, 27 Jun 2022 20:04:09 +0800 Subject: [PATCH 0725/1436] devtmpfs: fix the dangling pointer of global devtmpfsd thread When the devtmpfs fails to mount, a dangling pointer still remains in global. Specifically, the err variable is passed by a pointer to the devtmpfsd. When the devtmpfsd exits, it sets the error and completes the setup_done. In this situation, the thread pointer is not set to null. After the devtmpfsd exited, the devtmpfs can wakes up the destroyed devtmpfsd thread by wake_up_process if a device change event comes. Signed-off-by: Yangxi Xiang Link: https://lore.kernel.org/r/20220627120409.11174-1-xyangxi5@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/devtmpfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 8a3ddbae3b70..e4bffeabf344 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -482,6 +482,7 @@ int __init devtmpfs_init(void) if (err) { printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); unregister_filesystem(&dev_fs_type); + thread = NULL; return err; } From 1d248d2302da5b96e06281a52056eeafec0d2e11 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 26 Jun 2022 10:32:21 +0100 Subject: [PATCH 0726/1436] ABI: testing/sysfs-devices-system-cpu: remove duplicated core_id This was already defined at stable/sysfs-devices-system-cpu with the same description, as pointed by get_abi.pl: Warning: /sys/devices/system/cpu/cpuX/topology/core_id is defined 2 times: Documentation/ABI/stable/sysfs-devices-system-cpu:38 Documentation/ABI/testing/sysfs-devices-system-cpu:69 Remove the duplicated one. Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/1e92337c1ef74f5eb9e1c1871e20b858b490d269.1656235926.git.mchehab@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-devices-system-cpu | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index 2ad01cad7f1c..7856f468e464 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -67,8 +67,7 @@ Description: Discover NUMA node a CPU belongs to /sys/devices/system/cpu/cpu42/node2 -> ../../node/node2 -What: /sys/devices/system/cpu/cpuX/topology/core_id - /sys/devices/system/cpu/cpuX/topology/core_siblings +What: /sys/devices/system/cpu/cpuX/topology/core_siblings /sys/devices/system/cpu/cpuX/topology/core_siblings_list /sys/devices/system/cpu/cpuX/topology/physical_package_id /sys/devices/system/cpu/cpuX/topology/thread_siblings @@ -84,10 +83,6 @@ Description: CPU topology files that describe a logical CPU's relationship Briefly, the files above are: - core_id: the CPU core ID of cpuX. Typically it is the - hardware platform's identifier (rather than the kernel's). - The actual value is architecture and platform dependent. - core_siblings: internal kernel map of cpuX's hardware threads within the same physical_package_id. From 70fe758352cafdee72a7b13bf9db065f9613ced8 Mon Sep 17 00:00:00 2001 From: Zhang Wensheng Date: Wed, 22 Jun 2022 15:43:27 +0800 Subject: [PATCH 0727/1436] driver core: fix potential deadlock in __driver_attach In __driver_attach function, There are also AA deadlock problem, like the commit b232b02bf3c2 ("driver core: fix deadlock in __device_attach"). stack like commit b232b02bf3c2 ("driver core: fix deadlock in __device_attach"). list below: In __driver_attach function, The lock holding logic is as follows: ... __driver_attach if (driver_allows_async_probing(drv)) device_lock(dev) // get lock dev async_schedule_dev(__driver_attach_async_helper, dev); // func async_schedule_node async_schedule_node_domain(func) entry = kzalloc(sizeof(struct async_entry), GFP_ATOMIC); /* when fail or work limit, sync to execute func, but __driver_attach_async_helper will get lock dev as will, which will lead to A-A deadlock. */ if (!entry || atomic_read(&entry_count) > MAX_WORK) { func; else queue_work_node(node, system_unbound_wq, &entry->work) device_unlock(dev) As above show, when it is allowed to do async probes, because of out of memory or work limit, async work is not be allowed, to do sync execute instead. it will lead to A-A deadlock because of __driver_attach_async_helper getting lock dev. Reproduce: and it can be reproduce by make the condition (if (!entry || atomic_read(&entry_count) > MAX_WORK)) untenable, like below: [ 370.785650] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 370.787154] task:swapper/0 state:D stack: 0 pid: 1 ppid: 0 flags:0x00004000 [ 370.788865] Call Trace: [ 370.789374] [ 370.789841] __schedule+0x482/0x1050 [ 370.790613] schedule+0x92/0x1a0 [ 370.791290] schedule_preempt_disabled+0x2c/0x50 [ 370.792256] __mutex_lock.isra.0+0x757/0xec0 [ 370.793158] __mutex_lock_slowpath+0x1f/0x30 [ 370.794079] mutex_lock+0x50/0x60 [ 370.794795] __device_driver_lock+0x2f/0x70 [ 370.795677] ? driver_probe_device+0xd0/0xd0 [ 370.796576] __driver_attach_async_helper+0x1d/0xd0 [ 370.797318] ? driver_probe_device+0xd0/0xd0 [ 370.797957] async_schedule_node_domain+0xa5/0xc0 [ 370.798652] async_schedule_node+0x19/0x30 [ 370.799243] __driver_attach+0x246/0x290 [ 370.799828] ? driver_allows_async_probing+0xa0/0xa0 [ 370.800548] bus_for_each_dev+0x9d/0x130 [ 370.801132] driver_attach+0x22/0x30 [ 370.801666] bus_add_driver+0x290/0x340 [ 370.802246] driver_register+0x88/0x140 [ 370.802817] ? virtio_scsi_init+0x116/0x116 [ 370.803425] scsi_register_driver+0x1a/0x30 [ 370.804057] init_sd+0x184/0x226 [ 370.804533] do_one_initcall+0x71/0x3a0 [ 370.805107] kernel_init_freeable+0x39a/0x43a [ 370.805759] ? rest_init+0x150/0x150 [ 370.806283] kernel_init+0x26/0x230 [ 370.806799] ret_from_fork+0x1f/0x30 To fix the deadlock, move the async_schedule_dev outside device_lock, as we can see, in async_schedule_node_domain, the parameter of queue_work_node is system_unbound_wq, so it can accept concurrent operations. which will also not change the code logic, and will not lead to deadlock. Fixes: ef0ff68351be ("driver core: Probe devices asynchronously instead of the driver") Signed-off-by: Zhang Wensheng Link: https://lore.kernel.org/r/20220622074327.497102-1-zhangwensheng5@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index e600dd2afc35..70f79fc71539 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -1099,6 +1099,7 @@ static void __driver_attach_async_helper(void *_dev, async_cookie_t cookie) static int __driver_attach(struct device *dev, void *data) { struct device_driver *drv = data; + bool async = false; int ret; /* @@ -1137,9 +1138,11 @@ static int __driver_attach(struct device *dev, void *data) if (!dev->driver && !dev->p->async_driver) { get_device(dev); dev->p->async_driver = drv; - async_schedule_dev(__driver_attach_async_helper, dev); + async = true; } device_unlock(dev); + if (async) + async_schedule_dev(__driver_attach_async_helper, dev); return 0; } From dcab8da13ff4886aab26348b925d20dca4f12bac Mon Sep 17 00:00:00 2001 From: Lin Feng Date: Fri, 17 Jun 2022 17:17:46 +0800 Subject: [PATCH 0728/1436] kernfs/file.c: remove redundant error return counter assignment Since previous 'rc = -EINVAL;', rc value doesn't change, so not necessary to re-assign it again. Signed-off-by: Lin Feng Link: https://lore.kernel.org/r/20220617091746.206515-1-linf@wangsu.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index e3abfa843879..54b2a13ac9a2 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -484,7 +484,6 @@ static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma) * It is not possible to successfully wrap close. * So error if someone is trying to use close. */ - rc = -EINVAL; if (vma->vm_ops && vma->vm_ops->close) goto out_put; From 086c00c71fc8d47db6983f419a45f9ee167de03f Mon Sep 17 00:00:00 2001 From: Imran Khan Date: Wed, 15 Jun 2022 12:10:56 +1000 Subject: [PATCH 0729/1436] kernfs: make ->attr.open RCU protected. After removal of kernfs_open_node->refcnt in the previous patch, kernfs_open_node_lock can be removed as well by making ->attr.open RCU protected. kernfs_put_open_node can delegate freeing to ->attr.open to RCU and other readers of ->attr.open can do so under rcu_read_(un)lock. Suggested by: Al Viro Acked-by: Tejun Heo Signed-off-by: Imran Khan Link: https://lore.kernel.org/r/20220615021059.862643-2-imran.f.khan@oracle.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 147 ++++++++++++++++++++++++++++------------- include/linux/kernfs.h | 2 +- 2 files changed, 102 insertions(+), 47 deletions(-) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 54b2a13ac9a2..22e7481e7b63 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -23,16 +23,16 @@ * for each kernfs_node with one or more open files. * * kernfs_node->attr.open points to kernfs_open_node. attr.open is - * protected by kernfs_open_node_lock. + * RCU protected. * * filp->private_data points to seq_file whose ->private points to * kernfs_open_file. kernfs_open_files are chained at * kernfs_open_node->files, which is protected by kernfs_open_file_mutex. */ -static DEFINE_SPINLOCK(kernfs_open_node_lock); static DEFINE_MUTEX(kernfs_open_file_mutex); struct kernfs_open_node { + struct rcu_head rcu_head; atomic_t event; wait_queue_head_t poll; struct list_head files; /* goes through kernfs_open_file.list */ @@ -51,6 +51,52 @@ struct kernfs_open_node { static DEFINE_SPINLOCK(kernfs_notify_lock); static struct kernfs_node *kernfs_notify_list = KERNFS_NOTIFY_EOL; +/** + * kernfs_deref_open_node - Get kernfs_open_node corresponding to @kn. + * + * @of: associated kernfs_open_file instance. + * @kn: target kernfs_node. + * + * Fetch and return ->attr.open of @kn if @of->list is non empty. + * If @of->list is not empty we can safely assume that @of is on + * @kn->attr.open->files list and this guarantees that @kn->attr.open + * will not vanish i.e. dereferencing outside RCU read-side critical + * section is safe here. + * + * The caller needs to make sure that @of->list is not empty. + */ +static struct kernfs_open_node * +kernfs_deref_open_node(struct kernfs_open_file *of, struct kernfs_node *kn) +{ + struct kernfs_open_node *on; + + on = rcu_dereference_check(kn->attr.open, !list_empty(&of->list)); + + return on; +} + +/** + * kernfs_deref_open_node_protected - Get kernfs_open_node corresponding to @kn + * + * @kn: target kernfs_node. + * + * Fetch and return ->attr.open of @kn when caller holds the + * kernfs_open_file_mutex. + * + * Update of ->attr.open happens under kernfs_open_file_mutex. So when + * the caller guarantees that this mutex is being held, other updaters can't + * change ->attr.open and this means that we can safely deref ->attr.open + * outside RCU read-side critical section. + * + * The caller needs to make sure that kernfs_open_file_mutex is held. + */ +static struct kernfs_open_node * +kernfs_deref_open_node_protected(struct kernfs_node *kn) +{ + return rcu_dereference_protected(kn->attr.open, + lockdep_is_held(&kernfs_open_file_mutex)); +} + static struct kernfs_open_file *kernfs_of(struct file *file) { return ((struct seq_file *)file->private_data)->private; @@ -156,8 +202,12 @@ static void kernfs_seq_stop(struct seq_file *sf, void *v) static int kernfs_seq_show(struct seq_file *sf, void *v) { struct kernfs_open_file *of = sf->private; + struct kernfs_open_node *on = kernfs_deref_open_node(of, of->kn); - of->event = atomic_read(&of->kn->attr.open->event); + if (!on) + return -EINVAL; + + of->event = atomic_read(&on->event); return of->kn->attr.ops->seq_show(sf, v); } @@ -180,6 +230,7 @@ static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) struct kernfs_open_file *of = kernfs_of(iocb->ki_filp); ssize_t len = min_t(size_t, iov_iter_count(iter), PAGE_SIZE); const struct kernfs_ops *ops; + struct kernfs_open_node *on; char *buf; buf = of->prealloc_buf; @@ -201,7 +252,15 @@ static ssize_t kernfs_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) goto out_free; } - of->event = atomic_read(&of->kn->attr.open->event); + on = kernfs_deref_open_node(of, of->kn); + if (!on) { + len = -EINVAL; + mutex_unlock(&of->mutex); + goto out_free; + } + + of->event = atomic_read(&on->event); + ops = kernfs_ops(of->kn); if (ops->read) len = ops->read(of, buf, len, iocb->ki_pos); @@ -518,36 +577,29 @@ static int kernfs_get_open_node(struct kernfs_node *kn, { struct kernfs_open_node *on, *new_on = NULL; - retry: mutex_lock(&kernfs_open_file_mutex); - spin_lock_irq(&kernfs_open_node_lock); - - if (!kn->attr.open && new_on) { - kn->attr.open = new_on; - new_on = NULL; - } - - on = kn->attr.open; - if (on) - list_add_tail(&of->list, &on->files); - - spin_unlock_irq(&kernfs_open_node_lock); - mutex_unlock(&kernfs_open_file_mutex); + on = kernfs_deref_open_node_protected(kn); if (on) { - kfree(new_on); + list_add_tail(&of->list, &on->files); + mutex_unlock(&kernfs_open_file_mutex); return 0; + } else { + /* not there, initialize a new one */ + new_on = kmalloc(sizeof(*new_on), GFP_KERNEL); + if (!new_on) { + mutex_unlock(&kernfs_open_file_mutex); + return -ENOMEM; + } + atomic_set(&new_on->event, 1); + init_waitqueue_head(&new_on->poll); + INIT_LIST_HEAD(&new_on->files); + list_add_tail(&of->list, &new_on->files); + rcu_assign_pointer(kn->attr.open, new_on); } + mutex_unlock(&kernfs_open_file_mutex); - /* not there, initialize a new one and retry */ - new_on = kmalloc(sizeof(*new_on), GFP_KERNEL); - if (!new_on) - return -ENOMEM; - - atomic_set(&new_on->event, 1); - init_waitqueue_head(&new_on->poll); - INIT_LIST_HEAD(&new_on->files); - goto retry; + return 0; } /** @@ -566,24 +618,25 @@ static int kernfs_get_open_node(struct kernfs_node *kn, static void kernfs_unlink_open_file(struct kernfs_node *kn, struct kernfs_open_file *of) { - struct kernfs_open_node *on = kn->attr.open; - unsigned long flags; + struct kernfs_open_node *on; mutex_lock(&kernfs_open_file_mutex); - spin_lock_irqsave(&kernfs_open_node_lock, flags); + + on = kernfs_deref_open_node_protected(kn); + if (!on) { + mutex_unlock(&kernfs_open_file_mutex); + return; + } if (of) list_del(&of->list); - if (list_empty(&on->files)) - kn->attr.open = NULL; - else - on = NULL; + if (list_empty(&on->files)) { + rcu_assign_pointer(kn->attr.open, NULL); + kfree_rcu(on, rcu_head); + } - spin_unlock_irqrestore(&kernfs_open_node_lock, flags); mutex_unlock(&kernfs_open_file_mutex); - - kfree(on); } static int kernfs_fop_open(struct inode *inode, struct file *file) @@ -773,17 +826,16 @@ void kernfs_drain_open_files(struct kernfs_node *kn) * check under kernfs_open_file_mutex will ensure bailing out if * ->attr.open became NULL while waiting for the mutex. */ - if (!kn->attr.open) + if (!rcu_access_pointer(kn->attr.open)) return; mutex_lock(&kernfs_open_file_mutex); - if (!kn->attr.open) { + on = kernfs_deref_open_node_protected(kn); + if (!on) { mutex_unlock(&kernfs_open_file_mutex); return; } - on = kn->attr.open; - list_for_each_entry(of, &on->files, list) { struct inode *inode = file_inode(of->file); @@ -814,7 +866,10 @@ void kernfs_drain_open_files(struct kernfs_node *kn) __poll_t kernfs_generic_poll(struct kernfs_open_file *of, poll_table *wait) { struct kernfs_node *kn = kernfs_dentry_node(of->file->f_path.dentry); - struct kernfs_open_node *on = kn->attr.open; + struct kernfs_open_node *on = kernfs_deref_open_node(of, kn); + + if (!on) + return EPOLLERR; poll_wait(of->file, &on->poll, wait); @@ -921,13 +976,13 @@ void kernfs_notify(struct kernfs_node *kn) return; /* kick poll immediately */ - spin_lock_irqsave(&kernfs_open_node_lock, flags); - on = kn->attr.open; + rcu_read_lock(); + on = rcu_dereference(kn->attr.open); if (on) { atomic_inc(&on->event); wake_up_interruptible(&on->poll); } - spin_unlock_irqrestore(&kernfs_open_node_lock, flags); + rcu_read_unlock(); /* schedule work to kick fsnotify */ spin_lock_irqsave(&kernfs_notify_lock, flags); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index e2ae15a6225e..13f54f078a52 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -114,7 +114,7 @@ struct kernfs_elem_symlink { struct kernfs_elem_attr { const struct kernfs_ops *ops; - struct kernfs_open_node *open; + struct kernfs_open_node __rcu *open; loff_t size; struct kernfs_node *notify_next; /* for kernfs_notify() */ }; From b8f35fa1188b84035c59d4842826c4e93a1b1c9f Mon Sep 17 00:00:00 2001 From: Imran Khan Date: Wed, 15 Jun 2022 12:10:57 +1000 Subject: [PATCH 0730/1436] kernfs: Change kernfs_notify_list to llist. At present kernfs_notify_list is implemented as a singly linked list of kernfs_node(s), where last element points to itself and value of ->attr.next tells if node is present on the list or not. Both addition and deletion to list happen under kernfs_notify_lock. Change kernfs_notify_list to llist so that addition to list can heppen locklessly. Suggested by: Al Viro Acked-by: Tejun Heo Signed-off-by: Imran Khan Link: https://lore.kernel.org/r/20220615021059.862643-3-imran.f.khan@oracle.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 47 ++++++++++++++++++------------------------ include/linux/kernfs.h | 2 +- 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 22e7481e7b63..7d9138d2be3b 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -38,18 +38,16 @@ struct kernfs_open_node { struct list_head files; /* goes through kernfs_open_file.list */ }; -/* - * kernfs_notify() may be called from any context and bounces notifications - * through a work item. To minimize space overhead in kernfs_node, the - * pending queue is implemented as a singly linked list of kernfs_nodes. - * The list is terminated with the self pointer so that whether a - * kernfs_node is on the list or not can be determined by testing the next - * pointer for NULL. +/** + * attribute_to_node - get kernfs_node object corresponding to a kernfs attribute + * @ptr: &struct kernfs_elem_attr + * @type: struct kernfs_node + * @member: name of member (i.e attr) */ -#define KERNFS_NOTIFY_EOL ((void *)&kernfs_notify_list) +#define attribute_to_node(ptr, type, member) \ + container_of(ptr, type, member) -static DEFINE_SPINLOCK(kernfs_notify_lock); -static struct kernfs_node *kernfs_notify_list = KERNFS_NOTIFY_EOL; +static LLIST_HEAD(kernfs_notify_list); /** * kernfs_deref_open_node - Get kernfs_open_node corresponding to @kn. @@ -902,18 +900,16 @@ static void kernfs_notify_workfn(struct work_struct *work) struct kernfs_node *kn; struct kernfs_super_info *info; struct kernfs_root *root; + struct llist_node *free; + struct kernfs_elem_attr *attr; repeat: /* pop one off the notify_list */ - spin_lock_irq(&kernfs_notify_lock); - kn = kernfs_notify_list; - if (kn == KERNFS_NOTIFY_EOL) { - spin_unlock_irq(&kernfs_notify_lock); + free = llist_del_first(&kernfs_notify_list); + if (free == NULL) return; - } - kernfs_notify_list = kn->attr.notify_next; - kn->attr.notify_next = NULL; - spin_unlock_irq(&kernfs_notify_lock); + attr = llist_entry(free, struct kernfs_elem_attr, notify_next); + kn = attribute_to_node(attr, struct kernfs_node, attr); root = kernfs_root(kn); /* kick fsnotify */ down_write(&root->kernfs_rwsem); @@ -969,12 +965,14 @@ repeat: void kernfs_notify(struct kernfs_node *kn) { static DECLARE_WORK(kernfs_notify_work, kernfs_notify_workfn); - unsigned long flags; struct kernfs_open_node *on; if (WARN_ON(kernfs_type(kn) != KERNFS_FILE)) return; + /* Because we are using llist for kernfs_notify_list */ + WARN_ON_ONCE(in_nmi()); + /* kick poll immediately */ rcu_read_lock(); on = rcu_dereference(kn->attr.open); @@ -985,14 +983,9 @@ void kernfs_notify(struct kernfs_node *kn) rcu_read_unlock(); /* schedule work to kick fsnotify */ - spin_lock_irqsave(&kernfs_notify_lock, flags); - if (!kn->attr.notify_next) { - kernfs_get(kn); - kn->attr.notify_next = kernfs_notify_list; - kernfs_notify_list = kn; - schedule_work(&kernfs_notify_work); - } - spin_unlock_irqrestore(&kernfs_notify_lock, flags); + kernfs_get(kn); + llist_add(&kn->attr.notify_next, &kernfs_notify_list); + schedule_work(&kernfs_notify_work); } EXPORT_SYMBOL_GPL(kernfs_notify); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 13f54f078a52..2dd9c8df0f4f 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -116,7 +116,7 @@ struct kernfs_elem_attr { const struct kernfs_ops *ops; struct kernfs_open_node __rcu *open; loff_t size; - struct kernfs_node *notify_next; /* for kernfs_notify() */ + struct llist_node notify_next; /* for kernfs_notify() */ }; /* From 41448c614815965d1cdfa720df34257b84afbb9d Mon Sep 17 00:00:00 2001 From: Imran Khan Date: Wed, 15 Jun 2022 12:10:58 +1000 Subject: [PATCH 0731/1436] kernfs: Introduce interface to access global kernfs_open_file_mutex. This allows to change underlying mutex locking, without needing to change the users of the lock. For example next patch modifies this interface to use hashed mutexes in place of a single global kernfs_open_file_mutex. Acked-by: Tejun Heo Signed-off-by: Imran Khan Link: https://lore.kernel.org/r/20220615021059.862643-4-imran.f.khan@oracle.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 56 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 7d9138d2be3b..3b354caad6b5 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -49,6 +49,22 @@ struct kernfs_open_node { static LLIST_HEAD(kernfs_notify_list); +static inline struct mutex *kernfs_open_file_mutex_ptr(struct kernfs_node *kn) +{ + return &kernfs_open_file_mutex; +} + +static inline struct mutex *kernfs_open_file_mutex_lock(struct kernfs_node *kn) +{ + struct mutex *lock; + + lock = kernfs_open_file_mutex_ptr(kn); + + mutex_lock(lock); + + return lock; +} + /** * kernfs_deref_open_node - Get kernfs_open_node corresponding to @kn. * @@ -79,9 +95,9 @@ kernfs_deref_open_node(struct kernfs_open_file *of, struct kernfs_node *kn) * @kn: target kernfs_node. * * Fetch and return ->attr.open of @kn when caller holds the - * kernfs_open_file_mutex. + * kernfs_open_file_mutex_ptr(kn). * - * Update of ->attr.open happens under kernfs_open_file_mutex. So when + * Update of ->attr.open happens under kernfs_open_file_mutex_ptr(kn). So when * the caller guarantees that this mutex is being held, other updaters can't * change ->attr.open and this means that we can safely deref ->attr.open * outside RCU read-side critical section. @@ -92,7 +108,7 @@ static struct kernfs_open_node * kernfs_deref_open_node_protected(struct kernfs_node *kn) { return rcu_dereference_protected(kn->attr.open, - lockdep_is_held(&kernfs_open_file_mutex)); + lockdep_is_held(kernfs_open_file_mutex_ptr(kn))); } static struct kernfs_open_file *kernfs_of(struct file *file) @@ -574,19 +590,20 @@ static int kernfs_get_open_node(struct kernfs_node *kn, struct kernfs_open_file *of) { struct kernfs_open_node *on, *new_on = NULL; + struct mutex *mutex = NULL; - mutex_lock(&kernfs_open_file_mutex); + mutex = kernfs_open_file_mutex_lock(kn); on = kernfs_deref_open_node_protected(kn); if (on) { list_add_tail(&of->list, &on->files); - mutex_unlock(&kernfs_open_file_mutex); + mutex_unlock(mutex); return 0; } else { /* not there, initialize a new one */ new_on = kmalloc(sizeof(*new_on), GFP_KERNEL); if (!new_on) { - mutex_unlock(&kernfs_open_file_mutex); + mutex_unlock(mutex); return -ENOMEM; } atomic_set(&new_on->event, 1); @@ -595,7 +612,7 @@ static int kernfs_get_open_node(struct kernfs_node *kn, list_add_tail(&of->list, &new_on->files); rcu_assign_pointer(kn->attr.open, new_on); } - mutex_unlock(&kernfs_open_file_mutex); + mutex_unlock(mutex); return 0; } @@ -617,12 +634,13 @@ static void kernfs_unlink_open_file(struct kernfs_node *kn, struct kernfs_open_file *of) { struct kernfs_open_node *on; + struct mutex *mutex = NULL; - mutex_lock(&kernfs_open_file_mutex); + mutex = kernfs_open_file_mutex_lock(kn); on = kernfs_deref_open_node_protected(kn); if (!on) { - mutex_unlock(&kernfs_open_file_mutex); + mutex_unlock(mutex); return; } @@ -634,7 +652,7 @@ static void kernfs_unlink_open_file(struct kernfs_node *kn, kfree_rcu(on, rcu_head); } - mutex_unlock(&kernfs_open_file_mutex); + mutex_unlock(mutex); } static int kernfs_fop_open(struct inode *inode, struct file *file) @@ -772,11 +790,11 @@ static void kernfs_release_file(struct kernfs_node *kn, /* * @of is guaranteed to have no other file operations in flight and * we just want to synchronize release and drain paths. - * @kernfs_open_file_mutex is enough. @of->mutex can't be used + * @kernfs_open_file_mutex_ptr(kn) is enough. @of->mutex can't be used * here because drain path may be called from places which can * cause circular dependency. */ - lockdep_assert_held(&kernfs_open_file_mutex); + lockdep_assert_held(kernfs_open_file_mutex_ptr(kn)); if (!of->released) { /* @@ -793,11 +811,12 @@ static int kernfs_fop_release(struct inode *inode, struct file *filp) { struct kernfs_node *kn = inode->i_private; struct kernfs_open_file *of = kernfs_of(filp); + struct mutex *mutex = NULL; if (kn->flags & KERNFS_HAS_RELEASE) { - mutex_lock(&kernfs_open_file_mutex); + mutex = kernfs_open_file_mutex_lock(kn); kernfs_release_file(kn, of); - mutex_unlock(&kernfs_open_file_mutex); + mutex_unlock(mutex); } kernfs_unlink_open_file(kn, of); @@ -812,6 +831,7 @@ void kernfs_drain_open_files(struct kernfs_node *kn) { struct kernfs_open_node *on; struct kernfs_open_file *of; + struct mutex *mutex = NULL; if (!(kn->flags & (KERNFS_HAS_MMAP | KERNFS_HAS_RELEASE))) return; @@ -821,16 +841,16 @@ void kernfs_drain_open_files(struct kernfs_node *kn) * ->attr.open at this point of time. This check allows early bail out * if ->attr.open is already NULL. kernfs_unlink_open_file makes * ->attr.open NULL only while holding kernfs_open_file_mutex so below - * check under kernfs_open_file_mutex will ensure bailing out if + * check under kernfs_open_file_mutex_ptr(kn) will ensure bailing out if * ->attr.open became NULL while waiting for the mutex. */ if (!rcu_access_pointer(kn->attr.open)) return; - mutex_lock(&kernfs_open_file_mutex); + mutex = kernfs_open_file_mutex_lock(kn); on = kernfs_deref_open_node_protected(kn); if (!on) { - mutex_unlock(&kernfs_open_file_mutex); + mutex_unlock(mutex); return; } @@ -844,7 +864,7 @@ void kernfs_drain_open_files(struct kernfs_node *kn) kernfs_release_file(kn, of); } - mutex_unlock(&kernfs_open_file_mutex); + mutex_unlock(mutex); } /* From 1d25b84e444ad66313c473407979ea9cd33deb3f Mon Sep 17 00:00:00 2001 From: Imran Khan Date: Wed, 15 Jun 2022 12:10:59 +1000 Subject: [PATCH 0732/1436] kernfs: Replace global kernfs_open_file_mutex with hashed mutexes. In current kernfs design a single mutex, kernfs_open_file_mutex, protects the list of kernfs_open_file instances corresponding to a sysfs attribute. So even if different tasks are opening or closing different sysfs files they can contend on osq_lock of this mutex. The contention is more apparent in large scale systems with few hundred CPUs where most of the CPUs have running tasks that are opening, accessing or closing sysfs files at any point of time. Using hashed mutexes in place of a single global mutex, can significantly reduce contention around global mutex and hence can provide better scalability. Moreover as these hashed mutexes are not part of kernfs_node objects we will not see any singnificant change in memory utilization of kernfs based file systems like sysfs, cgroupfs etc. Modify interface introduced in previous patch to make use of hashed mutexes. Use kernfs_node address as hashing key. Acked-by: Tejun Heo Signed-off-by: Imran Khan Link: https://lore.kernel.org/r/20220615021059.862643-5-imran.f.khan@oracle.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 17 ++--------- fs/kernfs/kernfs-internal.h | 4 +++ fs/kernfs/mount.c | 19 +++++++++++++ include/linux/kernfs.h | 57 +++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 14 deletions(-) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 3b354caad6b5..bb933221b4ba 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -18,19 +18,6 @@ #include "kernfs-internal.h" -/* - * There's one kernfs_open_file for each open file and one kernfs_open_node - * for each kernfs_node with one or more open files. - * - * kernfs_node->attr.open points to kernfs_open_node. attr.open is - * RCU protected. - * - * filp->private_data points to seq_file whose ->private points to - * kernfs_open_file. kernfs_open_files are chained at - * kernfs_open_node->files, which is protected by kernfs_open_file_mutex. - */ -static DEFINE_MUTEX(kernfs_open_file_mutex); - struct kernfs_open_node { struct rcu_head rcu_head; atomic_t event; @@ -51,7 +38,9 @@ static LLIST_HEAD(kernfs_notify_list); static inline struct mutex *kernfs_open_file_mutex_ptr(struct kernfs_node *kn) { - return &kernfs_open_file_mutex; + int idx = hash_ptr(kn, NR_KERNFS_LOCK_BITS); + + return &kernfs_locks->open_file_mutex[idx]; } static inline struct mutex *kernfs_open_file_mutex_lock(struct kernfs_node *kn) diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index eeaa779b929c..3ae214d02d44 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -164,4 +164,8 @@ void kernfs_drain_open_files(struct kernfs_node *kn); */ extern const struct inode_operations kernfs_symlink_iops; +/* + * kernfs locks + */ +extern struct kernfs_global_locks *kernfs_locks; #endif /* __KERNFS_INTERNAL_H */ diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index cfa79715fc1a..d0859f72d2d6 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -20,6 +20,7 @@ #include "kernfs-internal.h" struct kmem_cache *kernfs_node_cache, *kernfs_iattrs_cache; +struct kernfs_global_locks *kernfs_locks; static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry) { @@ -387,6 +388,22 @@ void kernfs_kill_sb(struct super_block *sb) kfree(info); } +static void __init kernfs_mutex_init(void) +{ + int count; + + for (count = 0; count < NR_KERNFS_LOCKS; count++) + mutex_init(&kernfs_locks->open_file_mutex[count]); +} + +static void __init kernfs_lock_init(void) +{ + kernfs_locks = kmalloc(sizeof(struct kernfs_global_locks), GFP_KERNEL); + WARN_ON(!kernfs_locks); + + kernfs_mutex_init(); +} + void __init kernfs_init(void) { kernfs_node_cache = kmem_cache_create("kernfs_node_cache", @@ -397,4 +414,6 @@ void __init kernfs_init(void) kernfs_iattrs_cache = kmem_cache_create("kernfs_iattrs_cache", sizeof(struct kernfs_iattrs), 0, SLAB_PANIC, NULL); + + kernfs_lock_init(); } diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 2dd9c8df0f4f..13e703f615f7 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -18,6 +18,7 @@ #include #include #include +#include struct file; struct dentry; @@ -34,6 +35,62 @@ struct kernfs_fs_context; struct kernfs_open_node; struct kernfs_iattrs; +/* + * NR_KERNFS_LOCK_BITS determines size (NR_KERNFS_LOCKS) of hash + * table of locks. + * Having a small hash table would impact scalability, since + * more and more kernfs_node objects will end up using same lock + * and having a very large hash table would waste memory. + * + * At the moment size of hash table of locks is being set based on + * the number of CPUs as follows: + * + * NR_CPU NR_KERNFS_LOCK_BITS NR_KERNFS_LOCKS + * 1 1 2 + * 2-3 2 4 + * 4-7 4 16 + * 8-15 6 64 + * 16-31 8 256 + * 32 and more 10 1024 + * + * The above relation between NR_CPU and number of locks is based + * on some internal experimentation which involved booting qemu + * with different values of smp, performing some sysfs operations + * on all CPUs and observing how increase in number of locks impacts + * completion time of these sysfs operations on each CPU. + */ +#ifdef CONFIG_SMP +#define NR_KERNFS_LOCK_BITS (2 * (ilog2(NR_CPUS < 32 ? NR_CPUS : 32))) +#else +#define NR_KERNFS_LOCK_BITS 1 +#endif + +#define NR_KERNFS_LOCKS (1 << NR_KERNFS_LOCK_BITS) + +/* + * There's one kernfs_open_file for each open file and one kernfs_open_node + * for each kernfs_node with one or more open files. + * + * filp->private_data points to seq_file whose ->private points to + * kernfs_open_file. + * + * kernfs_open_files are chained at kernfs_open_node->files, which is + * protected by kernfs_global_locks.open_file_mutex[i]. + * + * To reduce possible contention in sysfs access, arising due to single + * locks, use an array of locks (e.g. open_file_mutex) and use kernfs_node + * object address as hash keys to get the index of these locks. + * + * Hashed mutexes are safe to use here because operations using these don't + * rely on global exclusion. + * + * In future we intend to replace other global locks with hashed ones as well. + * kernfs_global_locks acts as a holder for all such hash tables. + */ +struct kernfs_global_locks { + struct mutex open_file_mutex[NR_KERNFS_LOCKS]; +}; + enum kernfs_node_type { KERNFS_DIR = 0x0001, KERNFS_FILE = 0x0002, From 8f486cab263ca1b761c1aab9b36975afd355b799 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Thu, 23 Jun 2022 01:03:42 -0700 Subject: [PATCH 0733/1436] driver core: fw_devlink: Allow firmware to mark devices as best effort When firmware sets the FWNODE_FLAG_BEST_EFFORT flag for a fwnode, fw_devlink will do a best effort ordering for that device where it'll only enforce the probe/suspend/resume ordering of that device with suppliers that have drivers. The driver of that device can then decide if it wants to defer probe or probe without the suppliers. This will be useful for avoid probe delays of the console device that were caused by commit 71066545b48e ("driver core: Set fw_devlink.strict=1 by default"). Fixes: 71066545b48e ("driver core: Set fw_devlink.strict=1 by default") Reported-by: Sascha Hauer Reported-by: Peng Fan Tested-by: Peng Fan Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220623080344.783549-2-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 3 ++- include/linux/fwnode.h | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/base/core.c b/drivers/base/core.c index 839f64485a55..ccdd5b4295de 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -968,7 +968,8 @@ static void device_links_missing_supplier(struct device *dev) static bool dev_is_best_effort(struct device *dev) { - return fw_devlink_best_effort && dev->can_match; + return (fw_devlink_best_effort && dev->can_match) || + (dev->fwnode && (dev->fwnode->flags & FWNODE_FLAG_BEST_EFFORT)); } /** diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h index 9a81c4410b9f..89b9bdfca925 100644 --- a/include/linux/fwnode.h +++ b/include/linux/fwnode.h @@ -27,11 +27,15 @@ struct device; * driver needs its child devices to be bound with * their respective drivers as soon as they are * added. + * BEST_EFFORT: The fwnode/device needs to probe early and might be missing some + * suppliers. Only enforce ordering with suppliers that have + * drivers. */ #define FWNODE_FLAG_LINKS_ADDED BIT(0) #define FWNODE_FLAG_NOT_DEVICE BIT(1) #define FWNODE_FLAG_INITIALIZED BIT(2) #define FWNODE_FLAG_NEEDS_CHILD_BOUND_ON_ADD BIT(3) +#define FWNODE_FLAG_BEST_EFFORT BIT(4) struct fwnode_handle { struct fwnode_handle *secondary; From a244ec3640e0dfe90f31750033433cb2c99446e8 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Thu, 23 Jun 2022 01:03:43 -0700 Subject: [PATCH 0734/1436] of: base: Avoid console probe delay when fw_devlink.strict=1 Commit 71066545b48e ("driver core: Set fw_devlink.strict=1 by default") enabled iommus and dmas dependency enforcement by default. On some systems, this caused the console device's probe to get delayed until the deferred_probe_timeout expires. We need consoles to work as soon as possible, so mark the console device node with FWNODE_FLAG_BEST_EFFORT so that fw_delink knows not to delay the probe of the console device for suppliers without drivers. The driver can then make the decision on where it can probe without those suppliers or defer its probe. Fixes: 71066545b48e ("driver core: Set fw_devlink.strict=1 by default") Reported-by: Sascha Hauer Reported-by: Peng Fan Tested-by: Peng Fan Signed-off-by: Saravana Kannan Link: https://lore.kernel.org/r/20220623080344.783549-3-saravanak@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/of/base.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index d4f98c8469ed..a19cd0c73644 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1919,6 +1919,8 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) of_property_read_string(of_aliases, "stdout", &name); if (name) of_stdout = of_find_node_opts_by_path(name, &of_stdout_options); + if (of_stdout) + of_stdout->fwnode.flags |= FWNODE_FLAG_BEST_EFFORT; } if (!of_aliases) From 3a5230a87c3b719bd536190b76b029c4cf2452cc Mon Sep 17 00:00:00 2001 From: Deming Wang Date: Thu, 23 Jun 2022 21:12:47 -0400 Subject: [PATCH 0735/1436] of: Drop duplicate 'the' in of_find_last_cache_level kerneldoc Delete duplicate words of "the". Signed-off-by: Deming Wang Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220624011247.1735-1-wangdeming@inspur.com --- drivers/of/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index d4f98c8469ed..88f86ee54b9a 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2077,7 +2077,7 @@ struct device_node *of_find_next_cache_node(const struct device_node *np) * * @cpu: cpu number(logical index) for which the last cache level is needed * - * Return: The the level at which the last cache is present. It is exactly + * Return: The level at which the last cache is present. It is exactly * same as the total number of cache levels for the given logical cpu. */ int of_find_last_cache_level(unsigned int cpu) From 3888bb741177718177c49a6b1b7c174b5b18c1be Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2022 13:23:34 +0200 Subject: [PATCH 0736/1436] ACPI: video: Change how we determine if brightness key-presses are handled Some systems have an ACPI video bus but not ACPI video devices with backlight capability. On these devices brightness key-presses are (logically) not reported through the ACPI video bus. Change how acpi_video_handles_brightness_key_presses() determines if brightness key-presses are handled by the ACPI video driver to avoid vendor specific drivers/platform/x86 drivers filtering out their brightness key-presses even though they are the only ones reporting these presses. Fixes: ed83c9171829 ("platform/x86: panasonic-laptop: Resolve hotkey double trigger bug") Reported-and-tested-by: Stefan Seyfried Reported-and-tested-by: Kenneth Chan Signed-off-by: Hans de Goede Acked-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220624112340.10130-2-hdegoede@redhat.com --- drivers/acpi/acpi_video.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index e07782b1fbb6..43177c20ce4f 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -73,6 +73,7 @@ module_param(device_id_scheme, bool, 0444); static int only_lcd = -1; module_param(only_lcd, int, 0444); +static bool has_backlight; static int register_count; static DEFINE_MUTEX(register_count_mutex); static DEFINE_MUTEX(video_list_lock); @@ -1222,6 +1223,9 @@ acpi_video_bus_get_one_device(struct acpi_device *device, acpi_video_device_bind(video, data); acpi_video_device_find_cap(data); + if (data->cap._BCM && data->cap._BCL) + has_backlight = true; + mutex_lock(&video->device_list_lock); list_add_tail(&data->entry, &video->video_device_list); mutex_unlock(&video->device_list_lock); @@ -2249,6 +2253,7 @@ void acpi_video_unregister(void) if (register_count) { acpi_bus_unregister_driver(&acpi_video_bus); register_count = 0; + has_backlight = false; } mutex_unlock(®ister_count_mutex); } @@ -2270,13 +2275,7 @@ void acpi_video_unregister_backlight(void) bool acpi_video_handles_brightness_key_presses(void) { - bool have_video_busses; - - mutex_lock(&video_list_lock); - have_video_busses = !list_empty(&video_bus_head); - mutex_unlock(&video_list_lock); - - return have_video_busses && + return has_backlight && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS); } EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses); From 758babb511d883cd2aa784d48a362d92119ade99 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Fri, 24 Jun 2022 13:23:35 +0200 Subject: [PATCH 0737/1436] platform/x86: panasonic-laptop: de-obfuscate button codes In the definition of panasonic_keymap[] the key codes are given in decimal, later checks are done with hexadecimal values, which does not help in understanding the code. Additionally use two helper variables to shorten the code and make the logic more obvious. Fixes: ed83c9171829 ("platform/x86: panasonic-laptop: Resolve hotkey double trigger bug") Signed-off-by: Stefan Seyfried Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220624112340.10130-3-hdegoede@redhat.com --- drivers/platform/x86/panasonic-laptop.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 37850d07987d..ca6137f4000f 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -762,6 +762,8 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) struct input_dev *hotk_input_dev = pcc->input_dev; int rc; unsigned long long result; + unsigned int key; + unsigned int updown; rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY, NULL, &result); @@ -770,18 +772,22 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) return; } + key = result & 0xf; + updown = result & 0x80; /* 0x80 == key down; 0x00 = key up */ + /* hack: some firmware sends no key down for sleep / hibernate */ - if ((result & 0xf) == 0x7 || (result & 0xf) == 0xa) { - if (result & 0x80) + if (key == 7 || key == 10) { + if (updown) sleep_keydown_seen = 1; if (!sleep_keydown_seen) sparse_keymap_report_event(hotk_input_dev, - result & 0xf, 0x80, false); + key, 0x80, false); } - if ((result & 0xf) == 0x7 || (result & 0xf) == 0x9 || (result & 0xf) == 0xa) { + /* for the magic values, see panasonic_keymap[] above */ + if (key == 7 || key == 9 || key == 10) { if (!sparse_keymap_report_event(hotk_input_dev, - result & 0xf, result & 0x80, false)) + key, updown, false)) pr_err("Unknown hotkey event: 0x%04llx\n", result); } } From 9cfebda442f73a5810d03c635645193634ba85e7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2022 13:23:36 +0200 Subject: [PATCH 0738/1436] platform/x86: panasonic-laptop: sort includes alphabetically Sort includes alphabetically, small cleanup patch in preparation of further changes. Fixes: ed83c9171829 ("platform/x86: panasonic-laptop: Resolve hotkey double trigger bug") Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220624112340.10130-4-hdegoede@redhat.com --- drivers/platform/x86/panasonic-laptop.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index ca6137f4000f..26e31ac09dc6 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -119,20 +119,19 @@ * - v0.1 start from toshiba_acpi driver written by John Belmonte */ -#include -#include -#include -#include +#include #include #include -#include -#include -#include -#include +#include #include #include +#include +#include #include - +#include +#include +#include +#include MODULE_AUTHOR("Hiroshi Miura "); MODULE_AUTHOR("David Bronaugh "); From cb1f7d49736e05862c7d7df1c97676bb42c75e5c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2022 13:23:37 +0200 Subject: [PATCH 0739/1436] platform/x86: panasonic-laptop: revert "Resolve hotkey double trigger bug" In hindsight blindly throwing away most of the key-press events is not a good idea. So revert commit ed83c9171829 ("platform/x86: panasonic-laptop: Resolve hotkey double trigger bug"). Fixes: ed83c9171829 ("platform/x86: panasonic-laptop: Resolve hotkey double trigger bug") Reported-and-tested-by: Stefan Seyfried Reported-and-tested-by: Kenneth Chan Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220624112340.10130-5-hdegoede@redhat.com --- drivers/platform/x86/panasonic-laptop.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 26e31ac09dc6..2e6531dd15f9 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -783,12 +783,8 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) key, 0x80, false); } - /* for the magic values, see panasonic_keymap[] above */ - if (key == 7 || key == 9 || key == 10) { - if (!sparse_keymap_report_event(hotk_input_dev, - key, updown, false)) - pr_err("Unknown hotkey event: 0x%04llx\n", result); - } + if (!sparse_keymap_report_event(hotk_input_dev, key, updown, false)) + pr_err("Unknown hotkey event: 0x%04llx\n", result); } static void acpi_pcc_hotkey_notify(struct acpi_device *device, u32 event) From 027f88453dbf34cafce1c31e93c216665cdd71d2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2022 13:23:38 +0200 Subject: [PATCH 0740/1436] platform/x86: panasonic-laptop: don't report duplicate brightness key-presses The brightness key-presses might also get reported by the ACPI video bus, check for this and in this case don't report the presses to avoid reporting 2 presses for a single key-press. Fixes: ed83c9171829 ("platform/x86: panasonic-laptop: Resolve hotkey double trigger bug") Reported-and-tested-by: Stefan Seyfried Reported-and-tested-by: Kenneth Chan Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220624112340.10130-6-hdegoede@redhat.com --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/panasonic-laptop.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f01f75589627..4decefcc0db1 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -918,6 +918,7 @@ config PANASONIC_LAPTOP tristate "Panasonic Laptop Extras" depends on INPUT && ACPI depends on BACKLIGHT_CLASS_DEVICE + depends on ACPI_VIDEO=n || ACPI_VIDEO select INPUT_SPARSEKMAP help This driver adds support for access to backlight control and hotkeys diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 2e6531dd15f9..d65e6c2372ca 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -132,6 +132,7 @@ #include #include #include +#include MODULE_AUTHOR("Hiroshi Miura "); MODULE_AUTHOR("David Bronaugh "); @@ -783,6 +784,13 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) key, 0x80, false); } + /* + * Don't report brightness key-presses if they are also reported + * by the ACPI video bus. + */ + if ((key == 1 || key == 2) && acpi_video_handles_brightness_key_presses()) + return; + if (!sparse_keymap_report_event(hotk_input_dev, key, updown, false)) pr_err("Unknown hotkey event: 0x%04llx\n", result); } From 5e24e1eca1f2a3aed924e44606134a9381c3ccb9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2022 13:23:39 +0200 Subject: [PATCH 0741/1436] platform/x86: panasonic-laptop: filter out duplicate volume up/down/mute keypresses On some Panasonic models the volume up/down/mute keypresses get reported both through the Panasonic ACPI HKEY interface as well as through the atkbd device. Filter out the atkbd scan-codes for these to avoid reporting presses twice. Note normally we would leave the filtering of these to userspace by mapping the scan-codes to KEY_UNKNOWN through /lib/udev/hwdb.d/60-keyboard.hwdb. However in this case that would cause regressions since we were filtering the Panasonic ACPI HKEY events before, so filter these in the kernel. Fixes: ed83c9171829 ("platform/x86: panasonic-laptop: Resolve hotkey double trigger bug") Reported-and-tested-by: Stefan Seyfried Reported-and-tested-by: Kenneth Chan Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220624112340.10130-7-hdegoede@redhat.com --- drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/panasonic-laptop.c | 41 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 4decefcc0db1..7fa88efeef4d 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -919,6 +919,7 @@ config PANASONIC_LAPTOP depends on INPUT && ACPI depends on BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO=n || ACPI_VIDEO + depends on SERIO_I8042 || SERIO_I8042 = n select INPUT_SPARSEKMAP help This driver adds support for access to backlight control and hotkeys diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index d65e6c2372ca..615e39cbbbf1 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -122,6 +122,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +130,7 @@ #include #include #include +#include #include #include #include @@ -241,6 +243,42 @@ struct pcc_acpi { struct platform_device *platform; }; +/* + * On some Panasonic models the volume up / down / mute keys send duplicate + * keypress events over the PS/2 kbd interface, filter these out. + */ +static bool panasonic_i8042_filter(unsigned char data, unsigned char str, + struct serio *port) +{ + static bool extended; + + if (str & I8042_STR_AUXDATA) + return false; + + if (data == 0xe0) { + extended = true; + return true; + } else if (extended) { + extended = false; + + switch (data & 0x7f) { + case 0x20: /* e0 20 / e0 a0, Volume Mute press / release */ + case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */ + case 0x30: /* e0 30 / e0 b0, Volume Up press / release */ + return true; + default: + /* + * Report the previously filtered e0 before continuing + * with the next non-filtered byte. + */ + serio_interrupt(port, 0xe0, 0); + return false; + } + } + + return false; +} + /* method access functions */ static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val) { @@ -1006,6 +1044,7 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) pcc->platform = NULL; } + i8042_install_filter(panasonic_i8042_filter); return 0; out_platform: @@ -1029,6 +1068,8 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device) if (!device || !pcc) return -EINVAL; + i8042_remove_filter(panasonic_i8042_filter); + if (pcc->platform) { device_remove_file(&pcc->platform->dev, &dev_attr_cdpower); platform_device_unregister(pcc->platform); From 4da4742236ce74b92590bc65184eb10826a12006 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 24 Jun 2022 13:23:40 +0200 Subject: [PATCH 0742/1436] platform/x86: panasonic-laptop: Use acpi_video_get_backlight_type() Use acpi_video_get_backlight_type() to determine if we should register the panasonic specific backlight interface. To avoid registering this on systems where the ACPI or GPU native backlight control methods should be used instead. Tested-by: Stefan Seyfried Tested-by: Kenneth Chan Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220624112340.10130-8-hdegoede@redhat.com --- drivers/platform/x86/panasonic-laptop.c | 28 ++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 615e39cbbbf1..d9a095d2c0eb 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -998,19 +998,23 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) pr_err("Couldn't retrieve BIOS data\n"); goto out_input; } - /* initialize backlight */ - memset(&props, 0, sizeof(struct backlight_properties)); - props.type = BACKLIGHT_PLATFORM; - props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT]; - pcc->backlight = backlight_device_register("panasonic", NULL, pcc, - &pcc_backlight_ops, &props); - if (IS_ERR(pcc->backlight)) { - result = PTR_ERR(pcc->backlight); - goto out_input; - } - /* read the initial brightness setting from the hardware */ - pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT]; + if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { + /* initialize backlight */ + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_PLATFORM; + props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT]; + + pcc->backlight = backlight_device_register("panasonic", NULL, pcc, + &pcc_backlight_ops, &props); + if (IS_ERR(pcc->backlight)) { + result = PTR_ERR(pcc->backlight); + goto out_input; + } + + /* read the initial brightness setting from the hardware */ + pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT]; + } /* Reset initial sticky key mode since the hardware register state is not consistent */ acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, 0); From 6991cd744f068349a934fd31254c77f48fa530ec Mon Sep 17 00:00:00 2001 From: Vincent Whitchurch Date: Tue, 28 Jun 2022 13:35:40 +0200 Subject: [PATCH 0743/1436] of: reserved-memory: Print allocation/reservation failures as error If the allocation/reservation of reserved-memory fails, it is normally an error, so print it as an error so that it doesn't get hidden from the console due to the loglevel. Also make the allocation failure include the size just like the reservation failure. Signed-off-by: Vincent Whitchurch Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220628113540.2790835-1-vincent.whitchurch@axis.com --- drivers/of/fdt.c | 4 ++-- drivers/of/of_reserved_mem.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index a8f5b6532165..4610729d2297 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -532,8 +532,8 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, kmemleak_alloc_phys(base, size, 0, 0); } else - pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n", - uname, &base, (unsigned long)(size / SZ_1M)); + pr_err("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n", + uname, &base, (unsigned long)(size / SZ_1M)); len -= t_len; if (first) { diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 75caa6f5d36f..65f3b02a0e4e 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c @@ -156,7 +156,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node, } if (base == 0) { - pr_info("failed to allocate memory for node '%s'\n", uname); + pr_err("failed to allocate memory for node '%s': size %lu MiB\n", + uname, (unsigned long)(size / SZ_1M)); return -ENOMEM; } From f2fb1b50fbac4a0a462e1705ac913abf52aae906 Mon Sep 17 00:00:00 2001 From: Piyush Mehta Date: Mon, 20 Jun 2022 13:07:17 +0530 Subject: [PATCH 0744/1436] dt-bindings: ata: ahci-ceva: convert to yaml Convert the ahci-ceva doc to yaml. Signed-off-by: Piyush Mehta Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220620073717.3079-1-piyush.mehta@xilinx.com --- .../devicetree/bindings/ata/ahci-ceva.txt | 63 ------ .../bindings/ata/ceva,ahci-1v84.yaml | 189 ++++++++++++++++++ 2 files changed, 189 insertions(+), 63 deletions(-) delete mode 100644 Documentation/devicetree/bindings/ata/ahci-ceva.txt create mode 100644 Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml diff --git a/Documentation/devicetree/bindings/ata/ahci-ceva.txt b/Documentation/devicetree/bindings/ata/ahci-ceva.txt deleted file mode 100644 index bfb6da0281ec..000000000000 --- a/Documentation/devicetree/bindings/ata/ahci-ceva.txt +++ /dev/null @@ -1,63 +0,0 @@ -Binding for CEVA AHCI SATA Controller - -Required properties: - - reg: Physical base address and size of the controller's register area. - - compatible: Compatibility string. Must be 'ceva,ahci-1v84'. - - clocks: Input clock specifier. Refer to common clock bindings. - - interrupts: Interrupt specifier. Refer to interrupt binding. - - ceva,p0-cominit-params: OOB timing value for COMINIT parameter for port 0. - - ceva,p1-cominit-params: OOB timing value for COMINIT parameter for port 1. - The fields for the above parameter must be as shown below: - ceva,pN-cominit-params = /bits/ 8 ; - CINMP : COMINIT Negate Minimum Period. - CIBGN : COMINIT Burst Gap Nominal. - CIBGMX: COMINIT Burst Gap Maximum. - CIBGMN: COMINIT Burst Gap Minimum. - - ceva,p0-comwake-params: OOB timing value for COMWAKE parameter for port 0. - - ceva,p1-comwake-params: OOB timing value for COMWAKE parameter for port 1. - The fields for the above parameter must be as shown below: - ceva,pN-comwake-params = /bits/ 8 ; - CWBGMN: COMWAKE Burst Gap Minimum. - CWBGMX: COMWAKE Burst Gap Maximum. - CWBGN: COMWAKE Burst Gap Nominal. - CWNMP: COMWAKE Negate Minimum Period. - - ceva,p0-burst-params: Burst timing value for COM parameter for port 0. - - ceva,p1-burst-params: Burst timing value for COM parameter for port 1. - The fields for the above parameter must be as shown below: - ceva,pN-burst-params = /bits/ 8 ; - BMX: COM Burst Maximum. - BNM: COM Burst Nominal. - SFD: Signal Failure Detection value. - PTST: Partial to Slumber timer value. - - ceva,p0-retry-params: Retry interval timing value for port 0. - - ceva,p1-retry-params: Retry interval timing value for port 1. - The fields for the above parameter must be as shown below: - ceva,pN-retry-params = /bits/ 16 ; - RIT: Retry Interval Timer. - RCT: Rate Change Timer. - -Optional properties: - - ceva,broken-gen2: limit to gen1 speed instead of gen2. - - phys: phandle for the PHY device - - resets: phandle to the reset controller for the SATA IP - -Examples: - ahci@fd0c0000 { - compatible = "ceva,ahci-1v84"; - reg = <0xfd0c0000 0x200>; - interrupt-parent = <&gic>; - interrupts = <0 133 4>; - clocks = <&clkc SATA_CLK_ID>; - ceva,p0-cominit-params = /bits/ 8 <0x0F 0x25 0x18 0x29>; - ceva,p0-comwake-params = /bits/ 8 <0x04 0x0B 0x08 0x0F>; - ceva,p0-burst-params = /bits/ 8 <0x0A 0x08 0x4A 0x06>; - ceva,p0-retry-params = /bits/ 16 <0x0216 0x7F06>; - - ceva,p1-cominit-params = /bits/ 8 <0x0F 0x25 0x18 0x29>; - ceva,p1-comwake-params = /bits/ 8 <0x04 0x0B 0x08 0x0F>; - ceva,p1-burst-params = /bits/ 8 <0x0A 0x08 0x4A 0x06>; - ceva,p1-retry-params = /bits/ 16 <0x0216 0x7F06>; - ceva,broken-gen2; - phys = <&psgtr 1 PHY_TYPE_SATA 1 1>; - resets = <&zynqmp_reset ZYNQMP_RESET_SATA>; - }; diff --git a/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml b/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml new file mode 100644 index 000000000000..9b31f864e071 --- /dev/null +++ b/Documentation/devicetree/bindings/ata/ceva,ahci-1v84.yaml @@ -0,0 +1,189 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ata/ceva,ahci-1v84.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Ceva AHCI SATA Controller + +maintainers: + - Piyush Mehta + +description: | + The Ceva SATA controller mostly conforms to the AHCI interface with some + special extensions to add functionality, is a high-performance dual-port + SATA host controller with an AHCI compliant command layer which supports + advanced features such as native command queuing and frame information + structure (FIS) based switching for systems employing port multipliers. + +properties: + compatible: + const: ceva,ahci-1v84 + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + dma-coherent: true + + interrupts: + maxItems: 1 + + iommus: + maxItems: 1 + + power-domains: + maxItems: 1 + + ceva,p0-cominit-params: + $ref: /schemas/types.yaml#/definitions/uint8-array + description: | + OOB timing value for COMINIT parameter for port 0. + The fields for the above parameter must be as shown below:- + ceva,p0-cominit-params = /bits/ 8 ; + items: + - description: CINMP - COMINIT Negate Minimum Period. + - description: CIBGN - COMINIT Burst Gap Nominal. + - description: CIBGMX - COMINIT Burst Gap Maximum. + - description: CIBGMN - COMINIT Burst Gap Minimum. + + ceva,p0-comwake-params: + $ref: /schemas/types.yaml#/definitions/uint8-array + description: | + OOB timing value for COMWAKE parameter for port 0. + The fields for the above parameter must be as shown below:- + ceva,p0-comwake-params = /bits/ 8 ; + items: + - description: CWBGMN - COMWAKE Burst Gap Minimum. + - description: CWBGMX - COMWAKE Burst Gap Maximum. + - description: CWBGN - COMWAKE Burst Gap Nominal. + - description: CWNMP - COMWAKE Negate Minimum Period. + + ceva,p0-burst-params: + $ref: /schemas/types.yaml#/definitions/uint8-array + description: | + Burst timing value for COM parameter for port 0. + The fields for the above parameter must be as shown below:- + ceva,p0-burst-params = /bits/ 8 ; + items: + - description: BMX - COM Burst Maximum. + - description: BNM - COM Burst Nominal. + - description: SFD - Signal Failure Detection value. + - description: PTST - Partial to Slumber timer value. + + ceva,p0-retry-params: + $ref: /schemas/types.yaml#/definitions/uint16-array + description: | + Retry interval timing value for port 0. + The fields for the above parameter must be as shown below:- + ceva,p0-retry-params = /bits/ 16 ; + items: + - description: RIT - Retry Interval Timer. + - description: RCT - Rate Change Timer. + + ceva,p1-cominit-params: + $ref: /schemas/types.yaml#/definitions/uint8-array + description: | + OOB timing value for COMINIT parameter for port 1. + The fields for the above parameter must be as shown below:- + ceva,p1-cominit-params = /bits/ 8 ; + items: + - description: CINMP - COMINIT Negate Minimum Period. + - description: CIBGN - COMINIT Burst Gap Nominal. + - description: CIBGMX - COMINIT Burst Gap Maximum. + - description: CIBGMN - COMINIT Burst Gap Minimum. + + ceva,p1-comwake-params: + $ref: /schemas/types.yaml#/definitions/uint8-array + description: | + OOB timing value for COMWAKE parameter for port 1. + The fields for the above parameter must be as shown below:- + ceva,p1-comwake-params = /bits/ 8 ; + items: + - description: CWBGMN - COMWAKE Burst Gap Minimum. + - description: CWBGMX - COMWAKE Burst Gap Maximum. + - description: CWBGN - COMWAKE Burst Gap Nominal. + - description: CWNMP - COMWAKE Negate Minimum Period. + + ceva,p1-burst-params: + $ref: /schemas/types.yaml#/definitions/uint8-array + description: | + Burst timing value for COM parameter for port 1. + The fields for the above parameter must be as shown below:- + ceva,p1-burst-params = /bits/ 8 ; + items: + - description: BMX - COM Burst Maximum. + - description: BNM - COM Burst Nominal. + - description: SFD - Signal Failure Detection value. + - description: PTST - Partial to Slumber timer value. + + ceva,p1-retry-params: + $ref: /schemas/types.yaml#/definitions/uint16-array + description: | + Retry interval timing value for port 1. + The fields for the above parameter must be as shown below:- + ceva,pN-retry-params = /bits/ 16 ; + items: + - description: RIT - Retry Interval Timer. + - description: RCT - Rate Change Timer. + + ceva,broken-gen2: + $ref: /schemas/types.yaml#/definitions/flag + description: | + limit to gen1 speed instead of gen2. + + phys: + maxItems: 1 + + phy-names: + items: + - const: sata-phy + + resets: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - interrupts + - ceva,p0-cominit-params + - ceva,p0-comwake-params + - ceva,p0-burst-params + - ceva,p0-retry-params + - ceva,p1-cominit-params + - ceva,p1-comwake-params + - ceva,p1-burst-params + - ceva,p1-retry-params + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + #include + + sata: ahci@fd0c0000 { + compatible = "ceva,ahci-1v84"; + reg = <0xfd0c0000 0x200>; + interrupt-parent = <&gic>; + interrupts = <0 133 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&zynqmp_clk SATA_REF>; + ceva,p0-cominit-params = /bits/ 8 <0x0F 0x25 0x18 0x29>; + ceva,p0-comwake-params = /bits/ 8 <0x04 0x0B 0x08 0x0F>; + ceva,p0-burst-params = /bits/ 8 <0x0A 0x08 0x4A 0x06>; + ceva,p0-retry-params = /bits/ 16 <0x0216 0x7F06>; + ceva,p1-cominit-params = /bits/ 8 <0x0F 0x25 0x18 0x29>; + ceva,p1-comwake-params = /bits/ 8 <0x04 0x0B 0x08 0x0F>; + ceva,p1-burst-params = /bits/ 8 <0x0A 0x08 0x4A 0x06>; + ceva,p1-retry-params = /bits/ 16 <0x0216 0x7F06>; + ceva,broken-gen2; + phys = <&psgtr 1 PHY_TYPE_SATA 1 1>; + resets = <&zynqmp_reset ZYNQMP_RESET_SATA>; + }; From 4908e3ace24be2f3a95a0cccd0993bd3ab44a073 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 28 Jun 2022 09:09:59 +0200 Subject: [PATCH 0745/1436] dt-bindings: nfc: nxp,nci: drop Charles Gorand's mail Mails to Charles get an auto reply, that he is no longer working at Eff'Innov technologies. Remove the entry. Signed-off-by: Michael Walle Reviewed-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220628070959.187734-1-michael@walle.cc --- Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml b/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml index e381a3c14836..b2558421268a 100644 --- a/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml +++ b/Documentation/devicetree/bindings/net/nfc/nxp,nci.yaml @@ -7,7 +7,6 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# title: NXP Semiconductors NCI NFC controller maintainers: - - Charles Gorand - Krzysztof Kozlowski properties: From 57a3487eefa598bdcc15df6dd3991b7ea843fb53 Mon Sep 17 00:00:00 2001 From: Mark Pearson Date: Mon, 27 Jun 2022 14:14:49 -0400 Subject: [PATCH 0746/1436] platform/x86: thinkpad_acpi: do not use PSC mode on Intel platforms PSC platform profile mode is only supported on Linux for AMD platforms. Some older Intel platforms (e.g T490) are advertising it's capability as Windows uses it - but on Linux we should only be using MMC profile for Intel systems. Add a check to prevent it being enabled incorrectly. Signed-off-by: Mark Pearson Link: https://lore.kernel.org/r/20220627181449.3537-1-markpearson@lenovo.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/thinkpad_acpi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 17d503e65a54..09047ca14b43 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -10565,6 +10565,11 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm) dytc_mmc_get_available = true; } } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) { /* PSC MODE */ + /* Support for this only works on AMD platforms */ + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) { + dbg_printk(TPACPI_DBG_INIT, "PSC not support on Intel platforms\n"); + return -ENODEV; + } pr_debug("PSC is supported\n"); } else { dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n"); From 2ac96c800dd18e7fc08589d5f5962710db6c927c Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 28 Jun 2022 20:37:26 +0800 Subject: [PATCH 0747/1436] platform/x86: hp-wmi: Ignore Sanitization Mode event After system resume the hp-wmi driver may complain: [ 702.620180] hp_wmi: Unknown event_id - 23 - 0x0 According to HP it means 'Sanitization Mode' and it's harmless to just ignore the event. Cc: Jorge Lopez Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220628123726.250062-1-kai.heng.feng@canonical.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/hp-wmi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 0d8cb22e30df..bc7020e9df9e 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -89,6 +89,7 @@ enum hp_wmi_event_ids { HPWMI_BACKLIT_KB_BRIGHTNESS = 0x0D, HPWMI_PEAKSHIFT_PERIOD = 0x0F, HPWMI_BATTERY_CHARGE_PERIOD = 0x10, + HPWMI_SANITIZATION_MODE = 0x17, }; /* @@ -853,6 +854,8 @@ static void hp_wmi_notify(u32 value, void *context) break; case HPWMI_BATTERY_CHARGE_PERIOD: break; + case HPWMI_SANITIZATION_MODE: + break; default: pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data); break; From b1da49088ac68a21c613efd734dada8272ec0b00 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:19 +0100 Subject: [PATCH 0748/1436] KVM: arm64: Move vcpu debug/SPE/TRBE flags to the input flag set The three debug flags (which deal with the debug registers, SPE and TRBE) all are input flags to the hypervisor code. Move them into the input set and convert them to the new accessors. Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 9 +++++--- arch/arm64/kvm/debug.c | 25 +++++++++++----------- arch/arm64/kvm/hyp/include/hyp/debug-sr.h | 6 +++--- arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 4 ++-- arch/arm64/kvm/hyp/nvhe/debug-sr.c | 8 +++---- arch/arm64/kvm/sys_regs.c | 8 +++---- 6 files changed, 31 insertions(+), 29 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index db42b4c06449..4c7446400b77 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -508,6 +508,12 @@ struct kvm_vcpu_arch { #define EXCEPT_AA64_EL2_IRQ __vcpu_except_flags(5) #define EXCEPT_AA64_EL2_FIQ __vcpu_except_flags(6) #define EXCEPT_AA64_EL2_SERR __vcpu_except_flags(7) +/* Guest debug is live */ +#define DEBUG_DIRTY __vcpu_single_flag(iflags, BIT(4)) +/* Save SPE context if active */ +#define DEBUG_STATE_SAVE_SPE __vcpu_single_flag(iflags, BIT(5)) +/* Save TRBE context if active */ +#define DEBUG_STATE_SAVE_TRBE __vcpu_single_flag(iflags, BIT(6)) /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */ #define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \ @@ -530,10 +536,7 @@ struct kvm_vcpu_arch { }) /* vcpu_arch flags field values: */ -#define KVM_ARM64_DEBUG_DIRTY (1 << 0) #define KVM_ARM64_HOST_SVE_ENABLED (1 << 4) /* SVE enabled for EL0 */ -#define KVM_ARM64_DEBUG_STATE_SAVE_SPE (1 << 12) /* Save SPE context if active */ -#define KVM_ARM64_DEBUG_STATE_SAVE_TRBE (1 << 13) /* Save TRBE context if active */ #define KVM_ARM64_ON_UNSUPPORTED_CPU (1 << 15) /* Physical CPU not in supported_cpus */ #define KVM_ARM64_HOST_SME_ENABLED (1 << 16) /* SME enabled for EL0 */ #define KVM_ARM64_WFIT (1 << 17) /* WFIT instruction trapped */ diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 4fd5c216c4bb..0b28d7db7c76 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -104,11 +104,11 @@ static void kvm_arm_setup_mdcr_el2(struct kvm_vcpu *vcpu) * Trap debug register access when one of the following is true: * - Userspace is using the hardware to debug the guest * (KVM_GUESTDBG_USE_HW is set). - * - The guest is not using debug (KVM_ARM64_DEBUG_DIRTY is clear). + * - The guest is not using debug (DEBUG_DIRTY clear). * - The guest has enabled the OS Lock (debug exceptions are blocked). */ if ((vcpu->guest_debug & KVM_GUESTDBG_USE_HW) || - !(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY) || + !vcpu_get_flag(vcpu, DEBUG_DIRTY) || kvm_vcpu_os_lock_enabled(vcpu)) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; @@ -147,8 +147,8 @@ void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) * debug related registers. * * Additionally, KVM only traps guest accesses to the debug registers if - * the guest is not actively using them (see the KVM_ARM64_DEBUG_DIRTY - * flag on vcpu->arch.flags). Since the guest must not interfere + * the guest is not actively using them (see the DEBUG_DIRTY + * flag on vcpu->arch.iflags). Since the guest must not interfere * with the hardware state when debugging the guest, we must ensure that * trapping is enabled whenever we are debugging the guest using the * debug registers. @@ -205,9 +205,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) * * We simply switch the debug_ptr to point to our new * external_debug_state which has been populated by the - * debug ioctl. The existing KVM_ARM64_DEBUG_DIRTY - * mechanism ensures the registers are updated on the - * world switch. + * debug ioctl. The existing DEBUG_DIRTY mechanism ensures + * the registers are updated on the world switch. */ if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) { /* Enable breakpoints/watchpoints */ @@ -216,7 +215,7 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu_write_sys_reg(vcpu, mdscr, MDSCR_EL1); vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state; - vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY; + vcpu_set_flag(vcpu, DEBUG_DIRTY); trace_kvm_arm_set_regset("BKPTS", get_num_brps(), &vcpu->arch.debug_ptr->dbg_bcr[0], @@ -246,7 +245,7 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) /* If KDE or MDE are set, perform a full save/restore cycle. */ if (vcpu_read_sys_reg(vcpu, MDSCR_EL1) & (DBG_MDSCR_KDE | DBG_MDSCR_MDE)) - vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY; + vcpu_set_flag(vcpu, DEBUG_DIRTY); /* Write mdcr_el2 changes since vcpu_load on VHE systems */ if (has_vhe() && orig_mdcr_el2 != vcpu->arch.mdcr_el2) @@ -298,16 +297,16 @@ void kvm_arch_vcpu_load_debug_state_flags(struct kvm_vcpu *vcpu) */ if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_PMSVER_SHIFT) && !(read_sysreg_s(SYS_PMBIDR_EL1) & BIT(SYS_PMBIDR_EL1_P_SHIFT))) - vcpu->arch.flags |= KVM_ARM64_DEBUG_STATE_SAVE_SPE; + vcpu_set_flag(vcpu, DEBUG_STATE_SAVE_SPE); /* Check if we have TRBE implemented and available at the host */ if (cpuid_feature_extract_unsigned_field(dfr0, ID_AA64DFR0_TRBE_SHIFT) && !(read_sysreg_s(SYS_TRBIDR_EL1) & TRBIDR_PROG)) - vcpu->arch.flags |= KVM_ARM64_DEBUG_STATE_SAVE_TRBE; + vcpu_set_flag(vcpu, DEBUG_STATE_SAVE_TRBE); } void kvm_arch_vcpu_put_debug_state_flags(struct kvm_vcpu *vcpu) { - vcpu->arch.flags &= ~(KVM_ARM64_DEBUG_STATE_SAVE_SPE | - KVM_ARM64_DEBUG_STATE_SAVE_TRBE); + vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_SPE); + vcpu_clear_flag(vcpu, DEBUG_STATE_SAVE_TRBE); } diff --git a/arch/arm64/kvm/hyp/include/hyp/debug-sr.h b/arch/arm64/kvm/hyp/include/hyp/debug-sr.h index 4ebe9f558f3a..961bbef104a6 100644 --- a/arch/arm64/kvm/hyp/include/hyp/debug-sr.h +++ b/arch/arm64/kvm/hyp/include/hyp/debug-sr.h @@ -132,7 +132,7 @@ static inline void __debug_switch_to_guest_common(struct kvm_vcpu *vcpu) struct kvm_guest_debug_arch *host_dbg; struct kvm_guest_debug_arch *guest_dbg; - if (!(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY)) + if (!vcpu_get_flag(vcpu, DEBUG_DIRTY)) return; host_ctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; @@ -151,7 +151,7 @@ static inline void __debug_switch_to_host_common(struct kvm_vcpu *vcpu) struct kvm_guest_debug_arch *host_dbg; struct kvm_guest_debug_arch *guest_dbg; - if (!(vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY)) + if (!vcpu_get_flag(vcpu, DEBUG_DIRTY)) return; host_ctxt = &this_cpu_ptr(&kvm_host_data)->host_ctxt; @@ -162,7 +162,7 @@ static inline void __debug_switch_to_host_common(struct kvm_vcpu *vcpu) __debug_save_state(guest_dbg, guest_ctxt); __debug_restore_state(host_dbg, host_ctxt); - vcpu->arch.flags &= ~KVM_ARM64_DEBUG_DIRTY; + vcpu_clear_flag(vcpu, DEBUG_DIRTY); } #endif /* __ARM64_KVM_HYP_DEBUG_SR_H__ */ diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h index 7ecca8b07851..baa5b9b3dde5 100644 --- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h @@ -195,7 +195,7 @@ static inline void __sysreg32_save_state(struct kvm_vcpu *vcpu) __vcpu_sys_reg(vcpu, DACR32_EL2) = read_sysreg(dacr32_el2); __vcpu_sys_reg(vcpu, IFSR32_EL2) = read_sysreg(ifsr32_el2); - if (has_vhe() || vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY) + if (has_vhe() || vcpu_get_flag(vcpu, DEBUG_DIRTY)) __vcpu_sys_reg(vcpu, DBGVCR32_EL2) = read_sysreg(dbgvcr32_el2); } @@ -212,7 +212,7 @@ static inline void __sysreg32_restore_state(struct kvm_vcpu *vcpu) write_sysreg(__vcpu_sys_reg(vcpu, DACR32_EL2), dacr32_el2); write_sysreg(__vcpu_sys_reg(vcpu, IFSR32_EL2), ifsr32_el2); - if (has_vhe() || vcpu->arch.flags & KVM_ARM64_DEBUG_DIRTY) + if (has_vhe() || vcpu_get_flag(vcpu, DEBUG_DIRTY)) write_sysreg(__vcpu_sys_reg(vcpu, DBGVCR32_EL2), dbgvcr32_el2); } diff --git a/arch/arm64/kvm/hyp/nvhe/debug-sr.c b/arch/arm64/kvm/hyp/nvhe/debug-sr.c index df361d839902..e17455773b98 100644 --- a/arch/arm64/kvm/hyp/nvhe/debug-sr.c +++ b/arch/arm64/kvm/hyp/nvhe/debug-sr.c @@ -84,10 +84,10 @@ static void __debug_restore_trace(u64 trfcr_el1) void __debug_save_host_buffers_nvhe(struct kvm_vcpu *vcpu) { /* Disable and flush SPE data generation */ - if (vcpu->arch.flags & KVM_ARM64_DEBUG_STATE_SAVE_SPE) + if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE)) __debug_save_spe(&vcpu->arch.host_debug_state.pmscr_el1); /* Disable and flush Self-Hosted Trace generation */ - if (vcpu->arch.flags & KVM_ARM64_DEBUG_STATE_SAVE_TRBE) + if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE)) __debug_save_trace(&vcpu->arch.host_debug_state.trfcr_el1); } @@ -98,9 +98,9 @@ void __debug_switch_to_guest(struct kvm_vcpu *vcpu) void __debug_restore_host_buffers_nvhe(struct kvm_vcpu *vcpu) { - if (vcpu->arch.flags & KVM_ARM64_DEBUG_STATE_SAVE_SPE) + if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_SPE)) __debug_restore_spe(vcpu->arch.host_debug_state.pmscr_el1); - if (vcpu->arch.flags & KVM_ARM64_DEBUG_STATE_SAVE_TRBE) + if (vcpu_get_flag(vcpu, DEBUG_STATE_SAVE_TRBE)) __debug_restore_trace(vcpu->arch.host_debug_state.trfcr_el1); } diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index c06c0477fab5..f24797c57df8 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -387,7 +387,7 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu, { if (p->is_write) { vcpu_write_sys_reg(vcpu, p->regval, r->reg); - vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY; + vcpu_set_flag(vcpu, DEBUG_DIRTY); } else { p->regval = vcpu_read_sys_reg(vcpu, r->reg); } @@ -403,8 +403,8 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu, * A 32 bit write to a debug register leave top bits alone * A 32 bit read from a debug register only returns the bottom bits * - * All writes will set the KVM_ARM64_DEBUG_DIRTY flag to ensure the - * hyp.S code switches between host and guest values in future. + * All writes will set the DEBUG_DIRTY flag to ensure the hyp code + * switches between host and guest values in future. */ static void reg_to_dbg(struct kvm_vcpu *vcpu, struct sys_reg_params *p, @@ -420,7 +420,7 @@ static void reg_to_dbg(struct kvm_vcpu *vcpu, val |= (p->regval & (mask >> shift)) << shift; *dbg_reg = val; - vcpu->arch.flags |= KVM_ARM64_DEBUG_DIRTY; + vcpu_set_flag(vcpu, DEBUG_DIRTY); } static void dbg_to_reg(struct kvm_vcpu *vcpu, From 0affa37fcd1d6f701a0fe805c4ceb7f348d377d5 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:20 +0100 Subject: [PATCH 0749/1436] KVM: arm64: Move vcpu SVE/SME flags to the state flag set The two HOST_{SVE,SME}_ENABLED are only used for the host kernel to track its own state across a vcpu run so that it can be fully restored. Move these flags to the so called state set. Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 8 +++++--- arch/arm64/kvm/fpsimd.c | 12 ++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 4c7446400b77..4f147bdc5ce9 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -515,6 +515,11 @@ struct kvm_vcpu_arch { /* Save TRBE context if active */ #define DEBUG_STATE_SAVE_TRBE __vcpu_single_flag(iflags, BIT(6)) +/* SVE enabled for host EL0 */ +#define HOST_SVE_ENABLED __vcpu_single_flag(sflags, BIT(0)) +/* SME enabled for EL0 */ +#define HOST_SME_ENABLED __vcpu_single_flag(sflags, BIT(1)) + /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */ #define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \ sve_ffr_offset((vcpu)->arch.sve_max_vl)) @@ -536,11 +541,8 @@ struct kvm_vcpu_arch { }) /* vcpu_arch flags field values: */ -#define KVM_ARM64_HOST_SVE_ENABLED (1 << 4) /* SVE enabled for EL0 */ #define KVM_ARM64_ON_UNSUPPORTED_CPU (1 << 15) /* Physical CPU not in supported_cpus */ -#define KVM_ARM64_HOST_SME_ENABLED (1 << 16) /* SME enabled for EL0 */ #define KVM_ARM64_WFIT (1 << 17) /* WFIT instruction trapped */ - #define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \ KVM_GUESTDBG_USE_SW_BP | \ KVM_GUESTDBG_USE_HW | \ diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c index d397efe1a378..557a96f8e06a 100644 --- a/arch/arm64/kvm/fpsimd.c +++ b/arch/arm64/kvm/fpsimd.c @@ -79,9 +79,9 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) vcpu->arch.fp_state = FP_STATE_HOST_OWNED; - vcpu->arch.flags &= ~KVM_ARM64_HOST_SVE_ENABLED; + vcpu_clear_flag(vcpu, HOST_SVE_ENABLED); if (read_sysreg(cpacr_el1) & CPACR_EL1_ZEN_EL0EN) - vcpu->arch.flags |= KVM_ARM64_HOST_SVE_ENABLED; + vcpu_set_flag(vcpu, HOST_SVE_ENABLED); /* * We don't currently support SME guests but if we leave @@ -93,9 +93,9 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) * operations. Do this for ZA as well for now for simplicity. */ if (system_supports_sme()) { - vcpu->arch.flags &= ~KVM_ARM64_HOST_SME_ENABLED; + vcpu_clear_flag(vcpu, HOST_SME_ENABLED); if (read_sysreg(cpacr_el1) & CPACR_EL1_SMEN_EL0EN) - vcpu->arch.flags |= KVM_ARM64_HOST_SME_ENABLED; + vcpu_set_flag(vcpu, HOST_SME_ENABLED); if (read_sysreg_s(SYS_SVCR) & (SVCR_SM_MASK | SVCR_ZA_MASK)) { vcpu->arch.fp_state = FP_STATE_FREE; @@ -164,7 +164,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu) */ if (has_vhe() && system_supports_sme()) { /* Also restore EL0 state seen on entry */ - if (vcpu->arch.flags & KVM_ARM64_HOST_SME_ENABLED) + if (vcpu_get_flag(vcpu, HOST_SME_ENABLED)) sysreg_clear_set(CPACR_EL1, 0, CPACR_EL1_SMEN_EL0EN | CPACR_EL1_SMEN_EL1EN); @@ -193,7 +193,7 @@ void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu) * for EL0. To avoid spurious traps, restore the trap state * seen by kvm_arch_vcpu_load_fp(): */ - if (vcpu->arch.flags & KVM_ARM64_HOST_SVE_ENABLED) + if (vcpu_get_flag(vcpu, HOST_SVE_ENABLED)) sysreg_clear_set(CPACR_EL1, 0, CPACR_EL1_ZEN_EL0EN); else sysreg_clear_set(CPACR_EL1, CPACR_EL1_ZEN_EL0EN, 0); From aff3ccd7320eed5814d317fcb80244f474d66a84 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:21 +0100 Subject: [PATCH 0750/1436] KVM: arm64: Move vcpu ON_UNSUPPORTED_CPU flag to the state flag set The ON_UNSUPPORTED_CPU flag is only there to track the sad fact that we have ended-up on a CPU where we cannot really run. Since this is only for the host kernel's use, move it to the state set. Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 4f147bdc5ce9..0c22514cb7c7 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -519,6 +519,8 @@ struct kvm_vcpu_arch { #define HOST_SVE_ENABLED __vcpu_single_flag(sflags, BIT(0)) /* SME enabled for EL0 */ #define HOST_SME_ENABLED __vcpu_single_flag(sflags, BIT(1)) +/* Physical CPU not in supported_cpus */ +#define ON_UNSUPPORTED_CPU __vcpu_single_flag(sflags, BIT(2)) /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */ #define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \ @@ -541,7 +543,6 @@ struct kvm_vcpu_arch { }) /* vcpu_arch flags field values: */ -#define KVM_ARM64_ON_UNSUPPORTED_CPU (1 << 15) /* Physical CPU not in supported_cpus */ #define KVM_ARM64_WFIT (1 << 17) /* WFIT instruction trapped */ #define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \ KVM_GUESTDBG_USE_SW_BP | \ @@ -561,13 +562,13 @@ struct kvm_vcpu_arch { #endif #define vcpu_on_unsupported_cpu(vcpu) \ - ((vcpu)->arch.flags & KVM_ARM64_ON_UNSUPPORTED_CPU) + vcpu_get_flag(vcpu, ON_UNSUPPORTED_CPU) #define vcpu_set_on_unsupported_cpu(vcpu) \ - ((vcpu)->arch.flags |= KVM_ARM64_ON_UNSUPPORTED_CPU) + vcpu_set_flag(vcpu, ON_UNSUPPORTED_CPU) #define vcpu_clear_on_unsupported_cpu(vcpu) \ - ((vcpu)->arch.flags &= ~KVM_ARM64_ON_UNSUPPORTED_CPU) + vcpu_clear_flag(vcpu, ON_UNSUPPORTED_CPU) #define vcpu_gp_regs(v) (&(v)->arch.ctxt.regs) From eebc538d8e07e0ec759823664cbe2011a8bd885d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:22 +0100 Subject: [PATCH 0751/1436] KVM: arm64: Move vcpu WFIT flag to the state flag set The host kernel uses the WFIT flag to remember that a vcpu has used this instruction and wake it up as required. Move it to the state set, as nothing in the hypervisor uses this information. Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 4 ++-- arch/arm64/kvm/arch_timer.c | 2 +- arch/arm64/kvm/arm.c | 2 +- arch/arm64/kvm/handle_exit.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 0c22514cb7c7..0fb1a5b86f16 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -521,6 +521,8 @@ struct kvm_vcpu_arch { #define HOST_SME_ENABLED __vcpu_single_flag(sflags, BIT(1)) /* Physical CPU not in supported_cpus */ #define ON_UNSUPPORTED_CPU __vcpu_single_flag(sflags, BIT(2)) +/* WFIT instruction trapped */ +#define IN_WFIT __vcpu_single_flag(sflags, BIT(3)) /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */ #define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \ @@ -542,8 +544,6 @@ struct kvm_vcpu_arch { __size_ret; \ }) -/* vcpu_arch flags field values: */ -#define KVM_ARM64_WFIT (1 << 17) /* WFIT instruction trapped */ #define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \ KVM_GUESTDBG_USE_SW_BP | \ KVM_GUESTDBG_USE_HW | \ diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c index 4e39ace073af..5290ca5db663 100644 --- a/arch/arm64/kvm/arch_timer.c +++ b/arch/arm64/kvm/arch_timer.c @@ -242,7 +242,7 @@ static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx) static bool vcpu_has_wfit_active(struct kvm_vcpu *vcpu) { return (cpus_have_final_cap(ARM64_HAS_WFXT) && - (vcpu->arch.flags & KVM_ARM64_WFIT)); + vcpu_get_flag(vcpu, IN_WFIT)); } static u64 wfit_delay_ns(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 5beabbe69585..8b9da9d30485 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -657,7 +657,7 @@ void kvm_vcpu_wfi(struct kvm_vcpu *vcpu) preempt_enable(); kvm_vcpu_halt(vcpu); - vcpu->arch.flags &= ~KVM_ARM64_WFIT; + vcpu_clear_flag(vcpu, IN_WFIT); kvm_clear_request(KVM_REQ_UNHALT, vcpu); preempt_disable(); diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index f66c0142b335..d045f5b973b9 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -120,7 +120,7 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu) kvm_vcpu_on_spin(vcpu, vcpu_mode_priv(vcpu)); } else { if (esr & ESR_ELx_WFx_ISS_WFxT) - vcpu->arch.flags |= KVM_ARM64_WFIT; + vcpu_set_flag(vcpu, IN_WFIT); kvm_vcpu_wfi(vcpu); } From 781e3ae148fd2f9b0cf9b5b94f6c32f2361eb7c0 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:23 +0100 Subject: [PATCH 0752/1436] KVM: arm64: Kill unused vcpu flags field Horray, we have now sorted all the preexisting flags, and the 'flags' field is now unused. Get rid of it while nobody is looking. Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 0fb1a5b86f16..39da28f85045 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -332,9 +332,6 @@ struct kvm_vcpu_arch { FP_STATE_GUEST_OWNED, } fp_state; - /* Miscellaneous vcpu state flags */ - u64 flags; - /* Configuration flags, set once and for all before the vcpu can run */ u64 cflags; From 30b6ab45f81334e83dcb440451b6a4c4a753a118 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:24 +0100 Subject: [PATCH 0753/1436] KVM: arm64: Convert vcpu sysregs_loaded_on_cpu to a state flag The aptly named boolean 'sysregs_loaded_on_cpu' tracks whether some of the vcpu system registers are resident on the physical CPU when running in VHE mode. This is obviously a flag in hidding, so let's convert it to a state flag, since this is solely a host concern (the hypervisor itself always knows which state we're in). Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 6 ++---- arch/arm64/kvm/hyp/vhe/sysreg-sr.c | 4 ++-- arch/arm64/kvm/sys_regs.c | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 39da28f85045..ffbeb5f5692e 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -410,10 +410,6 @@ struct kvm_vcpu_arch { /* Additional reset state */ struct vcpu_reset_state reset_state; - /* True when deferrable sysregs are loaded on the physical CPU, - * see kvm_vcpu_load_sysregs_vhe and kvm_vcpu_put_sysregs_vhe. */ - bool sysregs_loaded_on_cpu; - /* Guest PV state */ struct { u64 last_steal; @@ -520,6 +516,8 @@ struct kvm_vcpu_arch { #define ON_UNSUPPORTED_CPU __vcpu_single_flag(sflags, BIT(2)) /* WFIT instruction trapped */ #define IN_WFIT __vcpu_single_flag(sflags, BIT(3)) +/* vcpu system registers loaded on physical CPU */ +#define SYSREGS_ON_CPU __vcpu_single_flag(sflags, BIT(4)) /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */ #define vcpu_sve_pffr(vcpu) (kern_hyp_va((vcpu)->arch.sve_state) + \ diff --git a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c index 007a12dd4351..7b44f6b3b547 100644 --- a/arch/arm64/kvm/hyp/vhe/sysreg-sr.c +++ b/arch/arm64/kvm/hyp/vhe/sysreg-sr.c @@ -79,7 +79,7 @@ void kvm_vcpu_load_sysregs_vhe(struct kvm_vcpu *vcpu) __sysreg_restore_user_state(guest_ctxt); __sysreg_restore_el1_state(guest_ctxt); - vcpu->arch.sysregs_loaded_on_cpu = true; + vcpu_set_flag(vcpu, SYSREGS_ON_CPU); activate_traps_vhe_load(vcpu); } @@ -110,5 +110,5 @@ void kvm_vcpu_put_sysregs_vhe(struct kvm_vcpu *vcpu) /* Restore host user state */ __sysreg_restore_user_state(host_ctxt); - vcpu->arch.sysregs_loaded_on_cpu = false; + vcpu_clear_flag(vcpu, SYSREGS_ON_CPU); } diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index f24797c57df8..1c562bcfeccf 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -72,7 +72,7 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg) { u64 val = 0x8badf00d8badf00d; - if (vcpu->arch.sysregs_loaded_on_cpu && + if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) && __vcpu_read_sys_reg_from_cpu(reg, &val)) return val; @@ -81,7 +81,7 @@ u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg) void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg) { - if (vcpu->arch.sysregs_loaded_on_cpu && + if (vcpu_get_flag(vcpu, SYSREGS_ON_CPU) && __vcpu_write_sys_reg_to_cpu(val, reg)) return; From e19f2c6cd14668c0d5b1cef280632b7ca5893118 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:25 +0100 Subject: [PATCH 0754/1436] KVM: arm64: Warn when PENDING_EXCEPTION and INCREMENT_PC are set together We really don't want PENDING_EXCEPTION and INCREMENT_PC to ever be set at the same time, as they are mutually exclusive. Add checks that will generate a warning should this ever happen. Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_emulate.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index 6ec58080ece8..9bdba47f7e14 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -473,11 +473,13 @@ static inline unsigned long vcpu_data_host_to_guest(struct kvm_vcpu *vcpu, static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu) { + WARN_ON(vcpu_get_flag(vcpu, PENDING_EXCEPTION)); vcpu_set_flag(vcpu, INCREMENT_PC); } #define kvm_pend_exception(v, e) \ do { \ + WARN_ON(vcpu_get_flag((v), INCREMENT_PC)); \ vcpu_set_flag((v), PENDING_EXCEPTION); \ vcpu_set_flag((v), e); \ } while (0) From 5a3984f4ec73d1c7cf31a4cee46cca7d4c75deee Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:26 +0100 Subject: [PATCH 0755/1436] KVM: arm64: Add build-time sanity checks for flags Flags are great, but flags can also be dangerous: it is easy to encode a flag that is bigger than its container (unless the container is a u64), and it is easy to construct a flag value that doesn't fit in the mask that is associated with it. Add a couple of build-time sanity checks that ensure we catch these two cases. Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index ffbeb5f5692e..6a37018f40b7 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -433,8 +433,20 @@ struct kvm_vcpu_arch { #define __unpack_flag(_set, _f, _m) _f #define unpack_vcpu_flag(...) __unpack_flag(__VA_ARGS__) +#define __build_check_flag(v, flagset, f, m) \ + do { \ + typeof(v->arch.flagset) *_fset; \ + \ + /* Check that the flags fit in the mask */ \ + BUILD_BUG_ON(HWEIGHT(m) != HWEIGHT((f) | (m))); \ + /* Check that the flags fit in the type */ \ + BUILD_BUG_ON((sizeof(*_fset) * 8) <= __fls(m)); \ + } while (0) + #define __vcpu_get_flag(v, flagset, f, m) \ ({ \ + __build_check_flag(v, flagset, f, m); \ + \ v->arch.flagset & (m); \ }) @@ -442,6 +454,8 @@ struct kvm_vcpu_arch { do { \ typeof(v->arch.flagset) *fset; \ \ + __build_check_flag(v, flagset, f, m); \ + \ fset = &v->arch.flagset; \ if (HWEIGHT(m) > 1) \ *fset &= ~(m); \ @@ -452,6 +466,8 @@ struct kvm_vcpu_arch { do { \ typeof(v->arch.flagset) *fset; \ \ + __build_check_flag(v, flagset, f, m); \ + \ fset = &v->arch.flagset; \ *fset &= ~(m); \ } while (0) From 54ddda919c4bc37c113727034619c4e15c184334 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:27 +0100 Subject: [PATCH 0756/1436] KVM: arm64: Reduce the size of the vcpu flag members Now that we can detect flags overflowing their container, reduce the size of all flag set members in the vcpu struct, turning them into 8bit quantities. Even with the FP state enum occupying 32bit, the whole of the state that was represented by flags is smaller by one byte. Profit! Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 6a37018f40b7..c6975ecf5a5f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -333,13 +333,13 @@ struct kvm_vcpu_arch { } fp_state; /* Configuration flags, set once and for all before the vcpu can run */ - u64 cflags; + u8 cflags; /* Input flags to the hypervisor code, potentially cleared after use */ - u64 iflags; + u8 iflags; /* State flags for kernel bookkeeping, unused by the hypervisor code */ - u64 sflags; + u8 sflags; /* * We maintain more than a single set of debug registers to support From 0fa4a3137e943cd6acab386ff26cd8d5e94e9559 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sat, 28 May 2022 12:38:28 +0100 Subject: [PATCH 0757/1436] KVM: arm64: Document why pause cannot be turned into a flag It would be tempting to turn the 'pause' state into a flag. However, this cannot easily be done as it is updated out of context, while all the flags expect to only be updated from the vcpu thread. Turning it into a flag would require to make all flag updates atomic, which isn't necessary desireable. Document this, and take this opportunity to move the field next to the flag sets, filling a hole in the vcpu structure. Reviewed-by: Fuad Tabba Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index c6975ecf5a5f..2cc42e1fec18 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -341,6 +341,15 @@ struct kvm_vcpu_arch { /* State flags for kernel bookkeeping, unused by the hypervisor code */ u8 sflags; + /* + * Don't run the guest (internal implementation need). + * + * Contrary to the flags above, this is set/cleared outside of + * a vcpu context, and thus cannot be mixed with the flags + * themselves (or the flag accesses need to be made atomic). + */ + bool pause; + /* * We maintain more than a single set of debug registers to support * debugging the guest from the host and to maintain separate host and @@ -394,9 +403,6 @@ struct kvm_vcpu_arch { /* vcpu power state */ struct kvm_mp_state mp_state; - /* Don't run the guest (internal implementation need) */ - bool pause; - /* Cache some mmu pages needed inside spinlock regions */ struct kvm_mmu_memory_cache mmu_page_cache; From b4da91879e98bdd5998ee84f47f02426ac50a729 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 8 Jun 2022 14:22:31 +0100 Subject: [PATCH 0758/1436] KVM: arm64: Move the handling of !FP outside of the fast path We currently start by assuming that the host owns the FP unit at load time, then check again whether this is the case as we are about to run. Only at this point do we account for the fact that there is a (vanishingly small) chance that we're running on a system without a FPSIMD unit (yes, this is madness). We can actually move this FPSIMD check as early as load-time, and drop the check at run time. No intended change in behaviour. Suggested-by: Reiji Watanabe Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/arm.c | 6 ++++++ arch/arm64/kvm/fpsimd.c | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 8b9da9d30485..a9dd7ec38f38 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -328,6 +328,12 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO; + /* + * Default value for the FP state, will be overloaded at load + * time if we support FP (pretty likely) + */ + vcpu->arch.fp_state = FP_STATE_FREE; + /* Set up the timer */ kvm_timer_vcpu_init(vcpu); diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c index 557a96f8e06a..ec8e4494873d 100644 --- a/arch/arm64/kvm/fpsimd.c +++ b/arch/arm64/kvm/fpsimd.c @@ -77,6 +77,9 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) BUG_ON(!current->mm); BUG_ON(test_thread_flag(TIF_SVE)); + if (!system_supports_fpsimd()) + return; + vcpu->arch.fp_state = FP_STATE_HOST_OWNED; vcpu_clear_flag(vcpu, HOST_SVE_ENABLED); @@ -110,13 +113,10 @@ void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) * FP while we were preemptible (such as off the back of an interrupt), * then neither the host nor the guest own the FP hardware (and it was the * responsibility of the code that used FP to save the existing state). - * - * Note that not supporting FP is basically the same thing as far as the - * hypervisor is concerned (nothing to save). */ void kvm_arch_vcpu_ctxflush_fp(struct kvm_vcpu *vcpu) { - if (!system_supports_fpsimd() || test_thread_flag(TIF_FOREIGN_FPSTATE)) + if (test_thread_flag(TIF_FOREIGN_FPSTATE)) vcpu->arch.fp_state = FP_STATE_FREE; } From 3d5697f95e492899d0bf813cbab2af03dde77fa2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 13 Jun 2022 18:20:25 +0900 Subject: [PATCH 0759/1436] KVM: arm64: nvhe: Rename confusing obj-y This Makefile appends several objects to obj-y from line 15, but none of them is linked to vmlinux in an ordinary way. obj-y is overwritten at line 30: obj-y := kvm_nvhe.o So, kvm_nvhe.o is the only object directly linked to vmlinux. Replace the abused obj-y with hyp-obj-y. Signed-off-by: Masahiro Yamada Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220613092026.1705630-1-masahiroy@kernel.org --- arch/arm64/kvm/hyp/nvhe/Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile index f9fe4dc21b1f..3c6d3a18171c 100644 --- a/arch/arm64/kvm/hyp/nvhe/Makefile +++ b/arch/arm64/kvm/hyp/nvhe/Makefile @@ -12,13 +12,13 @@ HOST_EXTRACFLAGS += -I$(objtree)/include lib-objs := clear_page.o copy_page.o memcpy.o memset.o lib-objs := $(addprefix ../../../lib/, $(lib-objs)) -obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o \ +hyp-obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o \ hyp-main.o hyp-smp.o psci-relay.o early_alloc.o page_alloc.o \ cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o -obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \ +hyp-obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \ ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o -obj-$(CONFIG_DEBUG_LIST) += list_debug.o -obj-y += $(lib-objs) +hyp-obj-$(CONFIG_DEBUG_LIST) += list_debug.o +hyp-obj-y += $(lib-objs) ## ## Build rules for compiling nVHE hyp code @@ -26,7 +26,7 @@ obj-y += $(lib-objs) ## file containing all nVHE hyp code and data. ## -hyp-obj := $(patsubst %.o,%.nvhe.o,$(obj-y)) +hyp-obj := $(patsubst %.o,%.nvhe.o,$(hyp-obj-y)) obj-y := kvm_nvhe.o extra-y := $(hyp-obj) kvm_nvhe.tmp.o kvm_nvhe.rel.o hyp.lds hyp-reloc.S hyp-reloc.o From 40c56bd8e1aea7929a09f1d4d68ac3221bb142c4 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 13 Jun 2022 18:20:26 +0900 Subject: [PATCH 0760/1436] KVM: arm64: nvhe: Add intermediates to 'targets' instead of extra-y These are generated on demand. Adding them to 'targets' is enough. Signed-off-by: Masahiro Yamada Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220613092026.1705630-2-masahiroy@kernel.org --- arch/arm64/kvm/hyp/nvhe/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile index 3c6d3a18171c..a2b0d043dddf 100644 --- a/arch/arm64/kvm/hyp/nvhe/Makefile +++ b/arch/arm64/kvm/hyp/nvhe/Makefile @@ -28,7 +28,7 @@ hyp-obj-y += $(lib-objs) hyp-obj := $(patsubst %.o,%.nvhe.o,$(hyp-obj-y)) obj-y := kvm_nvhe.o -extra-y := $(hyp-obj) kvm_nvhe.tmp.o kvm_nvhe.rel.o hyp.lds hyp-reloc.S hyp-reloc.o +targets += $(hyp-obj) kvm_nvhe.tmp.o kvm_nvhe.rel.o hyp.lds hyp-reloc.S hyp-reloc.o # 1) Compile all source files to `.nvhe.o` object files. The file extension # avoids file name clashes for files shared with VHE. From ae92b1c84306a68c361d90b46ad3acef99c10e29 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 28 Jun 2022 10:46:24 +0100 Subject: [PATCH 0761/1436] usb: typec_altmode: add a missing "@" at a kernel-doc parameter Without that, the parameter is not properly parsed: include/linux/usb/typec_altmode.h:132: warning: Function parameter or member 'altmode' not described in 'typec_altmode_get_orientation' Signed-off-by: Mauro Carvalho Chehab Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/70dc4c5d744cf1fe9a0efe6b85deaa0489628282.1656409369.git.mchehab@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/typec_altmode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h index 65933cbe9129..350d49012659 100644 --- a/include/linux/usb/typec_altmode.h +++ b/include/linux/usb/typec_altmode.h @@ -124,7 +124,7 @@ struct typec_altmode *typec_match_altmode(struct typec_altmode **altmodes, /** * typec_altmode_get_orientation - Get cable plug orientation - * altmode: Handle to the alternate mode + * @altmode: Handle to the alternate mode */ static inline enum typec_orientation typec_altmode_get_orientation(struct typec_altmode *altmode) From ad44cf402486a0c84e65e6f0a65c20ce58a65a96 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 28 Jun 2022 10:46:25 +0100 Subject: [PATCH 0762/1436] usb: dwc3: document async_callbacks field Avoid a kernel-doc warning by documenting it: drivers/usb/dwc3/core.h:1328: warning: Function parameter or member 'async_callbacks' not described in 'dwc3' Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/2c3de5935934baec097286f525ce4beff0a31ec0.1656409369.git.mchehab@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 722808d8c0af..4fe4287dc934 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1087,6 +1087,8 @@ struct dwc3_scratchpad_array { * @dis_u1_entry_quirk: set if link entering into U1 state needs to be disabled. * @dis_u2_entry_quirk: set if link entering into U2 state needs to be disabled. * @dis_rxdet_inp3_quirk: set if we disable Rx.Detect in P3 + * @async_callbacks: if set, indicate that async callbacks will be used. + * * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists * in GUSB2PHYCFG, specify that USB2 PHY doesn't * provide a free-running PHY clock. From babfcd947eba6e4c80a023683a37723ad43816e2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 28 Jun 2022 10:46:26 +0100 Subject: [PATCH 0763/1436] usb: dwc3: gadget: fix a kernel-doc warning The multiplier parameter of dwc3_gadget_calc_tx_fifo_size() was not documented: drivers/usb/dwc3/gadget.c:675: warning: Function parameter or member 'mult' not described in 'dwc3_gadget_calc_tx_fifo_size' Signed-off-by: Mauro Carvalho Chehab Link: https://lore.kernel.org/r/bd599a18cea45c57d91c69d3e30d8b1e8ea69dd1.1656409369.git.mchehab@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 8716bece1072..a944c7a6c83a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -657,6 +657,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3_ep *dep, unsigned int action) /** * dwc3_gadget_calc_tx_fifo_size - calculates the txfifo size value * @dwc: pointer to the DWC3 context + * @mult: multiplier to be used when calculating the fifo_size * * Calculates the size value based on the equation below: * From 70cdb930f7e97e0abe4ec4ac30e63ada490ef375 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 28 Jun 2022 11:21:43 +0300 Subject: [PATCH 0764/1436] usb: gadget: aspeed_udc: fix handling of tx_len == 0 The bug is that we should still enter this loop if "tx_len" is zero. After adding the "last" variable, then the "chunk >= 0" condition is no longer required but I left it for readability. Fixes: c09b1f372e74 ("usb: gadget: aspeed_udc: cleanup loop in ast_dma_descriptor_setup()") Reported-by: Neal Liu Reviewed-by: Neal Liu Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/Yrq6F5okoX1y05rT@kili Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/aspeed_udc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c index d75a4e070bf7..01968e2167f9 100644 --- a/drivers/usb/gadget/udc/aspeed_udc.c +++ b/drivers/usb/gadget/udc/aspeed_udc.c @@ -476,6 +476,7 @@ static int ast_dma_descriptor_setup(struct ast_udc_ep *ep, u32 dma_buf, { struct ast_udc_dev *udc = ep->udc; struct device *dev = &udc->pdev->dev; + bool last = false; int chunk, count; u32 offset; @@ -493,14 +494,16 @@ static int ast_dma_descriptor_setup(struct ast_udc_ep *ep, u32 dma_buf, "tx_len", tx_len); /* Create Descriptor Lists */ - while (chunk > 0 && count < AST_UDC_DESCS_COUNT) { + while (chunk >= 0 && !last && count < AST_UDC_DESCS_COUNT) { ep->descs[ep->descs_wptr].des_0 = dma_buf + offset; - if (chunk > ep->chunk_max) + if (chunk > ep->chunk_max) { ep->descs[ep->descs_wptr].des_1 = ep->chunk_max; - else + } else { ep->descs[ep->descs_wptr].des_1 = chunk; + last = true; + } chunk -= ep->chunk_max; From 98ceba7559280cdd09feccc7af4406d93187fbfb Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Tue, 28 Jun 2022 22:05:27 +0800 Subject: [PATCH 0765/1436] usb: musb: mpfs: add missing clk_disable_unprepare() in mpfs_remove() clock source is prepared and enabled by clk_prepare_enable() in probe function, but no disable or unprepare in remove. Fixes: 7a96b6ea90a4 ("usb: musb: Add support for PolarFire SoC's musb controller") Reported-by: Hulk Robot Reviewed-by: Conor Dooley Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220628140527.1404439-1-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/mpfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/musb/mpfs.c b/drivers/usb/musb/mpfs.c index a69ca338eace..cea2e8108867 100644 --- a/drivers/usb/musb/mpfs.c +++ b/drivers/usb/musb/mpfs.c @@ -239,6 +239,7 @@ static int mpfs_remove(struct platform_device *pdev) { struct mpfs_glue *glue = platform_get_drvdata(pdev); + clk_disable_unprepare(glue->clk); platform_device_unregister(glue->musb); usb_phy_generic_unregister(pdev); From df574080fad0d73f7aaf472a0fa45ea3f18230e0 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 29 Jun 2022 15:26:38 +0200 Subject: [PATCH 0766/1436] USB: cdc-acm: use define for timeout We have a symbolic name for the standard timeout. Use it. No functional change intended. Signed-off-by: Oliver Neukum Link: https://lore.kernel.org/r/20220629132638.31810-1-oneukum@suse.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 9b9aea24d58c..fedf3065670e 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -119,7 +119,7 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), request, USB_RT_ACM, value, acm->control->altsetting[0].desc.bInterfaceNumber, - buf, len, 5000); + buf, len, USB_CTRL_SET_TIMEOUT); dev_dbg(&acm->control->dev, "%s - rq 0x%02x, val %#x, len %#x, result %d\n", From 3b91edd624ab1ab694deef513a45eb9e9d49d75f Mon Sep 17 00:00:00 2001 From: Neal Liu Date: Tue, 28 Jun 2022 10:14:36 +0800 Subject: [PATCH 0767/1436] usb: gadget: f_mass_storage: Make CD-ROM emulation works with Windows OS Add read TOC with format 1 to support CD-ROM emulation with Windows OS. This patch is tested on Windows OS Server 2019. Fixes: 89ada0fe669a ("usb: gadget: f_mass_storage: Make CD-ROM emulation work with Mac OS-X") Reviewed-by: Alan Stern Signed-off-by: Neal Liu Link: https://lore.kernel.org/r/20220628021436.3252262-1-neal_liu@aspeedtech.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_mass_storage.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 3a77bca0ebe1..e884f295504f 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -1192,13 +1192,14 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) u8 format; int i, len; + format = common->cmnd[2] & 0xf; + if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ - start_track > 1) { + (start_track > 1 && format != 0x1)) { curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } - format = common->cmnd[2] & 0xf; /* * Check if CDB is old style SFF-8020i * i.e. format is in 2 MSBs of byte 9 @@ -1208,8 +1209,8 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) format = (common->cmnd[9] >> 6) & 0x3; switch (format) { - case 0: - /* Formatted TOC */ + case 0: /* Formatted TOC */ + case 1: /* Multi-session info */ len = 4 + 2*8; /* 4 byte header + 2 descriptors */ memset(buf, 0, len); buf[1] = len - 2; /* TOC Length excludes length field */ @@ -1250,7 +1251,7 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) return len; default: - /* Multi-session, PMA, ATIP, CD-TEXT not supported/required */ + /* PMA, ATIP, CD-TEXT not supported/required */ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; return -EINVAL; } From 864138ab0e09d241c704a851aaddc29d997e45db Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 6 Jun 2022 13:49:43 -0500 Subject: [PATCH 0768/1436] media: dt-bindings: rc: Allow 'ir-receiver' node names Most existing 'gpio-ir-receiver' nodes use 'ir-receiver' for their node name, so add it as an allowed node name. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220606184944.1067068-1-robh@kernel.org --- Documentation/devicetree/bindings/media/rc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml index d4c541c4b164..b11d14ab89c4 100644 --- a/Documentation/devicetree/bindings/media/rc.yaml +++ b/Documentation/devicetree/bindings/media/rc.yaml @@ -12,7 +12,7 @@ maintainers: properties: $nodename: - pattern: "^ir(@[a-f0-9]+)?$" + pattern: "^ir(-receiver)?(@[a-f0-9]+)?$" linux,rc-map-name: description: From 2d5a64707aa0c97c1aa5533234afd4aa1d99040c Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 6 Jun 2022 13:49:44 -0500 Subject: [PATCH 0769/1436] media: dt-bindings: Convert gpio-ir-receiver to DT schema Convert the gpio-ir-receiver binding to DT schema format. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220606184944.1067068-2-robh@kernel.org --- .../bindings/media/gpio-ir-receiver.txt | 20 ---------- .../bindings/media/gpio-ir-receiver.yaml | 40 +++++++++++++++++++ 2 files changed, 40 insertions(+), 20 deletions(-) delete mode 100644 Documentation/devicetree/bindings/media/gpio-ir-receiver.txt create mode 100644 Documentation/devicetree/bindings/media/gpio-ir-receiver.yaml diff --git a/Documentation/devicetree/bindings/media/gpio-ir-receiver.txt b/Documentation/devicetree/bindings/media/gpio-ir-receiver.txt deleted file mode 100644 index 108bf435b933..000000000000 --- a/Documentation/devicetree/bindings/media/gpio-ir-receiver.txt +++ /dev/null @@ -1,20 +0,0 @@ -Device-Tree bindings for GPIO IR receiver - -Required properties: - - compatible: should be "gpio-ir-receiver". - - gpios: specifies GPIO used for IR signal reception. - -Optional properties: - - linux,rc-map-name: see rc.txt file in the same - directory. - - linux,autosuspend-period: autosuspend delay time, - the unit is milisecond. - -Example node: - - ir: ir-receiver { - compatible = "gpio-ir-receiver"; - gpios = <&gpio0 19 1>; - linux,rc-map-name = "rc-rc6-mce"; - linux,autosuspend-period = <125>; - }; diff --git a/Documentation/devicetree/bindings/media/gpio-ir-receiver.yaml b/Documentation/devicetree/bindings/media/gpio-ir-receiver.yaml new file mode 100644 index 000000000000..61072745b983 --- /dev/null +++ b/Documentation/devicetree/bindings/media/gpio-ir-receiver.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/gpio-ir-receiver.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GPIO Based IR receiver + +maintainers: + - Sebastian Hesselbarth + +allOf: + - $ref: rc.yaml# + +properties: + compatible: + const: gpio-ir-receiver + + gpios: + maxItems: 1 + + linux,autosuspend-period: + description: autosuspend delay time in milliseconds + $ref: /schemas/types.yaml#/definitions/uint32 + +required: + - compatible + - gpios + +unevaluatedProperties: false + +examples: + - | + ir-receiver { + compatible = "gpio-ir-receiver"; + gpios = <&gpio0 19 1>; + linux,rc-map-name = "rc-rc6-mce"; + linux,autosuspend-period = <125>; + }; +... From 1ce69c35b86038dd11d3a6115a04501c5b89a940 Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Thu, 30 Jun 2022 15:46:45 +0300 Subject: [PATCH 0770/1436] usb: host: xhci: use snprintf() in xhci_decode_trb() Commit cbf286e8ef83 ("xhci: fix unsafe memory usage in xhci tracing") apparently missed one sprintf() call in xhci_decode_trb() -- replace it with the snprintf() call as well... Found by Linux Verification Center (linuxtesting.org) with the SVACE static analysis tool. Fixes: cbf286e8ef83 ("xhci: fix unsafe memory usage in xhci tracing") Signed-off-by: Sergey Shtylyov Signed-off-by: Mathias Nyman Link: https://lore.kernel.org/r/20220630124645.1805902-2-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 28aaf031f9a8..1960b47acfb2 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2417,7 +2417,7 @@ static inline const char *xhci_decode_trb(char *str, size_t size, field3 & TRB_CYCLE ? 'C' : 'c'); break; case TRB_STOP_RING: - sprintf(str, + snprintf(str, size, "%s: slot %d sp %d ep %d flags %c", xhci_trb_type_string(type), TRB_TO_SLOT_ID(field3), From fbd2251d3ee9937ec21762dd7c785877e1c9faaa Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 27 Jun 2022 23:39:50 +0100 Subject: [PATCH 0771/1436] docs: dt: writing-bindings: Update URL to DT schemas The previous URL was giving a 404 error. Signed-off-by: Paul Cercueil Reviewed-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220627223950.35748-1-paul@crapouillou.net --- Documentation/devicetree/bindings/writing-bindings.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/writing-bindings.rst b/Documentation/devicetree/bindings/writing-bindings.rst index 5465eced2af1..1ad081de2dd0 100644 --- a/Documentation/devicetree/bindings/writing-bindings.rst +++ b/Documentation/devicetree/bindings/writing-bindings.rst @@ -53,7 +53,7 @@ Properties - DO use common property unit suffixes for properties with scientific units. Recommended suffixes are listed at - https://github.com/devicetree-org/dt-schema/blob/master/schemas/property-units.yaml + https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/property-units.yaml - DO define properties in terms of constraints. How many entries? What are possible values? What is the order? From f25b0d9dd6d9579294ef43fb8dfad4757b0ed447 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Jun 2022 18:21:41 +0200 Subject: [PATCH 0772/1436] dt-bindings: connector: usb: align example indentation to four-space One DTS example was using 8-space indentation, while others 2-space. For complex DTS with multiple levels, 2-space is not that readable and in DTS examples 4-space is preferred. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220624162141.25890-1-krzysztof.kozlowski@linaro.org --- .../bindings/connector/usb-connector.yaml | 152 +++++++++--------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml index 0420fa563532..ae515651fc6b 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.yaml +++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml @@ -263,11 +263,11 @@ examples: # Micro-USB connector with HS lines routed via controller (MUIC). - | muic-max77843 { - usb_con1: connector { - compatible = "usb-b-connector"; - label = "micro-USB"; - type = "micro"; - }; + usb_con1: connector { + compatible = "usb-b-connector"; + label = "micro-USB"; + type = "micro"; + }; }; # USB-C connector attached to CC controller (s2mm005), HS lines routed @@ -275,34 +275,34 @@ examples: # DisplayPort video lines are routed to the connector via SS mux in USB3 PHY. - | ccic: s2mm005 { - usb_con2: connector { - compatible = "usb-c-connector"; - label = "USB-C"; + usb_con2: connector { + compatible = "usb-c-connector"; + label = "USB-C"; - ports { - #address-cells = <1>; - #size-cells = <0>; + ports { + #address-cells = <1>; + #size-cells = <0>; - port@0 { - reg = <0>; - usb_con_hs: endpoint { - remote-endpoint = <&max77865_usbc_hs>; + port@0 { + reg = <0>; + usb_con_hs: endpoint { + remote-endpoint = <&max77865_usbc_hs>; + }; + }; + port@1 { + reg = <1>; + usb_con_ss: endpoint { + remote-endpoint = <&usbdrd_phy_ss>; + }; + }; + port@2 { + reg = <2>; + usb_con_sbu: endpoint { + remote-endpoint = <&dp_aux>; + }; + }; }; - }; - port@1 { - reg = <1>; - usb_con_ss: endpoint { - remote-endpoint = <&usbdrd_phy_ss>; - }; - }; - port@2 { - reg = <2>; - usb_con_sbu: endpoint { - remote-endpoint = <&dp_aux>; - }; - }; }; - }; }; # USB-C connector attached to a typec port controller(ptn5110), which has @@ -310,16 +310,16 @@ examples: - | #include typec: ptn5110 { - usb_con3: connector { - compatible = "usb-c-connector"; - label = "USB-C"; - power-role = "dual"; - try-power-role = "sink"; - source-pdos = ; - sink-pdos = ; - op-sink-microwatt = <10000000>; - }; + usb_con3: connector { + compatible = "usb-c-connector"; + label = "USB-C"; + power-role = "dual"; + try-power-role = "sink"; + source-pdos = ; + sink-pdos = ; + op-sink-microwatt = <10000000>; + }; }; # USB-C connector attached to SoC and USB3 typec port controller(hd3ss3220) @@ -332,20 +332,20 @@ examples: data-role = "dual"; ports { - #address-cells = <1>; - #size-cells = <0>; - port@0 { - reg = <0>; - hs_ep: endpoint { - remote-endpoint = <&usb3_hs_ep>; - }; + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + hs_ep: endpoint { + remote-endpoint = <&usb3_hs_ep>; }; - port@1 { - reg = <1>; - ss_ep: endpoint { - remote-endpoint = <&hd3ss3220_in_ep>; - }; + }; + port@1 { + reg = <1>; + ss_ep: endpoint { + remote-endpoint = <&hd3ss3220_in_ep>; }; + }; }; }; @@ -354,12 +354,12 @@ examples: #include usb { - connector { - compatible = "gpio-usb-b-connector", "usb-b-connector"; - type = "micro"; - id-gpios = <&pio 12 GPIO_ACTIVE_HIGH>; - vbus-supply = <&usb_p0_vbus>; - }; + connector { + compatible = "gpio-usb-b-connector", "usb-b-connector"; + type = "micro"; + id-gpios = <&pio 12 GPIO_ACTIVE_HIGH>; + vbus-supply = <&usb_p0_vbus>; + }; }; # Micro-USB connector with HS lines routed via controller (MUIC) and MHL @@ -367,27 +367,27 @@ examples: # mobile phone - | muic-max77843 { - usb_con4: connector { - compatible = "samsung,usb-connector-11pin", "usb-b-connector"; - label = "micro-USB"; - type = "micro"; + usb_con4: connector { + compatible = "samsung,usb-connector-11pin", "usb-b-connector"; + label = "micro-USB"; + type = "micro"; - ports { - #address-cells = <1>; - #size-cells = <0>; + ports { + #address-cells = <1>; + #size-cells = <0>; - port@0 { - reg = <0>; - muic_to_usb: endpoint { - remote-endpoint = <&usb_to_muic>; + port@0 { + reg = <0>; + muic_to_usb: endpoint { + remote-endpoint = <&usb_to_muic>; + }; + }; + port@3 { + reg = <3>; + usb_con_mhl: endpoint { + remote-endpoint = <&sii8620_mhl>; + }; + }; }; - }; - port@3 { - reg = <3>; - usb_con_mhl: endpoint { - remote-endpoint = <&sii8620_mhl>; - }; - }; }; - }; }; From c87d8e90bccb835184749621d990f7626c3daf31 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sun, 26 Jun 2022 20:07:34 +0200 Subject: [PATCH 0773/1436] staging: r8188eu: drop return value from receive_disconnect The receive_disconnect function always returns _SUCCESS. None of the callers checks the return value. We can remove it. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220626180734.287137-1-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 5 ++--- drivers/staging/r8188eu/include/rtw_mlme_ext.h | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index cce0575e93b7..fc6e06d7b5ca 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -6191,14 +6191,14 @@ void start_clnt_assoc(struct adapter *padapter) set_link_timer(pmlmeext, REASSOC_TO); } -unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) +void receive_disconnect(struct adapter *padapter, unsigned char *MacAddr, unsigned short reason) { struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; /* check A3 */ if (!(!memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN))) - return _SUCCESS; + return; if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) { if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) { @@ -6209,7 +6209,6 @@ unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr report_join_res(padapter, -2); } } - return _SUCCESS; } static void process_80211d(struct adapter *padapter, struct wlan_bssid_ex *bssid) diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h index 71864733b1c0..56c0e584bb6c 100644 --- a/drivers/staging/r8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h @@ -468,8 +468,7 @@ unsigned int update_MSC_rate(struct HT_caps_element *pHT_caps); void Update_RA_Entry(struct adapter *padapter, u32 mac_id); void set_sta_rate(struct adapter *padapter, struct sta_info *psta); -unsigned int receive_disconnect(struct adapter *padapter, - unsigned char *macaddr, unsigned short reason); +void receive_disconnect(struct adapter *padapter, unsigned char *macaddr, unsigned short reason); unsigned char get_highest_rate_idx(u32 mask); int support_short_GI(struct adapter *padapter, struct HT_caps_element *caps); From d61da1d7a1bf9f6483ec15e9dd3b1023bf293264 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Thu, 30 Jun 2022 08:17:36 +0200 Subject: [PATCH 0774/1436] staging: r8188eu: remove HW_VAR_H2C_MEDIA_STATUS_RPT from SetHwReg8188EU() The HW_VAR_H2C_MEDIA_STATUS_RPT case in SetHwReg8188EU() only calls rtl8188e_set_FwMediaStatus_cmd(). In order to get rid of SetHwReg8188EU() remove the case HW_VAR_H2C_MEDIA_STATUS_RPT and call rtl8188e_set_FwMediaStatus_cmd() directly. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220630061736.9200-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme.c | 4 ++-- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 2 +- drivers/staging/r8188eu/hal/usb_halinit.c | 3 --- drivers/staging/r8188eu/include/hal_intf.h | 1 - 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme.c b/drivers/staging/r8188eu/core/rtw_mlme.c index 56c8bd5f4c60..2705c9d87b14 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme.c +++ b/drivers/staging/r8188eu/core/rtw_mlme.c @@ -1117,7 +1117,7 @@ void rtw_sta_media_status_rpt(struct adapter *adapter, struct sta_info *psta, /* MACID|OPMODE:1 connect */ media_status_rpt = (u16)((psta->mac_id << 8) | mstatus); - SetHwReg8188EU(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status_rpt); + rtl8188e_set_FwMediaStatus_cmd(adapter, media_status_rpt); } void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) @@ -1195,7 +1195,7 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) u16 media_status; media_status = (mac_id << 8) | 0; /* MACID|OPMODE:0 means disconnect */ /* for STA, AP, ADHOC mode, report disconnect stauts to FW */ - SetHwReg8188EU(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); + rtl8188e_set_FwMediaStatus_cmd(adapter, media_status); } if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index fc6e06d7b5ca..21485c57dc3f 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -6708,7 +6708,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) rtw_set_max_rpt_macid(padapter, psta->mac_id); media_status = (psta->mac_id << 8) | 1; /* MACID|OPMODE: 1 means connect */ - SetHwReg8188EU(padapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status); + rtl8188e_set_FwMediaStatus_cmd(padapter, media_status); } mlme_join(padapter, 2); diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index bb3045111147..3908c46d2fbe 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -1235,9 +1235,6 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) } } break; - case HW_VAR_H2C_MEDIA_STATUS_RPT: - rtl8188e_set_FwMediaStatus_cmd(Adapter, (*(__le16 *)val)); - break; default: break; } diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index 0104ee463a10..c3704618bccc 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -18,7 +18,6 @@ enum hw_variables { HW_VAR_DM_FUNC_RESET, HW_VAR_DM_FUNC_CLR, HW_VAR_AMPDU_FACTOR, - HW_VAR_H2C_MEDIA_STATUS_RPT, }; typedef s32 (*c2h_id_filter)(u8 id); From 3355a12760deceb09e1888c5b9ad1f89bf86939b Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 30 Jun 2022 17:09:37 +0800 Subject: [PATCH 0775/1436] staging: r8188eu: remove unneeded semicolon Eliminate the following coccicheck warning: ./drivers/staging/r8188eu/hal/HalPwrSeqCmd.c:70:2-3: Unneeded semicolon Fixes: df8d0a55047b ("staging: r8188eu: make power sequences static") Reviewed-by: Martin Kaiser Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20220630090937.4983-1-yang.lee@linux.alibaba.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/HalPwrSeqCmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c index b5f6d41464db..5b0f66573d94 100644 --- a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c +++ b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c @@ -67,7 +67,7 @@ u8 HalPwrSeqCmdParsing(struct adapter *padapter, enum r8188eu_pwr_seq seq) break; default: return false; - }; + } do { pwrcfgcmd = pwrseqcmd[aryidx]; From 90557fa89d3e99286506593fd5180f699c41b152 Mon Sep 17 00:00:00 2001 From: Herve Codina Date: Fri, 1 Jul 2022 09:09:27 +0200 Subject: [PATCH 0776/1436] dt-bindings: usb: atmel: Add Microchip LAN9662 compatible string The USB device controller available in the Microchip LAN9662 SOC is the same IP as the one present in the SAMA5D3 SOC. Add the LAN9662 compatible string and set the SAMA5D3 compatible string as a fallback for the LAN9662. Signed-off-by: Herve Codina Acked-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20220701070928.459135-3-herve.codina@bootlin.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/atmel-usb.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/atmel-usb.txt b/Documentation/devicetree/bindings/usb/atmel-usb.txt index f512f0290728..12183ef47ee4 100644 --- a/Documentation/devicetree/bindings/usb/atmel-usb.txt +++ b/Documentation/devicetree/bindings/usb/atmel-usb.txt @@ -87,6 +87,9 @@ Required properties: "atmel,at91sam9g45-udc" "atmel,sama5d3-udc" "microchip,sam9x60-udc" + "microchip,lan9662-udc" + For "microchip,lan9662-udc" the fallback "atmel,sama5d3-udc" + is required. - reg: Address and length of the register set for the device - interrupts: Should contain usba interrupt - clocks: Should reference the peripheral and host clocks From c882716b6d411495f221bdd73e9137357c16a3ea Mon Sep 17 00:00:00 2001 From: Liang He Date: Tue, 28 Jun 2022 10:16:40 +0800 Subject: [PATCH 0777/1436] firmware: Hold a reference for of_find_compatible_node() In of_register_trusted_foundations(), we need to hold the reference returned by of_find_compatible_node() and then use it to call of_node_put() for refcount balance. Signed-off-by: Liang He Link: https://lore.kernel.org/r/20220628021640.4015-1-windhl@126.com Signed-off-by: Greg Kroah-Hartman --- include/linux/firmware/trusted_foundations.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/firmware/trusted_foundations.h b/include/linux/firmware/trusted_foundations.h index be5984bda592..931b6c5c72df 100644 --- a/include/linux/firmware/trusted_foundations.h +++ b/include/linux/firmware/trusted_foundations.h @@ -71,12 +71,16 @@ static inline void register_trusted_foundations( static inline void of_register_trusted_foundations(void) { + struct device_node *np = of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations"); + + if (!np) + return; + of_node_put(np); /* * If we find the target should enable TF but does not support it, * fail as the system won't be able to do much anyway */ - if (of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations")) - register_trusted_foundations(NULL); + register_trusted_foundations(NULL); } static inline bool trusted_foundations_registered(void) From 72b5d5aef246a0387cefa23121dd90901c7a691a Mon Sep 17 00:00:00 2001 From: Yushan Zhou Date: Thu, 30 Jun 2022 16:25:12 +0800 Subject: [PATCH 0778/1436] kernfs: fix potential NULL dereference in __kernfs_remove When lockdep is enabled, lockdep_assert_held_write would cause potential NULL pointer dereference. Fix the following smatch warnings: fs/kernfs/dir.c:1353 __kernfs_remove() warn: variable dereferenced before check 'kn' (see line 1346) Fixes: 393c3714081a ("kernfs: switch global kernfs_rwsem lock to per-fs lock") Signed-off-by: Yushan Zhou Link: https://lore.kernel.org/r/20220630082512.3482581-1-zys.zljxml@gmail.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 6eca72cfa1f2..1cc88ba6de90 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -1343,14 +1343,17 @@ static void __kernfs_remove(struct kernfs_node *kn) { struct kernfs_node *pos; + /* Short-circuit if non-root @kn has already finished removal. */ + if (!kn) + return; + lockdep_assert_held_write(&kernfs_root(kn)->kernfs_rwsem); /* - * Short-circuit if non-root @kn has already finished removal. * This is for kernfs_remove_self() which plays with active ref * after removal. */ - if (!kn || (kn->parent && RB_EMPTY_NODE(&kn->rb))) + if (kn->parent && RB_EMPTY_NODE(&kn->rb)) return; pr_debug("kernfs %s: removing\n", kn->name); From ad6c94de2ec453d966f71654cd7dd68cafd03dc3 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Tue, 28 Jun 2022 17:33:54 +0200 Subject: [PATCH 0779/1436] dt-bindings: chosen: remove old .txt binding chosen.txt has been replaced by a schema in dtschema[1] and is now out of date as well. Remove it to avoid confusion. [1] https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/chosen.yaml Link: https://lore.kernel.org/lkml/c8dddfe6-6385-ed34-e789-9f845c8a32bd@linaro.org/ Link: https://lore.kernel.org/lkml/CAL_Jsq+uSdk9YNbUW35yjN3q8-3FDobrxHmBpy=4RKmCfnB0KQ@mail.gmail.com/ Signed-off-by: Jason A. Donenfeld [robh: Improve commmit msg] Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220628153354.870543-1-Jason@zx2c4.com --- Documentation/devicetree/bindings/chosen.txt | 137 ------------------- 1 file changed, 137 deletions(-) delete mode 100644 Documentation/devicetree/bindings/chosen.txt diff --git a/Documentation/devicetree/bindings/chosen.txt b/Documentation/devicetree/bindings/chosen.txt deleted file mode 100644 index 1cc3aa10dcb1..000000000000 --- a/Documentation/devicetree/bindings/chosen.txt +++ /dev/null @@ -1,137 +0,0 @@ -The chosen node ---------------- - -The chosen node does not represent a real device, but serves as a place -for passing data between firmware and the operating system, like boot -arguments. Data in the chosen node does not represent the hardware. - -The following properties are recognized: - - -kaslr-seed ------------ - -This property is used when booting with CONFIG_RANDOMIZE_BASE as the -entropy used to randomize the kernel image base address location. Since -it is used directly, this value is intended only for KASLR, and should -not be used for other purposes (as it may leak information about KASLR -offsets). It is parsed as a u64 value, e.g. - -/ { - chosen { - kaslr-seed = <0xfeedbeef 0xc0def00d>; - }; -}; - -Note that if this property is set from UEFI (or a bootloader in EFI -mode) when EFI_RNG_PROTOCOL is supported, it will be overwritten by -the Linux EFI stub (which will populate the property itself, using -EFI_RNG_PROTOCOL). - -stdout-path ------------ - -Device trees may specify the device to be used for boot console output -with a stdout-path property under /chosen, as described in the Devicetree -Specification, e.g. - -/ { - chosen { - stdout-path = "/serial@f00:115200"; - }; - - serial@f00 { - compatible = "vendor,some-uart"; - reg = <0xf00 0x10>; - }; -}; - -If the character ":" is present in the value, this terminates the path. -The meaning of any characters following the ":" is device-specific, and -must be specified in the relevant binding documentation. - -For UART devices, the preferred binding is a string in the form: - - {{{}}} - -where - - baud - baud rate in decimal - parity - 'n' (none), 'o', (odd) or 'e' (even) - bits - number of data bits - flow - 'r' (rts) - -For example: 115200n8r - -Implementation note: Linux will look for the property "linux,stdout-path" or -on PowerPC "stdout" if "stdout-path" is not found. However, the -"linux,stdout-path" and "stdout" properties are deprecated. New platforms -should only use the "stdout-path" property. - -linux,booted-from-kexec ------------------------ - -This property is set (currently only on PowerPC, and only needed on -book3e) by some versions of kexec-tools to tell the new kernel that it -is being booted by kexec, as the booting environment may differ (e.g. -a different secondary CPU release mechanism) - -linux,usable-memory-range -------------------------- - -This property holds a base address and size, describing a limited region in -which memory may be considered available for use by the kernel. Memory outside -of this range is not available for use. - -This property describes a limitation: memory within this range is only -valid when also described through another mechanism that the kernel -would otherwise use to determine available memory (e.g. memory nodes -or the EFI memory map). Valid memory may be sparse within the range. -e.g. - -/ { - chosen { - linux,usable-memory-range = <0x9 0xf0000000 0x0 0x10000000>; - }; -}; - -The main usage is for crash dump kernel to identify its own usable -memory and exclude, at its boot time, any other memory areas that are -part of the panicked kernel's memory. - -While this property does not represent a real hardware, the address -and the size are expressed in #address-cells and #size-cells, -respectively, of the root node. - -linux,elfcorehdr ----------------- - -This property holds the memory range, the address and the size, of the elf -core header which mainly describes the panicked kernel's memory layout as -PT_LOAD segments of elf format. -e.g. - -/ { - chosen { - linux,elfcorehdr = <0x9 0xfffff000 0x0 0x800>; - }; -}; - -While this property does not represent a real hardware, the address -and the size are expressed in #address-cells and #size-cells, -respectively, of the root node. - -linux,initrd-start and linux,initrd-end ---------------------------------------- - -These properties hold the physical start and end address of an initrd that's -loaded by the bootloader. Note that linux,initrd-start is inclusive, but -linux,initrd-end is exclusive. -e.g. - -/ { - chosen { - linux,initrd-start = <0x82000000>; - linux,initrd-end = <0x82800000>; - }; -}; From e35330f879cf5d202ef5e13005b3505f07373614 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 25 May 2022 20:41:27 -0500 Subject: [PATCH 0780/1436] dt-bindings: watchdog: faraday: Fix typo in example 'timeout-sec' property The 'unevaluatedProperties' schema checks is not fully working and doesn't catch some cases where there's a $ref to another schema. A fix is pending, but results in new warnings in examples. The correct common watchdog property is 'timeout-sec', not 'timeout-secs'. Signed-off-by: Rob Herring Reviewed-by: Linus Walleij Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220526014127.2872254-1-robh@kernel.org --- .../devicetree/bindings/watchdog/faraday,ftwdt010.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml b/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml index ca9e1beff76b..6ecd429f76b5 100644 --- a/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml +++ b/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml @@ -55,7 +55,7 @@ examples: compatible = "faraday,ftwdt010"; reg = <0x41000000 0x1000>; interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; - timeout-secs = <5>; + timeout-sec = <5>; }; - | watchdog: watchdog@98500000 { From eb003bf3ba221bb3d21d1fdcddaa36c158fd2d8f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 24 Jun 2022 20:36:39 +0200 Subject: [PATCH 0781/1436] platform/surface: aggregator: Add helper macros for requests with argument and return value Add helper macros for synchronous stack-allocated Surface Aggregator request with both argument and return value, similar to the current argument-only and return-value-only ones. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220624183642.910893-2-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- include/linux/surface_aggregator/controller.h | 125 ++++++++++++++++++ include/linux/surface_aggregator/device.h | 36 +++++ 2 files changed, 161 insertions(+) diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h index 50a2b4926c06..d11a1c6e3186 100644 --- a/include/linux/surface_aggregator/controller.h +++ b/include/linux/surface_aggregator/controller.h @@ -469,6 +469,67 @@ struct ssam_request_spec_md { return 0; \ } +/** + * SSAM_DEFINE_SYNC_REQUEST_WR() - Define synchronous SAM request function with + * both argument and return value. + * @name: Name of the generated function. + * @atype: Type of the request's argument. + * @rtype: Type of the request's return value. + * @spec: Specification (&struct ssam_request_spec) defining the request. + * + * Defines a function executing the synchronous SAM request specified by @spec, + * with the request taking an argument of type @atype and having a return value + * of type @rtype. The generated function takes care of setting up the request + * and response structs, buffer allocation, as well as execution of the request + * itself, returning once the request has been fully completed. The required + * transport buffer will be allocated on the stack. + * + * The generated function is defined as ``static int name(struct + * ssam_controller *ctrl, const atype *arg, rtype *ret)``, returning the status + * of the request, which is zero on success and negative on failure. The + * ``ctrl`` parameter is the controller via which the request is sent. The + * request argument is specified via the ``arg`` pointer. The request's return + * value is written to the memory pointed to by the ``ret`` parameter. + * + * Refer to ssam_request_sync_onstack() for more details on the behavior of + * the generated function. + */ +#define SSAM_DEFINE_SYNC_REQUEST_WR(name, atype, rtype, spec...) \ + static int name(struct ssam_controller *ctrl, const atype *arg, rtype *ret) \ + { \ + struct ssam_request_spec s = (struct ssam_request_spec)spec; \ + struct ssam_request rqst; \ + struct ssam_response rsp; \ + int status; \ + \ + rqst.target_category = s.target_category; \ + rqst.target_id = s.target_id; \ + rqst.command_id = s.command_id; \ + rqst.instance_id = s.instance_id; \ + rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE; \ + rqst.length = sizeof(atype); \ + rqst.payload = (u8 *)arg; \ + \ + rsp.capacity = sizeof(rtype); \ + rsp.length = 0; \ + rsp.pointer = (u8 *)ret; \ + \ + status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \ + if (status) \ + return status; \ + \ + if (rsp.length != sizeof(rtype)) { \ + struct device *dev = ssam_controller_device(ctrl); \ + dev_err(dev, \ + "rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \ + sizeof(rtype), rsp.length, rqst.target_category,\ + rqst.command_id); \ + return -EIO; \ + } \ + \ + return 0; \ + } + /** * SSAM_DEFINE_SYNC_REQUEST_MD_N() - Define synchronous multi-device SAM * request function with neither argument nor return value. @@ -613,6 +674,70 @@ struct ssam_request_spec_md { return 0; \ } +/** + * SSAM_DEFINE_SYNC_REQUEST_MD_WR() - Define synchronous multi-device SAM + * request function with both argument and return value. + * @name: Name of the generated function. + * @atype: Type of the request's argument. + * @rtype: Type of the request's return value. + * @spec: Specification (&struct ssam_request_spec_md) defining the request. + * + * Defines a function executing the synchronous SAM request specified by @spec, + * with the request taking an argument of type @atype and having a return value + * of type @rtype. Device specifying parameters are not hard-coded, but instead + * must be provided to the function. The generated function takes care of + * setting up the request and response structs, buffer allocation, as well as + * execution of the request itself, returning once the request has been fully + * completed. The required transport buffer will be allocated on the stack. + * + * The generated function is defined as ``static int name(struct + * ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg, rtype *ret)``, + * returning the status of the request, which is zero on success and negative + * on failure. The ``ctrl`` parameter is the controller via which the request + * is sent, ``tid`` the target ID for the request, and ``iid`` the instance ID. + * The request argument is specified via the ``arg`` pointer. The request's + * return value is written to the memory pointed to by the ``ret`` parameter. + * + * Refer to ssam_request_sync_onstack() for more details on the behavior of + * the generated function. + */ +#define SSAM_DEFINE_SYNC_REQUEST_MD_WR(name, atype, rtype, spec...) \ + static int name(struct ssam_controller *ctrl, u8 tid, u8 iid, \ + const atype *arg, rtype *ret) \ + { \ + struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \ + struct ssam_request rqst; \ + struct ssam_response rsp; \ + int status; \ + \ + rqst.target_category = s.target_category; \ + rqst.target_id = tid; \ + rqst.command_id = s.command_id; \ + rqst.instance_id = iid; \ + rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE; \ + rqst.length = sizeof(atype); \ + rqst.payload = (u8 *)arg; \ + \ + rsp.capacity = sizeof(rtype); \ + rsp.length = 0; \ + rsp.pointer = (u8 *)ret; \ + \ + status = ssam_request_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \ + if (status) \ + return status; \ + \ + if (rsp.length != sizeof(rtype)) { \ + struct device *dev = ssam_controller_device(ctrl); \ + dev_err(dev, \ + "rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \ + sizeof(rtype), rsp.length, rqst.target_category,\ + rqst.command_id); \ + return -EIO; \ + } \ + \ + return 0; \ + } + /* -- Event notifier/callbacks. --------------------------------------------- */ diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index c418f7f2732d..6cf7e80312d5 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -483,6 +483,42 @@ static inline void ssam_remove_clients(struct device *dev) {} sdev->uid.instance, ret); \ } +/** + * SSAM_DEFINE_SYNC_REQUEST_CL_WR() - Define synchronous client-device SAM + * request function with argument and return value. + * @name: Name of the generated function. + * @atype: Type of the request's argument. + * @rtype: Type of the request's return value. + * @spec: Specification (&struct ssam_request_spec_md) defining the request. + * + * Defines a function executing the synchronous SAM request specified by @spec, + * with the request taking an argument of type @atype and having a return value + * of type @rtype. Device specifying parameters are not hard-coded, but instead + * are provided via the client device, specifically its UID, supplied when + * calling this function. The generated function takes care of setting up the + * request struct, buffer allocation, as well as execution of the request + * itself, returning once the request has been fully completed. The required + * transport buffer will be allocated on the stack. + * + * The generated function is defined as ``static int name(struct ssam_device + * *sdev, const atype *arg, rtype *ret)``, returning the status of the request, + * which is zero on success and negative on failure. The ``sdev`` parameter + * specifies both the target device of the request and by association the + * controller via which the request is sent. The request's argument is + * specified via the ``arg`` pointer. The request's return value is written to + * the memory pointed to by the ``ret`` parameter. + * + * Refer to ssam_request_sync_onstack() for more details on the behavior of + * the generated function. + */ +#define SSAM_DEFINE_SYNC_REQUEST_CL_WR(name, atype, rtype, spec...) \ + SSAM_DEFINE_SYNC_REQUEST_MD_WR(__raw_##name, atype, rtype, spec) \ + static int name(struct ssam_device *sdev, const atype *arg, rtype *ret) \ + { \ + return __raw_##name(sdev->ctrl, sdev->uid.target, \ + sdev->uid.instance, arg, ret); \ + } + /* -- Helpers for client-device notifiers. ---------------------------------- */ From 9f794056db5bb1e1add83ed553b6aec57298358c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 24 Jun 2022 20:36:40 +0200 Subject: [PATCH 0782/1436] platform/surface: Add KIP/POS tablet-mode switch driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a driver providing a tablet-mode switch input device for Microsoft Surface devices using the Surface Aggregator KIP subsystem (to manage detachable peripherals) or POS subsystem (to obtain device posture information). The KIP (full name unknown, abbreviation found through reverse engineering) subsystem is used on the Surface Pro 8 and Surface Pro X to manage the keyboard cover. Among other things, it provides information on the positioning (posture) of the cover (closed, laptop-style, detached, folded-back, ...), which can be used to implement an input device providing the SW_TABLET_MODE event. Similarly, the POS (posture information) subsystem provides such information on the Surface Laptop Studio, with the difference being that the keyboard is not detachable. As implementing the tablet-mode switch for both subsystems is largely similar, the driver proposed in this commit, in large, acts as a generic tablet mode switch driver framework for the Surface Aggregator Module. Specific implementations using this framework are provided for the KIP and POS subsystems, adding tablet-mode switch support to the aforementioned devices. A few more notes on the Surface Laptop Studio: A peculiarity of the Surface Laptop Studio is its "slate/tent" mode (symbolized: user> _/\). In this mode, the screen covers the keyboard but leaves the touchpad exposed. This is essentially a mode in-between tablet and laptop, and it is debatable whether tablet-mode should be enabled in this mode. We therefore let the user decide this via a module parameter. In particular, tablet-mode may bring up the on-screen touch keyboard more easily, which would be desirable in this mode. However, some user-space software currently also decides to disable keyboard and, more importantly, touchpad input, while the touchpad is still accessible in the "slate/tent" mode. Furthermore, this mode shares its identifier with "slate/flipped" mode where the screen is flipped 180° and the keyboard points away from the user (symbolized: user> /_). In this mode we would like to enable auto-rotation, something that user-space software may only do when tablet-mode is enabled. We therefore default to the slate-mode enabling the tablet-mode switch. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220624183642.910893-3-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../sysfs-bus-surface_aggregator-tabletsw | 57 ++ MAINTAINERS | 6 + drivers/platform/surface/Kconfig | 23 + drivers/platform/surface/Makefile | 1 + .../surface/surface_aggregator_tabletsw.c | 533 ++++++++++++++++++ 5 files changed, 620 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-surface_aggregator-tabletsw create mode 100644 drivers/platform/surface/surface_aggregator_tabletsw.c diff --git a/Documentation/ABI/testing/sysfs-bus-surface_aggregator-tabletsw b/Documentation/ABI/testing/sysfs-bus-surface_aggregator-tabletsw new file mode 100644 index 000000000000..74cd9d754e60 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-surface_aggregator-tabletsw @@ -0,0 +1,57 @@ +What: /sys/bus/surface_aggregator/devices/01:0e:01:00:01/state +Date: July 2022 +KernelVersion: 5.20 +Contact: Maximilian Luz +Description: + This attribute returns a string with the current type-cover + or device posture, as indicated by the embedded controller. + Currently returned posture states are: + + - "disconnected": The type-cover has been disconnected. + + - "closed": The type-cover has been folded closed and lies on + top of the display. + + - "laptop": The type-cover is open and in laptop-mode, i.e., + ready for normal use. + + - "folded-canvas": The type-cover has been folded back + part-ways, but does not lie flush with the back side of the + device. In general, this means that the kick-stand is used + and extended atop of the cover. + + - "folded-back": The type cover has been fully folded back and + lies flush with the back side of the device. + + - "": The current state is unknown to the driver, for + example due to newer as-of-yet unsupported hardware. + + New states may be introduced with new hardware. Users therefore + must not rely on this list of states being exhaustive and + gracefully handle unknown states. + +What: /sys/bus/surface_aggregator/devices/01:26:01:00:01/state +Date: July 2022 +KernelVersion: 5.20 +Contact: Maximilian Luz +Description: + This attribute returns a string with the current device posture, as indicated by the embedded controller. Currently + returned posture states are: + + - "closed": The lid of the device is closed. + + - "laptop": The lid of the device is opened and the device + operates as a normal laptop. + + - "slate": The screen covers the keyboard or has been flipped + back and the device operates mainly based on touch input. + + - "tablet": The device operates as tablet and exclusively + relies on touch input (or external peripherals). + + - "": The current state is unknown to the driver, for + example due to newer as-of-yet unsupported hardware. + + New states may be introduced with new hardware. Users therefore + must not rely on this list of states being exhaustive and + gracefully handle unknown states. diff --git a/MAINTAINERS b/MAINTAINERS index 2a34deb24594..c6d8c0c6bf6e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13176,6 +13176,12 @@ F: drivers/scsi/smartpqi/smartpqi*.[ch] F: include/linux/cciss*.h F: include/uapi/linux/cciss*.h +MICROSOFT SURFACE AGGREGATOR TABLET-MODE SWITCH +M: Maximilian Luz +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/surface/surface_aggregator_tablet_switch.c + MICROSOFT SURFACE BATTERY AND AC DRIVERS M: Maximilian Luz L: linux-pm@vger.kernel.org diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig index eb79fbed8059..b152e930cc84 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -99,6 +99,29 @@ config SURFACE_AGGREGATOR_REGISTRY the respective client devices. Drivers for these devices still need to be selected via the other options. +config SURFACE_AGGREGATOR_TABLET_SWITCH + tristate "Surface Aggregator Generic Tablet-Mode Switch Driver" + depends on SURFACE_AGGREGATOR + depends on SURFACE_AGGREGATOR_BUS + depends on INPUT + help + Provides a tablet-mode switch input device on Microsoft Surface models + using the KIP subsystem for detachable keyboards (e.g. keyboard covers) + or the POS subsystem for device/screen posture changes. + + The KIP subsystem is used on newer Surface generations to handle + detachable input peripherals, specifically the keyboard cover (containing + keyboard and touchpad) on the Surface Pro 8 and Surface Pro X. The POS + subsystem is used for device posture change notifications on the Surface + Laptop Studio. This module provides a driver to let user-space know when + the device should be considered in tablet-mode due to the keyboard cover + being detached or folded back (essentially signaling when the keyboard is + not available for input). It does so by creating a tablet-mode switch + input device, sending the standard SW_TABLET_MODE event on mode change. + + Select M or Y here, if you want to provide tablet-mode switch input + events on the Surface Pro 8, Surface Pro X, and Surface Laptop Studio. + config SURFACE_DTX tristate "Surface DTX (Detachment System) Driver" depends on SURFACE_AGGREGATOR diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile index 0fc9cd3e4dd9..18b27898543e 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o +obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o obj-$(CONFIG_SURFACE_HOTPLUG) += surface_hotplug.o diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c new file mode 100644 index 000000000000..596ca6c80681 --- /dev/null +++ b/drivers/platform/surface/surface_aggregator_tabletsw.c @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface System Aggregator Module (SSAM) tablet mode switch driver. + * + * Copyright (C) 2022 Maximilian Luz + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* -- SSAM generic tablet switch driver framework. -------------------------- */ + +struct ssam_tablet_sw; + +struct ssam_tablet_sw_ops { + int (*get_state)(struct ssam_tablet_sw *sw, u32 *state); + const char *(*state_name)(struct ssam_tablet_sw *sw, u32 state); + bool (*state_is_tablet_mode)(struct ssam_tablet_sw *sw, u32 state); +}; + +struct ssam_tablet_sw { + struct ssam_device *sdev; + + u32 state; + struct work_struct update_work; + struct input_dev *mode_switch; + + struct ssam_tablet_sw_ops ops; + struct ssam_event_notifier notif; +}; + +struct ssam_tablet_sw_desc { + struct { + const char *name; + const char *phys; + } dev; + + struct { + u32 (*notify)(struct ssam_event_notifier *nf, const struct ssam_event *event); + int (*get_state)(struct ssam_tablet_sw *sw, u32 *state); + const char *(*state_name)(struct ssam_tablet_sw *sw, u32 state); + bool (*state_is_tablet_mode)(struct ssam_tablet_sw *sw, u32 state); + } ops; + + struct { + struct ssam_event_registry reg; + struct ssam_event_id id; + enum ssam_event_mask mask; + u8 flags; + } event; +}; + +static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct ssam_tablet_sw *sw = dev_get_drvdata(dev); + const char *state = sw->ops.state_name(sw, sw->state); + + return sysfs_emit(buf, "%s\n", state); +} +static DEVICE_ATTR_RO(state); + +static struct attribute *ssam_tablet_sw_attrs[] = { + &dev_attr_state.attr, + NULL, +}; + +static const struct attribute_group ssam_tablet_sw_group = { + .attrs = ssam_tablet_sw_attrs, +}; + +static void ssam_tablet_sw_update_workfn(struct work_struct *work) +{ + struct ssam_tablet_sw *sw = container_of(work, struct ssam_tablet_sw, update_work); + int tablet, status; + u32 state; + + status = sw->ops.get_state(sw, &state); + if (status) + return; + + if (sw->state == state) + return; + sw->state = state; + + /* Send SW_TABLET_MODE event. */ + tablet = sw->ops.state_is_tablet_mode(sw, state); + input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet); + input_sync(sw->mode_switch); +} + +static int __maybe_unused ssam_tablet_sw_resume(struct device *dev) +{ + struct ssam_tablet_sw *sw = dev_get_drvdata(dev); + + schedule_work(&sw->update_work); + return 0; +} +static SIMPLE_DEV_PM_OPS(ssam_tablet_sw_pm_ops, NULL, ssam_tablet_sw_resume); + +static int ssam_tablet_sw_probe(struct ssam_device *sdev) +{ + const struct ssam_tablet_sw_desc *desc; + struct ssam_tablet_sw *sw; + int tablet, status; + + desc = ssam_device_get_match_data(sdev); + if (!desc) { + WARN(1, "no driver match data specified"); + return -EINVAL; + } + + sw = devm_kzalloc(&sdev->dev, sizeof(*sw), GFP_KERNEL); + if (!sw) + return -ENOMEM; + + sw->sdev = sdev; + + sw->ops.get_state = desc->ops.get_state; + sw->ops.state_name = desc->ops.state_name; + sw->ops.state_is_tablet_mode = desc->ops.state_is_tablet_mode; + + INIT_WORK(&sw->update_work, ssam_tablet_sw_update_workfn); + + ssam_device_set_drvdata(sdev, sw); + + /* Get initial state. */ + status = sw->ops.get_state(sw, &sw->state); + if (status) + return status; + + /* Set up tablet mode switch. */ + sw->mode_switch = devm_input_allocate_device(&sdev->dev); + if (!sw->mode_switch) + return -ENOMEM; + + sw->mode_switch->name = desc->dev.name; + sw->mode_switch->phys = desc->dev.phys; + sw->mode_switch->id.bustype = BUS_HOST; + sw->mode_switch->dev.parent = &sdev->dev; + + tablet = sw->ops.state_is_tablet_mode(sw, sw->state); + input_set_capability(sw->mode_switch, EV_SW, SW_TABLET_MODE); + input_report_switch(sw->mode_switch, SW_TABLET_MODE, tablet); + + status = input_register_device(sw->mode_switch); + if (status) + return status; + + /* Set up notifier. */ + sw->notif.base.priority = 0; + sw->notif.base.fn = desc->ops.notify; + sw->notif.event.reg = desc->event.reg; + sw->notif.event.id = desc->event.id; + sw->notif.event.mask = desc->event.mask; + sw->notif.event.flags = SSAM_EVENT_SEQUENCED; + + status = ssam_device_notifier_register(sdev, &sw->notif); + if (status) + return status; + + status = sysfs_create_group(&sdev->dev.kobj, &ssam_tablet_sw_group); + if (status) + goto err; + + /* We might have missed events during setup, so check again. */ + schedule_work(&sw->update_work); + return 0; + +err: + ssam_device_notifier_unregister(sdev, &sw->notif); + cancel_work_sync(&sw->update_work); + return status; +} + +static void ssam_tablet_sw_remove(struct ssam_device *sdev) +{ + struct ssam_tablet_sw *sw = ssam_device_get_drvdata(sdev); + + sysfs_remove_group(&sdev->dev.kobj, &ssam_tablet_sw_group); + + ssam_device_notifier_unregister(sdev, &sw->notif); + cancel_work_sync(&sw->update_work); +} + + +/* -- SSAM KIP tablet switch implementation. -------------------------------- */ + +#define SSAM_EVENT_KIP_CID_COVER_STATE_CHANGED 0x1d + +enum ssam_kip_cover_state { + SSAM_KIP_COVER_STATE_DISCONNECTED = 0x01, + SSAM_KIP_COVER_STATE_CLOSED = 0x02, + SSAM_KIP_COVER_STATE_LAPTOP = 0x03, + SSAM_KIP_COVER_STATE_FOLDED_CANVAS = 0x04, + SSAM_KIP_COVER_STATE_FOLDED_BACK = 0x05, +}; + +static const char *ssam_kip_cover_state_name(struct ssam_tablet_sw *sw, u32 state) +{ + switch (state) { + case SSAM_KIP_COVER_STATE_DISCONNECTED: + return "disconnected"; + + case SSAM_KIP_COVER_STATE_CLOSED: + return "closed"; + + case SSAM_KIP_COVER_STATE_LAPTOP: + return "laptop"; + + case SSAM_KIP_COVER_STATE_FOLDED_CANVAS: + return "folded-canvas"; + + case SSAM_KIP_COVER_STATE_FOLDED_BACK: + return "folded-back"; + + default: + dev_warn(&sw->sdev->dev, "unknown KIP cover state: %u\n", state); + return ""; + } +} + +static bool ssam_kip_cover_state_is_tablet_mode(struct ssam_tablet_sw *sw, u32 state) +{ + switch (state) { + case SSAM_KIP_COVER_STATE_DISCONNECTED: + case SSAM_KIP_COVER_STATE_FOLDED_CANVAS: + case SSAM_KIP_COVER_STATE_FOLDED_BACK: + return true; + + case SSAM_KIP_COVER_STATE_CLOSED: + case SSAM_KIP_COVER_STATE_LAPTOP: + return false; + + default: + dev_warn(&sw->sdev->dev, "unknown KIP cover state: %d\n", sw->state); + return true; + } +} + +SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_cover_state, u8, { + .target_category = SSAM_SSH_TC_KIP, + .target_id = 0x01, + .command_id = 0x1d, + .instance_id = 0x00, +}); + +static int ssam_kip_get_cover_state(struct ssam_tablet_sw *sw, u32 *state) +{ + int status; + u8 raw; + + status = ssam_retry(__ssam_kip_get_cover_state, sw->sdev->ctrl, &raw); + if (status < 0) { + dev_err(&sw->sdev->dev, "failed to query KIP lid state: %d\n", status); + return status; + } + + *state = raw; + return 0; +} + +static u32 ssam_kip_sw_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) +{ + struct ssam_tablet_sw *sw = container_of(nf, struct ssam_tablet_sw, notif); + + if (event->command_id != SSAM_EVENT_KIP_CID_COVER_STATE_CHANGED) + return 0; /* Return "unhandled". */ + + if (event->length < 1) + dev_warn(&sw->sdev->dev, "unexpected payload size: %u\n", event->length); + + schedule_work(&sw->update_work); + return SSAM_NOTIF_HANDLED; +} + +static const struct ssam_tablet_sw_desc ssam_kip_sw_desc = { + .dev = { + .name = "Microsoft Surface KIP Tablet Mode Switch", + .phys = "ssam/01:0e:01:00:01/input0", + }, + .ops = { + .notify = ssam_kip_sw_notif, + .get_state = ssam_kip_get_cover_state, + .state_name = ssam_kip_cover_state_name, + .state_is_tablet_mode = ssam_kip_cover_state_is_tablet_mode, + }, + .event = { + .reg = SSAM_EVENT_REGISTRY_SAM, + .id = { + .target_category = SSAM_SSH_TC_KIP, + .instance = 0, + }, + .mask = SSAM_EVENT_MASK_TARGET, + }, +}; + + +/* -- SSAM POS tablet switch implementation. -------------------------------- */ + +static bool tablet_mode_in_slate_state = true; +module_param(tablet_mode_in_slate_state, bool, 0644); +MODULE_PARM_DESC(tablet_mode_in_slate_state, "Enable tablet mode in slate device posture, default is 'true'"); + +#define SSAM_EVENT_POS_CID_POSTURE_CHANGED 0x03 +#define SSAM_POS_MAX_SOURCES 4 + +enum ssam_pos_state { + SSAM_POS_POSTURE_LID_CLOSED = 0x00, + SSAM_POS_POSTURE_LAPTOP = 0x01, + SSAM_POS_POSTURE_SLATE = 0x02, + SSAM_POS_POSTURE_TABLET = 0x03, +}; + +struct ssam_sources_list { + __le32 count; + __le32 id[SSAM_POS_MAX_SOURCES]; +} __packed; + +static const char *ssam_pos_state_name(struct ssam_tablet_sw *sw, u32 state) +{ + switch (state) { + case SSAM_POS_POSTURE_LID_CLOSED: + return "closed"; + + case SSAM_POS_POSTURE_LAPTOP: + return "laptop"; + + case SSAM_POS_POSTURE_SLATE: + return "slate"; + + case SSAM_POS_POSTURE_TABLET: + return "tablet"; + + default: + dev_warn(&sw->sdev->dev, "unknown device posture: %u\n", state); + return ""; + } +} + +static bool ssam_pos_state_is_tablet_mode(struct ssam_tablet_sw *sw, u32 state) +{ + switch (state) { + case SSAM_POS_POSTURE_LAPTOP: + case SSAM_POS_POSTURE_LID_CLOSED: + return false; + + case SSAM_POS_POSTURE_SLATE: + return tablet_mode_in_slate_state; + + case SSAM_POS_POSTURE_TABLET: + return true; + + default: + dev_warn(&sw->sdev->dev, "unknown device posture: %u\n", state); + return true; + } +} + +static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sources_list *sources) +{ + struct ssam_request rqst; + struct ssam_response rsp; + int status; + + rqst.target_category = SSAM_SSH_TC_POS; + rqst.target_id = 0x01; + rqst.command_id = 0x01; + rqst.instance_id = 0x00; + rqst.flags = SSAM_REQUEST_HAS_RESPONSE; + rqst.length = 0; + rqst.payload = NULL; + + rsp.capacity = sizeof(*sources); + rsp.length = 0; + rsp.pointer = (u8 *)sources; + + status = ssam_retry(ssam_request_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0); + if (status) + return status; + + /* We need at least the 'sources->count' field. */ + if (rsp.length < sizeof(__le32)) { + dev_err(&sw->sdev->dev, "received source list response is too small\n"); + return -EPROTO; + } + + /* Make sure 'sources->count' matches with the response length. */ + if (get_unaligned_le32(&sources->count) * sizeof(__le32) + sizeof(__le32) != rsp.length) { + dev_err(&sw->sdev->dev, "mismatch between number of sources and response size\n"); + return -EPROTO; + } + + return 0; +} + +static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id) +{ + struct ssam_sources_list sources = {}; + int status; + + status = ssam_pos_get_sources_list(sw, &sources); + if (status) + return status; + + if (sources.count == 0) { + dev_err(&sw->sdev->dev, "no posture sources found\n"); + return -ENODEV; + } + + /* + * We currently don't know what to do with more than one posture + * source. At the moment, only one source seems to be used/provided. + * The WARN_ON() here should hopefully let us know quickly once there + * is a device that provides multiple sources, at which point we can + * then try to figure out how to handle them. + */ + WARN_ON(sources.count > 1); + + *source_id = get_unaligned_le32(&sources.id[0]); + return 0; +} + +SSAM_DEFINE_SYNC_REQUEST_WR(__ssam_pos_get_posture_for_source, __le32, __le32, { + .target_category = SSAM_SSH_TC_POS, + .target_id = 0x01, + .command_id = 0x02, + .instance_id = 0x00, +}); + +static int ssam_pos_get_posture_for_source(struct ssam_tablet_sw *sw, u32 source_id, u32 *posture) +{ + __le32 source_le = cpu_to_le32(source_id); + __le32 rspval_le = 0; + int status; + + status = ssam_retry(__ssam_pos_get_posture_for_source, sw->sdev->ctrl, + &source_le, &rspval_le); + if (status) + return status; + + *posture = le32_to_cpu(rspval_le); + return 0; +} + +static int ssam_pos_get_posture(struct ssam_tablet_sw *sw, u32 *state) +{ + u32 source_id; + int status; + + status = ssam_pos_get_source(sw, &source_id); + if (status) { + dev_err(&sw->sdev->dev, "failed to get posture source ID: %d\n", status); + return status; + } + + status = ssam_pos_get_posture_for_source(sw, source_id, state); + if (status) { + dev_err(&sw->sdev->dev, "failed to get posture value for source %u: %d\n", + source_id, status); + return status; + } + + return 0; +} + +static u32 ssam_pos_sw_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) +{ + struct ssam_tablet_sw *sw = container_of(nf, struct ssam_tablet_sw, notif); + + if (event->command_id != SSAM_EVENT_POS_CID_POSTURE_CHANGED) + return 0; /* Return "unhandled". */ + + if (event->length != sizeof(__le32) * 3) + dev_warn(&sw->sdev->dev, "unexpected payload size: %u\n", event->length); + + schedule_work(&sw->update_work); + return SSAM_NOTIF_HANDLED; +} + +static const struct ssam_tablet_sw_desc ssam_pos_sw_desc = { + .dev = { + .name = "Microsoft Surface POS Tablet Mode Switch", + .phys = "ssam/01:26:01:00:01/input0", + }, + .ops = { + .notify = ssam_pos_sw_notif, + .get_state = ssam_pos_get_posture, + .state_name = ssam_pos_state_name, + .state_is_tablet_mode = ssam_pos_state_is_tablet_mode, + }, + .event = { + .reg = SSAM_EVENT_REGISTRY_SAM, + .id = { + .target_category = SSAM_SSH_TC_POS, + .instance = 0, + }, + .mask = SSAM_EVENT_MASK_TARGET, + }, +}; + + +/* -- Driver registration. -------------------------------------------------- */ + +static const struct ssam_device_id ssam_tablet_sw_match[] = { + { SSAM_SDEV(KIP, 0x01, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc }, + { SSAM_SDEV(POS, 0x01, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc }, + { }, +}; +MODULE_DEVICE_TABLE(ssam, ssam_tablet_sw_match); + +static struct ssam_device_driver ssam_tablet_sw_driver = { + .probe = ssam_tablet_sw_probe, + .remove = ssam_tablet_sw_remove, + .match_table = ssam_tablet_sw_match, + .driver = { + .name = "surface_aggregator_tablet_mode_switch", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &ssam_tablet_sw_pm_ops, + }, +}; +module_ssam_device_driver(ssam_tablet_sw_driver); + +MODULE_AUTHOR("Maximilian Luz "); +MODULE_DESCRIPTION("Tablet mode switch driver for Surface devices using the Surface Aggregator Module"); +MODULE_LICENSE("GPL"); From f9eb5c4babed86197000a12068245b40fd639747 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 24 Jun 2022 20:36:41 +0200 Subject: [PATCH 0783/1436] platform/surface: aggregator_registry: Add support for tablet mode switch on Surface Pro 8 Add a KIP subsystem tablet-mode switch device for the Surface Pro 8. The respective driver for this device provides SW_TABLET_MODE input events for user-space based on the state of the keyboard cover (e.g. detached, folded-back, normal/laptop mode). Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220624183642.910893-4-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_registry.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index bf3303f1aa71..8f249df673a4 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -77,6 +77,12 @@ static const struct software_node ssam_node_tmp_pprof = { .parent = &ssam_node_root, }; +/* Tablet-mode switch via KIP subsystem. */ +static const struct software_node ssam_node_kip_tablet_switch = { + .name = "ssam:01:0e:01:00:01", + .parent = &ssam_node_root, +}; + /* DTX / detachment-system device (Surface Book 3). */ static const struct software_node ssam_node_bas_dtx = { .name = "ssam:01:11:01:00:00", @@ -264,11 +270,11 @@ static const struct software_node *ssam_node_group_sp8[] = { &ssam_node_bat_ac, &ssam_node_bat_main, &ssam_node_tmp_pprof, + &ssam_node_kip_tablet_switch, &ssam_node_hid_kip_keyboard, &ssam_node_hid_kip_penstash, &ssam_node_hid_kip_touchpad, &ssam_node_hid_kip_iid5, - /* TODO: Add support for tablet mode switch. */ NULL, }; From 70e85eb071a118c13b690df595bd8129e9fbbe79 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 24 Jun 2022 20:36:42 +0200 Subject: [PATCH 0784/1436] platform/surface: aggregator_registry: Add support for tablet mode switch on Surface Laptop Studio Add a POS subsystem tablet-mode switch device for the Surface Laptop Studio. The respective driver for this device provides SW_TABLET_MODE input events for user-space based on the posture of the screen. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220624183642.910893-5-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_registry.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 8f249df673a4..f1c5905f1c16 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -191,6 +191,12 @@ static const struct software_node ssam_node_hid_kip_iid5 = { .parent = &ssam_node_hub_kip, }; +/* Tablet-mode switch via POS subsystem. */ +static const struct software_node ssam_node_pos_tablet_switch = { + .name = "ssam:01:26:01:00:01", + .parent = &ssam_node_root, +}; + /* * Devices for 5th- and 6th-generations models: * - Surface Book 2, @@ -237,6 +243,7 @@ static const struct software_node *ssam_node_group_sls[] = { &ssam_node_bat_ac, &ssam_node_bat_main, &ssam_node_tmp_pprof, + &ssam_node_pos_tablet_switch, &ssam_node_hid_tid1_keyboard, &ssam_node_hid_tid1_penstash, &ssam_node_hid_tid1_touchpad, From 4a4ab610b8ae912c28a4fd28442ef24ed7a1a5bd Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 24 Jun 2022 22:57:58 +0200 Subject: [PATCH 0785/1436] platform/surface: aggregator: Move device registry helper functions to core module Move helper functions for client device registration to the core module. This simplifies addition of future DT/OF support and also allows us to split out the device hub drivers into their own module. At the same time, also improve device node validation a bit by not silently skipping devices with invalid device UID specifiers. Further, ensure proper lifetime management for the firmware/software nodes associated with the added devices. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220624205800.1355621-2-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/aggregator/bus.c | 149 ++++++++++++++++-- .../surface/surface_aggregator_registry.c | 75 +-------- include/linux/surface_aggregator/device.h | 52 ++++++ 3 files changed, 187 insertions(+), 89 deletions(-) diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c index abbbb5b08b07..e0b0381a2834 100644 --- a/drivers/platform/surface/aggregator/bus.c +++ b/drivers/platform/surface/aggregator/bus.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -14,6 +15,9 @@ #include "bus.h" #include "controller.h" + +/* -- Device and bus functions. --------------------------------------------- */ + static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -46,6 +50,7 @@ static void ssam_device_release(struct device *dev) struct ssam_device *sdev = to_ssam_device(dev); ssam_controller_put(sdev->ctrl); + fwnode_handle_put(sdev->dev.fwnode); kfree(sdev); } @@ -363,6 +368,134 @@ void ssam_device_driver_unregister(struct ssam_device_driver *sdrv) } EXPORT_SYMBOL_GPL(ssam_device_driver_unregister); + +/* -- Bus registration. ----------------------------------------------------- */ + +/** + * ssam_bus_register() - Register and set-up the SSAM client device bus. + */ +int ssam_bus_register(void) +{ + return bus_register(&ssam_bus_type); +} + +/** + * ssam_bus_unregister() - Unregister the SSAM client device bus. + */ +void ssam_bus_unregister(void) +{ + return bus_unregister(&ssam_bus_type); +} + + +/* -- Helpers for controller and hub devices. ------------------------------- */ + +static int ssam_device_uid_from_string(const char *str, struct ssam_device_uid *uid) +{ + u8 d, tc, tid, iid, fn; + int n; + + n = sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx", &d, &tc, &tid, &iid, &fn); + if (n != 5) + return -EINVAL; + + uid->domain = d; + uid->category = tc; + uid->target = tid; + uid->instance = iid; + uid->function = fn; + + return 0; +} + +static int ssam_get_uid_for_node(struct fwnode_handle *node, struct ssam_device_uid *uid) +{ + const char *str = fwnode_get_name(node); + + /* + * To simplify definitions of firmware nodes, we set the device name + * based on the UID of the device, prefixed with "ssam:". + */ + if (strncmp(str, "ssam:", strlen("ssam:")) != 0) + return -ENODEV; + + str += strlen("ssam:"); + return ssam_device_uid_from_string(str, uid); +} + +static int ssam_add_client_device(struct device *parent, struct ssam_controller *ctrl, + struct fwnode_handle *node) +{ + struct ssam_device_uid uid; + struct ssam_device *sdev; + int status; + + status = ssam_get_uid_for_node(node, &uid); + if (status) + return status; + + sdev = ssam_device_alloc(ctrl, uid); + if (!sdev) + return -ENOMEM; + + sdev->dev.parent = parent; + sdev->dev.fwnode = fwnode_handle_get(node); + + status = ssam_device_add(sdev); + if (status) + ssam_device_put(sdev); + + return status; +} + +/** + * __ssam_register_clients() - Register client devices defined under the + * given firmware node as children of the given device. + * @parent: The parent device under which clients should be registered. + * @ctrl: The controller with which client should be registered. + * @node: The firmware node holding definitions of the devices to be added. + * + * Register all clients that have been defined as children of the given root + * firmware node as children of the given parent device. The respective child + * firmware nodes will be associated with the correspondingly created child + * devices. + * + * The given controller will be used to instantiate the new devices. See + * ssam_device_add() for details. + * + * Note that, generally, the use of either ssam_device_register_clients() or + * ssam_register_clients() should be preferred as they directly use the + * firmware node and/or controller associated with the given device. This + * function is only intended for use when different device specifications (e.g. + * ACPI and firmware nodes) need to be combined (as is done in the platform hub + * of the device registry). + * + * Return: Returns zero on success, nonzero on failure. + */ +int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl, + struct fwnode_handle *node) +{ + struct fwnode_handle *child; + int status; + + fwnode_for_each_child_node(node, child) { + /* + * Try to add the device specified in the firmware node. If + * this fails with -ENODEV, the node does not specify any SSAM + * device, so ignore it and continue with the next one. + */ + status = ssam_add_client_device(parent, ctrl, child); + if (status && status != -ENODEV) + goto err; + } + + return 0; +err: + ssam_remove_clients(parent); + return status; +} +EXPORT_SYMBOL_GPL(__ssam_register_clients); + static int ssam_remove_device(struct device *dev, void *_data) { struct ssam_device *sdev = to_ssam_device(dev); @@ -387,19 +520,3 @@ void ssam_remove_clients(struct device *dev) device_for_each_child_reverse(dev, NULL, ssam_remove_device); } EXPORT_SYMBOL_GPL(ssam_remove_clients); - -/** - * ssam_bus_register() - Register and set-up the SSAM client device bus. - */ -int ssam_bus_register(void) -{ - return bus_register(&ssam_bus_type); -} - -/** - * ssam_bus_unregister() - Unregister the SSAM client device bus. - */ -void ssam_bus_unregister(void) -{ - return bus_unregister(&ssam_bus_type); -} diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index f1c5905f1c16..c680792a037e 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -286,76 +286,6 @@ static const struct software_node *ssam_node_group_sp8[] = { }; -/* -- Device registry helper functions. ------------------------------------- */ - -static int ssam_uid_from_string(const char *str, struct ssam_device_uid *uid) -{ - u8 d, tc, tid, iid, fn; - int n; - - n = sscanf(str, "ssam:%hhx:%hhx:%hhx:%hhx:%hhx", &d, &tc, &tid, &iid, &fn); - if (n != 5) - return -EINVAL; - - uid->domain = d; - uid->category = tc; - uid->target = tid; - uid->instance = iid; - uid->function = fn; - - return 0; -} - -static int ssam_hub_add_device(struct device *parent, struct ssam_controller *ctrl, - struct fwnode_handle *node) -{ - struct ssam_device_uid uid; - struct ssam_device *sdev; - int status; - - status = ssam_uid_from_string(fwnode_get_name(node), &uid); - if (status) - return status; - - sdev = ssam_device_alloc(ctrl, uid); - if (!sdev) - return -ENOMEM; - - sdev->dev.parent = parent; - sdev->dev.fwnode = node; - - status = ssam_device_add(sdev); - if (status) - ssam_device_put(sdev); - - return status; -} - -static int ssam_hub_register_clients(struct device *parent, struct ssam_controller *ctrl, - struct fwnode_handle *node) -{ - struct fwnode_handle *child; - int status; - - fwnode_for_each_child_node(node, child) { - /* - * Try to add the device specified in the firmware node. If - * this fails with -EINVAL, the node does not specify any SSAM - * device, so ignore it and continue with the next one. - */ - - status = ssam_hub_add_device(parent, ctrl, child); - if (status && status != -EINVAL) - goto err; - } - - return 0; -err: - ssam_remove_clients(parent); - return status; -} - - /* -- SSAM generic subsystem hub driver framework. -------------------------- */ enum ssam_hub_state { @@ -385,7 +315,6 @@ struct ssam_hub { static void ssam_hub_update_workfn(struct work_struct *work) { struct ssam_hub *hub = container_of(work, struct ssam_hub, update_work.work); - struct fwnode_handle *node = dev_fwnode(&hub->sdev->dev); enum ssam_hub_state state; int status = 0; @@ -425,7 +354,7 @@ static void ssam_hub_update_workfn(struct work_struct *work) hub->state = state; if (hub->state == SSAM_HUB_CONNECTED) - status = ssam_hub_register_clients(&hub->sdev->dev, hub->sdev->ctrl, node); + status = ssam_device_register_clients(hub->sdev); else ssam_remove_clients(&hub->sdev->dev); @@ -769,7 +698,7 @@ static int ssam_platform_hub_probe(struct platform_device *pdev) set_secondary_fwnode(&pdev->dev, root); - status = ssam_hub_register_clients(&pdev->dev, ctrl, root); + status = __ssam_register_clients(&pdev->dev, ctrl, root); if (status) { set_secondary_fwnode(&pdev->dev, NULL); software_node_unregister_node_group(nodes); diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index 6cf7e80312d5..46c45d1b6368 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -375,11 +376,62 @@ void ssam_device_driver_unregister(struct ssam_device_driver *d); /* -- Helpers for controller and hub devices. ------------------------------- */ #ifdef CONFIG_SURFACE_AGGREGATOR_BUS + +int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl, + struct fwnode_handle *node); void ssam_remove_clients(struct device *dev); + #else /* CONFIG_SURFACE_AGGREGATOR_BUS */ + +static inline int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl, + struct fwnode_handle *node) +{ + return 0; +} + static inline void ssam_remove_clients(struct device *dev) {} + #endif /* CONFIG_SURFACE_AGGREGATOR_BUS */ +/** + * ssam_register_clients() - Register all client devices defined under the + * given parent device. + * @dev: The parent device under which clients should be registered. + * @ctrl: The controller with which client should be registered. + * + * Register all clients that have via firmware nodes been defined as children + * of the given (parent) device. The respective child firmware nodes will be + * associated with the correspondingly created child devices. + * + * The given controller will be used to instantiate the new devices. See + * ssam_device_add() for details. + * + * Return: Returns zero on success, nonzero on failure. + */ +static inline int ssam_register_clients(struct device *dev, struct ssam_controller *ctrl) +{ + return __ssam_register_clients(dev, ctrl, dev_fwnode(dev)); +} + +/** + * ssam_device_register_clients() - Register all client devices defined under + * the given SSAM parent device. + * @sdev: The parent device under which clients should be registered. + * + * Register all clients that have via firmware nodes been defined as children + * of the given (parent) device. The respective child firmware nodes will be + * associated with the correspondingly created child devices. + * + * The controller used by the parent device will be used to instantiate the new + * devices. See ssam_device_add() for details. + * + * Return: Returns zero on success, nonzero on failure. + */ +static inline int ssam_device_register_clients(struct ssam_device *sdev) +{ + return ssam_register_clients(&sdev->dev, sdev->ctrl); +} + /* -- Helpers for client-device requests. ----------------------------------- */ From 993a9e2aca6e6432695082d689353a03662d18d1 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 24 Jun 2022 22:57:59 +0200 Subject: [PATCH 0786/1436] platform/surface: aggregator: Move subsystem hub drivers to their own module Split out subsystem device hub drivers into their own module. This allows us to load the hub drivers separately from the registry, which will help future DT/OF support. While doing so, also remove a small bit of code duplication. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220624205800.1355621-3-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- MAINTAINERS | 6 + drivers/platform/surface/Kconfig | 35 +- drivers/platform/surface/Makefile | 1 + .../platform/surface/surface_aggregator_hub.c | 371 ++++++++++++++++++ .../surface/surface_aggregator_registry.c | 371 +----------------- 5 files changed, 410 insertions(+), 374 deletions(-) create mode 100644 drivers/platform/surface/surface_aggregator_hub.c diff --git a/MAINTAINERS b/MAINTAINERS index c6d8c0c6bf6e..e01478062c56 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13253,6 +13253,12 @@ F: include/linux/surface_acpi_notify.h F: include/linux/surface_aggregator/ F: include/uapi/linux/surface_aggregator/ +MICROSOFT SURFACE SYSTEM AGGREGATOR HUB DRIVER +M: Maximilian Luz +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/platform/surface/surface_aggregator_hub.c + MICROTEK X6 SCANNER M: Oliver Neukum S: Maintained diff --git a/drivers/platform/surface/Kconfig b/drivers/platform/surface/Kconfig index b152e930cc84..b629e82af97c 100644 --- a/drivers/platform/surface/Kconfig +++ b/drivers/platform/surface/Kconfig @@ -72,18 +72,45 @@ config SURFACE_AGGREGATOR_CDEV The provided interface is intended for debugging and development only, and should not be used otherwise. +config SURFACE_AGGREGATOR_HUB + tristate "Surface System Aggregator Module Subsystem Device Hubs" + depends on SURFACE_AGGREGATOR + depends on SURFACE_AGGREGATOR_BUS + help + Device-hub drivers for Surface System Aggregator Module (SSAM) subsystem + devices. + + Provides subsystem hub drivers which manage client devices on various + SSAM subsystems. In some subsystems, notably the BAS subsystem managing + devices contained in the base of the Surface Book 3 and the KIP subsystem + managing type-cover devices in the Surface Pro 8 and Surface Pro X, + devices can be (hot-)removed. Hub devices and drivers are required to + manage these subdevices. + + Devices managed via these hubs are: + - Battery/AC devices (Surface Book 3). + - HID input devices (7th-generation and later models with detachable + input devices). + + Select M (recommended) or Y here if you want support for the above + mentioned devices on the corresponding Surface models. Without this + module, the respective devices mentioned above will not be instantiated + and thus any functionality provided by them will be missing, even when + drivers for these devices are present. This module only provides the + respective subsystem hubs. Both drivers and device specification (e.g. + via the Surface Aggregator Registry) for these devices still need to be + selected via other options. + config SURFACE_AGGREGATOR_REGISTRY tristate "Surface System Aggregator Module Device Registry" depends on SURFACE_AGGREGATOR depends on SURFACE_AGGREGATOR_BUS help - Device-registry and device-hubs for Surface System Aggregator Module - (SSAM) devices. + Device-registry for Surface System Aggregator Module (SSAM) devices. Provides a module and driver which act as a device-registry for SSAM client devices that cannot be detected automatically, e.g. via ACPI. - Such devices are instead provided via this registry and attached via - device hubs, also provided in this module. + Such devices are instead provided and managed via this registry. Devices provided via this registry are: - Platform profile (performance-/cooling-mode) device (5th- and later diff --git a/drivers/platform/surface/Makefile b/drivers/platform/surface/Makefile index 18b27898543e..53344330939b 100644 --- a/drivers/platform/surface/Makefile +++ b/drivers/platform/surface/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o obj-$(CONFIG_SURFACE_ACPI_NOTIFY) += surface_acpi_notify.o obj-$(CONFIG_SURFACE_AGGREGATOR) += aggregator/ obj-$(CONFIG_SURFACE_AGGREGATOR_CDEV) += surface_aggregator_cdev.o +obj-$(CONFIG_SURFACE_AGGREGATOR_HUB) += surface_aggregator_hub.o obj-$(CONFIG_SURFACE_AGGREGATOR_REGISTRY) += surface_aggregator_registry.o obj-$(CONFIG_SURFACE_AGGREGATOR_TABLET_SWITCH) += surface_aggregator_tabletsw.o obj-$(CONFIG_SURFACE_DTX) += surface_dtx.o diff --git a/drivers/platform/surface/surface_aggregator_hub.c b/drivers/platform/surface/surface_aggregator_hub.c new file mode 100644 index 000000000000..43061514be38 --- /dev/null +++ b/drivers/platform/surface/surface_aggregator_hub.c @@ -0,0 +1,371 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for Surface System Aggregator Module (SSAM) subsystem device hubs. + * + * Provides a driver for SSAM subsystems device hubs. This driver performs + * instantiation of the devices managed by said hubs and takes care of + * (hot-)removal. + * + * Copyright (C) 2020-2022 Maximilian Luz + */ + +#include +#include +#include +#include +#include + +#include + + +/* -- SSAM generic subsystem hub driver framework. -------------------------- */ + +enum ssam_hub_state { + SSAM_HUB_UNINITIALIZED, /* Only set during initialization. */ + SSAM_HUB_CONNECTED, + SSAM_HUB_DISCONNECTED, +}; + +enum ssam_hub_flags { + SSAM_HUB_HOT_REMOVED, +}; + +struct ssam_hub; + +struct ssam_hub_ops { + int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state); +}; + +struct ssam_hub { + struct ssam_device *sdev; + + enum ssam_hub_state state; + unsigned long flags; + + struct delayed_work update_work; + unsigned long connect_delay; + + struct ssam_event_notifier notif; + struct ssam_hub_ops ops; +}; + +struct ssam_hub_desc { + struct { + struct ssam_event_registry reg; + struct ssam_event_id id; + enum ssam_event_mask mask; + } event; + + struct { + u32 (*notify)(struct ssam_event_notifier *nf, const struct ssam_event *event); + int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state); + } ops; + + unsigned long connect_delay_ms; +}; + +static void ssam_hub_update_workfn(struct work_struct *work) +{ + struct ssam_hub *hub = container_of(work, struct ssam_hub, update_work.work); + enum ssam_hub_state state; + int status = 0; + + status = hub->ops.get_state(hub, &state); + if (status) + return; + + /* + * There is a small possibility that hub devices were hot-removed and + * re-added before we were able to remove them here. In that case, both + * the state returned by get_state() and the state of the hub will + * equal SSAM_HUB_CONNECTED and we would bail early below, which would + * leave child devices without proper (re-)initialization and the + * hot-remove flag set. + * + * Therefore, we check whether devices have been hot-removed via an + * additional flag on the hub and, in this case, override the returned + * hub state. In case of a missed disconnect (i.e. get_state returned + * "connected"), we further need to re-schedule this work (with the + * appropriate delay) as the actual connect work submission might have + * been merged with this one. + * + * This then leads to one of two cases: Either we submit an unnecessary + * work item (which will get ignored via either the queue or the state + * checks) or, in the unlikely case that the work is actually required, + * double the normal connect delay. + */ + if (test_and_clear_bit(SSAM_HUB_HOT_REMOVED, &hub->flags)) { + if (state == SSAM_HUB_CONNECTED) + schedule_delayed_work(&hub->update_work, hub->connect_delay); + + state = SSAM_HUB_DISCONNECTED; + } + + if (hub->state == state) + return; + hub->state = state; + + if (hub->state == SSAM_HUB_CONNECTED) + status = ssam_device_register_clients(hub->sdev); + else + ssam_remove_clients(&hub->sdev->dev); + + if (status) + dev_err(&hub->sdev->dev, "failed to update hub child devices: %d\n", status); +} + +static int ssam_hub_mark_hot_removed(struct device *dev, void *_data) +{ + struct ssam_device *sdev = to_ssam_device(dev); + + if (is_ssam_device(dev)) + ssam_device_mark_hot_removed(sdev); + + return 0; +} + +static void ssam_hub_update(struct ssam_hub *hub, bool connected) +{ + unsigned long delay; + + /* Mark devices as hot-removed before we remove any. */ + if (!connected) { + set_bit(SSAM_HUB_HOT_REMOVED, &hub->flags); + device_for_each_child_reverse(&hub->sdev->dev, NULL, ssam_hub_mark_hot_removed); + } + + /* + * Delay update when the base/keyboard cover is being connected to give + * devices/EC some time to set up. + */ + delay = connected ? hub->connect_delay : 0; + + schedule_delayed_work(&hub->update_work, delay); +} + +static int __maybe_unused ssam_hub_resume(struct device *dev) +{ + struct ssam_hub *hub = dev_get_drvdata(dev); + + schedule_delayed_work(&hub->update_work, 0); + return 0; +} +static SIMPLE_DEV_PM_OPS(ssam_hub_pm_ops, NULL, ssam_hub_resume); + +static int ssam_hub_probe(struct ssam_device *sdev) +{ + const struct ssam_hub_desc *desc; + struct ssam_hub *hub; + int status; + + desc = ssam_device_get_match_data(sdev); + if (!desc) { + WARN(1, "no driver match data specified"); + return -EINVAL; + } + + hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + hub->sdev = sdev; + hub->state = SSAM_HUB_UNINITIALIZED; + + hub->notif.base.priority = INT_MAX; /* This notifier should run first. */ + hub->notif.base.fn = desc->ops.notify; + hub->notif.event.reg = desc->event.reg; + hub->notif.event.id = desc->event.id; + hub->notif.event.mask = desc->event.mask; + hub->notif.event.flags = SSAM_EVENT_SEQUENCED; + + hub->connect_delay = msecs_to_jiffies(desc->connect_delay_ms); + hub->ops.get_state = desc->ops.get_state; + + INIT_DELAYED_WORK(&hub->update_work, ssam_hub_update_workfn); + + ssam_device_set_drvdata(sdev, hub); + + status = ssam_device_notifier_register(sdev, &hub->notif); + if (status) + return status; + + schedule_delayed_work(&hub->update_work, 0); + return 0; +} + +static void ssam_hub_remove(struct ssam_device *sdev) +{ + struct ssam_hub *hub = ssam_device_get_drvdata(sdev); + + ssam_device_notifier_unregister(sdev, &hub->notif); + cancel_delayed_work_sync(&hub->update_work); + ssam_remove_clients(&sdev->dev); +} + + +/* -- SSAM base-subsystem hub driver. --------------------------------------- */ + +/* + * Some devices (especially battery) may need a bit of time to be fully usable + * after being (re-)connected. This delay has been determined via + * experimentation. + */ +#define SSAM_BASE_UPDATE_CONNECT_DELAY 2500 + +SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x0d, + .instance_id = 0x00, +}); + +#define SSAM_BAS_OPMODE_TABLET 0x00 +#define SSAM_EVENT_BAS_CID_CONNECTION 0x0c + +static int ssam_base_hub_query_state(struct ssam_hub *hub, enum ssam_hub_state *state) +{ + u8 opmode; + int status; + + status = ssam_retry(ssam_bas_query_opmode, hub->sdev->ctrl, &opmode); + if (status < 0) { + dev_err(&hub->sdev->dev, "failed to query base state: %d\n", status); + return status; + } + + if (opmode != SSAM_BAS_OPMODE_TABLET) + *state = SSAM_HUB_CONNECTED; + else + *state = SSAM_HUB_DISCONNECTED; + + return 0; +} + +static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) +{ + struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif); + + if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION) + return 0; + + if (event->length < 1) { + dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length); + return 0; + } + + ssam_hub_update(hub, event->data[0]); + + /* + * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and + * consumed by the detachment system driver. We're just a (more or less) + * silent observer. + */ + return 0; +} + +static const struct ssam_hub_desc base_hub = { + .event = { + .reg = SSAM_EVENT_REGISTRY_SAM, + .id = { + .target_category = SSAM_SSH_TC_BAS, + .instance = 0, + }, + .mask = SSAM_EVENT_MASK_NONE, + }, + .ops = { + .notify = ssam_base_hub_notif, + .get_state = ssam_base_hub_query_state, + }, + .connect_delay_ms = SSAM_BASE_UPDATE_CONNECT_DELAY, +}; + + +/* -- SSAM KIP-subsystem hub driver. ---------------------------------------- */ + +/* + * Some devices may need a bit of time to be fully usable after being + * (re-)connected. This delay has been determined via experimentation. + */ +#define SSAM_KIP_UPDATE_CONNECT_DELAY 250 + +#define SSAM_EVENT_KIP_CID_CONNECTION 0x2c + +SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_query_state, u8, { + .target_category = SSAM_SSH_TC_KIP, + .target_id = 0x01, + .command_id = 0x2c, + .instance_id = 0x00, +}); + +static int ssam_kip_hub_query_state(struct ssam_hub *hub, enum ssam_hub_state *state) +{ + int status; + u8 connected; + + status = ssam_retry(__ssam_kip_query_state, hub->sdev->ctrl, &connected); + if (status < 0) { + dev_err(&hub->sdev->dev, "failed to query KIP connection state: %d\n", status); + return status; + } + + *state = connected ? SSAM_HUB_CONNECTED : SSAM_HUB_DISCONNECTED; + return 0; +} + +static u32 ssam_kip_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) +{ + struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif); + + if (event->command_id != SSAM_EVENT_KIP_CID_CONNECTION) + return 0; /* Return "unhandled". */ + + if (event->length < 1) { + dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length); + return 0; + } + + ssam_hub_update(hub, event->data[0]); + return SSAM_NOTIF_HANDLED; +} + +static const struct ssam_hub_desc kip_hub = { + .event = { + .reg = SSAM_EVENT_REGISTRY_SAM, + .id = { + .target_category = SSAM_SSH_TC_KIP, + .instance = 0, + }, + .mask = SSAM_EVENT_MASK_TARGET, + }, + .ops = { + .notify = ssam_kip_hub_notif, + .get_state = ssam_kip_hub_query_state, + }, + .connect_delay_ms = SSAM_KIP_UPDATE_CONNECT_DELAY, +}; + + +/* -- Driver registration. -------------------------------------------------- */ + +static const struct ssam_device_id ssam_hub_match[] = { + { SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub }, + { SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub }, + { } +}; +MODULE_DEVICE_TABLE(ssam, ssam_hub_match); + +static struct ssam_device_driver ssam_subsystem_hub_driver = { + .probe = ssam_hub_probe, + .remove = ssam_hub_remove, + .match_table = ssam_hub_match, + .driver = { + .name = "surface_aggregator_subsystem_hub", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &ssam_hub_pm_ops, + }, +}; +module_ssam_device_driver(ssam_subsystem_hub_driver); + +MODULE_AUTHOR("Maximilian Luz "); +MODULE_DESCRIPTION("Subsystem device hub driver for Surface System Aggregator Module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index c680792a037e..0cbb7f3a6b2d 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -11,14 +11,11 @@ #include #include -#include #include #include #include #include -#include -#include #include @@ -286,335 +283,6 @@ static const struct software_node *ssam_node_group_sp8[] = { }; -/* -- SSAM generic subsystem hub driver framework. -------------------------- */ - -enum ssam_hub_state { - SSAM_HUB_UNINITIALIZED, /* Only set during initialization. */ - SSAM_HUB_CONNECTED, - SSAM_HUB_DISCONNECTED, -}; - -enum ssam_hub_flags { - SSAM_HUB_HOT_REMOVED, -}; - -struct ssam_hub { - struct ssam_device *sdev; - - enum ssam_hub_state state; - unsigned long flags; - - struct delayed_work update_work; - unsigned long connect_delay; - - struct ssam_event_notifier notif; - - int (*get_state)(struct ssam_hub *hub, enum ssam_hub_state *state); -}; - -static void ssam_hub_update_workfn(struct work_struct *work) -{ - struct ssam_hub *hub = container_of(work, struct ssam_hub, update_work.work); - enum ssam_hub_state state; - int status = 0; - - status = hub->get_state(hub, &state); - if (status) - return; - - /* - * There is a small possibility that hub devices were hot-removed and - * re-added before we were able to remove them here. In that case, both - * the state returned by get_state() and the state of the hub will - * equal SSAM_HUB_CONNECTED and we would bail early below, which would - * leave child devices without proper (re-)initialization and the - * hot-remove flag set. - * - * Therefore, we check whether devices have been hot-removed via an - * additional flag on the hub and, in this case, override the returned - * hub state. In case of a missed disconnect (i.e. get_state returned - * "connected"), we further need to re-schedule this work (with the - * appropriate delay) as the actual connect work submission might have - * been merged with this one. - * - * This then leads to one of two cases: Either we submit an unnecessary - * work item (which will get ignored via either the queue or the state - * checks) or, in the unlikely case that the work is actually required, - * double the normal connect delay. - */ - if (test_and_clear_bit(SSAM_HUB_HOT_REMOVED, &hub->flags)) { - if (state == SSAM_HUB_CONNECTED) - schedule_delayed_work(&hub->update_work, hub->connect_delay); - - state = SSAM_HUB_DISCONNECTED; - } - - if (hub->state == state) - return; - hub->state = state; - - if (hub->state == SSAM_HUB_CONNECTED) - status = ssam_device_register_clients(hub->sdev); - else - ssam_remove_clients(&hub->sdev->dev); - - if (status) - dev_err(&hub->sdev->dev, "failed to update hub child devices: %d\n", status); -} - -static int ssam_hub_mark_hot_removed(struct device *dev, void *_data) -{ - struct ssam_device *sdev = to_ssam_device(dev); - - if (is_ssam_device(dev)) - ssam_device_mark_hot_removed(sdev); - - return 0; -} - -static void ssam_hub_update(struct ssam_hub *hub, bool connected) -{ - unsigned long delay; - - /* Mark devices as hot-removed before we remove any. */ - if (!connected) { - set_bit(SSAM_HUB_HOT_REMOVED, &hub->flags); - device_for_each_child_reverse(&hub->sdev->dev, NULL, ssam_hub_mark_hot_removed); - } - - /* - * Delay update when the base/keyboard cover is being connected to give - * devices/EC some time to set up. - */ - delay = connected ? hub->connect_delay : 0; - - schedule_delayed_work(&hub->update_work, delay); -} - -static int __maybe_unused ssam_hub_resume(struct device *dev) -{ - struct ssam_hub *hub = dev_get_drvdata(dev); - - schedule_delayed_work(&hub->update_work, 0); - return 0; -} -static SIMPLE_DEV_PM_OPS(ssam_hub_pm_ops, NULL, ssam_hub_resume); - -static int ssam_hub_setup(struct ssam_device *sdev, struct ssam_hub *hub) -{ - int status; - - hub->sdev = sdev; - hub->state = SSAM_HUB_UNINITIALIZED; - - INIT_DELAYED_WORK(&hub->update_work, ssam_hub_update_workfn); - - ssam_device_set_drvdata(sdev, hub); - - status = ssam_device_notifier_register(sdev, &hub->notif); - if (status) - return status; - - schedule_delayed_work(&hub->update_work, 0); - return 0; -} - -static void ssam_hub_remove(struct ssam_device *sdev) -{ - struct ssam_hub *hub = ssam_device_get_drvdata(sdev); - - ssam_device_notifier_unregister(sdev, &hub->notif); - cancel_delayed_work_sync(&hub->update_work); - ssam_remove_clients(&sdev->dev); -} - - -/* -- SSAM base-hub driver. ------------------------------------------------- */ - -/* - * Some devices (especially battery) may need a bit of time to be fully usable - * after being (re-)connected. This delay has been determined via - * experimentation. - */ -#define SSAM_BASE_UPDATE_CONNECT_DELAY msecs_to_jiffies(2500) - -SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, { - .target_category = SSAM_SSH_TC_BAS, - .target_id = 0x01, - .command_id = 0x0d, - .instance_id = 0x00, -}); - -#define SSAM_BAS_OPMODE_TABLET 0x00 -#define SSAM_EVENT_BAS_CID_CONNECTION 0x0c - -static int ssam_base_hub_query_state(struct ssam_hub *hub, enum ssam_hub_state *state) -{ - u8 opmode; - int status; - - status = ssam_retry(ssam_bas_query_opmode, hub->sdev->ctrl, &opmode); - if (status < 0) { - dev_err(&hub->sdev->dev, "failed to query base state: %d\n", status); - return status; - } - - if (opmode != SSAM_BAS_OPMODE_TABLET) - *state = SSAM_HUB_CONNECTED; - else - *state = SSAM_HUB_DISCONNECTED; - - return 0; -} - -static u32 ssam_base_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) -{ - struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif); - - if (event->command_id != SSAM_EVENT_BAS_CID_CONNECTION) - return 0; - - if (event->length < 1) { - dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length); - return 0; - } - - ssam_hub_update(hub, event->data[0]); - - /* - * Do not return SSAM_NOTIF_HANDLED: The event should be picked up and - * consumed by the detachment system driver. We're just a (more or less) - * silent observer. - */ - return 0; -} - -static int ssam_base_hub_probe(struct ssam_device *sdev) -{ - struct ssam_hub *hub; - - hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL); - if (!hub) - return -ENOMEM; - - hub->notif.base.priority = INT_MAX; /* This notifier should run first. */ - hub->notif.base.fn = ssam_base_hub_notif; - hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM; - hub->notif.event.id.target_category = SSAM_SSH_TC_BAS, - hub->notif.event.id.instance = 0, - hub->notif.event.mask = SSAM_EVENT_MASK_NONE; - hub->notif.event.flags = SSAM_EVENT_SEQUENCED; - - hub->connect_delay = SSAM_BASE_UPDATE_CONNECT_DELAY; - hub->get_state = ssam_base_hub_query_state; - - return ssam_hub_setup(sdev, hub); -} - -static const struct ssam_device_id ssam_base_hub_match[] = { - { SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00) }, - { }, -}; - -static struct ssam_device_driver ssam_base_hub_driver = { - .probe = ssam_base_hub_probe, - .remove = ssam_hub_remove, - .match_table = ssam_base_hub_match, - .driver = { - .name = "surface_aggregator_base_hub", - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .pm = &ssam_hub_pm_ops, - }, -}; - - -/* -- SSAM KIP-subsystem hub driver. ---------------------------------------- */ - -/* - * Some devices may need a bit of time to be fully usable after being - * (re-)connected. This delay has been determined via experimentation. - */ -#define SSAM_KIP_UPDATE_CONNECT_DELAY msecs_to_jiffies(250) - -#define SSAM_EVENT_KIP_CID_CONNECTION 0x2c - -SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_connection_state, u8, { - .target_category = SSAM_SSH_TC_KIP, - .target_id = 0x01, - .command_id = 0x2c, - .instance_id = 0x00, -}); - -static int ssam_kip_get_connection_state(struct ssam_hub *hub, enum ssam_hub_state *state) -{ - int status; - u8 connected; - - status = ssam_retry(__ssam_kip_get_connection_state, hub->sdev->ctrl, &connected); - if (status < 0) { - dev_err(&hub->sdev->dev, "failed to query KIP connection state: %d\n", status); - return status; - } - - *state = connected ? SSAM_HUB_CONNECTED : SSAM_HUB_DISCONNECTED; - return 0; -} - -static u32 ssam_kip_hub_notif(struct ssam_event_notifier *nf, const struct ssam_event *event) -{ - struct ssam_hub *hub = container_of(nf, struct ssam_hub, notif); - - if (event->command_id != SSAM_EVENT_KIP_CID_CONNECTION) - return 0; /* Return "unhandled". */ - - if (event->length < 1) { - dev_err(&hub->sdev->dev, "unexpected payload size: %u\n", event->length); - return 0; - } - - ssam_hub_update(hub, event->data[0]); - return SSAM_NOTIF_HANDLED; -} - -static int ssam_kip_hub_probe(struct ssam_device *sdev) -{ - struct ssam_hub *hub; - - hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL); - if (!hub) - return -ENOMEM; - - hub->notif.base.priority = INT_MAX; /* This notifier should run first. */ - hub->notif.base.fn = ssam_kip_hub_notif; - hub->notif.event.reg = SSAM_EVENT_REGISTRY_SAM; - hub->notif.event.id.target_category = SSAM_SSH_TC_KIP, - hub->notif.event.id.instance = 0, - hub->notif.event.mask = SSAM_EVENT_MASK_TARGET; - hub->notif.event.flags = SSAM_EVENT_SEQUENCED; - - hub->connect_delay = SSAM_KIP_UPDATE_CONNECT_DELAY; - hub->get_state = ssam_kip_get_connection_state; - - return ssam_hub_setup(sdev, hub); -} - -static const struct ssam_device_id ssam_kip_hub_match[] = { - { SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00) }, - { }, -}; - -static struct ssam_device_driver ssam_kip_hub_driver = { - .probe = ssam_kip_hub_probe, - .remove = ssam_hub_remove, - .match_table = ssam_kip_hub_match, - .driver = { - .name = "surface_kip_hub", - .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .pm = &ssam_hub_pm_ops, - }, -}; - - /* -- SSAM platform/meta-hub driver. ---------------------------------------- */ static const struct acpi_device_id ssam_platform_hub_match[] = { @@ -727,44 +395,7 @@ static struct platform_driver ssam_platform_hub_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; - - -/* -- Module initialization. ------------------------------------------------ */ - -static int __init ssam_device_hub_init(void) -{ - int status; - - status = platform_driver_register(&ssam_platform_hub_driver); - if (status) - goto err_platform; - - status = ssam_device_driver_register(&ssam_base_hub_driver); - if (status) - goto err_base; - - status = ssam_device_driver_register(&ssam_kip_hub_driver); - if (status) - goto err_kip; - - return 0; - -err_kip: - ssam_device_driver_unregister(&ssam_base_hub_driver); -err_base: - platform_driver_unregister(&ssam_platform_hub_driver); -err_platform: - return status; -} -module_init(ssam_device_hub_init); - -static void __exit ssam_device_hub_exit(void) -{ - ssam_device_driver_unregister(&ssam_kip_hub_driver); - ssam_device_driver_unregister(&ssam_base_hub_driver); - platform_driver_unregister(&ssam_platform_hub_driver); -} -module_exit(ssam_device_hub_exit); +module_platform_driver(ssam_platform_hub_driver); MODULE_AUTHOR("Maximilian Luz "); MODULE_DESCRIPTION("Device-registry for Surface System Aggregator Module"); From 221756e61b7cc3d7f47f57fb4f371242aa4ccb1d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Fri, 24 Jun 2022 22:58:00 +0200 Subject: [PATCH 0787/1436] platform/surface: Update copyright year of various drivers Update the copyright of various Surface drivers to the current year. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220624205800.1355621-4-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/aggregator/Kconfig | 2 +- drivers/platform/surface/aggregator/Makefile | 2 +- drivers/platform/surface/aggregator/bus.c | 2 +- drivers/platform/surface/aggregator/bus.h | 2 +- drivers/platform/surface/aggregator/controller.c | 2 +- drivers/platform/surface/aggregator/controller.h | 2 +- drivers/platform/surface/aggregator/core.c | 2 +- drivers/platform/surface/aggregator/ssh_msgb.h | 2 +- drivers/platform/surface/aggregator/ssh_packet_layer.c | 2 +- drivers/platform/surface/aggregator/ssh_packet_layer.h | 2 +- drivers/platform/surface/aggregator/ssh_parser.c | 2 +- drivers/platform/surface/aggregator/ssh_parser.h | 2 +- drivers/platform/surface/aggregator/ssh_request_layer.c | 2 +- drivers/platform/surface/aggregator/ssh_request_layer.h | 2 +- drivers/platform/surface/aggregator/trace.h | 2 +- drivers/platform/surface/surface_acpi_notify.c | 2 +- drivers/platform/surface/surface_aggregator_cdev.c | 2 +- drivers/platform/surface/surface_aggregator_registry.c | 2 +- drivers/platform/surface/surface_dtx.c | 2 +- drivers/platform/surface/surface_gpe.c | 2 +- drivers/platform/surface/surface_hotplug.c | 2 +- drivers/platform/surface/surface_platform_profile.c | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/platform/surface/aggregator/Kconfig b/drivers/platform/surface/aggregator/Kconfig index cab020324256..c114f9dd5fe1 100644 --- a/drivers/platform/surface/aggregator/Kconfig +++ b/drivers/platform/surface/aggregator/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0+ -# Copyright (C) 2019-2021 Maximilian Luz +# Copyright (C) 2019-2022 Maximilian Luz menuconfig SURFACE_AGGREGATOR tristate "Microsoft Surface System Aggregator Module Subsystem and Drivers" diff --git a/drivers/platform/surface/aggregator/Makefile b/drivers/platform/surface/aggregator/Makefile index c0d550eda5cd..fdf664a217f9 100644 --- a/drivers/platform/surface/aggregator/Makefile +++ b/drivers/platform/surface/aggregator/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0+ -# Copyright (C) 2019-2021 Maximilian Luz +# Copyright (C) 2019-2022 Maximilian Luz # For include/trace/define_trace.h to include trace.h CFLAGS_core.o = -I$(src) diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c index e0b0381a2834..de539938896e 100644 --- a/drivers/platform/surface/aggregator/bus.c +++ b/drivers/platform/surface/aggregator/bus.c @@ -2,7 +2,7 @@ /* * Surface System Aggregator Module bus and device integration. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/aggregator/bus.h b/drivers/platform/surface/aggregator/bus.h index 6964ee84e79c..5b4dbf21906c 100644 --- a/drivers/platform/surface/aggregator/bus.h +++ b/drivers/platform/surface/aggregator/bus.h @@ -2,7 +2,7 @@ /* * Surface System Aggregator Module bus and device integration. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #ifndef _SURFACE_AGGREGATOR_BUS_H diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c index 6de834b52b63..43e765199137 100644 --- a/drivers/platform/surface/aggregator/controller.c +++ b/drivers/platform/surface/aggregator/controller.c @@ -2,7 +2,7 @@ /* * Main SSAM/SSH controller structure and functionality. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/aggregator/controller.h b/drivers/platform/surface/aggregator/controller.h index a0963c3562ff..f0d987abc51e 100644 --- a/drivers/platform/surface/aggregator/controller.h +++ b/drivers/platform/surface/aggregator/controller.h @@ -2,7 +2,7 @@ /* * Main SSAM/SSH controller structure and functionality. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #ifndef _SURFACE_AGGREGATOR_CONTROLLER_H diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c index a62c5dfe42d6..1a6373dea109 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -7,7 +7,7 @@ * Handles communication via requests as well as enabling, disabling, and * relaying of events. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/aggregator/ssh_msgb.h b/drivers/platform/surface/aggregator/ssh_msgb.h index e562958ffdf0..f3ecad92eefd 100644 --- a/drivers/platform/surface/aggregator/ssh_msgb.h +++ b/drivers/platform/surface/aggregator/ssh_msgb.h @@ -2,7 +2,7 @@ /* * SSH message builder functions. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #ifndef _SURFACE_AGGREGATOR_SSH_MSGB_H diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.c b/drivers/platform/surface/aggregator/ssh_packet_layer.c index 8a4451c1ffe5..6748fe4ac5d5 100644 --- a/drivers/platform/surface/aggregator/ssh_packet_layer.c +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.c @@ -2,7 +2,7 @@ /* * SSH packet transport layer. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/aggregator/ssh_packet_layer.h b/drivers/platform/surface/aggregator/ssh_packet_layer.h index 2eb329f0b91a..64633522f971 100644 --- a/drivers/platform/surface/aggregator/ssh_packet_layer.h +++ b/drivers/platform/surface/aggregator/ssh_packet_layer.h @@ -2,7 +2,7 @@ /* * SSH packet transport layer. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #ifndef _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H diff --git a/drivers/platform/surface/aggregator/ssh_parser.c b/drivers/platform/surface/aggregator/ssh_parser.c index b77912f8f13b..a6f668694365 100644 --- a/drivers/platform/surface/aggregator/ssh_parser.c +++ b/drivers/platform/surface/aggregator/ssh_parser.c @@ -2,7 +2,7 @@ /* * SSH message parser. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/aggregator/ssh_parser.h b/drivers/platform/surface/aggregator/ssh_parser.h index 3bd6e180fd16..801d8fa69fb5 100644 --- a/drivers/platform/surface/aggregator/ssh_parser.h +++ b/drivers/platform/surface/aggregator/ssh_parser.h @@ -2,7 +2,7 @@ /* * SSH message parser. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #ifndef _SURFACE_AGGREGATOR_SSH_PARSER_H diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c index 790f7f0eee98..f5565570f16c 100644 --- a/drivers/platform/surface/aggregator/ssh_request_layer.c +++ b/drivers/platform/surface/aggregator/ssh_request_layer.c @@ -2,7 +2,7 @@ /* * SSH request transport layer. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.h b/drivers/platform/surface/aggregator/ssh_request_layer.h index 9c3cbae2d4bd..4e387a031351 100644 --- a/drivers/platform/surface/aggregator/ssh_request_layer.h +++ b/drivers/platform/surface/aggregator/ssh_request_layer.h @@ -2,7 +2,7 @@ /* * SSH request transport layer. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #ifndef _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h index cc9e73fbc18e..2a2c17771d01 100644 --- a/drivers/platform/surface/aggregator/trace.h +++ b/drivers/platform/surface/aggregator/trace.h @@ -2,7 +2,7 @@ /* * Trace points for SSAM/SSH. * - * Copyright (C) 2020-2021 Maximilian Luz + * Copyright (C) 2020-2022 Maximilian Luz */ #undef TRACE_SYSTEM diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c index c0e12f0b9b79..44e317970557 100644 --- a/drivers/platform/surface/surface_acpi_notify.c +++ b/drivers/platform/surface/surface_acpi_notify.c @@ -8,7 +8,7 @@ * notifications sent from ACPI via the SAN interface by providing them to any * registered external driver. * - * Copyright (C) 2019-2020 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c index 30fb50fde450..492c82e69182 100644 --- a/drivers/platform/surface/surface_aggregator_cdev.c +++ b/drivers/platform/surface/surface_aggregator_cdev.c @@ -3,7 +3,7 @@ * Provides user-space access to the SSAM EC via the /dev/surface/aggregator * misc device. Intended for debugging and development. * - * Copyright (C) 2020-2021 Maximilian Luz + * Copyright (C) 2020-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c index 0cbb7f3a6b2d..d5655f6a4a41 100644 --- a/drivers/platform/surface/surface_aggregator_registry.c +++ b/drivers/platform/surface/surface_aggregator_registry.c @@ -6,7 +6,7 @@ * cannot be auto-detected. Provides device-hubs and performs instantiation * for these devices. * - * Copyright (C) 2020-2021 Maximilian Luz + * Copyright (C) 2020-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c index 1203b9a82993..ed36944467f9 100644 --- a/drivers/platform/surface/surface_dtx.c +++ b/drivers/platform/surface/surface_dtx.c @@ -8,7 +8,7 @@ * acknowledge (to speed things up), abort (e.g. in case the dGPU is still in * use), or request detachment via user-space. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c index ec66fde28e75..27365cbe1ee9 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -4,7 +4,7 @@ * properly configuring the respective GPEs. Required for wakeup via lid on * newer Intel-based Microsoft Surface devices. * - * Copyright (C) 2020 Maximilian Luz + * Copyright (C) 2020-2022 Maximilian Luz */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/platform/surface/surface_hotplug.c b/drivers/platform/surface/surface_hotplug.c index cfcc15cfbacb..f004a2495201 100644 --- a/drivers/platform/surface/surface_hotplug.c +++ b/drivers/platform/surface/surface_hotplug.c @@ -10,7 +10,7 @@ * Event signaling is handled via ACPI, which will generate the appropriate * device-check notifications to be picked up by the PCIe hot-plug driver. * - * Copyright (C) 2019-2021 Maximilian Luz + * Copyright (C) 2019-2022 Maximilian Luz */ #include diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c index 6373d3b5eb7f..fbf2e11fd6ce 100644 --- a/drivers/platform/surface/surface_platform_profile.c +++ b/drivers/platform/surface/surface_platform_profile.c @@ -3,7 +3,7 @@ * Surface Platform Profile / Performance Mode driver for Surface System * Aggregator Module (thermal subsystem). * - * Copyright (C) 2021 Maximilian Luz + * Copyright (C) 2021-2022 Maximilian Luz */ #include From 9a1aac8a96dc014bec49806a7a964bf2fdbd315f Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 29 Jun 2022 12:48:17 -0700 Subject: [PATCH 0788/1436] platform/x86: ISST: PUNIT device mapping with Sub-NUMA clustering On a multiple package system using Sub-NUMA clustering, there is an issue in mapping Linux CPU number to PUNIT PCI device when manufacturer decided to reuse the PCI bus number across packages. Bus number can be reused as long as they are in different domain or segment. In this case some CPU will fail to find a PCI device to issue SST requests. When bus numbers are reused across CPU packages, we are using proximity information by matching CPU numa node id to PUNIT PCI device numa node id. But on a package there can be only one PUNIT PCI device, but multiple numa nodes (one for each sub cluster). So, the numa node ID of the PUNIT PCI device can only match with one numa node id of CPUs in a sub cluster in the package. Since there can be only one PUNIT PCI device per package, if we match with numa node id of any sub cluster in that package, we can use that mapping for any CPU in that package. So, store the match information in a per package data structure and return the information when there is no match. While here, use defines for max bus number instead of hardcoding. Signed-off-by: Srinivas Pandruvada Link: https://lore.kernel.org/r/20220629194817.2418240-1-srinivas.pandruvada@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../intel/speed_select_if/isst_if_common.c | 39 +++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c index e8424e70d81d..fd102678c75f 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c @@ -277,29 +277,38 @@ static int isst_if_get_platform_info(void __user *argp) return 0; } +#define ISST_MAX_BUS_NUMBER 2 struct isst_if_cpu_info { /* For BUS 0 and BUS 1 only, which we need for PUNIT interface */ - int bus_info[2]; - struct pci_dev *pci_dev[2]; + int bus_info[ISST_MAX_BUS_NUMBER]; + struct pci_dev *pci_dev[ISST_MAX_BUS_NUMBER]; int punit_cpu_id; int numa_node; }; +struct isst_if_pkg_info { + struct pci_dev *pci_dev[ISST_MAX_BUS_NUMBER]; +}; + static struct isst_if_cpu_info *isst_cpu_info; +static struct isst_if_pkg_info *isst_pkg_info; + #define ISST_MAX_PCI_DOMAINS 8 static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn) { struct pci_dev *matched_pci_dev = NULL; struct pci_dev *pci_dev = NULL; - int no_matches = 0; + int no_matches = 0, pkg_id; int i, bus_number; - if (bus_no < 0 || bus_no > 1 || cpu < 0 || cpu >= nr_cpu_ids || - cpu >= num_possible_cpus()) + if (bus_no < 0 || bus_no >= ISST_MAX_BUS_NUMBER || cpu < 0 || + cpu >= nr_cpu_ids || cpu >= num_possible_cpus()) return NULL; + pkg_id = topology_physical_package_id(cpu); + bus_number = isst_cpu_info[cpu].bus_info[bus_no]; if (bus_number < 0) return NULL; @@ -324,6 +333,8 @@ static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn } if (node == isst_cpu_info[cpu].numa_node) { + isst_pkg_info[pkg_id].pci_dev[bus_no] = _pci_dev; + pci_dev = _pci_dev; break; } @@ -342,6 +353,10 @@ static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn if (!pci_dev && no_matches == 1) pci_dev = matched_pci_dev; + /* Return pci_dev pointer for any matched CPU in the package */ + if (!pci_dev) + pci_dev = isst_pkg_info[pkg_id].pci_dev[bus_no]; + return pci_dev; } @@ -361,8 +376,8 @@ struct pci_dev *isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn) { struct pci_dev *pci_dev; - if (bus_no < 0 || bus_no > 1 || cpu < 0 || cpu >= nr_cpu_ids || - cpu >= num_possible_cpus()) + if (bus_no < 0 || bus_no >= ISST_MAX_BUS_NUMBER || cpu < 0 || + cpu >= nr_cpu_ids || cpu >= num_possible_cpus()) return NULL; pci_dev = isst_cpu_info[cpu].pci_dev[bus_no]; @@ -417,10 +432,19 @@ static int isst_if_cpu_info_init(void) if (!isst_cpu_info) return -ENOMEM; + isst_pkg_info = kcalloc(topology_max_packages(), + sizeof(*isst_pkg_info), + GFP_KERNEL); + if (!isst_pkg_info) { + kfree(isst_cpu_info); + return -ENOMEM; + } + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "platform/x86/isst-if:online", isst_if_cpu_online, NULL); if (ret < 0) { + kfree(isst_pkg_info); kfree(isst_cpu_info); return ret; } @@ -433,6 +457,7 @@ static int isst_if_cpu_info_init(void) static void isst_if_cpu_info_exit(void) { cpuhp_remove_state(isst_if_online_id); + kfree(isst_pkg_info); kfree(isst_cpu_info); }; From f21c179e1206e88d187d517d97d270c6492d4673 Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Wed, 29 Jun 2022 15:13:31 -0700 Subject: [PATCH 0789/1436] platform/x86/intel/vsec: Rework early hardware code In the Intel VSEC PCI driver, use a new VSEC_QUIRK_EARLY_HW flag in driver_data to indicate the need for early hardware quirks in auxiliary devices. Remove the separate PCI ID list maintained by the Intel PMT auxiliary driver. Cc: Srinivas Pandruvada Signed-off-by: David E. Box Signed-off-by: Gayatri Kammela Link: https://lore.kernel.org/r/20220629221334.434307-2-gayatri.kammela@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/pmt/class.c | 23 ++++--------- drivers/platform/x86/intel/vsec.c | 46 ++++++++++++-------------- drivers/platform/x86/intel/vsec.h | 11 +++++- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c index 1c9e3f3ea41c..53d7fd2943b4 100644 --- a/drivers/platform/x86/intel/pmt/class.c +++ b/drivers/platform/x86/intel/pmt/class.c @@ -20,25 +20,16 @@ #define PMT_XA_MAX INT_MAX #define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX) -/* - * Early implementations of PMT on client platforms have some - * differences from the server platforms (which use the Out Of Band - * Management Services Module OOBMSM). This list tracks those - * platforms as needed to handle those differences. Newer client - * platforms are expected to be fully compatible with server. - */ -static const struct pci_device_id pmt_telem_early_client_pci_ids[] = { - { PCI_VDEVICE(INTEL, 0x467d) }, /* ADL */ - { PCI_VDEVICE(INTEL, 0x490e) }, /* DG1 */ - { PCI_VDEVICE(INTEL, 0x9a0d) }, /* TGL */ - { } -}; - bool intel_pmt_is_early_client_hw(struct device *dev) { - struct pci_dev *parent = to_pci_dev(dev->parent); + struct intel_vsec_device *ivdev = dev_to_ivdev(dev); - return !!pci_match_id(pmt_telem_early_client_pci_ids, parent); + /* + * Early implementations of PMT on client platforms have some + * differences from the server platforms (which use the Out Of Band + * Management Services Module OOBMSM). + */ + return !!(ivdev->info->quirks & VSEC_QUIRK_EARLY_HW); } EXPORT_SYMBOL_GPL(intel_pmt_is_early_client_hw); diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index bed436bf181f..d48df46e2e27 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -54,12 +54,6 @@ struct intel_vsec_header { u32 offset; }; -/* Platform specific data */ -struct intel_vsec_platform_info { - struct intel_vsec_header **capabilities; - unsigned long quirks; -}; - enum intel_vsec_id { VSEC_ID_TELEMETRY = 2, VSEC_ID_WATCHER = 3, @@ -169,10 +163,11 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in } static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header, - unsigned long quirks) + struct intel_vsec_platform_info *info) { struct intel_vsec_device *intel_vsec_dev; struct resource *res, *tmp; + unsigned long quirks = info->quirks; int i; if (!intel_vsec_allowed(header->id) || intel_vsec_disabled(header->id, quirks)) @@ -216,7 +211,7 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he intel_vsec_dev->pcidev = pdev; intel_vsec_dev->resource = res; intel_vsec_dev->num_resources = header->num_entries; - intel_vsec_dev->quirks = quirks; + intel_vsec_dev->info = info; if (header->id == VSEC_ID_SDSI) intel_vsec_dev->ida = &intel_vsec_sdsi_ida; @@ -226,14 +221,15 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he return intel_vsec_add_aux(pdev, intel_vsec_dev, intel_vsec_name(header->id)); } -static bool intel_vsec_walk_header(struct pci_dev *pdev, unsigned long quirks, - struct intel_vsec_header **header) +static bool intel_vsec_walk_header(struct pci_dev *pdev, + struct intel_vsec_platform_info *info) { + struct intel_vsec_header **header = info->capabilities; bool have_devices = false; int ret; for ( ; *header; header++) { - ret = intel_vsec_add_dev(pdev, *header, quirks); + ret = intel_vsec_add_dev(pdev, *header, info); if (ret) dev_info(&pdev->dev, "Could not add device for DVSEC id %d\n", (*header)->id); @@ -244,7 +240,8 @@ static bool intel_vsec_walk_header(struct pci_dev *pdev, unsigned long quirks, return have_devices; } -static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, unsigned long quirks) +static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, + struct intel_vsec_platform_info *info) { bool have_devices = false; int pos = 0; @@ -283,7 +280,7 @@ static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, unsigned long quirks) pci_read_config_dword(pdev, pos + PCI_DVSEC_HEADER2, &hdr); header.id = PCI_DVSEC_HEADER2_ID(hdr); - ret = intel_vsec_add_dev(pdev, &header, quirks); + ret = intel_vsec_add_dev(pdev, &header, info); if (ret) continue; @@ -293,7 +290,8 @@ static bool intel_vsec_walk_dvsec(struct pci_dev *pdev, unsigned long quirks) return have_devices; } -static bool intel_vsec_walk_vsec(struct pci_dev *pdev, unsigned long quirks) +static bool intel_vsec_walk_vsec(struct pci_dev *pdev, + struct intel_vsec_platform_info *info) { bool have_devices = false; int pos = 0; @@ -327,7 +325,7 @@ static bool intel_vsec_walk_vsec(struct pci_dev *pdev, unsigned long quirks) header.tbir = INTEL_DVSEC_TABLE_BAR(table); header.offset = INTEL_DVSEC_TABLE_OFFSET(table); - ret = intel_vsec_add_dev(pdev, &header, quirks); + ret = intel_vsec_add_dev(pdev, &header, info); if (ret) continue; @@ -341,7 +339,6 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id { struct intel_vsec_platform_info *info; bool have_devices = false; - unsigned long quirks = 0; int ret; ret = pcim_enable_device(pdev); @@ -349,17 +346,17 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id return ret; info = (struct intel_vsec_platform_info *)id->driver_data; - if (info) - quirks = info->quirks; + if (!info) + return -EINVAL; - if (intel_vsec_walk_dvsec(pdev, quirks)) + if (intel_vsec_walk_dvsec(pdev, info)) have_devices = true; - if (intel_vsec_walk_vsec(pdev, quirks)) + if (intel_vsec_walk_vsec(pdev, info)) have_devices = true; if (info && (info->quirks & VSEC_QUIRK_NO_DVSEC) && - intel_vsec_walk_header(pdev, quirks, info->capabilities)) + intel_vsec_walk_header(pdev, info)) have_devices = true; if (!have_devices) @@ -370,7 +367,8 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id /* TGL info */ static const struct intel_vsec_platform_info tgl_info = { - .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG | VSEC_QUIRK_TABLE_SHIFT, + .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG | + VSEC_QUIRK_TABLE_SHIFT | VSEC_QUIRK_EARLY_HW, }; /* DG1 info */ @@ -390,7 +388,7 @@ static struct intel_vsec_header *dg1_capabilities[] = { static const struct intel_vsec_platform_info dg1_info = { .capabilities = dg1_capabilities, - .quirks = VSEC_QUIRK_NO_DVSEC, + .quirks = VSEC_QUIRK_NO_DVSEC | VSEC_QUIRK_EARLY_HW, }; #define PCI_DEVICE_ID_INTEL_VSEC_ADL 0x467d @@ -400,7 +398,7 @@ static const struct intel_vsec_platform_info dg1_info = { static const struct pci_device_id intel_vsec_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) }, - { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, NULL) }, + { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, &(struct intel_vsec_platform_info) {}) }, { PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) }, { } }; diff --git a/drivers/platform/x86/intel/vsec.h b/drivers/platform/x86/intel/vsec.h index 4cc36678e8c5..3deeb05cf394 100644 --- a/drivers/platform/x86/intel/vsec.h +++ b/drivers/platform/x86/intel/vsec.h @@ -20,6 +20,15 @@ enum intel_vsec_quirks { /* DVSEC not present (provided in driver data) */ VSEC_QUIRK_NO_DVSEC = BIT(3), + + /* Platforms requiring quirk in the auxiliary driver */ + VSEC_QUIRK_EARLY_HW = BIT(4), +}; + +/* Platform specific data */ +struct intel_vsec_platform_info { + struct intel_vsec_header **capabilities; + unsigned long quirks; }; struct intel_vsec_device { @@ -27,7 +36,7 @@ struct intel_vsec_device { struct pci_dev *pcidev; struct resource *resource; struct ida *ida; - unsigned long quirks; + struct intel_vsec_platform_info *info; int num_resources; }; From 99de05043e77cdecc34c09e4fabffdc6d9147c80 Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Wed, 29 Jun 2022 15:13:32 -0700 Subject: [PATCH 0790/1436] platform/x86/intel/vsec: Add support for Raptor Lake Add Raptor Lake support to Intel's PMT driver. Cc: Srinivas Pandruvada Signed-off-by: David E. Box Signed-off-by: Gayatri Kammela Link: https://lore.kernel.org/r/20220629221334.434307-3-gayatri.kammela@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/vsec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index d48df46e2e27..9368a3d587ab 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -394,11 +394,13 @@ static const struct intel_vsec_platform_info dg1_info = { #define PCI_DEVICE_ID_INTEL_VSEC_ADL 0x467d #define PCI_DEVICE_ID_INTEL_VSEC_DG1 0x490e #define PCI_DEVICE_ID_INTEL_VSEC_OOBMSM 0x09a7 +#define PCI_DEVICE_ID_INTEL_VSEC_RPL 0xa77d #define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d static const struct pci_device_id intel_vsec_pci_ids[] = { { PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, &(struct intel_vsec_platform_info) {}) }, + { PCI_DEVICE_DATA(INTEL, VSEC_RPL, &tgl_info) }, { PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) }, { } }; From ba7e421eee0f98fb2f6aedc83bc5231df64556a1 Mon Sep 17 00:00:00 2001 From: "David E. Box" Date: Wed, 29 Jun 2022 15:13:33 -0700 Subject: [PATCH 0791/1436] platform/x86/intel/pmt: telemetry: Fix fixed region handling Use the telem_type and the fixed block guid to determine if an entry is a fixed region. For certain platforms we don't support this. Cc: Srinivas Pandruvada Signed-off-by: David E. Box Signed-off-by: Gayatri Kammela Link: https://lore.kernel.org/r/20220629221334.434307-4-gayatri.kammela@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/pmt/telemetry.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c index f73ecfd4a309..5e4009c05ecf 100644 --- a/drivers/platform/x86/intel/pmt/telemetry.c +++ b/drivers/platform/x86/intel/pmt/telemetry.c @@ -23,12 +23,19 @@ #define TELEM_GUID_OFFSET 0x4 #define TELEM_BASE_OFFSET 0x8 #define TELEM_ACCESS(v) ((v) & GENMASK(3, 0)) +#define TELEM_TYPE(v) (((v) & GENMASK(7, 4)) >> 4) /* size is in bytes */ #define TELEM_SIZE(v) (((v) & GENMASK(27, 12)) >> 10) /* Used by client hardware to identify a fixed telemetry entry*/ #define TELEM_CLIENT_FIXED_BLOCK_GUID 0x10000000 +enum telem_type { + TELEM_TYPE_PUNIT = 0, + TELEM_TYPE_CRASHLOG, + TELEM_TYPE_PUNIT_FIXED, +}; + struct pmt_telem_priv { int num_entries; struct intel_pmt_entry entry[]; @@ -39,10 +46,15 @@ static bool pmt_telem_region_overlaps(struct intel_pmt_entry *entry, { u32 guid = readl(entry->disc_table + TELEM_GUID_OFFSET); - if (guid != TELEM_CLIENT_FIXED_BLOCK_GUID) - return false; + if (intel_pmt_is_early_client_hw(dev)) { + u32 type = TELEM_TYPE(readl(entry->disc_table)); - return intel_pmt_is_early_client_hw(dev); + if ((type == TELEM_TYPE_PUNIT_FIXED) || + (guid == TELEM_CLIENT_FIXED_BLOCK_GUID)) + return true; + } + + return false; } static int pmt_telem_header_decode(struct intel_pmt_entry *entry, From 0d4c331af4d169de26186170010c7b7acd49f266 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:45 +0100 Subject: [PATCH 0792/1436] ACPI: PPTT: Use table offset as fw_token instead of virtual address There is need to use the cache sharing information quite early during the boot before the secondary cores are up and running. The permanent memory map for all the ACPI tables(via acpi_permanent_mmap) is turned on in acpi_early_init() which is quite late for the above requirement. As a result there is possibility that the ACPI PPTT gets mapped to different virtual addresses. In such scenarios, using virtual address as fw_token before the acpi_permanent_mmap is enabled results in different fw_token for the same cache entity and hence wrong cache sharing information will be deduced based on the same. Instead of using virtual address, just use the table offset as the unique firmware token for the caches. The same offset is used as ACPI identifiers if the firmware has not set a valid one for other entries in the ACPI PPTT. Link: https://lore.kernel.org/r/20220704101605.1318280-2-sudeep.holla@arm.com Cc: linux-acpi@vger.kernel.org Tested-by: Ionela Voinescu Tested-by: Conor Dooley Acked-by: Rafael J. Wysocki Signed-off-by: Sudeep Holla --- drivers/acpi/pptt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c index 701f61c01359..763f021d45e6 100644 --- a/drivers/acpi/pptt.c +++ b/drivers/acpi/pptt.c @@ -437,7 +437,8 @@ static void cache_setup_acpi_cpu(struct acpi_table_header *table, pr_debug("found = %p %p\n", found_cache, cpu_node); if (found_cache) update_cache_properties(this_leaf, found_cache, - cpu_node, table->revision); + ACPI_TO_POINTER(ACPI_PTR_DIFF(cpu_node, table)), + table->revision); index++; } From d4ec840baecbed280c7305f9103a10641d4d3799 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:46 +0100 Subject: [PATCH 0793/1436] cacheinfo: Use of_cpu_device_node_get instead cpu_dev->of_node The of_cpu_device_node_get takes care of fetching the CPU'd device node either from cached cpu_dev->of_node if cpu_dev is initialised or uses of_get_cpu_node to parse and fetch node if cpu_dev isn't available yet. Just use of_cpu_device_node_get instead of getting the cpu device first and then using cpu_dev->of_node for two reasons: 1. There is no other use of cpu_dev and can be simplified 2. It enabled the use detect_cache_attributes and hence cache_setup_of_node much earlier before the CPUs are registered as devices. Link: https://lore.kernel.org/r/20220704101605.1318280-3-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/cacheinfo.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index dad296229161..b0bde272e2ae 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -157,7 +157,6 @@ static int cache_setup_of_node(unsigned int cpu) { struct device_node *np; struct cacheinfo *this_leaf; - struct device *cpu_dev = get_cpu_device(cpu); struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); unsigned int index = 0; @@ -166,11 +165,7 @@ static int cache_setup_of_node(unsigned int cpu) return 0; } - if (!cpu_dev) { - pr_err("No cpu device for CPU %d\n", cpu); - return -ENODEV; - } - np = cpu_dev->of_node; + np = of_cpu_device_node_get(cpu); if (!np) { pr_err("Failed to find cpu%d device node\n", cpu); return -ENOENT; From b14e8d21f726f4ffeaf8833783eda68a1c152b15 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:47 +0100 Subject: [PATCH 0794/1436] cacheinfo: Add helper to access any cache index for a given CPU The cacheinfo for a given CPU at a given index is used at quite a few places by fetching the base point for index 0 using the helper per_cpu_cacheinfo(cpu) and offsetting it by the required index. Instead, add another helper to fetch the required pointer directly and use it to simplify and improve readability. Link: https://lore.kernel.org/r/20220704101605.1318280-4-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/cacheinfo.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index b0bde272e2ae..e13ef41763e4 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -25,6 +25,8 @@ static DEFINE_PER_CPU(struct cpu_cacheinfo, ci_cpu_cacheinfo); #define ci_cacheinfo(cpu) (&per_cpu(ci_cpu_cacheinfo, cpu)) #define cache_leaves(cpu) (ci_cacheinfo(cpu)->num_leaves) #define per_cpu_cacheinfo(cpu) (ci_cacheinfo(cpu)->info_list) +#define per_cpu_cacheinfo_idx(cpu, idx) \ + (per_cpu_cacheinfo(cpu) + (idx)) struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu) { @@ -172,7 +174,7 @@ static int cache_setup_of_node(unsigned int cpu) } while (index < cache_leaves(cpu)) { - this_leaf = this_cpu_ci->info_list + index; + this_leaf = per_cpu_cacheinfo_idx(cpu, index); if (this_leaf->level != 1) np = of_find_next_cache_node(np); else @@ -231,7 +233,7 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) for (index = 0; index < cache_leaves(cpu); index++) { unsigned int i; - this_leaf = this_cpu_ci->info_list + index; + this_leaf = per_cpu_cacheinfo_idx(cpu, index); /* skip if shared_cpu_map is already populated */ if (!cpumask_empty(&this_leaf->shared_cpu_map)) continue; @@ -242,7 +244,7 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) if (i == cpu || !sib_cpu_ci->info_list) continue;/* skip if itself or no cacheinfo */ - sib_leaf = sib_cpu_ci->info_list + index; + sib_leaf = per_cpu_cacheinfo_idx(i, index); if (cache_leaves_are_shared(this_leaf, sib_leaf)) { cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map); cpumask_set_cpu(i, &this_leaf->shared_cpu_map); @@ -258,12 +260,11 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) static void cache_shared_cpu_map_remove(unsigned int cpu) { - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); struct cacheinfo *this_leaf, *sib_leaf; unsigned int sibling, index; for (index = 0; index < cache_leaves(cpu); index++) { - this_leaf = this_cpu_ci->info_list + index; + this_leaf = per_cpu_cacheinfo_idx(cpu, index); for_each_cpu(sibling, &this_leaf->shared_cpu_map) { struct cpu_cacheinfo *sib_cpu_ci; @@ -274,7 +275,7 @@ static void cache_shared_cpu_map_remove(unsigned int cpu) if (!sib_cpu_ci->info_list) continue; - sib_leaf = sib_cpu_ci->info_list + index; + sib_leaf = per_cpu_cacheinfo_idx(sibling, index); cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map); cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map); } @@ -609,7 +610,6 @@ static int cache_add_dev(unsigned int cpu) int rc; struct device *ci_dev, *parent; struct cacheinfo *this_leaf; - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); const struct attribute_group **cache_groups; rc = cpu_cache_sysfs_init(cpu); @@ -618,7 +618,7 @@ static int cache_add_dev(unsigned int cpu) parent = per_cpu_cache_dev(cpu); for (i = 0; i < cache_leaves(cpu); i++) { - this_leaf = this_cpu_ci->info_list + i; + this_leaf = per_cpu_cacheinfo_idx(cpu, i); if (this_leaf->disable_sysfs) continue; if (this_leaf->type == CACHE_TYPE_NOCACHE) From 9447eb0f1575572218267180b4edff937b3aec57 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:48 +0100 Subject: [PATCH 0795/1436] cacheinfo: Move cache_leaves_are_shared out of CONFIG_OF cache_leaves_are_shared is already used even with ACPI and PPTT. It checks if the cache leaves are the shared based on fw_token pointer. However it is defined conditionally only if CONFIG_OF is enabled which is wrong. Move the function cache_leaves_are_shared out of CONFIG_OF and keep it generic. It also handles the case where both OF and ACPI is not defined. Link: https://lore.kernel.org/r/20220704101605.1318280-5-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/cacheinfo.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index e13ef41763e4..2cea9201f31c 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -33,13 +33,21 @@ struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu) return ci_cacheinfo(cpu); } -#ifdef CONFIG_OF static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, struct cacheinfo *sib_leaf) { + /* + * For non DT/ACPI systems, assume unique level 1 caches, + * system-wide shared caches for all other levels. This will be used + * only if arch specific code has not populated shared_cpu_map + */ + if (!(IS_ENABLED(CONFIG_OF) || IS_ENABLED(CONFIG_ACPI))) + return !(this_leaf->level == 1); + return sib_leaf->fw_token == this_leaf->fw_token; } +#ifdef CONFIG_OF /* OF properties to query for a given cache type */ struct cache_type_info { const char *size_prop; @@ -193,16 +201,6 @@ static int cache_setup_of_node(unsigned int cpu) } #else static inline int cache_setup_of_node(unsigned int cpu) { return 0; } -static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, - struct cacheinfo *sib_leaf) -{ - /* - * For non-DT/ACPI systems, assume unique level 1 caches, system-wide - * shared caches for all other levels. This will be used only if - * arch specific code has not populated shared_cpu_map - */ - return !(this_leaf->level == 1); -} #endif int __weak cache_setup_acpi(unsigned int cpu) From cc1cfc47ea47187a21ec1f079b3c53264157fe15 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:49 +0100 Subject: [PATCH 0796/1436] cacheinfo: Add support to check if last level cache(LLC) is valid or shared It is useful to have helper to check if the given two CPUs share last level cache. We can do that check by comparing fw_token or by comparing the cache ID. Currently we check just for fw_token as the cache ID is optional. This helper can be used to build the llc_sibling during arch specific topology parsing and feeding information to the sched_domains. This also helps to get rid of llc_id in the CPU topology as it is sort of duplicate information. Also add helper to check if the llc information in cacheinfo is valid or not. Link: https://lore.kernel.org/r/20220704101605.1318280-6-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/cacheinfo.c | 26 ++++++++++++++++++++++++++ include/linux/cacheinfo.h | 2 ++ 2 files changed, 28 insertions(+) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 2cea9201f31c..fdc1baa342f1 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -47,6 +47,32 @@ static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, return sib_leaf->fw_token == this_leaf->fw_token; } +bool last_level_cache_is_valid(unsigned int cpu) +{ + struct cacheinfo *llc; + + if (!cache_leaves(cpu)) + return false; + + llc = per_cpu_cacheinfo_idx(cpu, cache_leaves(cpu) - 1); + + return !!llc->fw_token; +} + +bool last_level_cache_is_shared(unsigned int cpu_x, unsigned int cpu_y) +{ + struct cacheinfo *llc_x, *llc_y; + + if (!last_level_cache_is_valid(cpu_x) || + !last_level_cache_is_valid(cpu_y)) + return false; + + llc_x = per_cpu_cacheinfo_idx(cpu_x, cache_leaves(cpu_x) - 1); + llc_y = per_cpu_cacheinfo_idx(cpu_y, cache_leaves(cpu_y) - 1); + + return cache_leaves_are_shared(llc_x, llc_y); +} + #ifdef CONFIG_OF /* OF properties to query for a given cache type */ struct cache_type_info { diff --git a/include/linux/cacheinfo.h b/include/linux/cacheinfo.h index 4ff37cb763ae..7e429bc5c1a4 100644 --- a/include/linux/cacheinfo.h +++ b/include/linux/cacheinfo.h @@ -82,6 +82,8 @@ struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu); int init_cache_level(unsigned int cpu); int populate_cache_leaves(unsigned int cpu); int cache_setup_acpi(unsigned int cpu); +bool last_level_cache_is_valid(unsigned int cpu); +bool last_level_cache_is_shared(unsigned int cpu_x, unsigned int cpu_y); #ifndef CONFIG_ACPI_PPTT /* * acpi_find_last_cache_level is only called on ACPI enabled From 36bbc5b4ffab33ccac0f4db27f619a6ba7a4fd32 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:50 +0100 Subject: [PATCH 0797/1436] cacheinfo: Allow early detection and population of cache attributes Some architecture/platforms may need to setup cache properties very early in the boot along with other cpu topologies so that all these information can be used to build sched_domains which is used by the scheduler. Allow detect_cache_attributes to be called quite early during the boot. Link: https://lore.kernel.org/r/20220704101605.1318280-7-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/cacheinfo.c | 55 ++++++++++++++++++++++++++------------- include/linux/cacheinfo.h | 1 + 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index fdc1baa342f1..4d21a1022fa9 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -193,14 +193,8 @@ static int cache_setup_of_node(unsigned int cpu) { struct device_node *np; struct cacheinfo *this_leaf; - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); unsigned int index = 0; - /* skip if fw_token is already populated */ - if (this_cpu_ci->info_list->fw_token) { - return 0; - } - np = of_cpu_device_node_get(cpu); if (!np) { pr_err("Failed to find cpu%d device node\n", cpu); @@ -236,6 +230,18 @@ int __weak cache_setup_acpi(unsigned int cpu) unsigned int coherency_max_size; +static int cache_setup_properties(unsigned int cpu) +{ + int ret = 0; + + if (of_have_populated_dt()) + ret = cache_setup_of_node(cpu); + else if (!acpi_disabled) + ret = cache_setup_acpi(cpu); + + return ret; +} + static int cache_shared_cpu_map_setup(unsigned int cpu) { struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); @@ -246,21 +252,21 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) if (this_cpu_ci->cpu_map_populated) return 0; - if (of_have_populated_dt()) - ret = cache_setup_of_node(cpu); - else if (!acpi_disabled) - ret = cache_setup_acpi(cpu); - - if (ret) - return ret; + /* + * skip setting up cache properties if LLC is valid, just need + * to update the shared cpu_map if the cache attributes were + * populated early before all the cpus are brought online + */ + if (!last_level_cache_is_valid(cpu)) { + ret = cache_setup_properties(cpu); + if (ret) + return ret; + } for (index = 0; index < cache_leaves(cpu); index++) { unsigned int i; this_leaf = per_cpu_cacheinfo_idx(cpu, index); - /* skip if shared_cpu_map is already populated */ - if (!cpumask_empty(&this_leaf->shared_cpu_map)) - continue; cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); for_each_online_cpu(i) { @@ -330,17 +336,28 @@ int __weak populate_cache_leaves(unsigned int cpu) return -ENOENT; } -static int detect_cache_attributes(unsigned int cpu) +int detect_cache_attributes(unsigned int cpu) { int ret; + /* Since early detection of the cacheinfo is allowed via this + * function and this also gets called as CPU hotplug callbacks via + * cacheinfo_cpu_online, the initialisation can be skipped and only + * CPU maps can be updated as the CPU online status would be update + * if called via cacheinfo_cpu_online path. + */ + if (per_cpu_cacheinfo(cpu)) + goto update_cpu_map; + if (init_cache_level(cpu) || !cache_leaves(cpu)) return -ENOENT; per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu), sizeof(struct cacheinfo), GFP_KERNEL); - if (per_cpu_cacheinfo(cpu) == NULL) + if (per_cpu_cacheinfo(cpu) == NULL) { + cache_leaves(cpu) = 0; return -ENOMEM; + } /* * populate_cache_leaves() may completely setup the cache leaves and @@ -349,6 +366,8 @@ static int detect_cache_attributes(unsigned int cpu) ret = populate_cache_leaves(cpu); if (ret) goto free_ci; + +update_cpu_map: /* * For systems using DT for cache hierarchy, fw_token * and shared_cpu_map will be set up here only if they are diff --git a/include/linux/cacheinfo.h b/include/linux/cacheinfo.h index 7e429bc5c1a4..00b7a6ae8617 100644 --- a/include/linux/cacheinfo.h +++ b/include/linux/cacheinfo.h @@ -84,6 +84,7 @@ int populate_cache_leaves(unsigned int cpu); int cache_setup_acpi(unsigned int cpu); bool last_level_cache_is_valid(unsigned int cpu); bool last_level_cache_is_shared(unsigned int cpu_x, unsigned int cpu_y); +int detect_cache_attributes(unsigned int cpu); #ifndef CONFIG_ACPI_PPTT /* * acpi_find_last_cache_level is only called on ACPI enabled From f16d1becf96f0a95dc9e1a5a7f97feeec2b149d5 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:51 +0100 Subject: [PATCH 0798/1436] cacheinfo: Use cache identifiers to check if the caches are shared if available The cache identifiers is an optional property on most of the platforms. The presence of one must be indicated by the CACHE_ID valid bit in the attributes. We can use the cache identifiers provided by the firmware to check if any two cpus share the same cache instead of relying on the fw_token generated and set in the OS. Link: https://lore.kernel.org/r/20220704101605.1318280-8-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Signed-off-by: Sudeep Holla --- drivers/base/cacheinfo.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 4d21a1022fa9..e331b399adeb 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -44,6 +44,10 @@ static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, if (!(IS_ENABLED(CONFIG_OF) || IS_ENABLED(CONFIG_ACPI))) return !(this_leaf->level == 1); + if ((sib_leaf->attributes & CACHE_ID) && + (this_leaf->attributes & CACHE_ID)) + return sib_leaf->id == this_leaf->id; + return sib_leaf->fw_token == this_leaf->fw_token; } @@ -56,7 +60,8 @@ bool last_level_cache_is_valid(unsigned int cpu) llc = per_cpu_cacheinfo_idx(cpu, cache_leaves(cpu) - 1); - return !!llc->fw_token; + return (llc->attributes & CACHE_ID) || !!llc->fw_token; + } bool last_level_cache_is_shared(unsigned int cpu_x, unsigned int cpu_y) From 521103134a0d07774c8b17f25ff0ef70cbd56c9d Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:52 +0100 Subject: [PATCH 0799/1436] cacheinfo: Align checks in cache_shared_cpu_map_{setup,remove} for readability The checks to skip the CPU itself or no cacheinfo case are implemented bit differently though the effect is exactly same. Just align the implementation in both cache_shared_cpu_map_{setup,remove} just for improved readability. No functional change. Link: https://lore.kernel.org/r/20220704101605.1318280-9-sudeep.holla@arm.com Tested-by: Conor Dooley Signed-off-by: Sudeep Holla --- drivers/base/cacheinfo.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index e331b399adeb..65d566ff24c4 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -279,6 +279,7 @@ static int cache_shared_cpu_map_setup(unsigned int cpu) if (i == cpu || !sib_cpu_ci->info_list) continue;/* skip if itself or no cacheinfo */ + sib_leaf = per_cpu_cacheinfo_idx(i, index); if (cache_leaves_are_shared(this_leaf, sib_leaf)) { cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map); @@ -301,14 +302,11 @@ static void cache_shared_cpu_map_remove(unsigned int cpu) for (index = 0; index < cache_leaves(cpu); index++) { this_leaf = per_cpu_cacheinfo_idx(cpu, index); for_each_cpu(sibling, &this_leaf->shared_cpu_map) { - struct cpu_cacheinfo *sib_cpu_ci; + struct cpu_cacheinfo *sib_cpu_ci = + get_cpu_cacheinfo(sibling); - if (sibling == cpu) /* skip itself */ - continue; - - sib_cpu_ci = get_cpu_cacheinfo(sibling); - if (!sib_cpu_ci->info_list) - continue; + if (sibling == cpu || !sib_cpu_ci->info_list) + continue;/* skip if itself or no cacheinfo */ sib_leaf = per_cpu_cacheinfo_idx(sibling, index); cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map); From 38db9b95464f82fed28794afe0214d9439d86f7c Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:53 +0100 Subject: [PATCH 0800/1436] arch_topology: Add support to parse and detect cache attributes Currently ACPI populates just the minimum information about the last level cache from PPTT in order to feed the same to build sched_domains. Similar support for DT platforms is not present. In order to enable the same, the entire cache hierarchy information can be built as part of CPU topoplogy parsing both on ACPI and DT platforms. Note that this change builds the cacheinfo early even on ACPI systems, but the current mechanism of building llc_sibling mask remains unchanged. Link: https://lore.kernel.org/r/20220704101605.1318280-10-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 579c851a2bd7..e2f7d9ea558e 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -780,15 +781,28 @@ __weak int __init parse_acpi_topology(void) #if defined(CONFIG_ARM64) || defined(CONFIG_RISCV) void __init init_cpu_topology(void) { - reset_cpu_topology(); + int ret, cpu; - /* - * Discard anything that was parsed if we hit an error so we - * don't use partial information. - */ - if (parse_acpi_topology()) - reset_cpu_topology(); - else if (of_have_populated_dt() && parse_dt_topology()) + reset_cpu_topology(); + ret = parse_acpi_topology(); + if (!ret) + ret = of_have_populated_dt() && parse_dt_topology(); + + if (ret) { + /* + * Discard anything that was parsed if we hit an error so we + * don't use partial information. + */ reset_cpu_topology(); + return; + } + + for_each_possible_cpu(cpu) { + ret = detect_cache_attributes(cpu); + if (ret) { + pr_info("Early cacheinfo failed, ret = %d\n", ret); + break; + } + } } #endif From f027db2f9a09e76858d06828b9ff817272d64ccc Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:54 +0100 Subject: [PATCH 0801/1436] arch_topology: Use the last level cache information from the cacheinfo The cacheinfo is now initialised early along with the CPU topology initialisation. Instead of relying on the LLC ID information parsed separately only with ACPI PPTT elsewhere, migrate to use the similar information from the cacheinfo. This is generic for both DT and ACPI systems. The ACPI LLC ID information parsed separately can now be removed from arch specific code. Link: https://lore.kernel.org/r/20220704101605.1318280-11-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index e2f7d9ea558e..4f936c984fb6 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -668,7 +668,8 @@ const struct cpumask *cpu_coregroup_mask(int cpu) /* not numa in package, lets use the package siblings */ core_mask = &cpu_topology[cpu].core_sibling; } - if (cpu_topology[cpu].llc_id != -1) { + + if (last_level_cache_is_valid(cpu)) { if (cpumask_subset(&cpu_topology[cpu].llc_sibling, core_mask)) core_mask = &cpu_topology[cpu].llc_sibling; } @@ -699,7 +700,7 @@ void update_siblings_masks(unsigned int cpuid) for_each_online_cpu(cpu) { cpu_topo = &cpu_topology[cpu]; - if (cpu_topo->llc_id != -1 && cpuid_topo->llc_id == cpu_topo->llc_id) { + if (last_level_cache_is_shared(cpu, cpuid)) { cpumask_set_cpu(cpu, &cpuid_topo->llc_sibling); cpumask_set_cpu(cpuid, &cpu_topo->llc_sibling); } From 798eb5b4d41b282f021afc90b5187e91fc731930 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:55 +0100 Subject: [PATCH 0802/1436] arm64: topology: Remove redundant setting of llc_id in CPU topology Since the cacheinfo LLC information is used directly in arch_topology, there is no need to parse and fetch the LLC ID information only for ACPI systems. Just drop the redundant parsing and setting of llc_id in CPU topology from ACPI PPTT. Link: https://lore.kernel.org/r/20220704101605.1318280-12-sudeep.holla@arm.com Cc: Will Deacon Cc: Catalin Marinas Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Acked-by: Catalin Marinas Signed-off-by: Sudeep Holla --- arch/arm64/kernel/topology.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 9ab78ad826e2..869ffc4d4484 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -89,8 +89,6 @@ int __init parse_acpi_topology(void) return 0; for_each_possible_cpu(cpu) { - int i, cache_id; - topology_id = find_acpi_cpu_topology(cpu, 0); if (topology_id < 0) return topology_id; @@ -107,18 +105,6 @@ int __init parse_acpi_topology(void) cpu_topology[cpu].cluster_id = topology_id; topology_id = find_acpi_cpu_topology_package(cpu); cpu_topology[cpu].package_id = topology_id; - - i = acpi_find_last_cache_level(cpu); - - if (i > 0) { - /* - * this is the only part of cpu_topology that has - * a direct relationship with the cache topology - */ - cache_id = find_acpi_cpu_cache_topology(cpu, i); - if (cache_id > 0) - cpu_topology[cpu].llc_id = cache_id; - } } return 0; From 5b8dc787ce4a45c87254d1b0b22f161347ab7f81 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:56 +0100 Subject: [PATCH 0803/1436] arch_topology: Drop LLC identifier stash from the CPU topology Since the cacheinfo LLC information is used directly in arch_topology, there is no need to parse and store the LLC ID information only for ACPI systems in the CPU topology. Remove the redundant LLC ID from the generic CPU arch_topology information. Link: https://lore.kernel.org/r/20220704101605.1318280-13-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 1 - include/linux/arch_topology.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 4f936c984fb6..8206990c679f 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -752,7 +752,6 @@ void __init reset_cpu_topology(void) cpu_topo->core_id = -1; cpu_topo->cluster_id = -1; cpu_topo->package_id = -1; - cpu_topo->llc_id = -1; clear_cpu_topology(cpu); } diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h index 58cbe18d825c..a07b510e7dc5 100644 --- a/include/linux/arch_topology.h +++ b/include/linux/arch_topology.h @@ -68,7 +68,6 @@ struct cpu_topology { int core_id; int cluster_id; int package_id; - int llc_id; cpumask_t thread_sibling; cpumask_t core_sibling; cpumask_t cluster_sibling; From 3f8283296b16c4e43fd79a5ac364ae8171fe1567 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:57 +0100 Subject: [PATCH 0804/1436] arch_topology: Set thread sibling cpumask only within the cluster Currently the cluster identifier is not set on the DT based platforms. The reset or default value is -1 for all the CPUs. Once we assign the cluster identifier values correctly that may result in getting the thread siblings wrong as the core identifiers can be same for 2 different CPUs belonging to 2 different cluster. So, in order to get the thread sibling cpumasks correct, we need to update them only if the cores they belong are in the same cluster within the socket. Let us skip updation of the thread sibling cpumaks if the cluster identifier doesn't match. This change won't affect even if the cluster identifiers are not set currently but will avoid any breakage once we set the same correctly. Link: https://lore.kernel.org/r/20220704101605.1318280-14-sudeep.holla@arm.com Tested-by: Gavin Shan Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 8206990c679f..6ab173caf1dc 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -708,15 +708,17 @@ void update_siblings_masks(unsigned int cpuid) if (cpuid_topo->package_id != cpu_topo->package_id) continue; - if (cpuid_topo->cluster_id == cpu_topo->cluster_id && - cpuid_topo->cluster_id != -1) { + cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); + cpumask_set_cpu(cpu, &cpuid_topo->core_sibling); + + if (cpuid_topo->cluster_id != cpu_topo->cluster_id) + continue; + + if (cpuid_topo->cluster_id != -1) { cpumask_set_cpu(cpu, &cpuid_topo->cluster_sibling); cpumask_set_cpu(cpuid, &cpu_topo->cluster_sibling); } - cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); - cpumask_set_cpu(cpu, &cpuid_topo->core_sibling); - if (cpuid_topo->core_id != cpu_topo->core_id) continue; From 9eb5e54f876dda1aae0aef10bdd61da4331509ba Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:58 +0100 Subject: [PATCH 0805/1436] arch_topology: Check for non-negative value rather than -1 for IDs validity Instead of just comparing the cpu topology IDs with -1 to check their validity, improve that by checking for a valid non-negative value. Link: https://lore.kernel.org/r/20220704101605.1318280-15-sudeep.holla@arm.com Suggested-by: Andy Shevchenko Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 6ab173caf1dc..c0b0ee64a79d 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -642,7 +642,7 @@ static int __init parse_dt_topology(void) * only mark cores described in the DT as possible. */ for_each_possible_cpu(cpu) - if (cpu_topology[cpu].package_id == -1) + if (cpu_topology[cpu].package_id < 0) ret = -EINVAL; out_map: @@ -714,7 +714,7 @@ void update_siblings_masks(unsigned int cpuid) if (cpuid_topo->cluster_id != cpu_topo->cluster_id) continue; - if (cpuid_topo->cluster_id != -1) { + if (cpuid_topo->cluster_id >= 0) { cpumask_set_cpu(cpu, &cpuid_topo->cluster_sibling); cpumask_set_cpu(cpuid, &cpu_topo->cluster_sibling); } From 5a01bb8efb5177236498fc57b147cabd2b792613 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:15:59 +0100 Subject: [PATCH 0806/1436] arch_topology: Avoid parsing through all the CPUs once a outlier CPU is found There is no point in looping through all the CPU's physical package identifier to check if it is valid or not once a CPU which is outside the topology(i.e. outlier CPU) is found. Let us just break out of the loop early in such case. Link: https://lore.kernel.org/r/20220704101605.1318280-16-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Gavin Shan Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index c0b0ee64a79d..8f6a964d2512 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -642,8 +642,10 @@ static int __init parse_dt_topology(void) * only mark cores described in the DT as possible. */ for_each_possible_cpu(cpu) - if (cpu_topology[cpu].package_id < 0) + if (cpu_topology[cpu].package_id < 0) { ret = -EINVAL; + break; + } out_map: of_node_put(map); From 26a2b73a7b15a51ec1409648c9b43882f66fbacf Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:16:00 +0100 Subject: [PATCH 0807/1436] arch_topology: Don't set cluster identifier as physical package identifier Currently as we parse the CPU topology from /cpu-map node from the device tree, we assign generated cluster count as the physical package identifier for each CPU which is wrong. The device tree bindings for CPU topology supports sockets to infer the socket or physical package identifier for a given CPU. Since it is fairly new and not supported on most of the old and existing systems, we can assume all such systems have single socket/physical package. Fix the physical package identifier to 0 by removing the assignment of cluster identifier to the same. Link: https://lore.kernel.org/r/20220704101605.1318280-17-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Ionela Voinescu Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 8f6a964d2512..e384afb6cac7 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -549,7 +549,6 @@ static int __init parse_cluster(struct device_node *cluster, int depth) bool leaf = true; bool has_cores = false; struct device_node *c; - static int package_id __initdata; int core_id = 0; int i, ret; @@ -588,7 +587,7 @@ static int __init parse_cluster(struct device_node *cluster, int depth) } if (leaf) { - ret = parse_core(c, package_id, core_id++); + ret = parse_core(c, 0, core_id++); } else { pr_err("%pOF: Non-leaf cluster with core %s\n", cluster, name); @@ -605,9 +604,6 @@ static int __init parse_cluster(struct device_node *cluster, int depth) if (leaf && !has_cores) pr_warn("%pOF: empty cluster\n", cluster); - if (leaf) - package_id++; - return 0; } From bfcc4397435dc0407099b9a805391abc05c2313b Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Mon, 4 Jul 2022 11:16:01 +0100 Subject: [PATCH 0808/1436] arch_topology: Limit span of cpu_clustergroup_mask() Currently the cluster identifier is not set on DT based platforms. The reset or default value is -1 for all the CPUs. Once we assign the cluster identifier values correctly, the cluster_sibling mask will be populated and returned by cpu_clustergroup_mask() to contribute in the creation of the CLS scheduling domain level, if SCHED_CLUSTER is enabled. To avoid topologies that will result in questionable or incorrect scheduling domains, impose restrictions regarding the span of clusters, as presented to scheduling domains building code: cluster_sibling should not span more or the same CPUs as cpu_coregroup_mask(). This is needed in order to obtain a strict separation between the MC and CLS levels, and maintain the same domains for existing platforms in the presence of CONFIG_SCHED_CLUSTER, where the new cluster information is redundant and irrelevant for the scheduler. While previously the scheduling domain builder code would have removed MC as redundant and kept CLS if SCHED_CLUSTER was enabled and the cpu_coregroup_mask() and cpu_clustergroup_mask() spanned the same CPUs, now CLS will be removed and MC kept. Link: https://lore.kernel.org/r/20220704101605.1318280-18-sudeep.holla@arm.com Cc: Darren Hart Tested-by: Conor Dooley Acked-by: Vincent Guittot Signed-off-by: Ionela Voinescu Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index e384afb6cac7..591c1f8e15e2 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -686,6 +686,14 @@ const struct cpumask *cpu_coregroup_mask(int cpu) const struct cpumask *cpu_clustergroup_mask(int cpu) { + /* + * Forbid cpu_clustergroup_mask() to span more or the same CPUs as + * cpu_coregroup_mask(). + */ + if (cpumask_subset(cpu_coregroup_mask(cpu), + &cpu_topology[cpu].cluster_sibling)) + return get_cpu_mask(cpu); + return &cpu_topology[cpu].cluster_sibling; } From 556c9678a7d4456a677588ce308200a673b7eb1f Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:16:02 +0100 Subject: [PATCH 0809/1436] arch_topology: Set cluster identifier in each core/thread from /cpu-map Let us set the cluster identifier as parsed from the device tree cluster nodes within /cpu-map. We don't support nesting of clusters yet as there are no real hardware to support clusters of clusters. Link: https://lore.kernel.org/r/20220704101605.1318280-19-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Ionela Voinescu Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 591c1f8e15e2..217a91fc1f59 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -497,7 +497,7 @@ static int __init get_cpu_for_node(struct device_node *node) } static int __init parse_core(struct device_node *core, int package_id, - int core_id) + int cluster_id, int core_id) { char name[20]; bool leaf = true; @@ -513,6 +513,7 @@ static int __init parse_core(struct device_node *core, int package_id, cpu = get_cpu_for_node(t); if (cpu >= 0) { cpu_topology[cpu].package_id = package_id; + cpu_topology[cpu].cluster_id = cluster_id; cpu_topology[cpu].core_id = core_id; cpu_topology[cpu].thread_id = i; } else if (cpu != -ENODEV) { @@ -534,6 +535,7 @@ static int __init parse_core(struct device_node *core, int package_id, } cpu_topology[cpu].package_id = package_id; + cpu_topology[cpu].cluster_id = cluster_id; cpu_topology[cpu].core_id = core_id; } else if (leaf && cpu != -ENODEV) { pr_err("%pOF: Can't get CPU for leaf core\n", core); @@ -543,7 +545,8 @@ static int __init parse_core(struct device_node *core, int package_id, return 0; } -static int __init parse_cluster(struct device_node *cluster, int depth) +static int __init +parse_cluster(struct device_node *cluster, int cluster_id, int depth) { char name[20]; bool leaf = true; @@ -563,7 +566,7 @@ static int __init parse_cluster(struct device_node *cluster, int depth) c = of_get_child_by_name(cluster, name); if (c) { leaf = false; - ret = parse_cluster(c, depth + 1); + ret = parse_cluster(c, i, depth + 1); of_node_put(c); if (ret != 0) return ret; @@ -587,7 +590,7 @@ static int __init parse_cluster(struct device_node *cluster, int depth) } if (leaf) { - ret = parse_core(c, 0, core_id++); + ret = parse_core(c, 0, cluster_id, core_id++); } else { pr_err("%pOF: Non-leaf cluster with core %s\n", cluster, name); @@ -627,7 +630,7 @@ static int __init parse_dt_topology(void) if (!map) goto out; - ret = parse_cluster(map, 0); + ret = parse_cluster(map, -1, 0); if (ret != 0) goto out_map; From dea8c0b40fb500be29f4649cf01202e42a8a54f8 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:16:03 +0100 Subject: [PATCH 0810/1436] arch_topology: Add support for parsing sockets in /cpu-map Finally let us add support for socket nodes in /cpu-map in the device tree. Since this may not be present in all the old platforms and even most of the existing platforms, we need to assume absence of the socket node indicates that it is a single socket system and handle appropriately. Also it is likely that most single socket systems skip to as the node since it is optional. Link: https://lore.kernel.org/r/20220704101605.1318280-20-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Reviewed-by: Ionela Voinescu Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 37 +++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 217a91fc1f59..8719c4458df9 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -545,8 +545,8 @@ static int __init parse_core(struct device_node *core, int package_id, return 0; } -static int __init -parse_cluster(struct device_node *cluster, int cluster_id, int depth) +static int __init parse_cluster(struct device_node *cluster, int package_id, + int cluster_id, int depth) { char name[20]; bool leaf = true; @@ -566,7 +566,7 @@ parse_cluster(struct device_node *cluster, int cluster_id, int depth) c = of_get_child_by_name(cluster, name); if (c) { leaf = false; - ret = parse_cluster(c, i, depth + 1); + ret = parse_cluster(c, package_id, i, depth + 1); of_node_put(c); if (ret != 0) return ret; @@ -590,7 +590,8 @@ parse_cluster(struct device_node *cluster, int cluster_id, int depth) } if (leaf) { - ret = parse_core(c, 0, cluster_id, core_id++); + ret = parse_core(c, package_id, cluster_id, + core_id++); } else { pr_err("%pOF: Non-leaf cluster with core %s\n", cluster, name); @@ -610,6 +611,32 @@ parse_cluster(struct device_node *cluster, int cluster_id, int depth) return 0; } +static int __init parse_socket(struct device_node *socket) +{ + char name[20]; + struct device_node *c; + bool has_socket = false; + int package_id = 0, ret; + + do { + snprintf(name, sizeof(name), "socket%d", package_id); + c = of_get_child_by_name(socket, name); + if (c) { + has_socket = true; + ret = parse_cluster(c, package_id, -1, 0); + of_node_put(c); + if (ret != 0) + return ret; + } + package_id++; + } while (c); + + if (!has_socket) + ret = parse_cluster(socket, 0, -1, 0); + + return ret; +} + static int __init parse_dt_topology(void) { struct device_node *cn, *map; @@ -630,7 +657,7 @@ static int __init parse_dt_topology(void) if (!map) goto out; - ret = parse_cluster(map, -1, 0); + ret = parse_socket(map); if (ret != 0) goto out_map; From 00e66e37af0090f9ed95ca4bc3d8f5c6171daaf0 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:16:04 +0100 Subject: [PATCH 0811/1436] arch_topology: Warn that topology for nested clusters is not supported We don't support the topology for clusters of CPU clusters while the DT and ACPI bindings theoritcally support the same. Just warn about the same so that it is clear to the users of arch_topology that the nested clusters are not yet supported. Link: https://lore.kernel.org/r/20220704101605.1318280-21-sudeep.holla@arm.com Tested-by: Ionela Voinescu Tested-by: Conor Dooley Signed-off-by: Sudeep Holla --- drivers/base/arch_topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 8719c4458df9..441e14ac33a4 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -567,6 +567,8 @@ static int __init parse_cluster(struct device_node *cluster, int package_id, if (c) { leaf = false; ret = parse_cluster(c, package_id, i, depth + 1); + if (depth > 0) + pr_warn("Topology for clusters of clusters not yet supported\n"); of_node_put(c); if (ret != 0) return ret; From 7128af87c7f1c30cd6cebe0b012cc25872c689e2 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 4 Jul 2022 11:16:05 +0100 Subject: [PATCH 0812/1436] ACPI: Remove the unused find_acpi_cpu_cache_topology() The sole user of this find_acpi_cpu_cache_topology() was arm64 topology which is now consolidated into the generic arch_topology without the need of this function. Drop the unused function find_acpi_cpu_cache_topology(). Link: https://lore.kernel.org/r/20220704101605.1318280-22-sudeep.holla@arm.com Cc: Rafael J. Wysocki Reported-by: Ionela Voinescu Tested-by: Conor Dooley Acked-by: Rafael J. Wysocki Signed-off-by: Sudeep Holla --- drivers/acpi/pptt.c | 37 ------------------------------------- include/linux/acpi.h | 5 ----- 2 files changed, 42 deletions(-) diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c index 763f021d45e6..dd3222a15c9c 100644 --- a/drivers/acpi/pptt.c +++ b/drivers/acpi/pptt.c @@ -691,43 +691,6 @@ int find_acpi_cpu_topology(unsigned int cpu, int level) return find_acpi_cpu_topology_tag(cpu, level, 0); } -/** - * find_acpi_cpu_cache_topology() - Determine a unique cache topology value - * @cpu: Kernel logical CPU number - * @level: The cache level for which we would like a unique ID - * - * Determine a unique ID for each unified cache in the system - * - * Return: -ENOENT if the PPTT doesn't exist, or the CPU cannot be found. - * Otherwise returns a value which represents a unique topological feature. - */ -int find_acpi_cpu_cache_topology(unsigned int cpu, int level) -{ - struct acpi_table_header *table; - struct acpi_pptt_cache *found_cache; - acpi_status status; - u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu); - struct acpi_pptt_processor *cpu_node = NULL; - int ret = -1; - - status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); - if (ACPI_FAILURE(status)) { - acpi_pptt_warn_missing(); - return -ENOENT; - } - - found_cache = acpi_find_cache_node(table, acpi_cpu_id, - CACHE_TYPE_UNIFIED, - level, - &cpu_node); - if (found_cache) - ret = ACPI_PTR_DIFF(cpu_node, table); - - acpi_put_table(table); - - return ret; -} - /** * find_acpi_cpu_topology_package() - Determine a unique CPU package value * @cpu: Kernel logical CPU number diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 4f82a5bc6d98..7b96a8bff6d2 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1429,7 +1429,6 @@ int find_acpi_cpu_topology(unsigned int cpu, int level); int find_acpi_cpu_topology_cluster(unsigned int cpu); int find_acpi_cpu_topology_package(unsigned int cpu); int find_acpi_cpu_topology_hetero_id(unsigned int cpu); -int find_acpi_cpu_cache_topology(unsigned int cpu, int level); #else static inline int acpi_pptt_cpu_is_thread(unsigned int cpu) { @@ -1451,10 +1450,6 @@ static inline int find_acpi_cpu_topology_hetero_id(unsigned int cpu) { return -EINVAL; } -static inline int find_acpi_cpu_cache_topology(unsigned int cpu, int level) -{ - return -EINVAL; -} #endif #ifdef CONFIG_ACPI_PCC From 1c3ace2b8b3995d3213c5e2d2aca01a0577a3b0f Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Tue, 5 Jul 2022 14:23:10 +0000 Subject: [PATCH 0813/1436] KVM: arm64: Don't return from void function Although harmless, the return statement in kvm_unexpected_el2_exception is rather confusing as the function itself has a void return type. The C standard is also pretty clear that "A return statement with an expression shall not appear in a function whose return type is void". Given that this return statement does not seem to add any actual value, let's not pointlessly violate the standard. Build-tested with GCC 10 and CLANG 13 for good measure, the disassembled code is identical with or without the return statement. Fixes: e9ee186bb735 ("KVM: arm64: Add kvm_extable for vaxorcism code") Signed-off-by: Quentin Perret Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220705142310.3847918-1-qperret@google.com --- arch/arm64/kvm/hyp/nvhe/switch.c | 2 +- arch/arm64/kvm/hyp/vhe/switch.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c index 6db801db8f27..925b34b7708d 100644 --- a/arch/arm64/kvm/hyp/nvhe/switch.c +++ b/arch/arm64/kvm/hyp/nvhe/switch.c @@ -386,5 +386,5 @@ asmlinkage void __noreturn hyp_panic_bad_stack(void) asmlinkage void kvm_unexpected_el2_exception(void) { - return __kvm_unexpected_el2_exception(); + __kvm_unexpected_el2_exception(); } diff --git a/arch/arm64/kvm/hyp/vhe/switch.c b/arch/arm64/kvm/hyp/vhe/switch.c index 969f20daf97a..390af1a6a9b4 100644 --- a/arch/arm64/kvm/hyp/vhe/switch.c +++ b/arch/arm64/kvm/hyp/vhe/switch.c @@ -249,5 +249,5 @@ void __noreturn hyp_panic(void) asmlinkage void kvm_unexpected_el2_exception(void) { - return __kvm_unexpected_el2_exception(); + __kvm_unexpected_el2_exception(); } From 2fd26970cf66bd52dc42843c46968040caa8c9a1 Mon Sep 17 00:00:00 2001 From: Imran Khan Date: Wed, 6 Jul 2022 06:10:26 +1000 Subject: [PATCH 0814/1436] Revert "kernfs: Change kernfs_notify_list to llist." This reverts commit b8f35fa1188b84035c59d4842826c4e93a1b1c9f. This is causing regression due to same kernfs_node getting added multiple times in kernfs_notify_list so revert it until safe way of using llist in this context is found. Reported-by: Nathan Chancellor Reported-by: Michael Walle Reported-by: Marek Szyprowski Signed-off-by: Imran Khan Cc: Tejun Heo Link: https://lore.kernel.org/r/20220705201026.2487665-1-imran.f.khan@oracle.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 47 ++++++++++++++++++++++++------------------ include/linux/kernfs.h | 2 +- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index bb933221b4ba..baff4b1d40c7 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -25,16 +25,18 @@ struct kernfs_open_node { struct list_head files; /* goes through kernfs_open_file.list */ }; -/** - * attribute_to_node - get kernfs_node object corresponding to a kernfs attribute - * @ptr: &struct kernfs_elem_attr - * @type: struct kernfs_node - * @member: name of member (i.e attr) +/* + * kernfs_notify() may be called from any context and bounces notifications + * through a work item. To minimize space overhead in kernfs_node, the + * pending queue is implemented as a singly linked list of kernfs_nodes. + * The list is terminated with the self pointer so that whether a + * kernfs_node is on the list or not can be determined by testing the next + * pointer for NULL. */ -#define attribute_to_node(ptr, type, member) \ - container_of(ptr, type, member) +#define KERNFS_NOTIFY_EOL ((void *)&kernfs_notify_list) -static LLIST_HEAD(kernfs_notify_list); +static DEFINE_SPINLOCK(kernfs_notify_lock); +static struct kernfs_node *kernfs_notify_list = KERNFS_NOTIFY_EOL; static inline struct mutex *kernfs_open_file_mutex_ptr(struct kernfs_node *kn) { @@ -909,16 +911,18 @@ static void kernfs_notify_workfn(struct work_struct *work) struct kernfs_node *kn; struct kernfs_super_info *info; struct kernfs_root *root; - struct llist_node *free; - struct kernfs_elem_attr *attr; repeat: /* pop one off the notify_list */ - free = llist_del_first(&kernfs_notify_list); - if (free == NULL) + spin_lock_irq(&kernfs_notify_lock); + kn = kernfs_notify_list; + if (kn == KERNFS_NOTIFY_EOL) { + spin_unlock_irq(&kernfs_notify_lock); return; + } + kernfs_notify_list = kn->attr.notify_next; + kn->attr.notify_next = NULL; + spin_unlock_irq(&kernfs_notify_lock); - attr = llist_entry(free, struct kernfs_elem_attr, notify_next); - kn = attribute_to_node(attr, struct kernfs_node, attr); root = kernfs_root(kn); /* kick fsnotify */ down_write(&root->kernfs_rwsem); @@ -974,14 +978,12 @@ repeat: void kernfs_notify(struct kernfs_node *kn) { static DECLARE_WORK(kernfs_notify_work, kernfs_notify_workfn); + unsigned long flags; struct kernfs_open_node *on; if (WARN_ON(kernfs_type(kn) != KERNFS_FILE)) return; - /* Because we are using llist for kernfs_notify_list */ - WARN_ON_ONCE(in_nmi()); - /* kick poll immediately */ rcu_read_lock(); on = rcu_dereference(kn->attr.open); @@ -992,9 +994,14 @@ void kernfs_notify(struct kernfs_node *kn) rcu_read_unlock(); /* schedule work to kick fsnotify */ - kernfs_get(kn); - llist_add(&kn->attr.notify_next, &kernfs_notify_list); - schedule_work(&kernfs_notify_work); + spin_lock_irqsave(&kernfs_notify_lock, flags); + if (!kn->attr.notify_next) { + kernfs_get(kn); + kn->attr.notify_next = kernfs_notify_list; + kernfs_notify_list = kn; + schedule_work(&kernfs_notify_work); + } + spin_unlock_irqrestore(&kernfs_notify_lock, flags); } EXPORT_SYMBOL_GPL(kernfs_notify); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 13e703f615f7..367044d7708c 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -173,7 +173,7 @@ struct kernfs_elem_attr { const struct kernfs_ops *ops; struct kernfs_open_node __rcu *open; loff_t size; - struct llist_node notify_next; /* for kernfs_notify() */ + struct kernfs_node *notify_next; /* for kernfs_notify() */ }; /* From 560045a46a071417f1c80d9cf1fd40e274cef5e8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Jul 2022 17:46:12 +0200 Subject: [PATCH 0815/1436] dt-bindings: hwinfo: group Chip ID-like devices Group devices like Chip ID or SoC information under "hwinfo" directory. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220705154613.453096-1-krzysztof.kozlowski@linaro.org --- .../exynos-chipid.yaml => hwinfo/samsung,exynos-chipid.yaml} | 2 +- .../{soc/ti/k3-socinfo.yaml => hwinfo/ti,k3-socinfo.yaml} | 2 +- MAINTAINERS | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) rename Documentation/devicetree/bindings/{soc/samsung/exynos-chipid.yaml => hwinfo/samsung,exynos-chipid.yaml} (92%) rename Documentation/devicetree/bindings/{soc/ti/k3-socinfo.yaml => hwinfo/ti,k3-socinfo.yaml} (92%) diff --git a/Documentation/devicetree/bindings/soc/samsung/exynos-chipid.yaml b/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml similarity index 92% rename from Documentation/devicetree/bindings/soc/samsung/exynos-chipid.yaml rename to Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml index 4bb8efb83ac1..95cbdcb56efe 100644 --- a/Documentation/devicetree/bindings/soc/samsung/exynos-chipid.yaml +++ b/Documentation/devicetree/bindings/hwinfo/samsung,exynos-chipid.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: http://devicetree.org/schemas/soc/samsung/exynos-chipid.yaml# +$id: http://devicetree.org/schemas/hwinfo/samsung,exynos-chipid.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Samsung Exynos SoC series Chipid driver diff --git a/Documentation/devicetree/bindings/soc/ti/k3-socinfo.yaml b/Documentation/devicetree/bindings/hwinfo/ti,k3-socinfo.yaml similarity index 92% rename from Documentation/devicetree/bindings/soc/ti/k3-socinfo.yaml rename to Documentation/devicetree/bindings/hwinfo/ti,k3-socinfo.yaml index a1a8423b2e2e..dada28b47ea0 100644 --- a/Documentation/devicetree/bindings/soc/ti/k3-socinfo.yaml +++ b/Documentation/devicetree/bindings/hwinfo/ti,k3-socinfo.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/soc/ti/k3-socinfo.yaml# +$id: http://devicetree.org/schemas/hwinfo/ti,k3-socinfo.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Texas Instruments K3 Multicore SoC platforms chipid module diff --git a/MAINTAINERS b/MAINTAINERS index b21af94149fe..1d99d54fa881 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2665,6 +2665,7 @@ B: mailto:linux-samsung-soc@vger.kernel.org T: git git://git.kernel.org/pub/scm/linux/kernel/git/krzk/linux.git F: Documentation/arm/samsung/ F: Documentation/devicetree/bindings/arm/samsung/ +F: Documentation/devicetree/bindings/hwinfo/samsung,* F: Documentation/devicetree/bindings/power/pd-samsung.yaml F: Documentation/devicetree/bindings/soc/samsung/ F: arch/arm/boot/dts/exynos* @@ -2898,6 +2899,7 @@ M: Tero Kristo L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: Documentation/devicetree/bindings/arm/ti/k3.yaml +F: Documentation/devicetree/bindings/hwinfo/ti,k3-socinfo.yaml F: arch/arm64/boot/dts/ti/Makefile F: arch/arm64/boot/dts/ti/k3-* F: include/dt-bindings/pinctrl/k3.h From 128a16b9704bc844fd0374b12eea16b563a7738a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 5 Jul 2022 17:46:13 +0200 Subject: [PATCH 0816/1436] dt-bindings: hwinfo: samsung,s5pv210-chipid: add S5PV210 ChipID Document already used S5PV210 ChipID block. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220705154613.453096-2-krzysztof.kozlowski@linaro.org --- .../hwinfo/samsung,s5pv210-chipid.yaml | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Documentation/devicetree/bindings/hwinfo/samsung,s5pv210-chipid.yaml diff --git a/Documentation/devicetree/bindings/hwinfo/samsung,s5pv210-chipid.yaml b/Documentation/devicetree/bindings/hwinfo/samsung,s5pv210-chipid.yaml new file mode 100644 index 000000000000..563ded4fca83 --- /dev/null +++ b/Documentation/devicetree/bindings/hwinfo/samsung,s5pv210-chipid.yaml @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwinfo/samsung,s5pv210-chipid.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Samsung S5PV210 SoC ChipID + +maintainers: + - Krzysztof Kozlowski + +properties: + compatible: + const: samsung,s5pv210-chipid + + reg: + maxItems: 1 + +required: + - compatible + - reg + +additionalProperties: false + +examples: + - | + chipid@e0000000 { + compatible = "samsung,s5pv210-chipid"; + reg = <0xe0000000 0x1000>; + }; From 177a561e0bebe81444473d5d779d163bd53bc949 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 1 Jul 2022 11:24:49 +0200 Subject: [PATCH 0817/1436] Staging: rtl8192e: Refactored rtllib_modes The initial reason for looking at this code was an issue raised by checkpatch.pl: $ ./scripts/checkpatch.pl --terse -f drivers/staging/rtl8192e/rtllib_wx.c CHECK: Please use a blank line after function/struct/union/enum declarations The additional blank line above the struct/before the headers is just cleaner. However, as it turns out since there is no str formatting required One can replace the error prone str + size struct with a char array. The rest of this patch fixes the usecases. Tested-by: Philipp Hortmann Signed-off-by: Felix Schlepper Link: https://lore.kernel.org/r/4dbc4939e88a2c94f1819b4b0cc2c81dc332710b.1656667089.git.f3sch.git@outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib_wx.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c index cf9a240924f2..b7f19b38b0e1 100644 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ b/drivers/staging/rtl8192e/rtllib_wx.c @@ -17,17 +17,9 @@ #include #include #include "rtllib.h" -struct modes_unit { - char *mode_string; - int mode_size; -}; -static struct modes_unit rtllib_modes[] = { - {"a", 1}, - {"b", 1}, - {"g", 1}, - {"?", 1}, - {"N-24G", 5}, - {"N-5G", 4}, + +static const char * const rtllib_modes[] = { + "a", "b", "g", "?", "N-24G", "N-5G" }; #define MAX_CUSTOM_LEN 64 @@ -72,10 +64,9 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) { - if (network->mode&(1<mode & BIT(i)) { + strcpy(pname, rtllib_modes[i]); + pname += strlen(rtllib_modes[i]); } } *pname = '\0'; From 2393ef09cad85a0563a7d30ea7a560a7af58f26c Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 1 Jul 2022 11:24:50 +0200 Subject: [PATCH 0818/1436] Staging: rtl8192e: Avoid multiple assignments This addresses an issue raised by checkpatch.pl: $ ./scripts/checkpatch.pl --terse -f drivers/staging/rtl8192e/rtllib_wx.c CHECK: multiple assignments should be avoided Tested-by: Philipp Hortmann Signed-off-by: Felix Schlepper Link: https://lore.kernel.org/r/899a1010643a05668465069951518e5dcab9c77e.1656667089.git.f3sch.git@outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib_wx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c index b7f19b38b0e1..121bf939c6a4 100644 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ b/drivers/staging/rtl8192e/rtllib_wx.c @@ -149,7 +149,8 @@ static inline char *rtl819x_translate_scan(struct rtllib_device *ieee, max_rate = rate; } iwe.cmd = SIOCGIWRATE; - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + iwe.u.bitrate.disabled = 0; + iwe.u.bitrate.fixed = 0; iwe.u.bitrate.value = max_rate * 500000; start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_PARAM_LEN); iwe.cmd = IWEVCUSTOM; From 907d2772f75168d2f39087c8c77195c16d3e019d Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 1 Jul 2022 11:24:51 +0200 Subject: [PATCH 0819/1436] Staging: rtl8192e: Remove unnecessary parentheses This addresses an issue raised by checkpatch.pl: $ ./scripts/checkpatch.pl --terse -f drivers/staging/rtl8192e/rtllib_wx.c Unnecessary parentheses around wrqu->encoding Tested-by: Philipp Hortmann Signed-off-by: Felix Schlepper Link: https://lore.kernel.org/r/0e4e340be3f4c7f35a5381b726b1db5fc6842f10.1656667089.git.f3sch.git@outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib_wx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c index 121bf939c6a4..db076e819993 100644 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ b/drivers/staging/rtl8192e/rtllib_wx.c @@ -277,7 +277,7 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *keybuf) { - struct iw_point *erq = &(wrqu->encoding); + struct iw_point *erq = &wrqu->encoding; struct net_device *dev = ieee->dev; struct rtllib_security sec = { .flags = 0 @@ -449,7 +449,7 @@ int rtllib_wx_get_encode(struct rtllib_device *ieee, struct iw_request_info *info, union iwreq_data *wrqu, char *keybuf) { - struct iw_point *erq = &(wrqu->encoding); + struct iw_point *erq = &wrqu->encoding; int len, key; struct lib80211_crypt_data *crypt; From 58f364ecb13ecece3a84d6517b6be4a4672db655 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 1 Jul 2022 11:24:52 +0200 Subject: [PATCH 0820/1436] Staging: rtl8192e: Added braces around else This addresses two issues raised by checkpatch.pl: $ ./scripts/checkpatch.pl --terse -f drivers/staging/rtl8192e/rtllib_wx.c CHECK: braces {} should be used on all arms of this statement CHECK: Unbalanced braces around else statement The coding style rule with not using unnecessary braces around if/else does not apply if only one branch is a single statement. Tested-by: Philipp Hortmann Signed-off-by: Felix Schlepper Link: https://lore.kernel.org/r/651f51d9f92e8a445ceaf9f2073f16dd10458a74.1656667089.git.f3sch.git@outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib_wx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c index db076e819993..b949e7234150 100644 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ b/drivers/staging/rtl8192e/rtllib_wx.c @@ -304,8 +304,9 @@ int rtllib_wx_set_encode(struct rtllib_device *ieee, netdev_dbg(ieee->dev, "Disabling encryption on key %d.\n", key); lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); - } else + } else { netdev_dbg(ieee->dev, "Disabling encryption.\n"); + } /* Check all the keys to see if any are still configured, * and if no key index was provided, de-init them all @@ -724,8 +725,9 @@ int rtllib_wx_set_auth(struct rtllib_device *ieee, } else if (data->value & IW_AUTH_ALG_LEAP) { ieee->open_wep = 1; ieee->auth_mode = 2; - } else + } else { return -EINVAL; + } break; case IW_AUTH_WPA_ENABLED: From ea32f580e853ca28709474f786134b574bbeacbf Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 1 Jul 2022 11:24:53 +0200 Subject: [PATCH 0821/1436] Staging: rtl8192e: Remove unnecessary blank line This addresses an issue raised by checkpatch.pl: $ ./scripts/checkpatch.pl --terse -f drivers/staging/rtl8192e/rtllib_wx.c CHECK: Blank lines aren't necessary before a close brace '}' Tested-by: Philipp Hortmann Signed-off-by: Felix Schlepper Link: https://lore.kernel.org/r/f3c6bd5c79331e82f006fb2694f791030b07c5ba.1656667089.git.f3sch.git@outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib_wx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c index b949e7234150..6b11908032d7 100644 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ b/drivers/staging/rtl8192e/rtllib_wx.c @@ -601,7 +601,6 @@ int rtllib_wx_set_encode_ext(struct rtllib_device *ieee, goto done; } *crypt = new_crypt; - } if (ext->key_len > 0 && (*crypt)->ops->set_key && From a27e2eb5e9febf16c503423424a67289a4eb03c3 Mon Sep 17 00:00:00 2001 From: Felix Schlepper Date: Fri, 1 Jul 2022 11:24:54 +0200 Subject: [PATCH 0822/1436] Staging: rtl8192e: Added spaces around '+' This addresses two issues raised by checkpatch.pl: $ ./scripts/checkpatch.pl --terse -f drivers/staging/rtl8192e/rtllib_wx.c CHECK: spaces preferred around that '+' (ctx:VxV) Tested-by: Philipp Hortmann Signed-off-by: Felix Schlepper Link: https://lore.kernel.org/r/87628a2dd08ec0e5b02090485e7a9a1d91b7d2a5.1656667089.git.f3sch.git@outlook.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/rtllib_wx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8192e/rtllib_wx.c b/drivers/staging/rtl8192e/rtllib_wx.c index 6b11908032d7..da2c41c9b92f 100644 --- a/drivers/staging/rtl8192e/rtllib_wx.c +++ b/drivers/staging/rtl8192e/rtllib_wx.c @@ -769,7 +769,7 @@ int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len) kfree(ieee->wps_ie); ieee->wps_ie = NULL; if (len) { - if (len != ie[1]+2) + if (len != ie[1] + 2) return -EINVAL; buf = kmemdup(ie, len, GFP_KERNEL); if (!buf) From 05710750974cff9c3a5b06beeb5ab3cbe64b95a3 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 1 Jul 2022 23:07:53 +0200 Subject: [PATCH 0823/1436] staging: r8188eu: remove HW_VAR_AMPDU_FACTOR from SetHwReg8188EU() Remove the case HW_VAR_AMPDU_FACTOR from SetHwReg8188EU() and move the functionality to a static function in rtw_wlan_util.c. This is part of the ongoing effort to get rid of SetHwReg8188EU(). Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220701210753.8210-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_wlan_util.c | 28 +++++++++++++++++++- drivers/staging/r8188eu/hal/usb_halinit.c | 26 ------------------ drivers/staging/r8188eu/include/hal_intf.h | 1 - 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_wlan_util.c b/drivers/staging/r8188eu/core/rtw_wlan_util.c index 2d5fd654ead9..aa6b549fd54d 100644 --- a/drivers/staging/r8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/r8188eu/core/rtw_wlan_util.c @@ -805,6 +805,32 @@ static void set_min_ampdu_spacing(struct adapter *adapter, u8 spacing) } } +static void set_ampdu_factor(struct adapter *adapter, u8 factor) +{ + u8 RegToSet_Normal[4] = {0x41, 0xa8, 0x72, 0xb9}; + u8 FactorToSet; + u8 *pRegToSet; + u8 index = 0; + + pRegToSet = RegToSet_Normal; /* 0xb972a841; */ + FactorToSet = factor; + if (FactorToSet <= 3) { + FactorToSet = (1 << (FactorToSet + 2)); + if (FactorToSet > 0xf) + FactorToSet = 0xf; + + for (index = 0; index < 4; index++) { + if ((pRegToSet[index] & 0xf0) > (FactorToSet << 4)) + pRegToSet[index] = (pRegToSet[index] & 0x0f) | (FactorToSet << 4); + + if ((pRegToSet[index] & 0x0f) > FactorToSet) + pRegToSet[index] = (pRegToSet[index] & 0xf0) | (FactorToSet); + + rtw_write8(adapter, (REG_AGGLEN_LMT + index), pRegToSet[index]); + } + } +} + void HTOnAssocRsp(struct adapter *padapter) { unsigned char max_AMPDU_len; @@ -831,7 +857,7 @@ void HTOnAssocRsp(struct adapter *padapter) set_min_ampdu_spacing(padapter, min_MPDU_spacing); - SetHwReg8188EU(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); + set_ampdu_factor(padapter, max_AMPDU_len); } void ERP_IE_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 3908c46d2fbe..1a08de85a6ae 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -1209,32 +1209,6 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) case HW_VAR_DM_FUNC_CLR: podmpriv->SupportAbility = 0; break; - case HW_VAR_AMPDU_FACTOR: - { - u8 RegToSet_Normal[4] = {0x41, 0xa8, 0x72, 0xb9}; - u8 FactorToSet; - u8 *pRegToSet; - u8 index = 0; - - pRegToSet = RegToSet_Normal; /* 0xb972a841; */ - FactorToSet = *((u8 *)val); - if (FactorToSet <= 3) { - FactorToSet = (1 << (FactorToSet + 2)); - if (FactorToSet > 0xf) - FactorToSet = 0xf; - - for (index = 0; index < 4; index++) { - if ((pRegToSet[index] & 0xf0) > (FactorToSet << 4)) - pRegToSet[index] = (pRegToSet[index] & 0x0f) | (FactorToSet << 4); - - if ((pRegToSet[index] & 0x0f) > FactorToSet) - pRegToSet[index] = (pRegToSet[index] & 0xf0) | (FactorToSet); - - rtw_write8(Adapter, (REG_AGGLEN_LMT + index), pRegToSet[index]); - } - } - } - break; default: break; } diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index c3704618bccc..b81144932d9a 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -17,7 +17,6 @@ enum hw_variables { HW_VAR_DM_FUNC_OP, HW_VAR_DM_FUNC_RESET, HW_VAR_DM_FUNC_CLR, - HW_VAR_AMPDU_FACTOR, }; typedef s32 (*c2h_id_filter)(u8 id); From e0e91965a10b79ca26a315eb283509b9de90f6eb Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 2 Jul 2022 08:46:26 +0200 Subject: [PATCH 0824/1436] staging: r8188eu: make ffaddr2pipehdl() static The function ffaddr2pipehdl() is only used in usb_ops_linux.c. Make it static. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220702064626.27506-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/include/usb_ops_linux.h | 2 -- drivers/staging/r8188eu/os_dep/usb_ops_linux.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/r8188eu/include/usb_ops_linux.h b/drivers/staging/r8188eu/include/usb_ops_linux.h index 641f059ffaf7..966688eedf66 100644 --- a/drivers/staging/r8188eu/include/usb_ops_linux.h +++ b/drivers/staging/r8188eu/include/usb_ops_linux.h @@ -26,6 +26,4 @@ #define usb_read_interrupt_complete(purb, regs) \ usb_read_interrupt_complete(purb) -unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr); - #endif diff --git a/drivers/staging/r8188eu/os_dep/usb_ops_linux.c b/drivers/staging/r8188eu/os_dep/usb_ops_linux.c index 0269e602b217..220e592b757c 100644 --- a/drivers/staging/r8188eu/os_dep/usb_ops_linux.c +++ b/drivers/staging/r8188eu/os_dep/usb_ops_linux.c @@ -7,7 +7,7 @@ #include "../include/usb_ops_linux.h" #include "../include/rtl8188e_recv.h" -unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) +static unsigned int ffaddr2pipehdl(struct dvobj_priv *pdvobj, u32 addr) { unsigned int pipe = 0, ep_num = 0; struct usb_device *pusbd = pdvobj->pusbdev; From 687a7264fca6dd8cd9cf0b84c9c16f88b0821575 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 16:52:17 +0200 Subject: [PATCH 0825/1436] staging: r8188eu: move pwr seq defines to HalPwrSeqCmd.c The power sequences are now defined and processed in the same file. We can move the defines for power sequences and the related struct and enum from HalPwrSeqCmd.h to HalPwrSeqCmd.c. They don't have to be visible in other files any more. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704145221.159949-2-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/HalPwrSeqCmd.c | 43 +++++++++++++++++ .../staging/r8188eu/include/HalPwrSeqCmd.h | 47 ------------------- 2 files changed, 43 insertions(+), 47 deletions(-) diff --git a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c index 5b0f66573d94..fb8eeaf51afa 100644 --- a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c +++ b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c @@ -3,6 +3,49 @@ #include "../include/HalPwrSeqCmd.h" +#define PWR_CMD_WRITE 0x01 + /* offset: the read register offset */ + /* msk: the mask of the write bits */ + /* value: write value */ + /* note: driver shall implement this cmd by read & msk after write */ + +#define PWR_CMD_POLLING 0x02 + /* offset: the read register offset */ + /* msk: the mask of the polled value */ + /* value: the value to be polled, masked by the msd field. */ + /* note: driver shall implement this cmd by */ + /* do{ */ + /* if ( (Read(offset) & msk) == (value & msk) ) */ + /* break; */ + /* } while (not timeout); */ + +#define PWR_CMD_DELAY 0x03 + /* offset: the value to delay */ + /* msk: N/A */ + /* value: the unit of delay, 0: us, 1: ms */ + +#define PWR_CMD_END 0x04 + /* offset: N/A */ + /* msk: N/A */ + /* value: N/A */ + +enum pwrseq_cmd_delat_unit { + PWRSEQ_DELAY_US, + PWRSEQ_DELAY_MS, +}; + +struct wl_pwr_cfg { + u16 offset; + u8 cmd:4; + u8 msk; + u8 value; +}; + +#define GET_PWR_CFG_OFFSET(__PWR_CMD) __PWR_CMD.offset +#define GET_PWR_CFG_CMD(__PWR_CMD) __PWR_CMD.cmd +#define GET_PWR_CFG_MASK(__PWR_CMD) __PWR_CMD.msk +#define GET_PWR_CFG_VALUE(__PWR_CMD) __PWR_CMD.value + static struct wl_pwr_cfg rtl8188E_power_on_flow[] = { { 0x0006, PWR_CMD_POLLING, BIT(1), BIT(1) }, { 0x0002, PWR_CMD_WRITE, BIT(0) | BIT(1), 0 }, /* reset BB */ diff --git a/drivers/staging/r8188eu/include/HalPwrSeqCmd.h b/drivers/staging/r8188eu/include/HalPwrSeqCmd.h index 869f54d99e57..0886300d26bf 100644 --- a/drivers/staging/r8188eu/include/HalPwrSeqCmd.h +++ b/drivers/staging/r8188eu/include/HalPwrSeqCmd.h @@ -6,53 +6,6 @@ #include "drv_types.h" -/*---------------------------------------------*/ -/* 3 The value of cmd: 4 bits */ -/*---------------------------------------------*/ - -#define PWR_CMD_WRITE 0x01 - /* offset: the read register offset */ - /* msk: the mask of the write bits */ - /* value: write value */ - /* note: driver shall implement this cmd by read & msk after write */ - -#define PWR_CMD_POLLING 0x02 - /* offset: the read register offset */ - /* msk: the mask of the polled value */ - /* value: the value to be polled, masked by the msd field. */ - /* note: driver shall implement this cmd by */ - /* do{ */ - /* if ( (Read(offset) & msk) == (value & msk) ) */ - /* break; */ - /* } while (not timeout); */ - -#define PWR_CMD_DELAY 0x03 - /* offset: the value to delay */ - /* msk: N/A */ - /* value: the unit of delay, 0: us, 1: ms */ - -#define PWR_CMD_END 0x04 - /* offset: N/A */ - /* msk: N/A */ - /* value: N/A */ - -enum pwrseq_cmd_delat_unit { - PWRSEQ_DELAY_US, - PWRSEQ_DELAY_MS, -}; - -struct wl_pwr_cfg { - u16 offset; - u8 cmd:4; - u8 msk; - u8 value; -}; - -#define GET_PWR_CFG_OFFSET(__PWR_CMD) __PWR_CMD.offset -#define GET_PWR_CFG_CMD(__PWR_CMD) __PWR_CMD.cmd -#define GET_PWR_CFG_MASK(__PWR_CMD) __PWR_CMD.msk -#define GET_PWR_CFG_VALUE(__PWR_CMD) __PWR_CMD.value - enum r8188eu_pwr_seq { PWR_ON_FLOW, DISABLE_FLOW, From 8be317cf61d8f07bde70ccda84fee5e6f502e7fa Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 16:52:18 +0200 Subject: [PATCH 0826/1436] staging: r8188eu: support only us in PWR_CMD_DELAY PWR_CMD_DELAY has only a single remaining user, who needs a delay in us. Remove the code and defines for delays in ms. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704145221.159949-3-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/HalPwrSeqCmd.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c index fb8eeaf51afa..273f134d0a40 100644 --- a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c +++ b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c @@ -20,20 +20,15 @@ /* } while (not timeout); */ #define PWR_CMD_DELAY 0x03 - /* offset: the value to delay */ + /* offset: the value to delay (in us) */ /* msk: N/A */ - /* value: the unit of delay, 0: us, 1: ms */ + /* value: N/A */ #define PWR_CMD_END 0x04 /* offset: N/A */ /* msk: N/A */ /* value: N/A */ -enum pwrseq_cmd_delat_unit { - PWRSEQ_DELAY_US, - PWRSEQ_DELAY_MS, -}; - struct wl_pwr_cfg { u16 offset; u8 cmd:4; @@ -79,7 +74,7 @@ static struct wl_pwr_cfg rtl8188E_enter_lps_flow[] = { { 0x05FA, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */ { 0x05FB, PWR_CMD_POLLING, 0xFF, 0 }, /* Should be zero if no packet is transmitted */ { 0x0002, PWR_CMD_WRITE, BIT(0), 0 }, /* CCK and OFDM are disabled, clocks are gated */ - { 0x0002, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US }, + { 0x0002, PWR_CMD_DELAY, 0, 0 }, { 0x0100, PWR_CMD_WRITE, 0xFF, 0x3F }, /* Reset MAC TRX */ { 0x0101, PWR_CMD_WRITE, BIT(1), 0 }, /* check if removed later */ { 0x0553, PWR_CMD_WRITE, BIT(5), BIT(5) }, /* Respond TxOK to scheduler */ @@ -149,10 +144,7 @@ u8 HalPwrSeqCmdParsing(struct adapter *padapter, enum r8188eu_pwr_seq seq) } while (!poll_bit); break; case PWR_CMD_DELAY: - if (GET_PWR_CFG_VALUE(pwrcfgcmd) == PWRSEQ_DELAY_US) - udelay(GET_PWR_CFG_OFFSET(pwrcfgcmd)); - else - udelay(GET_PWR_CFG_OFFSET(pwrcfgcmd) * 1000); + udelay(GET_PWR_CFG_OFFSET(pwrcfgcmd)); break; case PWR_CMD_END: /* When this command is parsed, end the process */ From 38fbc32e83d6c09fe2f89cd1007f1a710393a7be Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 16:52:19 +0200 Subject: [PATCH 0827/1436] staging: r8188eu: read pwr seq length, remove PWR_CMD_END The definitions of the power sequences are in the same file as the function which processes them. We can simply read the number of entries in a power sequence. There's no need for a PWR_CMD_END command to indicate the end of a sequence. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704145221.159949-4-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/HalPwrSeqCmd.c | 25 ++++++---------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c index 273f134d0a40..6c0b1368383d 100644 --- a/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c +++ b/drivers/staging/r8188eu/hal/HalPwrSeqCmd.c @@ -24,11 +24,6 @@ /* msk: N/A */ /* value: N/A */ -#define PWR_CMD_END 0x04 - /* offset: N/A */ - /* msk: N/A */ - /* value: N/A */ - struct wl_pwr_cfg { u16 offset; u8 cmd:4; @@ -50,7 +45,6 @@ static struct wl_pwr_cfg rtl8188E_power_on_flow[] = { { 0x0005, PWR_CMD_WRITE, BIT(0), BIT(0) }, { 0x0005, PWR_CMD_POLLING, BIT(0), 0 }, { 0x0023, PWR_CMD_WRITE, BIT(4), 0 }, - { 0xFFFF, PWR_CMD_END, 0, 0 }, }; static struct wl_pwr_cfg rtl8188E_card_disable_flow[] = { @@ -63,7 +57,6 @@ static struct wl_pwr_cfg rtl8188E_card_disable_flow[] = { { 0x0007, PWR_CMD_WRITE, 0xFF, 0 }, /* enable bandgap mbias in suspend */ { 0x0041, PWR_CMD_WRITE, BIT(4), 0 }, /* Clear SIC_EN register */ { 0xfe10, PWR_CMD_WRITE, BIT(4), BIT(4) }, /* Set USB suspend enable local register */ - { 0xFFFF, PWR_CMD_END, 0, 0 }, }; /* This is used by driver for LPSRadioOff Procedure, not for FW LPS Step */ @@ -78,7 +71,6 @@ static struct wl_pwr_cfg rtl8188E_enter_lps_flow[] = { { 0x0100, PWR_CMD_WRITE, 0xFF, 0x3F }, /* Reset MAC TRX */ { 0x0101, PWR_CMD_WRITE, BIT(1), 0 }, /* check if removed later */ { 0x0553, PWR_CMD_WRITE, BIT(5), BIT(5) }, /* Respond TxOK to scheduler */ - { 0xFFFF, PWR_CMD_END, 0, 0 }, }; u8 HalPwrSeqCmdParsing(struct adapter *padapter, enum r8188eu_pwr_seq seq) @@ -86,7 +78,7 @@ u8 HalPwrSeqCmdParsing(struct adapter *padapter, enum r8188eu_pwr_seq seq) struct wl_pwr_cfg pwrcfgcmd = {0}; struct wl_pwr_cfg *pwrseqcmd; u8 poll_bit = false; - u32 aryidx = 0; + u8 idx, num_steps; u8 value = 0; u32 offset = 0; u32 poll_count = 0; /* polling autoload done. */ @@ -96,19 +88,22 @@ u8 HalPwrSeqCmdParsing(struct adapter *padapter, enum r8188eu_pwr_seq seq) switch (seq) { case PWR_ON_FLOW: pwrseqcmd = rtl8188E_power_on_flow; + num_steps = ARRAY_SIZE(rtl8188E_power_on_flow); break; case DISABLE_FLOW: pwrseqcmd = rtl8188E_card_disable_flow; + num_steps = ARRAY_SIZE(rtl8188E_card_disable_flow); break; case LPS_ENTER_FLOW: pwrseqcmd = rtl8188E_enter_lps_flow; + num_steps = ARRAY_SIZE(rtl8188E_enter_lps_flow); break; default: return false; } - do { - pwrcfgcmd = pwrseqcmd[aryidx]; + for (idx = 0; idx < num_steps; idx++) { + pwrcfgcmd = pwrseqcmd[idx]; switch (GET_PWR_CFG_CMD(pwrcfgcmd)) { case PWR_CMD_WRITE: @@ -146,15 +141,9 @@ u8 HalPwrSeqCmdParsing(struct adapter *padapter, enum r8188eu_pwr_seq seq) case PWR_CMD_DELAY: udelay(GET_PWR_CFG_OFFSET(pwrcfgcmd)); break; - case PWR_CMD_END: - /* When this command is parsed, end the process */ - return true; - break; default: break; } - - aryidx++;/* Add Array Index */ - } while (1); + } return true; } From 4023f5f8449b9a23f95615aa2b5f5a0f46123ac3 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 16:52:20 +0200 Subject: [PATCH 0828/1436] staging: r8188eu: remove sdio definitions The r8188eu chipset is connected via usb. We don't need the register and bit field definitions for the sdio interface. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704145221.159949-5-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- .../staging/r8188eu/include/rtl8188e_spec.h | 136 ------------------ 1 file changed, 136 deletions(-) diff --git a/drivers/staging/r8188eu/include/rtl8188e_spec.h b/drivers/staging/r8188eu/include/rtl8188e_spec.h index ef42c4b2f20c..d3651ec71dc4 100644 --- a/drivers/staging/r8188eu/include/rtl8188e_spec.h +++ b/drivers/staging/r8188eu/include/rtl8188e_spec.h @@ -1059,142 +1059,6 @@ Current IOREG MAP #define SCR_TXBCUSEDK BIT(6) /* Force Tx Bcast pkt Use Default Key */ #define SCR_RXBCUSEDK BIT(7) /* Force Rx Bcast pkt Use Default Key */ -/* RTL8188E SDIO Configuration */ - -/* I/O bus domain address mapping */ -#define SDIO_LOCAL_BASE 0x10250000 -#define WLAN_IOREG_BASE 0x10260000 -#define FIRMWARE_FIFO_BASE 0x10270000 -#define TX_HIQ_BASE 0x10310000 -#define TX_MIQ_BASE 0x10320000 -#define TX_LOQ_BASE 0x10330000 -#define RX_RX0FF_BASE 0x10340000 - -/* SDIO host local register space mapping. */ -#define SDIO_LOCAL_MSK 0x0FFF -#define WLAN_IOREG_MSK 0x7FFF -#define WLAN_FIFO_MSK 0x1FFF /* Aggregation Length[12:0] */ -#define WLAN_RX0FF_MSK 0x0003 - -/* Without ref to the SDIO Device ID */ -#define SDIO_WITHOUT_REF_DEVICE_ID 0 -#define SDIO_LOCAL_DEVICE_ID 0 /* 0b[16], 000b[15:13] */ -#define WLAN_TX_HIQ_DEVICE_ID 4 /* 0b[16], 100b[15:13] */ -#define WLAN_TX_MIQ_DEVICE_ID 5 /* 0b[16], 101b[15:13] */ -#define WLAN_TX_LOQ_DEVICE_ID 6 /* 0b[16], 110b[15:13] */ -#define WLAN_RX0FF_DEVICE_ID 7 /* 0b[16], 111b[15:13] */ -#define WLAN_IOREG_DEVICE_ID 8 /* 1b[16] */ - -/* SDIO Tx Free Page Index */ -#define HI_QUEUE_IDX 0 -#define MID_QUEUE_IDX 1 -#define LOW_QUEUE_IDX 2 -#define PUBLIC_QUEUE_IDX 3 - -#define SDIO_MAX_TX_QUEUE 3 /* HIQ, MIQ and LOQ */ -#define SDIO_MAX_RX_QUEUE 1 - -/* SDIO Tx Control */ -#define SDIO_REG_TX_CTRL 0x0000 -/* SDIO Host Interrupt Mask */ -#define SDIO_REG_HIMR 0x0014 -/* SDIO Host Interrupt Service Routine */ -#define SDIO_REG_HISR 0x0018 -/* HCI Current Power Mode */ -#define SDIO_REG_HCPWM 0x0019 -/* RXDMA Request Length */ -#define SDIO_REG_RX0_REQ_LEN 0x001C -/* Free Tx Buffer Page */ -#define SDIO_REG_FREE_TXPG 0x0020 -/* HCI Current Power Mode 1 */ -#define SDIO_REG_HCPWM1 0x0024 -/* HCI Current Power Mode 2 */ -#define SDIO_REG_HCPWM2 0x0026 -/* HTSF Informaion */ -#define SDIO_REG_HTSFR_INFO 0x0030 -/* HCI Request Power Mode 1 */ -#define SDIO_REG_HRPWM1 0x0080 -/* HCI Request Power Mode 2 */ -#define SDIO_REG_HRPWM2 0x0082 -/* HCI Power Save Clock */ -#define SDIO_REG_HPS_CLKR 0x0084 -/* SDIO HCI Suspend Control */ -#define SDIO_REG_HSUS_CTRL 0x0086 -/* SDIO Host Extension Interrupt Mask Always */ -#define SDIO_REG_HIMR_ON 0x0090 -/* SDIO Host Extension Interrupt Status Always */ -#define SDIO_REG_HISR_ON 0x0091 - -#define SDIO_HIMR_DISABLED 0 - -/* RTL8188E SDIO Host Interrupt Mask Register */ -#define SDIO_HIMR_RX_REQUEST_MSK BIT(0) -#define SDIO_HIMR_AVAL_MSK BIT(1) -#define SDIO_HIMR_TXERR_MSK BIT(2) -#define SDIO_HIMR_RXERR_MSK BIT(3) -#define SDIO_HIMR_TXFOVW_MSK BIT(4) -#define SDIO_HIMR_RXFOVW_MSK BIT(5) -#define SDIO_HIMR_TXBCNOK_MSK BIT(6) -#define SDIO_HIMR_TXBCNERR_MSK BIT(7) -#define SDIO_HIMR_BCNERLY_INT_MSK BIT(16) -#define SDIO_HIMR_C2HCMD_MSK BIT(17) -#define SDIO_HIMR_CPWM1_MSK BIT(18) -#define SDIO_HIMR_CPWM2_MSK BIT(19) -#define SDIO_HIMR_HSISR_IND_MSK BIT(20) -#define SDIO_HIMR_GTINT3_IND_MSK BIT(21) -#define SDIO_HIMR_GTINT4_IND_MSK BIT(22) -#define SDIO_HIMR_PSTIMEOUT_MSK BIT(23) -#define SDIO_HIMR_OCPINT_MSK BIT(24) -#define SDIO_HIMR_ATIMEND_MSK BIT(25) -#define SDIO_HIMR_ATIMEND_E_MSK BIT(26) -#define SDIO_HIMR_CTWEND_MSK BIT(27) - -/* RTL8188E SDIO Specific */ -#define SDIO_HIMR_MCU_ERR_MSK BIT(28) -#define SDIO_HIMR_TSF_BIT32_TOGGLE_MSK BIT(29) - -/* SDIO Host Interrupt Service Routine */ -#define SDIO_HISR_RX_REQUEST BIT(0) -#define SDIO_HISR_AVAL BIT(1) -#define SDIO_HISR_TXERR BIT(2) -#define SDIO_HISR_RXERR BIT(3) -#define SDIO_HISR_TXFOVW BIT(4) -#define SDIO_HISR_RXFOVW BIT(5) -#define SDIO_HISR_TXBCNOK BIT(6) -#define SDIO_HISR_TXBCNERR BIT(7) -#define SDIO_HISR_BCNERLY_INT BIT(16) -#define SDIO_HISR_C2HCMD BIT(17) -#define SDIO_HISR_CPWM1 BIT(18) -#define SDIO_HISR_CPWM2 BIT(19) -#define SDIO_HISR_HSISR_IND BIT(20) -#define SDIO_HISR_GTINT3_IND BIT(21) -#define SDIO_HISR_GTINT4_IND BIT(22) -#define SDIO_HISR_PSTIME BIT(23) -#define SDIO_HISR_OCPINT BIT(24) -#define SDIO_HISR_ATIMEND BIT(25) -#define SDIO_HISR_ATIMEND_E BIT(26) -#define SDIO_HISR_CTWEND BIT(27) - -/* RTL8188E SDIO Specific */ -#define SDIO_HISR_MCU_ERR BIT(28) -#define SDIO_HISR_TSF_BIT32_TOGGLE BIT(29) - -#define MASK_SDIO_HISR_CLEAR \ - (SDIO_HISR_TXERR | SDIO_HISR_RXERR | SDIO_HISR_TXFOVW |\ - SDIO_HISR_RXFOVW | SDIO_HISR_TXBCNOK | SDIO_HISR_TXBCNERR |\ - SDIO_HISR_C2HCMD | SDIO_HISR_CPWM1 | SDIO_HISR_CPWM2 |\ - SDIO_HISR_HSISR_IND | SDIO_HISR_GTINT3_IND | SDIO_HISR_GTINT4_IND |\ - SDIO_HISR_PSTIMEOUT | SDIO_HISR_OCPINT) - -/* SDIO HCI Suspend Control Register */ -#define HCI_RESUME_PWR_RDY BIT(1) -#define HCI_SUS_CTRL BIT(0) - -/* SDIO Tx FIFO related */ -/* The number of Tx FIFO free page */ -#define SDIO_TX_FREE_PG_QUEUE 4 -#define SDIO_TX_FIFO_PAGE_SZ 128 - /* 0xFE00h ~ 0xFE55h USB Configuration */ /* 2 USB Information (0xFE17) */ From 1681e6f4d773873506798151beae01c22d835e39 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 16:52:21 +0200 Subject: [PATCH 0829/1436] staging: r8188eu: mac addr len is unused The MAC_ADDR_LEN define is not used. Remove it. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704145221.159949-6-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/include/rtl8188e_spec.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/r8188eu/include/rtl8188e_spec.h b/drivers/staging/r8188eu/include/rtl8188e_spec.h index d3651ec71dc4..ce5dd2e5b72a 100644 --- a/drivers/staging/r8188eu/include/rtl8188e_spec.h +++ b/drivers/staging/r8188eu/include/rtl8188e_spec.h @@ -9,7 +9,6 @@ #define HAL_PS_TIMER_INT_DELAY 50 /* 50 microseconds */ #define HAL_92C_NAV_UPPER_UNIT 128 /* micro-second */ -#define MAC_ADDR_LEN 6 /* 8188E PKT_BUFF_ACCESS_CTRL value */ #define TXPKT_BUF_SELECT 0x69 #define RXPKT_BUF_SELECT 0xA5 From a3e20d9046fcb087c621a2914e1d016eb20f5ab3 Mon Sep 17 00:00:00 2001 From: Rommel Rodriguez Perez Date: Mon, 4 Jul 2022 18:55:35 -0500 Subject: [PATCH 0830/1436] staging: r8188eu: Block comments use * on subsequent lines This patch modifies a comment in order for it to comply with Linux Kernel style guidelines on comments belonging to net/ or drivers/net/ by fixing the missing * at the beginning of each comment line and removing the initial almost-blank initial line from the comment block. checkpatch output: WARNING: Block comments use * on subsequent lines Reviewed-by: Philipp Hortmann Signed-off-by: Rommel Rodriguez Perez Link: https://lore.kernel.org/r/YsN993FTljv5LYT3@debianmain.debian.pc.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_ap.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_ap.c b/drivers/staging/r8188eu/core/rtw_ap.c index ac6effbecf6d..5bd9dfa57cc5 100644 --- a/drivers/staging/r8188eu/core/rtw_ap.c +++ b/drivers/staging/r8188eu/core/rtw_ap.c @@ -654,18 +654,17 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx) set_tx_beacon_cmd(padapter); } -/* -op_mode -Set to 0 (HT pure) under the following conditions - - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or - - all STAs in the BSS are 20 MHz HT in 20 MHz BSS -Set to 1 (HT non-member protection) if there may be non-HT STAs - in both the primary and the secondary channel -Set to 2 if only HT STAs are associated in BSS, - however and at least one 20 MHz HT STA is associated -Set to 3 (HT mixed mode) when one or more non-HT STAs are associated - (currently non-GF HT station is considered as non-HT STA also) -*/ +/* op_mode + * Set to 0 (HT pure) under the following conditions + * - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or + * - all STAs in the BSS are 20 MHz HT in 20 MHz BSS + * Set to 1 (HT non-member protection) if there may be non-HT STAs + * in both the primary and the secondary channel + * Set to 2 if only HT STAs are associated in BSS, + * however and at least one 20 MHz HT STA is associated + * Set to 3 (HT mixed mode) when one or more non-HT STAs are associated + * (currently non-GF HT station is considered as non-HT STA also) + */ static int rtw_ht_operation_update(struct adapter *padapter) { u16 cur_op_mode, new_op_mode; From c45f5c02a00a636311045a5efef58a60501a862b Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 22:16:49 +0200 Subject: [PATCH 0831/1436] staging: r8188eu: set bssid only once In function ap2sta_data_frame, for WIFI_MP_STATE && _FW_LINKED, the code sets pattrib->bssid twice. Remove the first one of these assignments. Remove an empty comment before the second assignment. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704201654.195574-2-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 020bc212532f..9c63319a7d48 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -706,11 +706,9 @@ static int ap2sta_data_frame( check_fwstate(pmlmepriv, _FW_LINKED)) { memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); - memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); memcpy(pattrib->ta, pattrib->src, ETH_ALEN); - /* */ memcpy(pattrib->bssid, mybssid, ETH_ALEN); *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */ From d6d0a11dd5b52de3286be5fa2298b2d72f09828f Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 22:16:50 +0200 Subject: [PATCH 0832/1436] staging: r8188eu: don't set pattrib->dst again Do not set pattrib->dst again in ap2sta_data_frame. This function is called by validate_recv_data_frame when the packet's ToDS==0 and FromDS==1. In this case, validate_recv_data_frame has already set pattrib->dst to addr1. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704201654.195574-3-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 9c63319a7d48..ea81501b3286 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -704,7 +704,6 @@ static int ap2sta_data_frame( } } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) { - memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); memcpy(pattrib->ta, pattrib->src, ETH_ALEN); From ff2833e3f8c842b9328306009579aeeea1a0a310 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 22:16:51 +0200 Subject: [PATCH 0833/1436] staging: r8188eu: don't set pattrib->ra again Do not set pattrib->ra again in ap2sta_data_frame. This function is called by validate_recv_data_frame when the packet's ToDS==0 and FromDS==1. validate_recv_data_frame has already set pattrib->ra to addr1. This is in line with the table in ieee80211.h. ap2sta_data_frame sets pattrib->ra to pattrib->dst. For ToDS==0, FromDS==1, dst is addr1, i.e. ap2sta_data_frame sets the same value again that was already set by validate_recv_data_frame. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704201654.195574-4-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index ea81501b3286..3619b1ab0267 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -705,7 +705,6 @@ static int ap2sta_data_frame( } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) { memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); - memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); memcpy(pattrib->ta, pattrib->src, ETH_ALEN); memcpy(pattrib->bssid, mybssid, ETH_ALEN); From 6afc29cb469678a7d8397acb83711beb1c12661e Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 22:16:52 +0200 Subject: [PATCH 0834/1436] staging: r8188eu: don't set pattrib->ta again The table in ieee80211.h shows that TA is addr2. This value was already set by validate_recv_data_frame, we don't have to set it again in ap2sta_data_frame. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704201654.195574-5-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 3619b1ab0267..a761d88d4711 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -705,7 +705,6 @@ static int ap2sta_data_frame( } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) { memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); - memcpy(pattrib->ta, pattrib->src, ETH_ALEN); memcpy(pattrib->bssid, mybssid, ETH_ALEN); From c82bf6a83e1b57d7783e39450ab899a31c0fff94 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 22:16:53 +0200 Subject: [PATCH 0835/1436] staging: r8188eu: remove a misleading comment Remove a misleading comment in ap2sta_data_frame. We are not checking for QOS frames. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704201654.195574-6-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index a761d88d4711..8b21ec8f111f 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -693,9 +693,6 @@ static int ap2sta_data_frame( goto exit; } - /* if ((GetFrameSubType(ptr) & WIFI_QOS_DATA_TYPE) == WIFI_QOS_DATA_TYPE) { */ - /* */ - if (GetFrameSubType(ptr) & BIT(6)) { /* No data, will not indicate to upper layer, temporily count it here */ count_rx_stats(adapter, precv_frame, *psta); From 234cf3971b15a140259e31ea4287143f56f2f3b0 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Mon, 4 Jul 2022 22:16:54 +0200 Subject: [PATCH 0836/1436] staging: r8188eu: use ieee80211 helper to check for nullfunc frame Use the ieee80211_is_nullfunc function from ieee80211.h to check for a nullfunc frame. This is a data frame whose subtype has bit6 set. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220704201654.195574-7-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 8b21ec8f111f..32cd452d1f3d 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -649,6 +649,7 @@ static int ap2sta_data_frame( struct sta_info **psta) { u8 *ptr = precv_frame->rx_data; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)precv_frame->rx_data; struct rx_pkt_attrib *pattrib = &precv_frame->attrib; int ret = _SUCCESS; struct sta_priv *pstapriv = &adapter->stapriv; @@ -693,8 +694,8 @@ static int ap2sta_data_frame( goto exit; } - if (GetFrameSubType(ptr) & BIT(6)) { - /* No data, will not indicate to upper layer, temporily count it here */ + if (ieee80211_is_nullfunc(hdr->frame_control)) { + /* We count the nullfunc frame, but we'll not pass it on to higher layers. */ count_rx_stats(adapter, precv_frame, *psta); ret = RTW_RX_HANDLED; goto exit; From 60c85e23bed17b4e5074cb2695837244cecc827a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Tue, 5 Jul 2022 15:58:01 -0700 Subject: [PATCH 0837/1436] staging: switch to netif_napi_add_weight() netif_napi_add() will soon default to weight of 64 instead of requiring the user to specify that parameter. Most users already pass or should pass 64. Move the callers in staging to netif_napi_add_weight() which will keep the argument. This way we'll avoid a huge cross-tree conversion when argument is removed. Signed-off-by: Jakub Kicinski Link: https://lore.kernel.org/r/20220705225801.923601-1-kuba@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/octeon/ethernet-rx.c | 4 ++-- drivers/staging/qlge/qlge_main.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 9ebd665e5d42..965330eec80a 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -469,8 +469,8 @@ void cvm_oct_rx_initialize(void) if (!(pow_receive_groups & BIT(i))) continue; - netif_napi_add(dev_for_napi, &oct_rx_group[i].napi, - cvm_oct_napi_poll, rx_napi_weight); + netif_napi_add_weight(dev_for_napi, &oct_rx_group[i].napi, + cvm_oct_napi_poll, rx_napi_weight); napi_enable(&oct_rx_group[i].napi); oct_rx_group[i].irq = OCTEON_IRQ_WORKQ0 + i; diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c index 689a87d58f27..1a378330d775 100644 --- a/drivers/staging/qlge/qlge_main.c +++ b/drivers/staging/qlge/qlge_main.c @@ -3037,8 +3037,8 @@ static int qlge_start_rx_ring(struct qlge_adapter *qdev, struct rx_ring *rx_ring /* Inbound completion handling rx_rings run in * separate NAPI contexts. */ - netif_napi_add(qdev->ndev, &rx_ring->napi, qlge_napi_poll_msix, - 64); + netif_napi_add_weight(qdev->ndev, &rx_ring->napi, + qlge_napi_poll_msix, 64); cqicb->irq_delay = cpu_to_le16(qdev->rx_coalesce_usecs); cqicb->pkt_delay = cpu_to_le16(qdev->rx_max_coalesced_frames); } else { From 20cbfe17a486332e78bab01383cb2814f86d74ee Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Mon, 4 Jul 2022 20:20:27 +0200 Subject: [PATCH 0838/1436] staging: vt6655: Rename pbyEtherAddr to mac_addr Fix name of a variable in two macros that use CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/fcc66446a04c1ecb3c2b66cdd47e932c231b1b9d.1656835310.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 102e575c965d..541c6ed6a62f 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -565,27 +565,27 @@ do { \ iowrite16(wData & ~(wBits), iobase + byRegOfs); \ } while (0) -#define MACvWriteBSSIDAddress(iobase, pbyEtherAddr) \ +#define MACvWriteBSSIDAddress(iobase, mac_addr) \ do { \ iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ - iowrite8(pbyEtherAddr[0], iobase + MAC_REG_BSSID0); \ - iowrite8(pbyEtherAddr[1], iobase + MAC_REG_BSSID0 + 1); \ - iowrite8(pbyEtherAddr[2], iobase + MAC_REG_BSSID0 + 2); \ - iowrite8(pbyEtherAddr[3], iobase + MAC_REG_BSSID0 + 3); \ - iowrite8(pbyEtherAddr[4], iobase + MAC_REG_BSSID0 + 4); \ - iowrite8(pbyEtherAddr[5], iobase + MAC_REG_BSSID0 + 5); \ + iowrite8(mac_addr[0], iobase + MAC_REG_BSSID0); \ + iowrite8(mac_addr[1], iobase + MAC_REG_BSSID0 + 1); \ + iowrite8(mac_addr[2], iobase + MAC_REG_BSSID0 + 2); \ + iowrite8(mac_addr[3], iobase + MAC_REG_BSSID0 + 3); \ + iowrite8(mac_addr[4], iobase + MAC_REG_BSSID0 + 4); \ + iowrite8(mac_addr[5], iobase + MAC_REG_BSSID0 + 5); \ iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ } while (0) -#define MACvReadEtherAddress(iobase, pbyEtherAddr) \ +#define MACvReadEtherAddress(iobase, mac_addr) \ do { \ iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ - pbyEtherAddr[0] = ioread8(iobase + MAC_REG_PAR0); \ - pbyEtherAddr[1] = ioread8(iobase + MAC_REG_PAR0 + 1); \ - pbyEtherAddr[2] = ioread8(iobase + MAC_REG_PAR0 + 2); \ - pbyEtherAddr[3] = ioread8(iobase + MAC_REG_PAR0 + 3); \ - pbyEtherAddr[4] = ioread8(iobase + MAC_REG_PAR0 + 4); \ - pbyEtherAddr[5] = ioread8(iobase + MAC_REG_PAR0 + 5); \ + mac_addr[0] = ioread8(iobase + MAC_REG_PAR0); \ + mac_addr[1] = ioread8(iobase + MAC_REG_PAR0 + 1); \ + mac_addr[2] = ioread8(iobase + MAC_REG_PAR0 + 2); \ + mac_addr[3] = ioread8(iobase + MAC_REG_PAR0 + 3); \ + mac_addr[4] = ioread8(iobase + MAC_REG_PAR0 + 4); \ + mac_addr[5] = ioread8(iobase + MAC_REG_PAR0 + 5); \ iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ } while (0) From 06f737ef8f5365dacb0e9f39f41a4fe32e92a79a Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Mon, 4 Jul 2022 20:20:35 +0200 Subject: [PATCH 0839/1436] staging: vt6655: Rename MACvWriteBSSIDAddress Fix name of a macro that uses CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/1190d93181409679f9ae348a95ea269b48b1115c.1656835310.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 2 +- drivers/staging/vt6655/mac.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 204994692c90..6cf21883d1fe 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1405,7 +1405,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, spin_lock_irqsave(&priv->lock, flags); - MACvWriteBSSIDAddress(priv->port_offset, conf->bssid); + vt6655_mac_write_bssid_addr(priv->port_offset, conf->bssid); spin_unlock_irqrestore(&priv->lock, flags); } diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 541c6ed6a62f..cfebd126e42f 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -565,7 +565,7 @@ do { \ iowrite16(wData & ~(wBits), iobase + byRegOfs); \ } while (0) -#define MACvWriteBSSIDAddress(iobase, mac_addr) \ +#define vt6655_mac_write_bssid_addr(iobase, mac_addr) \ do { \ iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ iowrite8(mac_addr[0], iobase + MAC_REG_BSSID0); \ From 41c8e56baeca9075f84a6155e7423ffadc28197e Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Mon, 4 Jul 2022 20:20:39 +0200 Subject: [PATCH 0840/1436] staging: vt6655: Rename MACvReadEtherAddress Fix name of a macro that uses CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/3714f7cd3425e0ef0a3df0cc291131cdb85a3796.1656835310.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 2 +- drivers/staging/vt6655/mac.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 6cf21883d1fe..b9c57c661729 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1722,7 +1722,7 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) } /* initial to reload eeprom */ MACvInitialize(priv); - MACvReadEtherAddress(priv->port_offset, priv->abyCurrentNetAddr); + vt6655_mac_read_ether_addr(priv->port_offset, priv->abyCurrentNetAddr); /* Get RFType */ priv->byRFType = SROMbyReadEmbedded(priv->port_offset, EEP_OFS_RFTYPE); diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index cfebd126e42f..ba5575d63db0 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -577,7 +577,7 @@ do { \ iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ } while (0) -#define MACvReadEtherAddress(iobase, mac_addr) \ +#define vt6655_mac_read_ether_addr(iobase, mac_addr) \ do { \ iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ mac_addr[0] = ioread8(iobase + MAC_REG_PAR0); \ From 52fbed10b8eaaab5e90ddf8c7270f532e43b0c00 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Mon, 4 Jul 2022 20:20:52 +0200 Subject: [PATCH 0841/1436] staging: vt6655: Move two macros to file where those are used Move two multiline macros to file of only useage to convert them later to static functions. checkpatch.pl does not accept multiline macros. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/b4a04608b3900186d4941b3bfe9463bb79e261e8.1656835310.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 24 ++++++++++++++++++++++++ drivers/staging/vt6655/mac.h | 24 ------------------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index b9c57c661729..fdb653071918 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -186,6 +186,30 @@ device_set_options(struct vnt_private *priv) pr_debug(" byBBType= %d\n", (int)priv->byBBType); } +#define vt6655_mac_write_bssid_addr(iobase, mac_addr) \ +do { \ + iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ + iowrite8(mac_addr[0], iobase + MAC_REG_BSSID0); \ + iowrite8(mac_addr[1], iobase + MAC_REG_BSSID0 + 1); \ + iowrite8(mac_addr[2], iobase + MAC_REG_BSSID0 + 2); \ + iowrite8(mac_addr[3], iobase + MAC_REG_BSSID0 + 3); \ + iowrite8(mac_addr[4], iobase + MAC_REG_BSSID0 + 4); \ + iowrite8(mac_addr[5], iobase + MAC_REG_BSSID0 + 5); \ + iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ +} while (0) + +#define vt6655_mac_read_ether_addr(iobase, mac_addr) \ +do { \ + iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ + mac_addr[0] = ioread8(iobase + MAC_REG_PAR0); \ + mac_addr[1] = ioread8(iobase + MAC_REG_PAR0 + 1); \ + mac_addr[2] = ioread8(iobase + MAC_REG_PAR0 + 2); \ + mac_addr[3] = ioread8(iobase + MAC_REG_PAR0 + 3); \ + mac_addr[4] = ioread8(iobase + MAC_REG_PAR0 + 4); \ + mac_addr[5] = ioread8(iobase + MAC_REG_PAR0 + 5); \ + iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ +} while (0) + /* * Initialisation of MAC & BBP registers */ diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index ba5575d63db0..5c14a76ed799 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -565,30 +565,6 @@ do { \ iowrite16(wData & ~(wBits), iobase + byRegOfs); \ } while (0) -#define vt6655_mac_write_bssid_addr(iobase, mac_addr) \ -do { \ - iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ - iowrite8(mac_addr[0], iobase + MAC_REG_BSSID0); \ - iowrite8(mac_addr[1], iobase + MAC_REG_BSSID0 + 1); \ - iowrite8(mac_addr[2], iobase + MAC_REG_BSSID0 + 2); \ - iowrite8(mac_addr[3], iobase + MAC_REG_BSSID0 + 3); \ - iowrite8(mac_addr[4], iobase + MAC_REG_BSSID0 + 4); \ - iowrite8(mac_addr[5], iobase + MAC_REG_BSSID0 + 5); \ - iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ -} while (0) - -#define vt6655_mac_read_ether_addr(iobase, mac_addr) \ -do { \ - iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ - mac_addr[0] = ioread8(iobase + MAC_REG_PAR0); \ - mac_addr[1] = ioread8(iobase + MAC_REG_PAR0 + 1); \ - mac_addr[2] = ioread8(iobase + MAC_REG_PAR0 + 2); \ - mac_addr[3] = ioread8(iobase + MAC_REG_PAR0 + 3); \ - mac_addr[4] = ioread8(iobase + MAC_REG_PAR0 + 4); \ - mac_addr[5] = ioread8(iobase + MAC_REG_PAR0 + 5); \ - iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ -} while (0) - #define MACvReceive0(iobase) \ do { \ unsigned long dwData; \ From 5df564ca11ce575b7378810faee2fc4c01149f9c Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Mon, 4 Jul 2022 20:20:57 +0200 Subject: [PATCH 0842/1436] staging: vt6655: Convert macro vt6655_mac_write_bssid_addr to function Convert macro vt6655_mac_write_bssid_addr to static function. checkpatch.pl does not accept multiline macros. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/caecf7287d92c5d25ba0dfc16a24a6ce4aa67d55.1656835310.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index fdb653071918..025a53b493d3 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -122,6 +122,8 @@ static int vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent); static void device_free_info(struct vnt_private *priv); static void device_print_info(struct vnt_private *priv); +static void vt6655_mac_write_bssid_addr(void __iomem *iobase, const u8 *mac_addr); + static int device_init_rd0_ring(struct vnt_private *priv); static int device_init_rd1_ring(struct vnt_private *priv); static int device_init_td0_ring(struct vnt_private *priv); @@ -186,17 +188,17 @@ device_set_options(struct vnt_private *priv) pr_debug(" byBBType= %d\n", (int)priv->byBBType); } -#define vt6655_mac_write_bssid_addr(iobase, mac_addr) \ -do { \ - iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ - iowrite8(mac_addr[0], iobase + MAC_REG_BSSID0); \ - iowrite8(mac_addr[1], iobase + MAC_REG_BSSID0 + 1); \ - iowrite8(mac_addr[2], iobase + MAC_REG_BSSID0 + 2); \ - iowrite8(mac_addr[3], iobase + MAC_REG_BSSID0 + 3); \ - iowrite8(mac_addr[4], iobase + MAC_REG_BSSID0 + 4); \ - iowrite8(mac_addr[5], iobase + MAC_REG_BSSID0 + 5); \ - iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ -} while (0) +static void vt6655_mac_write_bssid_addr(void __iomem *iobase, const u8 *mac_addr) +{ + iowrite8(1, iobase + MAC_REG_PAGE1SEL); + iowrite8(mac_addr[0], iobase + MAC_REG_BSSID0); + iowrite8(mac_addr[1], iobase + MAC_REG_BSSID0 + 1); + iowrite8(mac_addr[2], iobase + MAC_REG_BSSID0 + 2); + iowrite8(mac_addr[3], iobase + MAC_REG_BSSID0 + 3); + iowrite8(mac_addr[4], iobase + MAC_REG_BSSID0 + 4); + iowrite8(mac_addr[5], iobase + MAC_REG_BSSID0 + 5); + iowrite8(0, iobase + MAC_REG_PAGE1SEL); +} #define vt6655_mac_read_ether_addr(iobase, mac_addr) \ do { \ From 7b5ec68ac1947929cc40e60d3748c1e6b6144682 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Mon, 4 Jul 2022 20:21:08 +0200 Subject: [PATCH 0843/1436] staging: vt6655: Convert macro vt6655_mac_read_ether_addr to function Convert macro vt6655_mac_read_ether_addr to static function. checkpatch.pl does not accept multiline macros. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/2e2524187d9d3a6140fe4a5a35926db14dddfe98.1656835310.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 025a53b493d3..298963cbca1d 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -123,6 +123,7 @@ static void device_free_info(struct vnt_private *priv); static void device_print_info(struct vnt_private *priv); static void vt6655_mac_write_bssid_addr(void __iomem *iobase, const u8 *mac_addr); +static void vt6655_mac_read_ether_addr(void __iomem *iobase, u8 *mac_addr); static int device_init_rd0_ring(struct vnt_private *priv); static int device_init_rd1_ring(struct vnt_private *priv); @@ -200,17 +201,17 @@ static void vt6655_mac_write_bssid_addr(void __iomem *iobase, const u8 *mac_addr iowrite8(0, iobase + MAC_REG_PAGE1SEL); } -#define vt6655_mac_read_ether_addr(iobase, mac_addr) \ -do { \ - iowrite8(1, iobase + MAC_REG_PAGE1SEL); \ - mac_addr[0] = ioread8(iobase + MAC_REG_PAR0); \ - mac_addr[1] = ioread8(iobase + MAC_REG_PAR0 + 1); \ - mac_addr[2] = ioread8(iobase + MAC_REG_PAR0 + 2); \ - mac_addr[3] = ioread8(iobase + MAC_REG_PAR0 + 3); \ - mac_addr[4] = ioread8(iobase + MAC_REG_PAR0 + 4); \ - mac_addr[5] = ioread8(iobase + MAC_REG_PAR0 + 5); \ - iowrite8(0, iobase + MAC_REG_PAGE1SEL); \ -} while (0) +static void vt6655_mac_read_ether_addr(void __iomem *iobase, u8 *mac_addr) +{ + iowrite8(1, iobase + MAC_REG_PAGE1SEL); + mac_addr[0] = ioread8(iobase + MAC_REG_PAR0); + mac_addr[1] = ioread8(iobase + MAC_REG_PAR0 + 1); + mac_addr[2] = ioread8(iobase + MAC_REG_PAR0 + 2); + mac_addr[3] = ioread8(iobase + MAC_REG_PAR0 + 3); + mac_addr[4] = ioread8(iobase + MAC_REG_PAR0 + 4); + mac_addr[5] = ioread8(iobase + MAC_REG_PAR0 + 5); + iowrite8(0, iobase + MAC_REG_PAGE1SEL); +} /* * Initialisation of MAC & BBP registers From 8eaa8197bc2230760c7b53175049ff5595079319 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 7 Jul 2022 21:49:13 +0200 Subject: [PATCH 0844/1436] staging: r8188eu: remove sta2sta_data_frame prototype Remove the prototype for sta2sta_data_frame. Make the function static, it is used only inside rtw_recv.c. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220707194914.63794-2-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 32cd452d1f3d..6a2a1b1664ac 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -556,13 +556,8 @@ static void count_rx_stats(struct adapter *padapter, struct recv_frame *prframe, } } -int sta2sta_data_frame( - struct adapter *adapter, - struct recv_frame *precv_frame, - struct sta_info **psta -); - -int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame, struct sta_info **psta) +static int sta2sta_data_frame(struct adapter *adapter, + struct recv_frame *precv_frame, struct sta_info **psta) { u8 *ptr = precv_frame->rx_data; int ret = _SUCCESS; From 3deb12ea54645a34ef326dc99d2d0c136b78f9c5 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Thu, 7 Jul 2022 21:49:14 +0200 Subject: [PATCH 0845/1436] staging: r8188eu: pattrib addresses were already set by the caller Do not set pattrib's src, dst, bssid, ra and ta again in sta2sta_data_frame. sta2sta_data_frame is called from validate_recv_data_frame when both to_ds and from_ds are 0. All pattrib address fields have already been set to the correct addresses when sta2sta_data_frame is called. memcpy(pattrib->dst, ieee80211_get_DA(hdr), ETH_ALEN); ieee80211_get_DA returns addr1 if to_ds and from_ds are 0 memcpy(pattrib->src, ieee80211_get_SA(hdr), ETH_ALEN); ieee80211_get_SA returns addr2 if to_ds and from_ds are 0 memcpy(pattrib->ra, hdr->addr1, ETH_ALEN); memcpy(pattrib->ta, hdr->addr2, ETH_ALEN); For pattrib->dst == addr1, pattrib->src == addr2, these assignments match those in sta2sta_data_frame that this patch removes. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220707194914.63794-3-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_recv.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_recv.c b/drivers/staging/r8188eu/core/rtw_recv.c index 6a2a1b1664ac..e5a7b7dfc387 100644 --- a/drivers/staging/r8188eu/core/rtw_recv.c +++ b/drivers/staging/r8188eu/core/rtw_recv.c @@ -559,7 +559,6 @@ static void count_rx_stats(struct adapter *padapter, struct recv_frame *prframe, static int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame, struct sta_info **psta) { - u8 *ptr = precv_frame->rx_data; int ret = _SUCCESS; struct rx_pkt_attrib *pattrib = &precv_frame->attrib; struct sta_priv *pstapriv = &adapter->stapriv; @@ -614,12 +613,6 @@ static int sta2sta_data_frame(struct adapter *adapter, sta_addr = pattrib->src; } } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) { - memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN); - memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN); - memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN); - memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); - memcpy(pattrib->ta, pattrib->src, ETH_ALEN); - sta_addr = mybssid; } else { ret = _FAIL; From 385b35ab80b00444e94f30891a2468a7f284e4c7 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 6 Jul 2022 21:19:01 +0200 Subject: [PATCH 0846/1436] staging: vt6655: Use loop in vt6655_mac_write_bssid_addr Use loop in vt6655_mac_write_bssid_addr to avoid multiple similar statements. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/b3b93ae7ce41562565e9007eb4580b9c47a2881f.1657134099.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 298963cbca1d..099f0b95417a 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -192,12 +192,8 @@ device_set_options(struct vnt_private *priv) static void vt6655_mac_write_bssid_addr(void __iomem *iobase, const u8 *mac_addr) { iowrite8(1, iobase + MAC_REG_PAGE1SEL); - iowrite8(mac_addr[0], iobase + MAC_REG_BSSID0); - iowrite8(mac_addr[1], iobase + MAC_REG_BSSID0 + 1); - iowrite8(mac_addr[2], iobase + MAC_REG_BSSID0 + 2); - iowrite8(mac_addr[3], iobase + MAC_REG_BSSID0 + 3); - iowrite8(mac_addr[4], iobase + MAC_REG_BSSID0 + 4); - iowrite8(mac_addr[5], iobase + MAC_REG_BSSID0 + 5); + for (int i = 0; i < 6; i++) + iowrite8(mac_addr[i], iobase + MAC_REG_BSSID0 + i); iowrite8(0, iobase + MAC_REG_PAGE1SEL); } From 2a1f94e45569b1cd9f002e65006f613c2a8360f2 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 6 Jul 2022 21:19:06 +0200 Subject: [PATCH 0847/1436] staging: vt6655: Use loop in vt6655_mac_read_ether_addr Use loop in vt6655_mac_read_ether_addr to avoid multiple similar statements. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/f233c8a007d75a8adcc99a07c582b75bdc1985db.1657134099.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/device_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 099f0b95417a..19840dddb4bf 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -200,12 +200,8 @@ static void vt6655_mac_write_bssid_addr(void __iomem *iobase, const u8 *mac_addr static void vt6655_mac_read_ether_addr(void __iomem *iobase, u8 *mac_addr) { iowrite8(1, iobase + MAC_REG_PAGE1SEL); - mac_addr[0] = ioread8(iobase + MAC_REG_PAR0); - mac_addr[1] = ioread8(iobase + MAC_REG_PAR0 + 1); - mac_addr[2] = ioread8(iobase + MAC_REG_PAR0 + 2); - mac_addr[3] = ioread8(iobase + MAC_REG_PAR0 + 3); - mac_addr[4] = ioread8(iobase + MAC_REG_PAR0 + 4); - mac_addr[5] = ioread8(iobase + MAC_REG_PAR0 + 5); + for (int i = 0; i < 6; i++) + mac_addr[i] = ioread8(iobase + MAC_REG_PAR0 + i); iowrite8(0, iobase + MAC_REG_PAGE1SEL); } From 14a6043379e2132c11b815972c0e2201e68d7467 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Google)" Date: Sun, 3 Jul 2022 09:14:49 -0400 Subject: [PATCH 0848/1436] USB: gadget: udc: tracing: Do not open code __string() with __dynamic_array() The event classes udc_log_ep and udc_log_req both declare: __dynamic_array(char, name, UDC_TRACE_STR_MAX) Which will reserve UDC_TRACE_STR_MAX bytes on the ring buffer for the event to write in name. It then uses snprintf() to write into that space. Assuming that the string being copied is nul terminated, it is better to just use the __string() helper. That way only the size of the string is saved into the ring buffer and not the max size (yes, the entire UDC_TRACE_STR_MAX is used in the trace event, and anything not used is just junk in the ring buffer). Worse, there's also meta data saved into the event that denotes where the string is stored in the event and also saves its size, which is always going to be UDC_TRACE_STR_MAX. Convert both to use the __string() and __assign_str() helpers that are for this kind of use case. Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Signed-off-by: Steven Rostedt (Google) Link: https://lore.kernel.org/r/20220703091449.317f94b1@rorschach.local.home Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/trace.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h index 98584f6b6c66..abdbcb1bacb0 100644 --- a/drivers/usb/gadget/udc/trace.h +++ b/drivers/usb/gadget/udc/trace.h @@ -140,7 +140,7 @@ DECLARE_EVENT_CLASS(udc_log_ep, TP_PROTO(struct usb_ep *ep, int ret), TP_ARGS(ep, ret), TP_STRUCT__entry( - __dynamic_array(char, name, UDC_TRACE_STR_MAX) + __string(name, ep->name) __field(unsigned, maxpacket) __field(unsigned, maxpacket_limit) __field(unsigned, max_streams) @@ -152,7 +152,7 @@ DECLARE_EVENT_CLASS(udc_log_ep, __field(int, ret) ), TP_fast_assign( - snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name); + __assign_str(name, ep->name); __entry->maxpacket = ep->maxpacket; __entry->maxpacket_limit = ep->maxpacket_limit; __entry->max_streams = ep->max_streams; @@ -214,7 +214,7 @@ DECLARE_EVENT_CLASS(udc_log_req, TP_PROTO(struct usb_ep *ep, struct usb_request *req, int ret), TP_ARGS(ep, req, ret), TP_STRUCT__entry( - __dynamic_array(char, name, UDC_TRACE_STR_MAX) + __string(name, ep->name) __field(unsigned, length) __field(unsigned, actual) __field(unsigned, num_sgs) @@ -228,7 +228,7 @@ DECLARE_EVENT_CLASS(udc_log_req, __field(struct usb_request *, req) ), TP_fast_assign( - snprintf(__get_str(name), UDC_TRACE_STR_MAX, "%s", ep->name); + __assign_str(name, ep->name); __entry->length = req->length; __entry->actual = req->actual; __entry->num_sgs = req->num_sgs; From e89676f65ef372fda6c392b3f99fcc7175b206e6 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 5 Jul 2022 15:19:50 +0200 Subject: [PATCH 0849/1436] usb: gadget: udc: atmel: check rc of devm_gpiod_get_optional() devm_gpiod_get_optional() might still return an error code, esp. EPROBE_DEFER. Return any errors. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20220705131951.1388968-1-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/atmel_usba_udc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index ae2bfbac603e..48355e0cee76 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2165,6 +2165,8 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, udc->vbus_pin = devm_gpiod_get_optional(&pdev->dev, "atmel,vbus", GPIOD_IN); + if (IS_ERR(udc->vbus_pin)) + return ERR_CAST(udc->vbus_pin); if (fifo_mode == 0) { udc->num_ep = udc_config->num_ep; From 1bd71816643a9e279c2a7b7a02c10de4a07bf9eb Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Tue, 5 Jul 2022 15:19:51 +0200 Subject: [PATCH 0850/1436] usb: gadget: udc: atmel: convert to platform driver The driver won't probe on a LAN9668 because the pinctrl driver isn't ready yet. Probe deferral is not supported because the init section is already discarded. With fw_devlink enabled, the probe won't even be called. Convert the driver to a proper platform driver. Signed-off-by: Michael Walle Link: https://lore.kernel.org/r/20220705131951.1388968-2-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/atmel_usba_udc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 48355e0cee76..53ca38c4b3ec 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -2060,7 +2060,7 @@ static const struct usba_udc_errata at91sam9g45_errata = { .pulse_bias = at91sam9g45_pulse_bias, }; -static const struct usba_ep_config ep_config_sam9[] __initconst = { +static const struct usba_ep_config ep_config_sam9[] = { { .nr_banks = 1 }, /* ep 0 */ { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 1 */ { .nr_banks = 2, .can_dma = 1, .can_isoc = 1 }, /* ep 2 */ @@ -2070,7 +2070,7 @@ static const struct usba_ep_config ep_config_sam9[] __initconst = { { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 6 */ }; -static const struct usba_ep_config ep_config_sama5[] __initconst = { +static const struct usba_ep_config ep_config_sama5[] = { { .nr_banks = 1 }, /* ep 0 */ { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 1 */ { .nr_banks = 3, .can_dma = 1, .can_isoc = 1 }, /* ep 2 */ @@ -2449,6 +2449,7 @@ static int usba_udc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(usba_udc_pm_ops, usba_udc_suspend, usba_udc_resume); static struct platform_driver udc_driver = { + .probe = usba_udc_probe, .remove = usba_udc_remove, .driver = { .name = "atmel_usba_udc", @@ -2456,8 +2457,7 @@ static struct platform_driver udc_driver = { .of_match_table = atmel_udc_dt_ids, }, }; - -module_platform_driver_probe(udc_driver, usba_udc_probe); +module_platform_driver(udc_driver); MODULE_DESCRIPTION("Atmel USBA UDC driver"); MODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); From 2e1421d6ce321118dfff370e473ba8d290b2ecbd Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Thu, 7 Jul 2022 09:50:41 +0800 Subject: [PATCH 0851/1436] dt-bindings: usb: mtk-xhci: add compatible for mt8188 Add compatible for mt8188 Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220707015041.12264-1-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index 1444d18ef9bc..04cbbca0e94e 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -31,6 +31,7 @@ properties: - mediatek,mt8173-xhci - mediatek,mt8183-xhci - mediatek,mt8186-xhci + - mediatek,mt8188-xhci - mediatek,mt8192-xhci - mediatek,mt8195-xhci - const: mediatek,mtk-xhci From 04cb742d4d8f30dc2e83b46ac317eec09191c68e Mon Sep 17 00:00:00 2001 From: Jozef Martiniak Date: Fri, 8 Jul 2022 09:06:44 +0200 Subject: [PATCH 0852/1436] gadgetfs: ep_io - wait until IRQ finishes after usb_ep_queue() if wait_for_completion_interruptible() is interrupted we need to wait until IRQ gets finished. Otherwise complete() from epio_complete() can corrupt stack. Signed-off-by: Jozef Martiniak Link: https://lore.kernel.org/r/20220708070645.6130-1-jomajm@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/legacy/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 79990597c39f..01c3ead7d1b4 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -362,6 +362,7 @@ ep_io (struct ep_data *epdata, void *buf, unsigned len) spin_unlock_irq (&epdata->dev->lock); DBG (epdata->dev, "endpoint gone\n"); + wait_for_completion(&done); epdata->status = -ENODEV; } } From 7963d4d710112bc457f99bdb56608211e561190e Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Wed, 6 Jul 2022 16:34:31 +0800 Subject: [PATCH 0853/1436] usb: typec: tcpci: move tcpci.h to include/linux/usb/ USB PD controllers which consisting of a microcontroller (acting as the TCPM) and a port controller (TCPC) - may require that the driver for the PD controller accesses directly also the on-chip port controller in some cases. Move tcpci.h to include/linux/usb/ is convenience access TCPC registers. Reviewed-by: Heikki Krogerus Signed-off-by: Xin Ji Link: https://lore.kernel.org/r/20220706083433.2415524-1-xji@analogixsemi.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpci.c | 3 +-- drivers/usb/typec/tcpm/tcpci_maxim.c | 3 +-- drivers/usb/typec/tcpm/tcpci_mt6360.c | 3 +-- drivers/usb/typec/tcpm/tcpci_rt1711h.c | 2 +- {drivers/usb/typec/tcpm => include/linux/usb}/tcpci.h | 1 + 5 files changed, 5 insertions(+), 7 deletions(-) rename {drivers/usb/typec/tcpm => include/linux/usb}/tcpci.h (99%) diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index f33e08eb7670..812784702d53 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c @@ -13,11 +13,10 @@ #include #include #include +#include #include #include -#include "tcpci.h" - #define PD_RETRY_COUNT_DEFAULT 3 #define PD_RETRY_COUNT_3_0_OR_HIGHER 2 #define AUTO_DISCHARGE_DEFAULT_THRESHOLD_MV 3500 diff --git a/drivers/usb/typec/tcpm/tcpci_maxim.c b/drivers/usb/typec/tcpm/tcpci_maxim.c index df2505570f07..4b6705f3d7b7 100644 --- a/drivers/usb/typec/tcpm/tcpci_maxim.c +++ b/drivers/usb/typec/tcpm/tcpci_maxim.c @@ -11,11 +11,10 @@ #include #include #include +#include #include #include -#include "tcpci.h" - #define PD_ACTIVITY_TIMEOUT_MS 10000 #define TCPC_VENDOR_ALERT 0x80 diff --git a/drivers/usb/typec/tcpm/tcpci_mt6360.c b/drivers/usb/typec/tcpm/tcpci_mt6360.c index 8a952eaf9016..1b7c31278ebb 100644 --- a/drivers/usb/typec/tcpm/tcpci_mt6360.c +++ b/drivers/usb/typec/tcpm/tcpci_mt6360.c @@ -11,10 +11,9 @@ #include #include #include +#include #include -#include "tcpci.h" - #define MT6360_REG_PHYCTRL1 0x80 #define MT6360_REG_PHYCTRL3 0x82 #define MT6360_REG_PHYCTRL7 0x86 diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index b56a0880a044..3291ca4948da 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -10,9 +10,9 @@ #include #include #include +#include #include #include -#include "tcpci.h" #define RT1711H_VID 0x29CF #define RT1711H_PID 0x1711 diff --git a/drivers/usb/typec/tcpm/tcpci.h b/include/linux/usb/tcpci.h similarity index 99% rename from drivers/usb/typec/tcpm/tcpci.h rename to include/linux/usb/tcpci.h index b2edd45f13c6..20c0bedb8ec8 100644 --- a/drivers/usb/typec/tcpm/tcpci.h +++ b/include/linux/usb/tcpci.h @@ -9,6 +9,7 @@ #define __LINUX_USB_TCPCI_H #include +#include #define TCPC_VENDOR_ID 0x0 #define TCPC_PRODUCT_ID 0x2 From 3cb7982207260e91cd7ba77120ba2e0613c8dbf2 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 8 Jul 2022 15:19:00 +0800 Subject: [PATCH 0854/1436] usb: mtu3: print endpoint type as string Print endpoint type as string instead of decimal value to make the log more readable. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220708071903.25752-2-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_debugfs.c | 8 ++++---- drivers/usb/mtu3/mtu3_trace.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/mtu3/mtu3_debugfs.c b/drivers/usb/mtu3/mtu3_debugfs.c index d27de647c86a..f0de99858353 100644 --- a/drivers/usb/mtu3/mtu3_debugfs.c +++ b/drivers/usb/mtu3/mtu3_debugfs.c @@ -101,13 +101,13 @@ static int mtu3_ep_used_show(struct seq_file *sf, void *unused) for (i = 0; i < mtu->num_eps; i++) { mep = mtu->in_eps + i; if (mep->flags & MTU3_EP_ENABLED) { - seq_printf(sf, "%s - type: %d\n", mep->name, mep->type); + seq_printf(sf, "%s - type: %s\n", mep->name, usb_ep_type_string(mep->type)); used++; } mep = mtu->out_eps + i; if (mep->flags & MTU3_EP_ENABLED) { - seq_printf(sf, "%s - type: %d\n", mep->name, mep->type); + seq_printf(sf, "%s - type: %s\n", mep->name, usb_ep_type_string(mep->type)); used++; } } @@ -177,8 +177,8 @@ static int mtu3_ep_info_show(struct seq_file *sf, void *unused) unsigned long flags; spin_lock_irqsave(&mtu->lock, flags); - seq_printf(sf, "ep - type:%d, maxp:%d, slot:%d, flags:%x\n", - mep->type, mep->maxp, mep->slot, mep->flags); + seq_printf(sf, "ep - type:%s, maxp:%d, slot:%d, flags:%x\n", + usb_ep_type_string(mep->type), mep->maxp, mep->slot, mep->flags); spin_unlock_irqrestore(&mtu->lock, flags); return 0; diff --git a/drivers/usb/mtu3/mtu3_trace.h b/drivers/usb/mtu3/mtu3_trace.h index 1b897636daf2..a09deae1146f 100644 --- a/drivers/usb/mtu3/mtu3_trace.h +++ b/drivers/usb/mtu3/mtu3_trace.h @@ -238,8 +238,8 @@ DECLARE_EVENT_CLASS(mtu3_log_ep, __entry->direction = mep->is_in; __entry->gpd_ring = &mep->gpd_ring; ), - TP_printk("%s: type %d maxp %d slot %d mult %d burst %d ring %p/%pad flags %c:%c%c%c:%c", - __get_str(name), __entry->type, + TP_printk("%s: type %s maxp %d slot %d mult %d burst %d ring %p/%pad flags %c:%c%c%c:%c", + __get_str(name), usb_ep_type_string(__entry->type), __entry->maxp, __entry->slot, __entry->mult, __entry->maxburst, __entry->gpd_ring, &__entry->gpd_ring->dma, From 269f49ff381aade6cfd20deeae86a8af7ae35b5a Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 8 Jul 2022 15:19:01 +0800 Subject: [PATCH 0855/1436] usb: mtu3: add feature to disable device's usb3 port We may want to disable device's usb3 port when the combo phy is switched from usb3 mode to pcie mode for some projects. Meanwhile rename member @is_u3_ip to @u3_capable to avoid misleading, due to the member's value may be changed when disable usb3 port, but the controller is still a usb3 IP which also tells us how to manage the fifo. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220708071903.25752-3-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3.h | 4 +++- drivers/usb/mtu3/mtu3_core.c | 32 +++++++++++++++++++------------- drivers/usb/mtu3/mtu3_plat.c | 4 ++-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 8408e1b1a24a..2d7b57e07eee 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -317,6 +317,7 @@ static inline struct ssusb_mtk *dev_to_ssusb(struct device *dev) * @ep0_req: dummy request used while handling standard USB requests * for GET_STATUS and SET_SEL * @setup_buf: ep0 response buffer for GET_STATUS and SET_SEL requests + * @u3_capable: is capable of supporting USB3 */ struct mtu3 { spinlock_t lock; @@ -353,11 +354,12 @@ struct mtu3 { unsigned softconnect:1; unsigned u1_enable:1; unsigned u2_enable:1; - unsigned is_u3_ip:1; + unsigned u3_capable:1; unsigned delayed_status:1; unsigned gen2cp:1; unsigned connected:1; unsigned async_callbacks:1; + unsigned separate_fifo:1; u8 address; u8 test_mode_nr; diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index 3c6a670efafa..0ca173af87bb 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -100,7 +100,7 @@ static int mtu3_device_enable(struct mtu3 *mtu) mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); - if (mtu->is_u3_ip) { + if (mtu->u3_capable) { check_clk = SSUSB_U3_MAC_RST_B_STS; mtu3_clrbits(ibase, SSUSB_U3_CTRL(0), (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN | @@ -112,7 +112,7 @@ static int mtu3_device_enable(struct mtu3 *mtu) if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) { mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL); - if (mtu->is_u3_ip) + if (mtu->u3_capable) mtu3_setbits(ibase, SSUSB_U3_CTRL(0), SSUSB_U3_PORT_DUAL_MODE); } @@ -124,7 +124,7 @@ static void mtu3_device_disable(struct mtu3 *mtu) { void __iomem *ibase = mtu->ippc_base; - if (mtu->is_u3_ip) + if (mtu->u3_capable) mtu3_setbits(ibase, SSUSB_U3_CTRL(0), (SSUSB_U3_PORT_DIS | SSUSB_U3_PORT_PDN)); @@ -133,7 +133,7 @@ static void mtu3_device_disable(struct mtu3 *mtu) if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) { mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL); - if (mtu->is_u3_ip) + if (mtu->u3_capable) mtu3_clrbits(ibase, SSUSB_U3_CTRL(0), SSUSB_U3_PORT_DUAL_MODE); } @@ -146,7 +146,7 @@ static void mtu3_dev_power_on(struct mtu3 *mtu) void __iomem *ibase = mtu->ippc_base; mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); - if (mtu->is_u3_ip) + if (mtu->u3_capable) mtu3_clrbits(ibase, SSUSB_U3_CTRL(0), SSUSB_U3_PORT_PDN); mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_PDN); @@ -156,7 +156,7 @@ static void mtu3_dev_power_down(struct mtu3 *mtu) { void __iomem *ibase = mtu->ippc_base; - if (mtu->is_u3_ip) + if (mtu->u3_capable) mtu3_setbits(ibase, SSUSB_U3_CTRL(0), SSUSB_U3_PORT_PDN); mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_PDN); @@ -213,7 +213,7 @@ static void mtu3_intr_enable(struct mtu3 *mtu) value = SUSPEND_INTR | RESUME_INTR | RESET_INTR; mtu3_writel(mbase, U3D_COMMON_USB_INTR_ENABLE, value); - if (mtu->is_u3_ip) { + if (mtu->u3_capable) { /* Enable U3 LTSSM interrupts */ value = HOT_RST_INTR | WARM_RST_INTR | ENTER_U3_INTR | EXIT_U3_INTR; @@ -273,7 +273,7 @@ static void mtu3_csr_init(struct mtu3 *mtu) { void __iomem *mbase = mtu->mac_base; - if (mtu->is_u3_ip) { + if (mtu->u3_capable) { /* disable LGO_U1/U2 by default */ mtu3_clrbits(mbase, U3D_LINK_POWER_CONTROL, SW_U1_REQUEST_ENABLE | SW_U2_REQUEST_ENABLE); @@ -341,7 +341,7 @@ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set) void mtu3_dev_on_off(struct mtu3 *mtu, int is_on) { - if (mtu->is_u3_ip && mtu->speed >= USB_SPEED_SUPER) + if (mtu->u3_capable && mtu->speed >= USB_SPEED_SUPER) mtu3_ss_func_set(mtu, is_on); else mtu3_hs_softconn_set(mtu, is_on); @@ -544,7 +544,7 @@ static void get_ep_fifo_config(struct mtu3 *mtu) struct mtu3_fifo_info *rx_fifo; u32 fifosize; - if (mtu->is_u3_ip) { + if (mtu->separate_fifo) { fifosize = mtu3_readl(mtu->mac_base, U3D_CAP_EPNTXFFSZ); tx_fifo = &mtu->tx_fifo; tx_fifo->base = 0; @@ -821,6 +821,10 @@ static irqreturn_t mtu3_irq(int irq, void *data) static void mtu3_check_params(struct mtu3 *mtu) { + /* device's u3 port (port0) is disabled */ + if (mtu->u3_capable && (mtu->ssusb->u3p_dis_msk & BIT(0))) + mtu->u3_capable = 0; + /* check the max_speed parameter */ switch (mtu->max_speed) { case USB_SPEED_FULL: @@ -838,7 +842,7 @@ static void mtu3_check_params(struct mtu3 *mtu) break; } - if (!mtu->is_u3_ip && (mtu->max_speed > USB_SPEED_HIGH)) + if (!mtu->u3_capable && (mtu->max_speed > USB_SPEED_HIGH)) mtu->max_speed = USB_SPEED_HIGH; mtu->speed = mtu->max_speed; @@ -857,10 +861,12 @@ static int mtu3_hw_init(struct mtu3 *mtu) mtu->gen2cp = !!(mtu->hw_version >= MTU3_TRUNK_VERS_1003); value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP); - mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(value); + mtu->u3_capable = !!SSUSB_IP_DEV_U3_PORT_NUM(value); + /* usb3 ip uses separate fifo */ + mtu->separate_fifo = mtu->u3_capable; dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version, - mtu->is_u3_ip ? "U3" : "U2"); + mtu->u3_capable ? "U3" : "U2"); mtu3_check_params(mtu); diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index d14494b30064..42987d08ce8c 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -244,6 +244,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN) ssusb->dr_mode = USB_DR_MODE_OTG; + of_property_read_u32(node, "mediatek,u3p-dis-msk", &ssusb->u3p_dis_msk); + if (ssusb->dr_mode == USB_DR_MODE_PERIPHERAL) goto out; @@ -255,8 +257,6 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) } /* optional property, ignore the error if it does not exist */ - of_property_read_u32(node, "mediatek,u3p-dis-msk", - &ssusb->u3p_dis_msk); of_property_read_u32(node, "mediatek,u2p-dis-msk", &ssusb->u2p_dis_msk); From 683ff6e485f1d16fe3ad4f5fbd04af11ce917caf Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 8 Jul 2022 15:19:02 +0800 Subject: [PATCH 0856/1436] usb: mtu3: check capability of usb3 dual role It is capable of supporting usb3 dual role if there is at least one usb3 port for device and xhci controller, we can check it from the controller's capability, so no need the property "mediatek,usb3-drd" anymore, but I find the property is not decribed in dt-binding. Meanwhile, also take into account if the u3 port is disabled when the u3 phy is shared with pcie. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220708071903.25752-4-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_plat.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 42987d08ce8c..4cb65346789d 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -190,6 +190,31 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb) mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); } +static void ssusb_u3_drd_check(struct ssusb_mtk *ssusb) +{ + struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; + u32 dev_u3p_num; + u32 host_u3p_num; + u32 value; + + /* u3 port0 is disabled */ + if (ssusb->u3p_dis_msk & BIT(0)) { + otg_sx->is_u3_drd = false; + goto out; + } + + value = mtu3_readl(ssusb->ippc_base, U3D_SSUSB_IP_DEV_CAP); + dev_u3p_num = SSUSB_IP_DEV_U3_PORT_NUM(value); + + value = mtu3_readl(ssusb->ippc_base, U3D_SSUSB_IP_XHCI_CAP); + host_u3p_num = SSUSB_IP_XHCI_U3_PORT_NUM(value); + + otg_sx->is_u3_drd = !!(dev_u3p_num && host_u3p_num); + +out: + dev_info(ssusb->dev, "usb3-drd: %d\n", otg_sx->is_u3_drd); +} + static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) { struct device_node *node = pdev->dev.of_node; @@ -270,7 +295,6 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) goto out; /* if dual-role mode is supported */ - otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd"); otg_sx->manual_drd_enabled = of_property_read_bool(node, "enable-manual-drd"); otg_sx->role_sw_used = of_property_read_bool(node, "usb-role-switch"); @@ -290,9 +314,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) } out: - dev_info(dev, "dr_mode: %d, is_u3_dr: %d, drd: %s\n", - ssusb->dr_mode, otg_sx->is_u3_drd, - otg_sx->manual_drd_enabled ? "manual" : "auto"); + dev_info(dev, "dr_mode: %d, drd: %s\n", ssusb->dr_mode, + otg_sx->manual_drd_enabled ? "manual" : "auto"); dev_info(dev, "u2p_dis_msk: %x, u3p_dis_msk: %x\n", ssusb->u2p_dis_msk, ssusb->u3p_dis_msk); @@ -353,6 +376,7 @@ static int mtu3_probe(struct platform_device *pdev) } ssusb_ip_sw_reset(ssusb); + ssusb_u3_drd_check(ssusb); if (IS_ENABLED(CONFIG_USB_MTU3_HOST)) ssusb->dr_mode = USB_DR_MODE_HOST; From 1742b765982cd6d9d5e76ba040598981d53e0a0f Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 8 Jul 2022 15:19:03 +0800 Subject: [PATCH 0857/1436] usb: mtu3: support function remote wakeup Add function wake notification to support function remote wakeup, currently assume the composite device only enable function wake for the first interface. Forward request to function driver when the recipient is an interface, including: GetStatus() request to the first interface in a function returns the information about 'function remote wakeup' and 'function remote wakeup capalbe'; SetFeature request of FUNCTION_SUSPEND to an interface recipient, the controller driver saves the suspend option; Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/20220708071903.25752-5-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mtu3/mtu3_gadget.c | 18 ++++++++++++++++++ drivers/usb/mtu3/mtu3_gadget_ep0.c | 8 ++++---- drivers/usb/mtu3/mtu3_hw_regs.h | 16 ++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index 30999b4debb8..80236e7b0895 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -433,6 +433,13 @@ static int mtu3_gadget_get_frame(struct usb_gadget *gadget) return (int)mtu3_readl(mtu->mac_base, U3D_USB20_FRAME_NUM); } +static void function_wake_notif(struct mtu3 *mtu, u8 intf) +{ + mtu3_writel(mtu->mac_base, U3D_DEV_NOTIF_0, + TYPE_FUNCTION_WAKE | DEV_NOTIF_VAL_FW(intf)); + mtu3_setbits(mtu->mac_base, U3D_DEV_NOTIF_0, SEND_DEV_NOTIF); +} + static int mtu3_gadget_wakeup(struct usb_gadget *gadget) { struct mtu3 *mtu = gadget_to_mtu3(gadget); @@ -446,7 +453,18 @@ static int mtu3_gadget_wakeup(struct usb_gadget *gadget) spin_lock_irqsave(&mtu->lock, flags); if (mtu->g.speed >= USB_SPEED_SUPER) { + /* + * class driver may do function wakeup even UFP is in U0, + * and UX_EXIT only takes effect in U1/U2/U3; + */ mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT); + /* + * Assume there's only one function on the composite device + * and enable remote wake for the first interface. + * FIXME if the IAD (interface association descriptor) shows + * there is more than one function. + */ + function_wake_notif(mtu, 0); } else { mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME); spin_unlock_irqrestore(&mtu->lock, flags); diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c index 7e7013508af6..e4fd1bb14a55 100644 --- a/drivers/usb/mtu3/mtu3_gadget_ep0.c +++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c @@ -226,6 +226,8 @@ ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) break; case USB_RECIP_INTERFACE: + /* status of function remote wakeup, forward request */ + handled = 0; break; case USB_RECIP_ENDPOINT: epnum = (u8) le16_to_cpu(setup->wIndex); @@ -397,10 +399,8 @@ static int ep0_handle_feature(struct mtu3 *mtu, /* superspeed only */ if (value == USB_INTRF_FUNC_SUSPEND && mtu->g.speed >= USB_SPEED_SUPER) { - /* - * forward the request because function drivers - * should handle it - */ + /* forward the request for function suspend */ + mtu->may_wakeup = !!(index & USB_INTRF_FUNC_SUSPEND_RW); handled = 0; } break; diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h index 072db1f6470e..519a58301f45 100644 --- a/drivers/usb/mtu3/mtu3_hw_regs.h +++ b/drivers/usb/mtu3/mtu3_hw_regs.h @@ -341,6 +341,8 @@ #define U3D_LINK_UX_INACT_TIMER (SSUSB_USB3_SYS_CSR_BASE + 0x020C) #define U3D_LINK_POWER_CONTROL (SSUSB_USB3_SYS_CSR_BASE + 0x0210) #define U3D_LINK_ERR_COUNT (SSUSB_USB3_SYS_CSR_BASE + 0x0214) +#define U3D_DEV_NOTIF_0 (SSUSB_USB3_SYS_CSR_BASE + 0x0290) +#define U3D_DEV_NOTIF_1 (SSUSB_USB3_SYS_CSR_BASE + 0x0294) /*---------------- SSUSB_USB3_SYS_CSR FIELD DEFINITION ----------------*/ @@ -365,6 +367,20 @@ #define CLR_LINK_ERR_CNT BIT(16) #define LINK_ERROR_COUNT GENMASK(15, 0) +/* U3D_DEV_NOTIF_0 */ +#define DEV_NOTIF_TYPE_SPECIFIC_LOW_MSK GENMASK(31, 8) +#define DEV_NOTIF_VAL_FW(x) (((x) & 0xff) << 8) +#define DEV_NOTIF_VAL_LTM(x) (((x) & 0xfff) << 8) +#define DEV_NOTIF_VAL_IAM(x) (((x) & 0xffff) << 8) +#define DEV_NOTIF_TYPE_MSK GENMASK(7, 4) +/* Notification Type */ +#define TYPE_FUNCTION_WAKE (0x1 << 4) +#define TYPE_LATENCY_TOLERANCE_MESSAGE (0x2 << 4) +#define TYPE_BUS_INTERVAL_ADJUST_MESSAGE (0x3 << 4) +#define TYPE_HOST_ROLE_REQUEST (0x4 << 4) +#define TYPE_SUBLINK_SPEED (0x5 << 4) +#define SEND_DEV_NOTIF BIT(0) + /*---------------- SSUSB_USB2_CSR REGISTER DEFINITION ----------------*/ #define U3D_POWER_MANAGEMENT (SSUSB_USB2_CSR_BASE + 0x0004) From 620e8e8ba6210003fa45081b63d90ef4f3a0637f Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 30 Jun 2022 12:35:27 -0700 Subject: [PATCH 0858/1436] of/platform: Add stubs for of_platform_device_create/destroy() Code for platform_device_create() and of_platform_device_destroy() is only generated if CONFIG_OF_ADDRESS=y. Add stubs to avoid unresolved symbols when CONFIG_OF_ADDRESS is not set. Reviewed-by: Stephen Boyd Reviewed-by: Douglas Anderson Acked-by: Rob Herring Signed-off-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/20220630123445.v24.1.I08fd2e1c775af04f663730e9fb4d00e6bbb38541@changeid Signed-off-by: Greg Kroah-Hartman --- include/linux/of_platform.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 84a966623e78..d15b6cd5e1c3 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -61,16 +61,18 @@ static inline struct platform_device *of_find_device_by_node(struct device_node } #endif +extern int of_platform_bus_probe(struct device_node *root, + const struct of_device_id *matches, + struct device *parent); + +#ifdef CONFIG_OF_ADDRESS /* Platform devices and busses creation */ extern struct platform_device *of_platform_device_create(struct device_node *np, const char *bus_id, struct device *parent); extern int of_platform_device_destroy(struct device *dev, void *data); -extern int of_platform_bus_probe(struct device_node *root, - const struct of_device_id *matches, - struct device *parent); -#ifdef CONFIG_OF_ADDRESS + extern int of_platform_populate(struct device_node *root, const struct of_device_id *matches, const struct of_dev_auxdata *lookup, @@ -84,6 +86,18 @@ extern int devm_of_platform_populate(struct device *dev); extern void devm_of_platform_depopulate(struct device *dev); #else +/* Platform devices and busses creation */ +static inline struct platform_device *of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent) +{ + return NULL; +} +static inline int of_platform_device_destroy(struct device *dev, void *data) +{ + return -ENODEV; +} + static inline int of_platform_populate(struct device_node *root, const struct of_device_id *matches, const struct of_dev_auxdata *lookup, From dee6719e887b8c539f5d4d3d08c4468498182937 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 30 Jun 2022 12:35:28 -0700 Subject: [PATCH 0859/1436] dt-bindings: usb: rts5411: Rename property 'companion-hub' to 'peer-hub' In the context of USB the term 'companion-hub' is misleading, change the name of the property to 'peer-hub'. There are no upstream users of the 'companion-hub' property, neither in the device tree, nor on the driver side, so renaming it shouldn't cause any compatibility issues with existing device trees. Changes in v24: - patch added to the series Reviewed-by: Douglas Anderson Acked-by: Rob Herring Signed-off-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/20220630123445.v24.2.Ie2bbbd3f690826404b8f1059d24edcab33ed898f@changeid Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/realtek,rts5411.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml index 04ee255eb4f0..50f2b505bdeb 100644 --- a/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml +++ b/Documentation/devicetree/bindings/usb/realtek,rts5411.yaml @@ -25,13 +25,13 @@ properties: description: phandle to the regulator that provides power to the hub. - companion-hub: + peer-hub: $ref: '/schemas/types.yaml#/definitions/phandle' description: - phandle to the companion hub on the controller. + phandle to the peer hub on the controller. required: - - companion-hub + - peer-hub - compatible - reg @@ -49,7 +49,7 @@ examples: compatible = "usbbda,5411"; reg = <1>; vdd-supply = <&pp3300_hub>; - companion-hub = <&hub_3_0>; + peer-hub = <&hub_3_0>; }; /* 3.0 hub on port 2 */ @@ -57,6 +57,6 @@ examples: compatible = "usbbda,411"; reg = <2>; vdd-supply = <&pp3300_hub>; - companion-hub = <&hub_2_0>; + peer-hub = <&hub_2_0>; }; }; From 8bc063641cebf9d555e41d135db2b5035b521768 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 30 Jun 2022 12:35:29 -0700 Subject: [PATCH 0860/1436] usb: misc: Add onboard_usb_hub driver The main issue this driver addresses is that a USB hub needs to be powered before it can be discovered. For discrete onboard hubs (an example for such a hub is the Realtek RTS5411) this is often solved by supplying the hub with an 'always-on' regulator, which is kind of a hack. Some onboard hubs may require further initialization steps, like changing the state of a GPIO or enabling a clock, which requires even more hacks. This driver creates a platform device representing the hub which performs the necessary initialization. Currently it only supports switching on a single regulator, support for multiple regulators or other actions can be added as needed. Different initialization sequences can be supported based on the compatible string. Besides performing the initialization the driver can be configured to power the hub off during system suspend. This can help to extend battery life on battery powered devices which have no requirements to keep the hub powered during suspend. The driver can also be configured to leave the hub powered when a wakeup capable USB device is connected when suspending, and power it off otherwise. Technically the driver consists of two drivers, the platform driver described above and a very thin USB driver that subclasses the generic driver. The purpose of this driver is to provide the platform driver with the USB devices corresponding to the hub(s) (a hub controller may provide multiple 'logical' hubs, e.g. one to support USB 2.0 and another for USB 3.x). Co-developed-by: Ravi Chandra Sadineni Reviewed-by: Douglas Anderson Signed-off-by: Ravi Chandra Sadineni Signed-off-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/20220630123445.v24.3.I7c9a1f1d6ced41dd8310e8a03da666a32364e790@changeid Signed-off-by: Greg Kroah-Hartman --- .../sysfs-bus-platform-onboard-usb-hub | 8 + MAINTAINERS | 7 + drivers/usb/core/Makefile | 4 + drivers/usb/misc/Kconfig | 16 + drivers/usb/misc/Makefile | 1 + drivers/usb/misc/onboard_usb_hub.c | 428 ++++++++++++++++++ drivers/usb/misc/onboard_usb_hub.h | 17 + drivers/usb/misc/onboard_usb_hub_pdevs.c | 142 ++++++ include/linux/usb/onboard_hub.h | 18 + 9 files changed, 641 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub create mode 100644 drivers/usb/misc/onboard_usb_hub.c create mode 100644 drivers/usb/misc/onboard_usb_hub.h create mode 100644 drivers/usb/misc/onboard_usb_hub_pdevs.c create mode 100644 include/linux/usb/onboard_hub.h diff --git a/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub b/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub new file mode 100644 index 000000000000..42deb0552065 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub @@ -0,0 +1,8 @@ +What: /sys/bus/platform/devices//always_powered_in_suspend +Date: June 2022 +KernelVersion: 5.20 +Contact: Matthias Kaehlcke + linux-usb@vger.kernel.org +Description: + (RW) Controls whether the USB hub remains always powered + during system suspend or not. \ No newline at end of file diff --git a/MAINTAINERS b/MAINTAINERS index 7533cb27adc0..f43b126eaf59 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14848,6 +14848,13 @@ S: Maintained T: git git://linuxtv.org/media_tree.git F: drivers/media/i2c/ov9734.c +ONBOARD USB HUB DRIVER +M: Matthias Kaehlcke +L: linux-usb@vger.kernel.org +S: Maintained +F: Documentation/ABI/testing/sysfs-bus-platform-onboard-usb-hub +F: drivers/usb/misc/onboard_usb_hub.c + ONENAND FLASH DRIVER M: Kyungmin Park L: linux-mtd@lists.infradead.org diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 18e874b0441e..7d338e9c0657 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -12,6 +12,10 @@ usbcore-$(CONFIG_OF) += of.o usbcore-$(CONFIG_USB_PCI) += hcd-pci.o usbcore-$(CONFIG_ACPI) += usb-acpi.o +ifdef CONFIG_USB_ONBOARD_HUB +usbcore-y += ../misc/onboard_usb_hub_pdevs.o +endif + obj-$(CONFIG_USB) += usbcore.o obj-$(CONFIG_USB_LEDS_TRIGGER_USBPORT) += ledtrig-usbport.o diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 4c5ddbd75b7e..9367c12c7e6f 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -295,3 +295,19 @@ config BRCM_USB_PINMAP This option enables support for remapping some USB external signals, which are typically on dedicated pins on the chip, to any gpio. + +config USB_ONBOARD_HUB + tristate "Onboard USB hub support" + depends on OF || COMPILE_TEST + help + Say Y here if you want to support discrete onboard USB hubs that + don't require an additional control bus for initialization, but + need some non-trivial form of initialization, such as enabling a + power regulator. An example for such a hub is the Realtek + RTS5411. + + This driver can be used as a module but its state (module vs + builtin) must match the state of the USB subsystem. Enabling + this config will enable the driver and it will automatically + match the state of the USB subsystem. If this driver is a + module it will be called onboard_usb_hub. diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 35bdb4b6c3b6..93581baec3a8 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -33,3 +33,4 @@ obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o obj-$(CONFIG_BRCM_USB_PINMAP) += brcmstb-usb-pinmap.o +obj-$(CONFIG_USB_ONBOARD_HUB) += onboard_usb_hub.o diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c new file mode 100644 index 000000000000..6b9b949d17d3 --- /dev/null +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -0,0 +1,428 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for onboard USB hubs + * + * Copyright (c) 2022, Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "onboard_usb_hub.h" + +static struct usb_device_driver onboard_hub_usbdev_driver; + +/************************** Platform driver **************************/ + +struct usbdev_node { + struct usb_device *udev; + struct list_head list; +}; + +struct onboard_hub { + struct regulator *vdd; + struct device *dev; + bool always_powered_in_suspend; + bool is_powered_on; + bool going_away; + struct list_head udev_list; + struct work_struct attach_usb_driver_work; + struct mutex lock; +}; + +static int onboard_hub_power_on(struct onboard_hub *hub) +{ + int err; + + err = regulator_enable(hub->vdd); + if (err) { + dev_err(hub->dev, "failed to enable regulator: %d\n", err); + return err; + } + + hub->is_powered_on = true; + + return 0; +} + +static int onboard_hub_power_off(struct onboard_hub *hub) +{ + int err; + + err = regulator_disable(hub->vdd); + if (err) { + dev_err(hub->dev, "failed to disable regulator: %d\n", err); + return err; + } + + hub->is_powered_on = false; + + return 0; +} + +static int __maybe_unused onboard_hub_suspend(struct device *dev) +{ + struct onboard_hub *hub = dev_get_drvdata(dev); + struct usbdev_node *node; + bool power_off = true; + + if (hub->always_powered_in_suspend) + return 0; + + mutex_lock(&hub->lock); + + list_for_each_entry(node, &hub->udev_list, list) { + if (!device_may_wakeup(node->udev->bus->controller)) + continue; + + if (usb_wakeup_enabled_descendants(node->udev)) { + power_off = false; + break; + } + } + + mutex_unlock(&hub->lock); + + if (!power_off) + return 0; + + return onboard_hub_power_off(hub); +} + +static int __maybe_unused onboard_hub_resume(struct device *dev) +{ + struct onboard_hub *hub = dev_get_drvdata(dev); + + if (hub->is_powered_on) + return 0; + + return onboard_hub_power_on(hub); +} + +static inline void get_udev_link_name(const struct usb_device *udev, char *buf, size_t size) +{ + snprintf(buf, size, "usb_dev.%s", dev_name(&udev->dev)); +} + +static int onboard_hub_add_usbdev(struct onboard_hub *hub, struct usb_device *udev) +{ + struct usbdev_node *node; + char link_name[64]; + int err; + + mutex_lock(&hub->lock); + + if (hub->going_away) { + err = -EINVAL; + goto error; + } + + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) { + err = -ENOMEM; + goto error; + } + + node->udev = udev; + + list_add(&node->list, &hub->udev_list); + + mutex_unlock(&hub->lock); + + get_udev_link_name(udev, link_name, sizeof(link_name)); + WARN_ON(sysfs_create_link(&hub->dev->kobj, &udev->dev.kobj, link_name)); + + return 0; + +error: + mutex_unlock(&hub->lock); + + return err; +} + +static void onboard_hub_remove_usbdev(struct onboard_hub *hub, const struct usb_device *udev) +{ + struct usbdev_node *node; + char link_name[64]; + + get_udev_link_name(udev, link_name, sizeof(link_name)); + sysfs_remove_link(&hub->dev->kobj, link_name); + + mutex_lock(&hub->lock); + + list_for_each_entry(node, &hub->udev_list, list) { + if (node->udev == udev) { + list_del(&node->list); + kfree(node); + break; + } + } + + mutex_unlock(&hub->lock); +} + +static ssize_t always_powered_in_suspend_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + const struct onboard_hub *hub = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", hub->always_powered_in_suspend); +} + +static ssize_t always_powered_in_suspend_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct onboard_hub *hub = dev_get_drvdata(dev); + bool val; + int ret; + + ret = kstrtobool(buf, &val); + if (ret < 0) + return ret; + + hub->always_powered_in_suspend = val; + + return count; +} +static DEVICE_ATTR_RW(always_powered_in_suspend); + +static struct attribute *onboard_hub_attrs[] = { + &dev_attr_always_powered_in_suspend.attr, + NULL, +}; +ATTRIBUTE_GROUPS(onboard_hub); + +static void onboard_hub_attach_usb_driver(struct work_struct *work) +{ + int err; + + err = driver_attach(&onboard_hub_usbdev_driver.drvwrap.driver); + if (err) + pr_err("Failed to attach USB driver: %d\n", err); +} + +static int onboard_hub_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct onboard_hub *hub; + int err; + + hub = devm_kzalloc(dev, sizeof(*hub), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + hub->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(hub->vdd)) + return PTR_ERR(hub->vdd); + + hub->dev = dev; + mutex_init(&hub->lock); + INIT_LIST_HEAD(&hub->udev_list); + + dev_set_drvdata(dev, hub); + + err = onboard_hub_power_on(hub); + if (err) + return err; + + /* + * The USB driver might have been detached from the USB devices by + * onboard_hub_remove() (e.g. through an 'unbind' by userspace), + * make sure to re-attach it if needed. + * + * This needs to be done deferred to avoid self-deadlocks on systems + * with nested onboard hubs. + */ + INIT_WORK(&hub->attach_usb_driver_work, onboard_hub_attach_usb_driver); + schedule_work(&hub->attach_usb_driver_work); + + return 0; +} + +static int onboard_hub_remove(struct platform_device *pdev) +{ + struct onboard_hub *hub = dev_get_drvdata(&pdev->dev); + struct usbdev_node *node; + struct usb_device *udev; + + hub->going_away = true; + + if (&hub->attach_usb_driver_work != current_work()) + cancel_work_sync(&hub->attach_usb_driver_work); + + mutex_lock(&hub->lock); + + /* unbind the USB devices to avoid dangling references to this device */ + while (!list_empty(&hub->udev_list)) { + node = list_first_entry(&hub->udev_list, struct usbdev_node, list); + udev = node->udev; + + /* + * Unbinding the driver will call onboard_hub_remove_usbdev(), + * which acquires hub->lock. We must release the lock first. + */ + get_device(&udev->dev); + mutex_unlock(&hub->lock); + device_release_driver(&udev->dev); + put_device(&udev->dev); + mutex_lock(&hub->lock); + } + + mutex_unlock(&hub->lock); + + return onboard_hub_power_off(hub); +} + +MODULE_DEVICE_TABLE(of, onboard_hub_match); + +static const struct dev_pm_ops __maybe_unused onboard_hub_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(onboard_hub_suspend, onboard_hub_resume) +}; + +static struct platform_driver onboard_hub_driver = { + .probe = onboard_hub_probe, + .remove = onboard_hub_remove, + + .driver = { + .name = "onboard-usb-hub", + .of_match_table = onboard_hub_match, + .pm = pm_ptr(&onboard_hub_pm_ops), + .dev_groups = onboard_hub_groups, + }, +}; + +/************************** USB driver **************************/ + +#define VENDOR_ID_REALTEK 0x0bda + +/* + * Returns the onboard_hub platform device that is associated with the USB + * device passed as parameter. + */ +static struct onboard_hub *_find_onboard_hub(struct device *dev) +{ + struct platform_device *pdev; + struct device_node *np; + struct onboard_hub *hub; + + pdev = of_find_device_by_node(dev->of_node); + if (!pdev) { + np = of_parse_phandle(dev->of_node, "peer-hub", 0); + if (!np) { + dev_err(dev, "failed to find device node for peer hub\n"); + return ERR_PTR(-EINVAL); + } + + pdev = of_find_device_by_node(np); + of_node_put(np); + + if (!pdev) + return ERR_PTR(-ENODEV); + } + + hub = dev_get_drvdata(&pdev->dev); + put_device(&pdev->dev); + + /* + * The presence of drvdata ('hub') indicates that the platform driver + * finished probing. This handles the case where (conceivably) we could + * be running at the exact same time as the platform driver's probe. If + * we detect the race we request probe deferral and we'll come back and + * try again. + */ + if (!hub) + return ERR_PTR(-EPROBE_DEFER); + + return hub; +} + +static int onboard_hub_usbdev_probe(struct usb_device *udev) +{ + struct device *dev = &udev->dev; + struct onboard_hub *hub; + int err; + + /* ignore supported hubs without device tree node */ + if (!dev->of_node) + return -ENODEV; + + hub = _find_onboard_hub(dev); + if (IS_ERR(hub)) + return PTR_ERR(hub); + + dev_set_drvdata(dev, hub); + + err = onboard_hub_add_usbdev(hub, udev); + if (err) + return err; + + return 0; +} + +static void onboard_hub_usbdev_disconnect(struct usb_device *udev) +{ + struct onboard_hub *hub = dev_get_drvdata(&udev->dev); + + onboard_hub_remove_usbdev(hub, udev); +} + +static const struct usb_device_id onboard_hub_id_table[] = { + { USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */ + { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */ + { USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 */ + { USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 */ + {} +}; +MODULE_DEVICE_TABLE(usb, onboard_hub_id_table); + +static struct usb_device_driver onboard_hub_usbdev_driver = { + .name = "onboard-usb-hub", + .probe = onboard_hub_usbdev_probe, + .disconnect = onboard_hub_usbdev_disconnect, + .generic_subclass = 1, + .supports_autosuspend = 1, + .id_table = onboard_hub_id_table, +}; + +static int __init onboard_hub_init(void) +{ + int ret; + + ret = platform_driver_register(&onboard_hub_driver); + if (ret) + return ret; + + ret = usb_register_device_driver(&onboard_hub_usbdev_driver, THIS_MODULE); + if (ret) + platform_driver_unregister(&onboard_hub_driver); + + return ret; +} +module_init(onboard_hub_init); + +static void __exit onboard_hub_exit(void) +{ + usb_deregister_device_driver(&onboard_hub_usbdev_driver); + platform_driver_unregister(&onboard_hub_driver); +} +module_exit(onboard_hub_exit); + +MODULE_AUTHOR("Matthias Kaehlcke "); +MODULE_DESCRIPTION("Driver for discrete onboard USB hubs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h new file mode 100644 index 000000000000..d3a5b6938582 --- /dev/null +++ b/drivers/usb/misc/onboard_usb_hub.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2022, Google LLC + */ + +#ifndef _USB_MISC_ONBOARD_USB_HUB_H +#define _USB_MISC_ONBOARD_USB_HUB_H + +static const struct of_device_id onboard_hub_match[] = { + { .compatible = "usbbda,411" }, + { .compatible = "usbbda,5411" }, + { .compatible = "usbbda,414" }, + { .compatible = "usbbda,5414" }, + {} +}; + +#endif /* _USB_MISC_ONBOARD_USB_HUB_H */ diff --git a/drivers/usb/misc/onboard_usb_hub_pdevs.c b/drivers/usb/misc/onboard_usb_hub_pdevs.c new file mode 100644 index 000000000000..a0a5f719129f --- /dev/null +++ b/drivers/usb/misc/onboard_usb_hub_pdevs.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * API for creating and destroying USB onboard hub platform devices + * + * Copyright (c) 2022, Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "onboard_usb_hub.h" + +struct pdev_list_entry { + struct platform_device *pdev; + struct list_head node; +}; + +static bool of_is_onboard_usb_hub(const struct device_node *np) +{ + return !!of_match_node(onboard_hub_match, np); +} + +/** + * onboard_hub_create_pdevs -- create platform devices for onboard USB hubs + * @parent_hub : parent hub to scan for connected onboard hubs + * @pdev_list : list of onboard hub platform devices owned by the parent hub + * + * Creates a platform device for each supported onboard hub that is connected to + * the given parent hub. The platform device is in charge of initializing the + * hub (enable regulators, take the hub out of reset, ...) and can optionally + * control whether the hub remains powered during system suspend or not. + * + * To keep track of the platform devices they are added to a list that is owned + * by the parent hub. + * + * Some background about the logic in this function, which can be a bit hard + * to follow: + * + * Root hubs don't have dedicated device tree nodes, but use the node of their + * HCD. The primary and secondary HCD are usually represented by a single DT + * node. That means the root hubs of the primary and secondary HCD share the + * same device tree node (the HCD node). As a result this function can be called + * twice with the same DT node for root hubs. We only want to create a single + * platform device for each physical onboard hub, hence for root hubs the loop + * is only executed for the root hub of the primary HCD. Since the function + * scans through all child nodes it still creates pdevs for onboard hubs + * connected to the root hub of the secondary HCD if needed. + * + * Further there must be only one platform device for onboard hubs with a peer + * hub (the hub is a single physical device). To achieve this two measures are + * taken: pdevs for onboard hubs with a peer are only created when the function + * is called on behalf of the parent hub that is connected to the primary HCD + * (directly or through other hubs). For onboard hubs connected to root hubs + * the function processes the nodes of both peers. A platform device is only + * created if the peer hub doesn't have one already. + */ +void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list) +{ + int i; + struct usb_hcd *hcd = bus_to_hcd(parent_hub->bus); + struct device_node *np, *npc; + struct platform_device *pdev; + struct pdev_list_entry *pdle; + + if (!parent_hub->dev.of_node) + return; + + if (!parent_hub->parent && !usb_hcd_is_primary_hcd(hcd)) + return; + + for (i = 1; i <= parent_hub->maxchild; i++) { + np = usb_of_get_device_node(parent_hub, i); + if (!np) + continue; + + if (!of_is_onboard_usb_hub(np)) + goto node_put; + + npc = of_parse_phandle(np, "peer-hub", 0); + if (npc) { + if (!usb_hcd_is_primary_hcd(hcd)) { + of_node_put(npc); + goto node_put; + } + + pdev = of_find_device_by_node(npc); + of_node_put(npc); + + if (pdev) { + put_device(&pdev->dev); + goto node_put; + } + } + + pdev = of_platform_device_create(np, NULL, &parent_hub->dev); + if (!pdev) { + dev_err(&parent_hub->dev, + "failed to create platform device for onboard hub '%pOF'\n", np); + goto node_put; + } + + pdle = kzalloc(sizeof(*pdle), GFP_KERNEL); + if (!pdle) { + of_platform_device_destroy(&pdev->dev, NULL); + goto node_put; + } + + pdle->pdev = pdev; + list_add(&pdle->node, pdev_list); + +node_put: + of_node_put(np); + } +} +EXPORT_SYMBOL_GPL(onboard_hub_create_pdevs); + +/** + * onboard_hub_destroy_pdevs -- free resources of onboard hub platform devices + * @pdev_list : list of onboard hub platform devices + * + * Destroys the platform devices in the given list and frees the memory associated + * with the list entry. + */ +void onboard_hub_destroy_pdevs(struct list_head *pdev_list) +{ + struct pdev_list_entry *pdle, *tmp; + + list_for_each_entry_safe(pdle, tmp, pdev_list, node) { + list_del(&pdle->node); + of_platform_device_destroy(&pdle->pdev->dev, NULL); + kfree(pdle); + } +} +EXPORT_SYMBOL_GPL(onboard_hub_destroy_pdevs); diff --git a/include/linux/usb/onboard_hub.h b/include/linux/usb/onboard_hub.h new file mode 100644 index 000000000000..d9373230556e --- /dev/null +++ b/include/linux/usb/onboard_hub.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __LINUX_USB_ONBOARD_HUB_H +#define __LINUX_USB_ONBOARD_HUB_H + +struct usb_device; +struct list_head; + +#if IS_ENABLED(CONFIG_USB_ONBOARD_HUB) +void onboard_hub_create_pdevs(struct usb_device *parent_hub, struct list_head *pdev_list); +void onboard_hub_destroy_pdevs(struct list_head *pdev_list); +#else +static inline void onboard_hub_create_pdevs(struct usb_device *parent_hub, + struct list_head *pdev_list) {} +static inline void onboard_hub_destroy_pdevs(struct list_head *pdev_list) {} +#endif + +#endif /* __LINUX_USB_ONBOARD_HUB_H */ From 3a6bf4a08142826698121bef16b244dcf50a6431 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 30 Jun 2022 12:35:30 -0700 Subject: [PATCH 0861/1436] usb: core: hub: Create platform devices for onboard hubs in hub_probe() Call onboard_hub_create/destroy_pdevs() from hub_probe/disconnect() to create/destroy platform devices for onboard USB hubs that may be connected to the hub. The onboard hubs must have nodes in the device tree. onboard_hub_create/destroy_pdevs() are NOPs unless CONFIG_USB_ONBOARD_HUB=y/m. Also add a field to struct usb_hub to keep track of the onboard hub platform devices that are owned by the hub. Reviewed-by: Douglas Anderson Signed-off-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/20220630123445.v24.4.Ic9dd36078f9d803de82ca01a6700c58b8e4de27e@changeid Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 9 ++++++++- drivers/usb/core/hub.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b7f66dcd1fe0..2633acde7ac1 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -1752,6 +1753,8 @@ static void hub_disconnect(struct usb_interface *intf) if (hub->quirk_disable_autosuspend) usb_autopm_put_interface(intf); + onboard_hub_destroy_pdevs(&hub->onboard_hub_devs); + kref_put(&hub->kref, hub_release); } @@ -1869,6 +1872,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) INIT_DELAYED_WORK(&hub->leds, led_work); INIT_DELAYED_WORK(&hub->init_work, NULL); INIT_WORK(&hub->events, hub_event); + INIT_LIST_HEAD(&hub->onboard_hub_devs); spin_lock_init(&hub->irq_urb_lock); timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0); usb_get_intf(intf); @@ -1889,8 +1893,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) usb_autopm_get_interface_no_resume(intf); } - if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) + if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) { + onboard_hub_create_pdevs(hdev, &hub->onboard_hub_devs); + return 0; + } hub_disconnect(intf); return -ENODEV; diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 3fcb38099ce3..b2925856b4cb 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -73,6 +73,7 @@ struct usb_hub { spinlock_t irq_urb_lock; struct timer_list irq_urb_retry; struct usb_port **ports; + struct list_head onboard_hub_devs; }; /** From b067fc284667ccbcfdb6c990568a3cfd8b73bb8a Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Fri, 8 Jul 2022 12:58:57 +0100 Subject: [PATCH 0862/1436] tools: usb: testusb: Add wireless speed reporting Add the ability to detect and print the USB speed as "wireless" if/when the kernel reports that speed. Signed-off-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20220708115859.2095714-2-bryan.odonoghue@linaro.org Signed-off-by: Greg Kroah-Hartman --- tools/usb/testusb.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c index 474bae868b35..6f428f925384 100644 --- a/tools/usb/testusb.c +++ b/tools/usb/testusb.c @@ -96,7 +96,8 @@ struct usb_interface_descriptor { enum usb_device_speed { USB_SPEED_UNKNOWN = 0, /* enumerating */ USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ - USB_SPEED_HIGH /* usb 2.0 */ + USB_SPEED_HIGH, /* usb 2.0 */ + USB_SPEED_WIRELESS, /* wireless (usb 2.5) */ }; /*-------------------------------------------------------------------------*/ @@ -104,11 +105,12 @@ enum usb_device_speed { static char *speed (enum usb_device_speed s) { switch (s) { - case USB_SPEED_UNKNOWN: return "unknown"; - case USB_SPEED_LOW: return "low"; - case USB_SPEED_FULL: return "full"; - case USB_SPEED_HIGH: return "high"; - default: return "??"; + case USB_SPEED_UNKNOWN: return "unknown"; + case USB_SPEED_LOW: return "low"; + case USB_SPEED_FULL: return "full"; + case USB_SPEED_HIGH: return "high"; + case USB_SPEED_WIRELESS: return "wireless"; + default: return "??"; } } From 7fbcd99ebc0b9df7f4a9bbcfbf3e71c6bfddf9cc Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Fri, 8 Jul 2022 12:58:58 +0100 Subject: [PATCH 0863/1436] tools: usb: testusb: Add super speed reporting Add the ability to detect and print the USB speed as "super" if/when the kernel reports that speed. Signed-off-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20220708115859.2095714-3-bryan.odonoghue@linaro.org Signed-off-by: Greg Kroah-Hartman --- tools/usb/testusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c index 6f428f925384..d996a3819322 100644 --- a/tools/usb/testusb.c +++ b/tools/usb/testusb.c @@ -98,6 +98,7 @@ enum usb_device_speed { USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ USB_SPEED_HIGH, /* usb 2.0 */ USB_SPEED_WIRELESS, /* wireless (usb 2.5) */ + USB_SPEED_SUPER, /* usb 3.0 */ }; /*-------------------------------------------------------------------------*/ @@ -110,6 +111,7 @@ static char *speed (enum usb_device_speed s) case USB_SPEED_FULL: return "full"; case USB_SPEED_HIGH: return "high"; case USB_SPEED_WIRELESS: return "wireless"; + case USB_SPEED_SUPER: return "super"; default: return "??"; } } From 5ea5746dfa051eaca6c79a598ff7dc4ec911cada Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Fri, 8 Jul 2022 12:58:59 +0100 Subject: [PATCH 0864/1436] tools: usb: testusb: Add super-plus speed reporting Add the ability to detect and print the USB speed as "super-plus" if/when the kernel reports that speed. Signed-off-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20220708115859.2095714-4-bryan.odonoghue@linaro.org Signed-off-by: Greg Kroah-Hartman --- tools/usb/testusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/usb/testusb.c b/tools/usb/testusb.c index d996a3819322..cbaa1b9fdeac 100644 --- a/tools/usb/testusb.c +++ b/tools/usb/testusb.c @@ -99,6 +99,7 @@ enum usb_device_speed { USB_SPEED_HIGH, /* usb 2.0 */ USB_SPEED_WIRELESS, /* wireless (usb 2.5) */ USB_SPEED_SUPER, /* usb 3.0 */ + USB_SPEED_SUPER_PLUS, /* usb 3.1 */ }; /*-------------------------------------------------------------------------*/ @@ -112,6 +113,7 @@ static char *speed (enum usb_device_speed s) case USB_SPEED_HIGH: return "high"; case USB_SPEED_WIRELESS: return "wireless"; case USB_SPEED_SUPER: return "super"; + case USB_SPEED_SUPER_PLUS: return "super-plus"; default: return "??"; } } From 23385cec5f354794dadced7f28c31da7ae3eb54c Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Mon, 4 Jul 2022 16:18:11 +0200 Subject: [PATCH 0865/1436] usb: dwc3: gadget: refactor dwc3_repare_one_trb The function __dwc3_prepare_one_trb has many parameters. Since it is only used in dwc3_prepare_one_trb there is no point in keeping the function. We merge both functions and get rid of the big list of parameters. Fixes: 40d829fb2ec6 ("usb: dwc3: gadget: Correct ISOC DATA PIDs for short packets") Cc: stable Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20220704141812.1532306-2-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 92 +++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 52 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a944c7a6c83a..dcd8fc209ccd 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1183,17 +1183,49 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) return trbs_left; } -static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, - dma_addr_t dma, unsigned int length, unsigned int chain, - unsigned int node, unsigned int stream_id, - unsigned int short_not_ok, unsigned int no_interrupt, - unsigned int is_last, bool must_interrupt) +/** + * dwc3_prepare_one_trb - setup one TRB from one request + * @dep: endpoint for which this request is prepared + * @req: dwc3_request pointer + * @trb_length: buffer size of the TRB + * @chain: should this TRB be chained to the next? + * @node: only for isochronous endpoints. First TRB needs different type. + * @use_bounce_buffer: set to use bounce buffer + * @must_interrupt: set to interrupt on TRB completion + */ +static void dwc3_prepare_one_trb(struct dwc3_ep *dep, + struct dwc3_request *req, unsigned int trb_length, + unsigned int chain, unsigned int node, bool use_bounce_buffer, + bool must_interrupt) { + struct dwc3_trb *trb; + dma_addr_t dma; + unsigned int stream_id = req->request.stream_id; + unsigned int short_not_ok = req->request.short_not_ok; + unsigned int no_interrupt = req->request.no_interrupt; + unsigned int is_last = req->request.is_last; struct dwc3 *dwc = dep->dwc; struct usb_gadget *gadget = dwc->gadget; enum usb_device_speed speed = gadget->speed; - trb->size = DWC3_TRB_SIZE_LENGTH(length); + if (use_bounce_buffer) + dma = dep->dwc->bounce_addr; + else if (req->request.num_sgs > 0) + dma = sg_dma_address(req->start_sg); + else + dma = req->request.dma; + + trb = &dep->trb_pool[dep->trb_enqueue]; + + if (!req->trb) { + dwc3_gadget_move_started_request(req); + req->trb = trb; + req->trb_dma = dwc3_trb_dma_offset(dep, trb); + } + + req->num_trbs++; + + trb->size = DWC3_TRB_SIZE_LENGTH(trb_length); trb->bpl = lower_32_bits(dma); trb->bph = upper_32_bits(dma); @@ -1233,10 +1265,10 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, unsigned int mult = 2; unsigned int maxp = usb_endpoint_maxp(ep->desc); - if (length <= (2 * maxp)) + if (trb_length <= (2 * maxp)) mult--; - if (length <= maxp) + if (trb_length <= maxp) mult--; trb->size |= DWC3_TRB_SIZE_PCM1(mult); @@ -1310,50 +1342,6 @@ static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, trace_dwc3_prepare_trb(dep, trb); } -/** - * dwc3_prepare_one_trb - setup one TRB from one request - * @dep: endpoint for which this request is prepared - * @req: dwc3_request pointer - * @trb_length: buffer size of the TRB - * @chain: should this TRB be chained to the next? - * @node: only for isochronous endpoints. First TRB needs different type. - * @use_bounce_buffer: set to use bounce buffer - * @must_interrupt: set to interrupt on TRB completion - */ -static void dwc3_prepare_one_trb(struct dwc3_ep *dep, - struct dwc3_request *req, unsigned int trb_length, - unsigned int chain, unsigned int node, bool use_bounce_buffer, - bool must_interrupt) -{ - struct dwc3_trb *trb; - dma_addr_t dma; - unsigned int stream_id = req->request.stream_id; - unsigned int short_not_ok = req->request.short_not_ok; - unsigned int no_interrupt = req->request.no_interrupt; - unsigned int is_last = req->request.is_last; - - if (use_bounce_buffer) - dma = dep->dwc->bounce_addr; - else if (req->request.num_sgs > 0) - dma = sg_dma_address(req->start_sg); - else - dma = req->request.dma; - - trb = &dep->trb_pool[dep->trb_enqueue]; - - if (!req->trb) { - dwc3_gadget_move_started_request(req); - req->trb = trb; - req->trb_dma = dwc3_trb_dma_offset(dep, trb); - } - - req->num_trbs++; - - __dwc3_prepare_one_trb(dep, trb, dma, trb_length, chain, node, - stream_id, short_not_ok, no_interrupt, is_last, - must_interrupt); -} - static bool dwc3_needs_extra_trb(struct dwc3_ep *dep, struct dwc3_request *req) { unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); From 8affe37c525d800a2628c4ecfaed13b77dc5634a Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Mon, 4 Jul 2022 16:18:12 +0200 Subject: [PATCH 0866/1436] usb: dwc3: gadget: fix high speed multiplier setting For High-Speed Transfers the prepare_one_trb function is calculating the multiplier setting for the trb based on the length parameter of the trb currently prepared. This assumption is wrong. For trbs with a sg list, the length of the actual request has to be taken instead. Fixes: 40d829fb2ec6 ("usb: dwc3: gadget: Correct ISOC DATA PIDs for short packets") Cc: stable Signed-off-by: Michael Grzeschik Link: https://lore.kernel.org/r/20220704141812.1532306-3-m.grzeschik@pengutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index dcd8fc209ccd..4366c45c28cf 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1265,10 +1265,10 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, unsigned int mult = 2; unsigned int maxp = usb_endpoint_maxp(ep->desc); - if (trb_length <= (2 * maxp)) + if (req->request.length <= (2 * maxp)) mult--; - if (trb_length <= maxp) + if (req->request.length <= maxp) mult--; trb->size |= DWC3_TRB_SIZE_PCM1(mult); From 936874b77dd0a86aafc1f03c11cb97ec938c16f1 Mon Sep 17 00:00:00 2001 From: Gayatri Kammela Date: Wed, 29 Jun 2022 15:13:34 -0700 Subject: [PATCH 0867/1436] platform/x86/intel/vsec: Add PCI error recovery support to Intel PMT Add PCI error recovery support for Intel PMT driver to recover from PCI fatal errors Cc: Srinivas Pandruvada Cc: David E Box Signed-off-by: Gayatri Kammela Link: https://lore.kernel.org/r/20220629221334.434307-5-gayatri.kammela@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/intel/vsec.c | 82 ++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index 9368a3d587ab..70c76f54f544 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -30,9 +31,13 @@ #define INTEL_DVSEC_TABLE_BAR(x) ((x) & GENMASK(2, 0)) #define INTEL_DVSEC_TABLE_OFFSET(x) ((x) & GENMASK(31, 3)) #define TABLE_OFFSET_SHIFT 3 +#define PMT_XA_START 0 +#define PMT_XA_MAX INT_MAX +#define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX) static DEFINE_IDA(intel_vsec_ida); static DEFINE_IDA(intel_vsec_sdsi_ida); +static DEFINE_XARRAY_ALLOC(auxdev_array); /** * struct intel_vsec_header - Common fields of Intel VSEC and DVSEC registers. @@ -132,7 +137,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in const char *name) { struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev; - int ret; + int ret, id; ret = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL); if (ret < 0) { @@ -159,7 +164,18 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in return ret; } - return devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux, auxdev); + ret = devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux, + auxdev); + if (ret < 0) + return ret; + + /* Add auxdev to list */ + ret = xa_alloc(&auxdev_array, &id, intel_vsec_dev, PMT_XA_LIMIT, + GFP_KERNEL); + if (ret) + return ret; + + return 0; } static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header, @@ -345,6 +361,7 @@ static int intel_vsec_pci_probe(struct pci_dev *pdev, const struct pci_device_id if (ret) return ret; + pci_save_state(pdev); info = (struct intel_vsec_platform_info *)id->driver_data; if (!info) return -EINVAL; @@ -406,10 +423,71 @@ static const struct pci_device_id intel_vsec_pci_ids[] = { }; MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids); +static pci_ers_result_t intel_vsec_pci_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + pci_channel_state_t status = PCI_ERS_RESULT_NEED_RESET; + + dev_info(&pdev->dev, "PCI error detected, state %d", state); + + if (state == pci_channel_io_perm_failure) + status = PCI_ERS_RESULT_DISCONNECT; + else + pci_disable_device(pdev); + + return status; +} + +static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev) +{ + struct intel_vsec_device *intel_vsec_dev; + pci_channel_state_t status = PCI_ERS_RESULT_DISCONNECT; + const struct pci_device_id *pci_dev_id; + unsigned long index; + + dev_info(&pdev->dev, "Resetting PCI slot\n"); + + msleep(2000); + if (pci_enable_device(pdev)) { + dev_info(&pdev->dev, + "Failed to re-enable PCI device after reset.\n"); + goto out; + } + + status = PCI_ERS_RESULT_RECOVERED; + + xa_for_each(&auxdev_array, index, intel_vsec_dev) { + /* check if pdev doesn't match */ + if (pdev != intel_vsec_dev->pcidev) + continue; + devm_release_action(&pdev->dev, intel_vsec_remove_aux, + &intel_vsec_dev->auxdev); + } + pci_disable_device(pdev); + pci_restore_state(pdev); + pci_dev_id = pci_match_id(intel_vsec_pci_ids, pdev); + intel_vsec_pci_probe(pdev, pci_dev_id); + +out: + return status; +} + +static void intel_vsec_pci_resume(struct pci_dev *pdev) +{ + dev_info(&pdev->dev, "Done resuming PCI device\n"); +} + +const struct pci_error_handlers intel_vsec_pci_err_handlers = { + .error_detected = intel_vsec_pci_error_detected, + .slot_reset = intel_vsec_pci_slot_reset, + .resume = intel_vsec_pci_resume, +}; + static struct pci_driver intel_vsec_pci_driver = { .name = "intel_vsec", .id_table = intel_vsec_pci_ids, .probe = intel_vsec_pci_probe, + .err_handler = &intel_vsec_pci_err_handlers, }; module_pci_driver(intel_vsec_pci_driver); From 221b8b21c3a7aa6a390be233994564bd864fc5e2 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Thu, 30 Jun 2022 10:33:23 +0530 Subject: [PATCH 0868/1436] platform/x86/amd/pmc: Add new acpi id for PMC controller New version of PMC controller will have a separate ACPI id, add that to the support list. Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220630050324.3780654-1-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index f11d18beac18..73d6867cc20b 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -91,6 +91,7 @@ #define AMD_CPU_ID_PCO AMD_CPU_ID_RV #define AMD_CPU_ID_CZN AMD_CPU_ID_RN #define AMD_CPU_ID_YC 0x14B5 +#define AMD_CPU_ID_CB 0x14D8 #define PMC_MSG_DELAY_MIN_US 50 #define RESPONSE_REGISTER_LOOP_MAX 20000 @@ -318,6 +319,7 @@ static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev, val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_CZN); break; case AMD_CPU_ID_YC: + case AMD_CPU_ID_CB: val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC); break; default: @@ -491,7 +493,7 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) &amd_pmc_idlemask_fops); /* Enable STB only when the module_param is set */ if (enable_stb) { - if (dev->cpu_id == AMD_CPU_ID_YC) + if (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB) debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, &amd_pmc_stb_debugfs_fops_v2); else @@ -615,6 +617,7 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev) return MSG_OS_HINT_PCO; case AMD_CPU_ID_RN: case AMD_CPU_ID_YC: + case AMD_CPU_ID_CB: return MSG_OS_HINT_RN; } return -EINVAL; @@ -735,6 +738,7 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = { #endif static const struct pci_device_id pmc_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CB) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_YC) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) }, @@ -877,7 +881,7 @@ static int amd_pmc_probe(struct platform_device *pdev) mutex_init(&dev->lock); - if (enable_stb && dev->cpu_id == AMD_CPU_ID_YC) { + if (enable_stb && (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB)) { err = amd_pmc_s2d_init(dev); if (err) return err; @@ -915,6 +919,7 @@ static const struct acpi_device_id amd_pmc_acpi_ids[] = { {"AMDI0005", 0}, {"AMDI0006", 0}, {"AMDI0007", 0}, + {"AMDI0008", 0}, {"AMD0004", 0}, {"AMD0005", 0}, { } From 035c8a91a11f4785ceff7ac89e009f82c9e01257 Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Thu, 30 Jun 2022 10:33:24 +0530 Subject: [PATCH 0869/1436] platform/x86/amd/pmc: Add new platform support PMC driver can be supported on a new upcoming platform. Add this information to the support list. Signed-off-by: Shyam Sundar S K Link: https://lore.kernel.org/r/20220630050324.3780654-2-Shyam-sundar.S-k@amd.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/amd/pmc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c index 73d6867cc20b..700eb19e8450 100644 --- a/drivers/platform/x86/amd/pmc.c +++ b/drivers/platform/x86/amd/pmc.c @@ -92,6 +92,7 @@ #define AMD_CPU_ID_CZN AMD_CPU_ID_RN #define AMD_CPU_ID_YC 0x14B5 #define AMD_CPU_ID_CB 0x14D8 +#define AMD_CPU_ID_PS 0x14E8 #define PMC_MSG_DELAY_MIN_US 50 #define RESPONSE_REGISTER_LOOP_MAX 20000 @@ -320,6 +321,7 @@ static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev, break; case AMD_CPU_ID_YC: case AMD_CPU_ID_CB: + case AMD_CPU_ID_PS: val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC); break; default: @@ -493,7 +495,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev) &amd_pmc_idlemask_fops); /* Enable STB only when the module_param is set */ if (enable_stb) { - if (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB) + if (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB || + dev->cpu_id == AMD_CPU_ID_PS) debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev, &amd_pmc_stb_debugfs_fops_v2); else @@ -618,6 +621,7 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev) case AMD_CPU_ID_RN: case AMD_CPU_ID_YC: case AMD_CPU_ID_CB: + case AMD_CPU_ID_PS: return MSG_OS_HINT_RN; } return -EINVAL; @@ -738,6 +742,7 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = { #endif static const struct pci_device_id pmc_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CB) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_YC) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) }, From 2368048bf5c2ec4b604ac3431564071e89a0bc71 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 12 May 2022 22:27:14 +0000 Subject: [PATCH 0870/1436] KVM: x86: Signal #GP, not -EPERM, on bad WRMSR(MCi_CTL/STATUS) Return '1', not '-1', when handling an illegal WRMSR to a MCi_CTL or MCi_STATUS MSR. The behavior of "all zeros' or "all ones" for CTL MSRs is architectural, as is the "only zeros" behavior for STATUS MSRs. I.e. the intent is to inject a #GP, not exit to userspace due to an unhandled emulation case. Returning '-1' gets interpreted as -EPERM up the stack and effecitvely kills the guest. Fixes: 890ca9aefa78 ("KVM: Add MCE support") Fixes: 9ffd986c6e4e ("KVM: X86: #GP when guest attempts to write MCi_STATUS register w/o 0") Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Link: https://lore.kernel.org/r/20220512222716.4112548-2-seanjc@google.com --- arch/x86/kvm/x86.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 7ce0c6fe166d..891ca973c838 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3239,13 +3239,13 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) */ if ((offset & 0x3) == 0 && data != 0 && (data | (1 << 10) | 1) != ~(u64)0) - return -1; + return 1; /* MCi_STATUS */ if (!msr_info->host_initiated && (offset & 0x3) == 1 && data != 0) { if (!can_set_mci_status(vcpu)) - return -1; + return 1; } vcpu->arch.mce_banks[offset] = data; From f5223a332f3647a0e3725e9b4a102e9659c84ce4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 12 May 2022 22:27:15 +0000 Subject: [PATCH 0871/1436] KVM: x86: Use explicit case-statements for MCx banks in {g,s}et_msr_mce() Use an explicit case statement to grab the full range of MCx bank MSRs in {g,s}et_msr_mce(), and manually check only the "end" (the number of banks configured by userspace may be less than the max). The "default" trick works, but is a bit odd now, and will be quite odd if/when support for accessing MCx_CTL2 MSRs is added, which has near identical logic. Hoist "offset" to function scope so as to avoid curly braces for the case statement, and because MCx_CTL2 support will need the same variables. Opportunstically clean up the comment about allowing bit 10 to be cleared from bank 4. No functional change intended. Cc: Jue Wang Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Link: https://lore.kernel.org/r/20220512222716.4112548-3-seanjc@google.com --- arch/x86/kvm/x86.c | 77 ++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 891ca973c838..c18d57027838 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3209,6 +3209,7 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) unsigned bank_num = mcg_cap & 0xff; u32 msr = msr_info->index; u64 data = msr_info->data; + u32 offset, last_msr; switch (msr) { case MSR_IA32_MCG_STATUS: @@ -3222,35 +3223,36 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) return 1; vcpu->arch.mcg_ctl = data; break; + case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: + last_msr = MSR_IA32_MCx_CTL(bank_num) - 1; + if (msr > last_msr) + return 1; + + offset = array_index_nospec(msr - MSR_IA32_MC0_CTL, + last_msr + 1 - MSR_IA32_MC0_CTL); + + /* + * Only 0 or all 1s can be written to IA32_MCi_CTL, all other + * values are architecturally undefined. But, some Linux + * kernels clear bit 10 in bank 4 to workaround a BIOS/GART TLB + * issue on AMD K8s, allow bit 10 to be clear when setting all + * other bits in order to avoid an uncaught #GP in the guest. + * + * UNIXWARE clears bit 0 of MC1_CTL to ignore correctable, + * single-bit ECC data errors. + */ + if ((offset & 0x3) == 0 && + data != 0 && (data | (1 << 10) | 1) != ~(u64)0) + return 1; + + /* MCi_STATUS */ + if (!msr_info->host_initiated && (offset & 0x3) == 1 && + data != 0 && !can_set_mci_status(vcpu)) + return 1; + + vcpu->arch.mce_banks[offset] = data; + break; default: - if (msr >= MSR_IA32_MC0_CTL && - msr < MSR_IA32_MCx_CTL(bank_num)) { - u32 offset = array_index_nospec( - msr - MSR_IA32_MC0_CTL, - MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL); - - /* only 0 or all 1s can be written to IA32_MCi_CTL - * some Linux kernels though clear bit 10 in bank 4 to - * workaround a BIOS/GART TBL issue on AMD K8s, ignore - * this to avoid an uncatched #GP in the guest. - * - * UNIXWARE clears bit 0 of MC1_CTL to ignore - * correctable, single-bit ECC data errors. - */ - if ((offset & 0x3) == 0 && - data != 0 && (data | (1 << 10) | 1) != ~(u64)0) - return 1; - - /* MCi_STATUS */ - if (!msr_info->host_initiated && - (offset & 0x3) == 1 && data != 0) { - if (!can_set_mci_status(vcpu)) - return 1; - } - - vcpu->arch.mce_banks[offset] = data; - break; - } return 1; } return 0; @@ -3819,6 +3821,7 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) u64 data; u64 mcg_cap = vcpu->arch.mcg_cap; unsigned bank_num = mcg_cap & 0xff; + u32 offset, last_msr; switch (msr) { case MSR_IA32_P5_MC_ADDR: @@ -3836,16 +3839,16 @@ static int get_msr_mce(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata, bool host) case MSR_IA32_MCG_STATUS: data = vcpu->arch.mcg_status; break; - default: - if (msr >= MSR_IA32_MC0_CTL && - msr < MSR_IA32_MCx_CTL(bank_num)) { - u32 offset = array_index_nospec( - msr - MSR_IA32_MC0_CTL, - MSR_IA32_MCx_CTL(bank_num) - MSR_IA32_MC0_CTL); + case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1: + last_msr = MSR_IA32_MCx_CTL(bank_num) - 1; + if (msr > last_msr) + return 1; - data = vcpu->arch.mce_banks[offset]; - break; - } + offset = array_index_nospec(msr - MSR_IA32_MC0_CTL, + last_msr + 1 - MSR_IA32_MC0_CTL); + data = vcpu->arch.mce_banks[offset]; + break; + default: return 1; } *pdata = data; From 54ad60ba9d2673293c72a7c1c4f092622a1f8789 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 12 May 2022 22:27:16 +0000 Subject: [PATCH 0872/1436] KVM: x86: Add helpers to identify CTL and STATUS MCi MSRs Add helpers to identify CTL (control) and STATUS MCi MSR types instead of open coding the checks using the offset. Using the offset is perfectly safe, but unintuitive, as understanding what the code does requires knowing that the offset calcuation will not affect the lower three bits. Opportunistically comment the STATUS logic to save readers a trip to Intel's SDM or AMD's APM to understand the "data != 0" check. No functional change intended. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Link: https://lore.kernel.org/r/20220512222716.4112548-4-seanjc@google.com --- arch/x86/kvm/x86.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c18d57027838..3b7c9c1b4540 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3191,6 +3191,16 @@ static void kvmclock_sync_fn(struct work_struct *work) KVMCLOCK_SYNC_PERIOD); } +/* These helpers are safe iff @msr is known to be an MCx bank MSR. */ +static bool is_mci_control_msr(u32 msr) +{ + return (msr & 3) == 0; +} +static bool is_mci_status_msr(u32 msr) +{ + return (msr & 3) == 1; +} + /* * On AMD, HWCR[McStatusWrEn] controls whether setting MCi_STATUS results in #GP. */ @@ -3228,9 +3238,6 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (msr > last_msr) return 1; - offset = array_index_nospec(msr - MSR_IA32_MC0_CTL, - last_msr + 1 - MSR_IA32_MC0_CTL); - /* * Only 0 or all 1s can be written to IA32_MCi_CTL, all other * values are architecturally undefined. But, some Linux @@ -3241,15 +3248,21 @@ static int set_msr_mce(struct kvm_vcpu *vcpu, struct msr_data *msr_info) * UNIXWARE clears bit 0 of MC1_CTL to ignore correctable, * single-bit ECC data errors. */ - if ((offset & 0x3) == 0 && + if (is_mci_control_msr(msr) && data != 0 && (data | (1 << 10) | 1) != ~(u64)0) return 1; - /* MCi_STATUS */ - if (!msr_info->host_initiated && (offset & 0x3) == 1 && + /* + * All CPUs allow writing 0 to MCi_STATUS MSRs to clear the MSR. + * AMD-based CPUs allow non-zero values, but if and only if + * HWCR[McStatusWrEn] is set. + */ + if (!msr_info->host_initiated && is_mci_status_msr(msr) && data != 0 && !can_set_mci_status(vcpu)) return 1; + offset = array_index_nospec(msr - MSR_IA32_MC0_CTL, + last_msr + 1 - MSR_IA32_MC0_CTL); vcpu->arch.mce_banks[offset] = data; break; default: From 03d84f96890662681feee129cf92491f49247d28 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 8 Jul 2022 15:38:51 -0700 Subject: [PATCH 0873/1436] KVM: x86: Initialize number of APIC LVT entries during APIC creation Initialize the number of LVT entries during APIC creation, else the field will be incorrectly left '0' if userspace never invokes KVM_X86_SETUP_MCE. Add and use a helper to calculate the number of entries even though MCG_CMCI_P is not set by default in vcpu->arch.mcg_cap. Relying on that to always be true is unnecessarily risky, and subtle/confusing as well. Fixes: 4b903561ec49 ("KVM: x86: Add Corrected Machine Check Interrupt (CMCI) emulation to lapic.") Reported-by: Xiaoyao Li Cc: Jue Wang Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 6ff17d5a2ae3..1540d01ecb67 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -405,6 +405,11 @@ static inline bool kvm_lapic_lvt_supported(struct kvm_lapic *apic, int lvt_index return apic->nr_lvt_entries > lvt_index; } +static inline int kvm_apic_calc_nr_lvt_entries(struct kvm_vcpu *vcpu) +{ + return KVM_APIC_MAX_NR_LVT_ENTRIES - !(vcpu->arch.mcg_cap & MCG_CMCI_P); +} + void kvm_apic_set_version(struct kvm_vcpu *vcpu) { struct kvm_lapic *apic = vcpu->arch.apic; @@ -2561,6 +2566,8 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu, int timer_advance_ns) } apic->vcpu = vcpu; + apic->nr_lvt_entries = kvm_apic_calc_nr_lvt_entries(vcpu); + hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD); apic->lapic_timer.timer.function = apic_timer_fn; From f83894b24c2a96fcecdff4858755aa79eb756465 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 8 Jul 2022 15:48:10 -0700 Subject: [PATCH 0874/1436] KVM: x86: Fix handling of APIC LVT updates when userspace changes MCG_CAP Add a helper to update KVM's in-kernel local APIC in response to MCG_CAP being changed by userspace to fix multiple bugs. First and foremost, KVM needs to check that there's an in-kernel APIC prior to dereferencing vcpu->arch.apic. Beyond that, any "new" LVT entries need to be masked, and the APIC version register needs to be updated as it reports out the number of LVT entries. Fixes: 4b903561ec49 ("KVM: x86: Add Corrected Machine Check Interrupt (CMCI) emulation to lapic.") Reported-by: syzbot+8cdad6430c24f396f158@syzkaller.appspotmail.com Cc: Siddh Raman Pant Cc: Jue Wang Signed-off-by: Sean Christopherson --- arch/x86/kvm/lapic.c | 19 +++++++++++++++++++ arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/x86.c | 4 ++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 1540d01ecb67..50354c7a2dc1 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -433,6 +433,25 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu) kvm_lapic_set_reg(apic, APIC_LVR, v); } +void kvm_apic_after_set_mcg_cap(struct kvm_vcpu *vcpu) +{ + int nr_lvt_entries = kvm_apic_calc_nr_lvt_entries(vcpu); + struct kvm_lapic *apic = vcpu->arch.apic; + int i; + + if (!lapic_in_kernel(vcpu) || nr_lvt_entries == apic->nr_lvt_entries) + return; + + /* Initialize/mask any "new" LVT entries. */ + for (i = apic->nr_lvt_entries; i < nr_lvt_entries; i++) + kvm_lapic_set_reg(apic, APIC_LVTx(i), APIC_LVT_MASKED); + + apic->nr_lvt_entries = nr_lvt_entries; + + /* The number of LVT entries is reflected in the version register. */ + kvm_apic_set_version(vcpu); +} + static const unsigned int apic_lvt_mask[KVM_APIC_MAX_NR_LVT_ENTRIES] = { [LVT_TIMER] = LVT_MASK, /* timer mode mask added at runtime */ [LVT_THERMAL_MONITOR] = LVT_MASK | APIC_MODE_MASK, diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 762bf6163798..117a46df5cc1 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h @@ -99,6 +99,7 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); void kvm_recalculate_apic_map(struct kvm *kvm); void kvm_apic_set_version(struct kvm_vcpu *vcpu); +void kvm_apic_after_set_mcg_cap(struct kvm_vcpu *vcpu); bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, int shorthand, unsigned int dest, int dest_mode); int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index fb37d11dec2d..801c3cfd3db5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4893,8 +4893,8 @@ static int kvm_vcpu_ioctl_x86_setup_mce(struct kvm_vcpu *vcpu, if (mcg_cap & MCG_CMCI_P) vcpu->arch.mci_ctl2_banks[bank] = 0; } - vcpu->arch.apic->nr_lvt_entries = - KVM_APIC_MAX_NR_LVT_ENTRIES - !(mcg_cap & MCG_CMCI_P); + + kvm_apic_after_set_mcg_cap(vcpu); static_call(kvm_x86_setup_mce)(vcpu); out: From 159e037d2e36d93a7b066228c6543537c25235c8 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Fri, 8 Jul 2022 14:51:47 +0200 Subject: [PATCH 0875/1436] KVM: x86: Fully initialize 'struct kvm_lapic_irq' in kvm_pv_kick_cpu_op() 'vector' and 'trig_mode' fields of 'struct kvm_lapic_irq' are left uninitialized in kvm_pv_kick_cpu_op(). While these fields are normally not needed for APIC_DM_REMRD, they're still referenced by __apic_accept_irq() for trace_kvm_apic_accept_irq(). Fully initialize the structure to avoid consuming random stack memory. Fixes: a183b638b61c ("KVM: x86: make apic_accept_irq tracepoint more generic") Reported-by: syzbot+d6caa905917d353f0d07@syzkaller.appspotmail.com Signed-off-by: Vitaly Kuznetsov Reviewed-by: Sean Christopherson Link: https://lore.kernel.org/r/20220708125147.593975-1-vkuznets@redhat.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 801c3cfd3db5..759bcc0a3300 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9340,15 +9340,17 @@ static int kvm_pv_clock_pairing(struct kvm_vcpu *vcpu, gpa_t paddr, */ static void kvm_pv_kick_cpu_op(struct kvm *kvm, int apicid) { - struct kvm_lapic_irq lapic_irq; + /* + * All other fields are unused for APIC_DM_REMRD, but may be consumed by + * common code, e.g. for tracing. Defer initialization to the compiler. + */ + struct kvm_lapic_irq lapic_irq = { + .delivery_mode = APIC_DM_REMRD, + .dest_mode = APIC_DEST_PHYSICAL, + .shorthand = APIC_DEST_NOSHORT, + .dest_id = apicid, + }; - lapic_irq.shorthand = APIC_DEST_NOSHORT; - lapic_irq.dest_mode = APIC_DEST_PHYSICAL; - lapic_irq.level = 0; - lapic_irq.dest_id = apicid; - lapic_irq.msi_redir_hint = false; - - lapic_irq.delivery_mode = APIC_DM_REMRD; kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL); } From c1bb6372c073e828db0203551c772081f9266140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A4r=20Eriksson?= Date: Tue, 5 Jul 2022 20:44:07 +0200 Subject: [PATCH 0876/1436] platform/x86: gigabyte-wmi: add support for B660I AORUS PRO DDR4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the B660I AORUS PRO DDR4. Signed-off-by: Pär Eriksson Link: https://lore.kernel.org/r/20220705184407.14181-1-parherman@gmail.com Signed-off-by: Hans de Goede --- drivers/platform/x86/gigabyte-wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/gigabyte-wmi.c b/drivers/platform/x86/gigabyte-wmi.c index 497ad2f64a51..5e7e6659a849 100644 --- a/drivers/platform/x86/gigabyte-wmi.c +++ b/drivers/platform/x86/gigabyte-wmi.c @@ -150,6 +150,7 @@ static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = { DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M AORUS PRO-P"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M DS3H"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660 GAMING X DDR4"), + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660I AORUS PRO DDR4"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z390 I AORUS PRO WIFI-CF"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z490 AORUS ELITE AC"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 AORUS ELITE"), From d80b83c911ca9b8d35213bf62e9cf336c78c5d24 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 8 Jul 2022 15:14:11 +0200 Subject: [PATCH 0877/1436] platform/x86: x86-android-tablets: Fix Lenovo Yoga Tablet 2 830/1050 poweroff again Commit 98f30d0ecf79 ("ACPI: power: Switch to sys-off handler API") switched the ACPI sleep code from directly setting the old global pm_power_off handler to using the new register_sys_off_handler() mechanism with a priority of SYS_OFF_PRIO_FIRMWARE. This is a problem in special cases where the old global pm_power_off handler later gets overwritten, such as the Lenovo Tab2 poweroff bugfix in x86-android-tablets. The old global pm_power_off handler gets run with a priority of SYS_OFF_PRIO_DEFAULT which is lower then SYS_OFF_PRIO_FIRMWARE, causing the troublesome ACPI poweroff (which freezes the system) to run first. Switch the registering of lenovo_yoga_tab2_830_1050_power_off over to register_sys_off_handler() with a priority of SYS_OFF_PRIO_FIRMWARE + 1 so that it will run before acpi_power_off() to fix this. Fixes: 98f30d0ecf79 ("ACPI: power: Switch to sys-off handler API") Cc: Dmitry Osipenko Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220708131412.81078-2-hdegoede@redhat.com --- drivers/platform/x86/x86-android-tablets.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/x86-android-tablets.c b/drivers/platform/x86/x86-android-tablets.c index f446be72e539..480375977435 100644 --- a/drivers/platform/x86/x86-android-tablets.c +++ b/drivers/platform/x86/x86-android-tablets.c @@ -27,8 +27,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -889,6 +889,7 @@ static const struct pinctrl_map lenovo_yoga_tab2_830_1050_codec_pinctrl_map = "INT33FC:02", "pmu_clk2_grp", "pmu_clk"); static struct pinctrl *lenovo_yoga_tab2_830_1050_codec_pinctrl; +static struct sys_off_handler *lenovo_yoga_tab2_830_1050_sys_off_handler; static int __init lenovo_yoga_tab2_830_1050_init_codec(void) { @@ -933,9 +934,11 @@ err_put_device: * followed by a normal 3 second press to recover. Avoid this by doing an EFI * poweroff instead. */ -static void lenovo_yoga_tab2_830_1050_power_off(void) +static int lenovo_yoga_tab2_830_1050_power_off(struct sys_off_data *data) { efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); + + return NOTIFY_DONE; } static int __init lenovo_yoga_tab2_830_1050_init(void) @@ -950,13 +953,19 @@ static int __init lenovo_yoga_tab2_830_1050_init(void) if (ret) return ret; - pm_power_off = lenovo_yoga_tab2_830_1050_power_off; + /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */ + lenovo_yoga_tab2_830_1050_sys_off_handler = + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1, + lenovo_yoga_tab2_830_1050_power_off, NULL); + if (IS_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler)) + return PTR_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler); + return 0; } static void lenovo_yoga_tab2_830_1050_exit(void) { - pm_power_off = NULL; /* Just turn poweroff into halt on module unload */ + unregister_sys_off_handler(lenovo_yoga_tab2_830_1050_sys_off_handler); if (lenovo_yoga_tab2_830_1050_codec_pinctrl) { pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl); From 650d9a14715f1968a693bb8282a82ca6c3c22541 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 8 Jul 2022 15:14:12 +0200 Subject: [PATCH 0878/1436] efi: Fix efi_power_off() not being run before acpi_power_off() when necessary Commit 98f30d0ecf79 ("ACPI: power: Switch to sys-off handler API") switched the ACPI sleep code from directly setting the old global pm_power_off handler to using the new register_sys_off_handler() mechanism with a priority of SYS_OFF_PRIO_FIRMWARE. This is a problem when the old global pm_power_off handler would later be overwritten, such as done by the late_initcall(efi_shutdown_init): if (efi_poweroff_required()) pm_power_off = efi_power_off; The old global pm_power_off handler gets run with a priority of SYS_OFF_PRIO_DEFAULT which is lower then SYS_OFF_PRIO_FIRMWARE, causing acpi_power_off() to run first, changing the behavior from before the ACPI sleep code switched to the new register_sys_off_handler(). Switch the registering of efi_power_off over to register_sys_off_handler() with a priority of SYS_OFF_PRIO_FIRMWARE + 1 so that it will run before acpi_power_off() as before. Note since the new sys-off-handler code will try all handlers in priority order, there is no more need for the EFI code to store and call the original pm_power_off handler. Fixes: 98f30d0ecf79 ("ACPI: power: Switch to sys-off handler API") Cc: Dmitry Osipenko Signed-off-by: Hans de Goede Acked-by: Ard Biesheuvel Link: https://lore.kernel.org/r/20220708131412.81078-3-hdegoede@redhat.com --- drivers/firmware/efi/reboot.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/firmware/efi/reboot.c b/drivers/firmware/efi/reboot.c index 73089a24f04b..ceae84c19d22 100644 --- a/drivers/firmware/efi/reboot.c +++ b/drivers/firmware/efi/reboot.c @@ -6,7 +6,7 @@ #include #include -static void (*orig_pm_power_off)(void); +static struct sys_off_handler *efi_sys_off_handler; int efi_reboot_quirk_mode = -1; @@ -51,15 +51,11 @@ bool __weak efi_poweroff_required(void) return false; } -static void efi_power_off(void) +static int efi_power_off(struct sys_off_data *data) { efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); - /* - * The above call should not return, if it does fall back to - * the original power off method (typically ACPI poweroff). - */ - if (orig_pm_power_off) - orig_pm_power_off(); + + return NOTIFY_DONE; } static int __init efi_shutdown_init(void) @@ -68,8 +64,13 @@ static int __init efi_shutdown_init(void) return -ENODEV; if (efi_poweroff_required()) { - orig_pm_power_off = pm_power_off; - pm_power_off = efi_power_off; + /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */ + efi_sys_off_handler = + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_FIRMWARE + 1, + efi_power_off, NULL); + if (IS_ERR(efi_sys_off_handler)) + return PTR_ERR(efi_sys_off_handler); } return 0; From 72cd7067839df6139bb46ae932a753d63bdbec06 Mon Sep 17 00:00:00 2001 From: Misaka19465 Date: Sun, 10 Jul 2022 19:37:27 +0800 Subject: [PATCH 0879/1436] platform/x86: asus-wmi: Add key mappings On laptops like ASUS TUF Gaming A15, which have hotkeys to start Armoury Crate or AURA Sync, these hotkeys are unavailable. This patch add mappings for them. Signed-off-by: Misaka19465 Link: https://lore.kernel.org/r/20220710113727.281634-1-misaka19465@olddoctor.net Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/asus-nb-wmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 57a07db659cb..478dd300b9c9 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -522,6 +522,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, { KE_KEY, 0x32, { KEY_MUTE } }, { KE_KEY, 0x35, { KEY_SCREENLOCK } }, + { KE_KEY, 0x38, { KEY_PROG3 } }, /* Armoury Crate */ { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, { KE_KEY, 0x41, { KEY_NEXTSONG } }, { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */ @@ -574,6 +575,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */ { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */ { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */ + { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */ { KE_KEY, 0xB5, { KEY_CALC } }, { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, From 553b53e490642995de8f9862b3de01ae72dda4e3 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Jul 2022 16:07:36 +0200 Subject: [PATCH 0880/1436] platform/x86/intel/ifs: Mark as BROKEN A recent suggested change to the IFS code has shown that the userspace API needs a bit more work, see: https://lore.kernel.org/platform-driver-x86/20220708151938.986530-1-jithu.joseph@intel.com/ Mark it as BROKEN before 5.19 ships, to give ourselves one more kernel-devel cycle to get the userspace API right. Link: https://lore.kernel.org/platform-driver-x86/20220708151938.986530-1-jithu.joseph@intel.com/ Cc: Jithu Joseph Cc: Ashok Raj Cc: Tony Luck Suggested-by: Greg KH Signed-off-by: Hans de Goede Acked-by: Greg Kroah-Hartman Link: https://lore.kernel.org/r/20220710140736.6492-1-hdegoede@redhat.com --- drivers/platform/x86/intel/ifs/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/x86/intel/ifs/Kconfig b/drivers/platform/x86/intel/ifs/Kconfig index 7ce896434b8f..c341a27cc1a3 100644 --- a/drivers/platform/x86/intel/ifs/Kconfig +++ b/drivers/platform/x86/intel/ifs/Kconfig @@ -1,6 +1,9 @@ config INTEL_IFS tristate "Intel In Field Scan" depends on X86 && CPU_SUP_INTEL && 64BIT && SMP + # Discussion on the list has shown that the sysfs API needs a bit + # more work, mark this as broken for now + depends on BROKEN select INTEL_IFS_DEVICE help Enable support for the In Field Scan capability in select From 2b5b27826a48eea579bf103161c76d3b435764a8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 10 Jul 2022 00:16:48 +0300 Subject: [PATCH 0881/1436] platform/x86: serial-multi-instantiate: Improve autodetection Instead of calling specific resource counter, let just probe each of the type and see what it says. Return -ENOENT if no resources found. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220709211653.18938-1-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../platform/x86/serial-multi-instantiate.c | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c index 1e8063b7c169..366087a9fce2 100644 --- a/drivers/platform/x86/serial-multi-instantiate.c +++ b/drivers/platform/x86/serial-multi-instantiate.c @@ -100,7 +100,7 @@ static int smi_spi_probe(struct platform_device *pdev, struct acpi_device *adev, if (ret < 0) return ret; else if (!ret) - return -ENODEV; + return -ENOENT; count = ret; @@ -184,7 +184,7 @@ static int smi_i2c_probe(struct platform_device *pdev, struct acpi_device *adev, if (ret < 0) return ret; else if (!ret) - return -ENODEV; + return -ENOENT; count = ret; @@ -232,6 +232,7 @@ static int smi_probe(struct platform_device *pdev) const struct smi_node *node; struct acpi_device *adev; struct smi *smi; + int ret; adev = ACPI_COMPANION(dev); if (!adev) @@ -255,15 +256,21 @@ static int smi_probe(struct platform_device *pdev) case SMI_SPI: return smi_spi_probe(pdev, adev, smi, node->instances); case SMI_AUTO_DETECT: - if (i2c_acpi_client_count(adev) > 0) - return smi_i2c_probe(pdev, adev, smi, node->instances); - else - return smi_spi_probe(pdev, adev, smi, node->instances); + /* + * For backwards-compatibility with the existing nodes I2C + * is checked first and if such entries are found ONLY I2C + * devices are created. Since some existing nodes that were + * already handled by this driver could also contain unrelated + * SpiSerialBus nodes that were previously ignored, and this + * preserves that behavior. + */ + ret = smi_i2c_probe(pdev, adev, smi, node->instances); + if (ret != -ENOENT) + return ret; + return smi_spi_probe(pdev, adev, smi, node->instances); default: return -EINVAL; } - - return 0; /* never reached */ } static int smi_remove(struct platform_device *pdev) From 8b50c48d59a9cd007cf0b09e479e4221b2b349ae Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 10 Jul 2022 00:16:49 +0300 Subject: [PATCH 0882/1436] platform/x86: serial-multi-instantiate: Drop duplicate check The device_get_match_data() checks for firmware node to be present, there is no need to check for ACPI companion. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220709211653.18938-2-andriy.shevchenko@linux.intel.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../platform/x86/serial-multi-instantiate.c | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c index 366087a9fce2..a1e04be858c5 100644 --- a/drivers/platform/x86/serial-multi-instantiate.c +++ b/drivers/platform/x86/serial-multi-instantiate.c @@ -81,16 +81,16 @@ static void smi_devs_unregister(struct smi *smi) /** * smi_spi_probe - Instantiate multiple SPI devices from inst array * @pdev: Platform device - * @adev: ACPI device * @smi: Internal struct for Serial multi instantiate driver * @inst_array: Array of instances to probe * * Returns the number of SPI devices instantiate, Zero if none is found or a negative error code. */ -static int smi_spi_probe(struct platform_device *pdev, struct acpi_device *adev, struct smi *smi, +static int smi_spi_probe(struct platform_device *pdev, struct smi *smi, const struct smi_instance *inst_array) { struct device *dev = &pdev->dev; + struct acpi_device *adev = ACPI_COMPANION(dev); struct spi_controller *ctlr; struct spi_device *spi_dev; char name[50]; @@ -166,17 +166,17 @@ error: /** * smi_i2c_probe - Instantiate multiple I2C devices from inst array * @pdev: Platform device - * @adev: ACPI device * @smi: Internal struct for Serial multi instantiate driver * @inst_array: Array of instances to probe * * Returns the number of I2C devices instantiate, Zero if none is found or a negative error code. */ -static int smi_i2c_probe(struct platform_device *pdev, struct acpi_device *adev, struct smi *smi, +static int smi_i2c_probe(struct platform_device *pdev, struct smi *smi, const struct smi_instance *inst_array) { struct i2c_board_info board_info = {}; struct device *dev = &pdev->dev; + struct acpi_device *adev = ACPI_COMPANION(dev); char name[32]; int i, ret, count; @@ -230,14 +230,9 @@ static int smi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct smi_node *node; - struct acpi_device *adev; struct smi *smi; int ret; - adev = ACPI_COMPANION(dev); - if (!adev) - return -ENODEV; - node = device_get_match_data(dev); if (!node) { dev_dbg(dev, "Error ACPI match data is missing\n"); @@ -252,9 +247,9 @@ static int smi_probe(struct platform_device *pdev) switch (node->bus_type) { case SMI_I2C: - return smi_i2c_probe(pdev, adev, smi, node->instances); + return smi_i2c_probe(pdev, smi, node->instances); case SMI_SPI: - return smi_spi_probe(pdev, adev, smi, node->instances); + return smi_spi_probe(pdev, smi, node->instances); case SMI_AUTO_DETECT: /* * For backwards-compatibility with the existing nodes I2C @@ -264,10 +259,10 @@ static int smi_probe(struct platform_device *pdev) * SpiSerialBus nodes that were previously ignored, and this * preserves that behavior. */ - ret = smi_i2c_probe(pdev, adev, smi, node->instances); + ret = smi_i2c_probe(pdev, smi, node->instances); if (ret != -ENOENT) return ret; - return smi_spi_probe(pdev, adev, smi, node->instances); + return smi_spi_probe(pdev, smi, node->instances); default: return -EINVAL; } From 14a9aa99aca6c28728de357b7be3c9ef4f2a5bb6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 10 Jul 2022 00:16:50 +0300 Subject: [PATCH 0883/1436] platform/x86: serial-multi-instantiate: Improve dev_err_probe() messaging Drop duplicate print of returned value in the messages and use pattern return dev_err_probe(...) where it's possible. Signed-off-by: Andy Shevchenko Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220709211653.18938-3-andriy.shevchenko@linux.intel.com Signed-off-by: Hans de Goede --- drivers/platform/x86/serial-multi-instantiate.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c index a1e04be858c5..970ede0ff002 100644 --- a/drivers/platform/x86/serial-multi-instantiate.c +++ b/drivers/platform/x86/serial-multi-instantiate.c @@ -61,10 +61,9 @@ static int smi_get_irq(struct platform_device *pdev, struct acpi_device *adev, default: return 0; } - if (ret < 0) - dev_err_probe(&pdev->dev, ret, "Error requesting irq at index %d: %d\n", - inst->irq_idx, ret); + return dev_err_probe(&pdev->dev, ret, "Error requesting irq at index %d\n", + inst->irq_idx); return ret; } @@ -112,9 +111,8 @@ static int smi_spi_probe(struct platform_device *pdev, struct smi *smi, spi_dev = acpi_spi_device_alloc(NULL, adev, i); if (IS_ERR(spi_dev)) { - ret = PTR_ERR(spi_dev); - dev_err_probe(dev, ret, "failed to allocate SPI device %s from ACPI: %d\n", - dev_name(&adev->dev), ret); + ret = dev_err_probe(dev, PTR_ERR(spi_dev), "failed to allocate SPI device %s from ACPI\n", + dev_name(&adev->dev)); goto error; } @@ -135,9 +133,8 @@ static int smi_spi_probe(struct platform_device *pdev, struct smi *smi, ret = spi_add_device(spi_dev); if (ret) { - dev_err_probe(&ctlr->dev, ret, - "failed to add SPI device %s from ACPI: %d\n", - dev_name(&adev->dev), ret); + dev_err_probe(&ctlr->dev, ret, "failed to add SPI device %s from ACPI\n", + dev_name(&adev->dev)); spi_dev_put(spi_dev); goto error; } From ed7adc2b69c6492ebb2733d8914c6d765ec9770b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 10 Jul 2022 00:16:51 +0300 Subject: [PATCH 0884/1436] platform/x86: serial-multi-instantiate: Use while (i--) pattern to clean up Use more natural while (i--) patter to clean up allocated resources. Signed-off-by: Andy Shevchenko Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220709211653.18938-4-andriy.shevchenko@linux.intel.com Signed-off-by: Hans de Goede --- drivers/platform/x86/serial-multi-instantiate.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c index 970ede0ff002..0a2335693f4f 100644 --- a/drivers/platform/x86/serial-multi-instantiate.c +++ b/drivers/platform/x86/serial-multi-instantiate.c @@ -70,11 +70,11 @@ static int smi_get_irq(struct platform_device *pdev, struct acpi_device *adev, static void smi_devs_unregister(struct smi *smi) { - while (smi->i2c_num > 0) - i2c_unregister_device(smi->i2c_devs[--smi->i2c_num]); + while (smi->i2c_num--) + i2c_unregister_device(smi->i2c_devs[smi->i2c_num]); - while (smi->spi_num > 0) - spi_unregister_device(smi->spi_devs[--smi->spi_num]); + while (smi->spi_num--) + spi_unregister_device(smi->spi_devs[smi->spi_num]); } /** From f3e13bbc6f5a84f9c15883a97649023522eec481 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 10 Jul 2022 00:16:52 +0300 Subject: [PATCH 0885/1436] platform/x86: serial-multi-instantiate: Get rid of redundant 'else' In the snippets like the following if (...) return / goto / break / continue ...; else ... the 'else' is redundant. Get rid of it. Signed-off-by: Andy Shevchenko Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220709211653.18938-5-andriy.shevchenko@linux.intel.com Signed-off-by: Hans de Goede --- drivers/platform/x86/serial-multi-instantiate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c index 0a2335693f4f..24f915bbdec1 100644 --- a/drivers/platform/x86/serial-multi-instantiate.c +++ b/drivers/platform/x86/serial-multi-instantiate.c @@ -98,7 +98,7 @@ static int smi_spi_probe(struct platform_device *pdev, struct smi *smi, ret = acpi_spi_count_resources(adev); if (ret < 0) return ret; - else if (!ret) + if (!ret) return -ENOENT; count = ret; @@ -180,7 +180,7 @@ static int smi_i2c_probe(struct platform_device *pdev, struct smi *smi, ret = i2c_acpi_client_count(adev); if (ret < 0) return ret; - else if (!ret) + if (!ret) return -ENOENT; count = ret; From e286044bf5b089801c20688c45b66fd6b6a712fa Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 10 Jul 2022 00:16:53 +0300 Subject: [PATCH 0886/1436] platform/x86: serial-multi-instantiate: Sort ACPI IDs by HID It's easier to maintain the sorted table. Keep the sorting order in sync with one in drivers/acpi/scan.c. Signed-off-by: Andy Shevchenko Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220709211653.18938-6-andriy.shevchenko@linux.intel.com Signed-off-by: Hans de Goede --- drivers/platform/x86/serial-multi-instantiate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c index 24f915bbdec1..67feed25c9db 100644 --- a/drivers/platform/x86/serial-multi-instantiate.c +++ b/drivers/platform/x86/serial-multi-instantiate.c @@ -324,8 +324,8 @@ static const struct smi_node cs35l41_hda = { static const struct acpi_device_id smi_acpi_ids[] = { { "BSG1160", (unsigned long)&bsg1160_data }, { "BSG2150", (unsigned long)&bsg2150_data }, - { "INT3515", (unsigned long)&int3515_data }, { "CSC3551", (unsigned long)&cs35l41_hda }, + { "INT3515", (unsigned long)&int3515_data }, /* Non-conforming _HID for Cirrus Logic already released */ { "CLSA0100", (unsigned long)&cs35l41_hda }, { } From fe16ecaa0e629ade1e1cc09781c7cc77e5d2c8bc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 10 Jul 2022 19:36:58 +0200 Subject: [PATCH 0887/1436] platform/x86: intel_atomisp2_led: Also turn off the always-on camera LED on the Asus T100TAF Like the Asus T100TA the Asus T100TAF has a camera LED which is always on by default and both also use the same GPIO for the LED. Relax the DMI match for the Asus T100TA so that it also matches the T100TAF. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220710173658.221528-1-hdegoede@redhat.com --- drivers/platform/x86/intel/atomisp2/led.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/intel/atomisp2/led.c b/drivers/platform/x86/intel/atomisp2/led.c index 5935dfca166f..10077a61d8c5 100644 --- a/drivers/platform/x86/intel/atomisp2/led.c +++ b/drivers/platform/x86/intel/atomisp2/led.c @@ -50,7 +50,8 @@ static const struct dmi_system_id atomisp2_led_systems[] __initconst = { { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), + /* Non exact match to also match T100TAF */ + DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), }, .driver_data = &asus_t100ta_lookup, }, From e3d27b62110c1ccea4d015f7c5c92f92150668db Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:05 -0400 Subject: [PATCH 0888/1436] s390/sclp: detect the zPCI load/store interpretation facility Detect the zPCI Load/Store Interpretation facility. Reviewed-by: Eric Farman Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-2-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/sclp.h | 1 + drivers/s390/char/sclp_early.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 236b34b75ddb..68ef0ddf6400 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -88,6 +88,7 @@ struct sclp_info { unsigned char has_sipl : 1; unsigned char has_dirq : 1; unsigned char has_iplcc : 1; + unsigned char has_zpci_lsi : 1; unsigned int ibc; unsigned int mtid; unsigned int mtid_cp; diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index dd313ff57df3..d5671c03d5cc 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -45,6 +45,7 @@ static void __init sclp_early_facilities_detect(void) sclp.has_gisaf = !!(sccb->fac118 & 0x08); sclp.has_hvs = !!(sccb->fac119 & 0x80); sclp.has_kss = !!(sccb->fac98 & 0x01); + sclp.has_zpci_lsi = !!(sccb->fac118 & 0x01); if (sccb->fac85 & 0x02) S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; if (sccb->fac91 & 0x40) From 9db153f4523069a89cab14ab9aa2438976f256fb Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:06 -0400 Subject: [PATCH 0889/1436] s390/sclp: detect the AISII facility Detect the Adapter Interruption Source ID Interpretation facility. Reviewed-by: Eric Farman Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-3-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/sclp.h | 1 + drivers/s390/char/sclp_early.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 68ef0ddf6400..d05fbffa7692 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -89,6 +89,7 @@ struct sclp_info { unsigned char has_dirq : 1; unsigned char has_iplcc : 1; unsigned char has_zpci_lsi : 1; + unsigned char has_aisii : 1; unsigned int ibc; unsigned int mtid; unsigned int mtid_cp; diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index d5671c03d5cc..39c9bd7e1c26 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -45,6 +45,7 @@ static void __init sclp_early_facilities_detect(void) sclp.has_gisaf = !!(sccb->fac118 & 0x08); sclp.has_hvs = !!(sccb->fac119 & 0x80); sclp.has_kss = !!(sccb->fac98 & 0x01); + sclp.has_aisii = !!(sccb->fac118 & 0x40); sclp.has_zpci_lsi = !!(sccb->fac118 & 0x01); if (sccb->fac85 & 0x02) S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; From efef0db77c939f105f7dc92a736dd66628406822 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:07 -0400 Subject: [PATCH 0890/1436] s390/sclp: detect the AENI facility Detect the Adapter Event Notification Interpretation facility. Reviewed-by: Eric Farman Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-4-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/sclp.h | 1 + drivers/s390/char/sclp_early.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index d05fbffa7692..b0e67414c492 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -90,6 +90,7 @@ struct sclp_info { unsigned char has_iplcc : 1; unsigned char has_zpci_lsi : 1; unsigned char has_aisii : 1; + unsigned char has_aeni : 1; unsigned int ibc; unsigned int mtid; unsigned int mtid_cp; diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index 39c9bd7e1c26..aefdf0b17dbe 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -46,6 +46,7 @@ static void __init sclp_early_facilities_detect(void) sclp.has_hvs = !!(sccb->fac119 & 0x80); sclp.has_kss = !!(sccb->fac98 & 0x01); sclp.has_aisii = !!(sccb->fac118 & 0x40); + sclp.has_aeni = !!(sccb->fac118 & 0x20); sclp.has_zpci_lsi = !!(sccb->fac118 & 0x01); if (sccb->fac85 & 0x02) S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; From b05a870c5e4e6a113b7f3fb61b5fa0869e40dd30 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:08 -0400 Subject: [PATCH 0891/1436] s390/sclp: detect the AISI facility Detect the Adapter Interruption Suppression Interpretation facility. Reviewed-by: Eric Farman Reviewed-by: Christian Borntraeger Reviewed-by: Claudio Imbrenda Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-5-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/sclp.h | 1 + drivers/s390/char/sclp_early.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index b0e67414c492..addefe8ccdba 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -91,6 +91,7 @@ struct sclp_info { unsigned char has_zpci_lsi : 1; unsigned char has_aisii : 1; unsigned char has_aeni : 1; + unsigned char has_aisi : 1; unsigned int ibc; unsigned int mtid; unsigned int mtid_cp; diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index aefdf0b17dbe..d15b0d541de3 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -47,6 +47,7 @@ static void __init sclp_early_facilities_detect(void) sclp.has_kss = !!(sccb->fac98 & 0x01); sclp.has_aisii = !!(sccb->fac118 & 0x40); sclp.has_aeni = !!(sccb->fac118 & 0x20); + sclp.has_aisi = !!(sccb->fac118 & 0x10); sclp.has_zpci_lsi = !!(sccb->fac118 & 0x01); if (sccb->fac85 & 0x02) S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; From d2197485a1883c60d044146b1ee69aac654c55e8 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:09 -0400 Subject: [PATCH 0892/1436] s390/airq: pass more TPI info to airq handlers A subsequent patch will introduce an airq handler that requires additional TPI information beyond directed vs floating, so pass the entire tpi_info structure via the handler. Only pci actually uses this information today, for the other airq handlers this is effectively a no-op. Reviewed-by: Eric Farman Reviewed-by: Claudio Imbrenda Reviewed-by: Pierre Morel Reviewed-by: Thomas Huth Acked-by: Christian Borntraeger Acked-by: Cornelia Huck Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-6-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/airq.h | 3 ++- arch/s390/kvm/interrupt.c | 4 +++- arch/s390/pci/pci_irq.c | 9 +++++++-- drivers/s390/cio/airq.c | 2 +- drivers/s390/cio/qdio_thinint.c | 6 ++++-- drivers/s390/crypto/ap_bus.c | 9 ++++++--- drivers/s390/virtio/virtio_ccw.c | 4 +++- 7 files changed, 26 insertions(+), 11 deletions(-) diff --git a/arch/s390/include/asm/airq.h b/arch/s390/include/asm/airq.h index 01936fdfaddb..7918a7d09028 100644 --- a/arch/s390/include/asm/airq.h +++ b/arch/s390/include/asm/airq.h @@ -12,10 +12,11 @@ #include #include +#include struct airq_struct { struct hlist_node list; /* Handler queueing. */ - void (*handler)(struct airq_struct *airq, bool floating); + void (*handler)(struct airq_struct *airq, struct tpi_info *tpi_info); u8 *lsi_ptr; /* Local-Summary-Indicator pointer */ u8 lsi_mask; /* Local-Summary-Indicator mask */ u8 isc; /* Interrupt-subclass */ diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index af96dc0549a4..17ff475157d8 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "kvm-s390.h" #include "gaccess.h" #include "trace-s390.h" @@ -3311,7 +3312,8 @@ out: } EXPORT_SYMBOL_GPL(kvm_s390_gisc_unregister); -static void gib_alert_irq_handler(struct airq_struct *airq, bool floating) +static void gib_alert_irq_handler(struct airq_struct *airq, + struct tpi_info *tpi_info) { inc_irq_stat(IRQIO_GAL); process_gib_alert_list(); diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c index 500cd2dbdf53..b805c75252ed 100644 --- a/arch/s390/pci/pci_irq.c +++ b/arch/s390/pci/pci_irq.c @@ -11,6 +11,7 @@ #include #include +#include static enum {FLOATING, DIRECTED} irq_delivery; @@ -216,8 +217,11 @@ static void zpci_handle_fallback_irq(void) } } -static void zpci_directed_irq_handler(struct airq_struct *airq, bool floating) +static void zpci_directed_irq_handler(struct airq_struct *airq, + struct tpi_info *tpi_info) { + bool floating = !tpi_info->directed_irq; + if (floating) { inc_irq_stat(IRQIO_PCF); zpci_handle_fallback_irq(); @@ -227,7 +231,8 @@ static void zpci_directed_irq_handler(struct airq_struct *airq, bool floating) } } -static void zpci_floating_irq_handler(struct airq_struct *airq, bool floating) +static void zpci_floating_irq_handler(struct airq_struct *airq, + struct tpi_info *tpi_info) { unsigned long si, ai; struct airq_iv *aibv; diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index c0ed364bf446..230eb5b5b64e 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -99,7 +99,7 @@ static irqreturn_t do_airq_interrupt(int irq, void *dummy) rcu_read_lock(); hlist_for_each_entry_rcu(airq, head, list) if ((*airq->lsi_ptr & airq->lsi_mask) != 0) - airq->handler(airq, !tpi_info->directed_irq); + airq->handler(airq, tpi_info); rcu_read_unlock(); return IRQ_HANDLED; diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index 8e09bf3a2fcd..9b9335dd06db 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "cio.h" #include "ioasm.h" @@ -93,9 +94,10 @@ static inline u32 clear_shared_ind(void) /** * tiqdio_thinint_handler - thin interrupt handler for qdio * @airq: pointer to adapter interrupt descriptor - * @floating: flag to recognize floating vs. directed interrupts (unused) + * @tpi_info: interrupt information (e.g. floating vs directed -- unused) */ -static void tiqdio_thinint_handler(struct airq_struct *airq, bool floating) +static void tiqdio_thinint_handler(struct airq_struct *airq, + struct tpi_info *tpi_info) { u64 irq_time = S390_lowcore.int_clock; u32 si_used = clear_shared_ind(); diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 5c13d2079d96..1b85f21c151b 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -131,7 +132,8 @@ static int ap_max_adapter_id = 63; static struct bus_type ap_bus_type; /* Adapter interrupt definitions */ -static void ap_interrupt_handler(struct airq_struct *airq, bool floating); +static void ap_interrupt_handler(struct airq_struct *airq, + struct tpi_info *tpi_info); static bool ap_irq_flag; @@ -452,9 +454,10 @@ static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused) /** * ap_interrupt_handler() - Schedule ap_tasklet on interrupt * @airq: pointer to adapter interrupt descriptor - * @floating: ignored + * @tpi_info: ignored */ -static void ap_interrupt_handler(struct airq_struct *airq, bool floating) +static void ap_interrupt_handler(struct airq_struct *airq, + struct tpi_info *tpi_info) { inc_irq_stat(IRQIO_APB); tasklet_schedule(&ap_tasklet); diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 97e51c34e6cf..58cca50996ee 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -33,6 +33,7 @@ #include #include #include +#include /* * virtio related functions @@ -204,7 +205,8 @@ static void drop_airq_indicator(struct virtqueue *vq, struct airq_info *info) write_unlock_irqrestore(&info->lock, flags); } -static void virtio_airq_handler(struct airq_struct *airq, bool floating) +static void virtio_airq_handler(struct airq_struct *airq, + struct tpi_info *tpi_info) { struct airq_info *info = container_of(airq, struct airq_info, airq); unsigned long ai; From 932b646727f9df312980d175e339248cdf7812f0 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:10 -0400 Subject: [PATCH 0893/1436] s390/airq: allow for airq structure that uses an input vector When doing device passthrough where interrupts are being forwarded from host to guest, we wish to use a pinned section of guest memory as the vector (the same memory used by the guest as the vector). To accomplish this, add a new parameter for airq_iv_create which allows passing an existing vector to be used instead of allocating a new one. The caller is responsible for ensuring the vector is pinned in memory as well as for unpinning the memory when the vector is no longer needed. A subsequent patch will use this new parameter for zPCI interpretation. Reviewed-by: Thomas Huth Reviewed-by: Pierre Morel Reviewed-by: Claudio Imbrenda Acked-by: Cornelia Huck Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-7-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/airq.h | 4 +++- arch/s390/pci/pci_irq.c | 8 ++++---- drivers/s390/cio/airq.c | 10 +++++++--- drivers/s390/virtio/virtio_ccw.c | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/arch/s390/include/asm/airq.h b/arch/s390/include/asm/airq.h index 7918a7d09028..e82e5626e139 100644 --- a/arch/s390/include/asm/airq.h +++ b/arch/s390/include/asm/airq.h @@ -47,8 +47,10 @@ struct airq_iv { #define AIRQ_IV_PTR 4 /* Allocate the ptr array */ #define AIRQ_IV_DATA 8 /* Allocate the data array */ #define AIRQ_IV_CACHELINE 16 /* Cacheline alignment for the vector */ +#define AIRQ_IV_GUESTVEC 32 /* Vector is a pinned guest page */ -struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags); +struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags, + unsigned long *vec); void airq_iv_release(struct airq_iv *iv); unsigned long airq_iv_alloc(struct airq_iv *iv, unsigned long num); void airq_iv_free(struct airq_iv *iv, unsigned long bit, unsigned long num); diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c index b805c75252ed..87c7d121c255 100644 --- a/arch/s390/pci/pci_irq.c +++ b/arch/s390/pci/pci_irq.c @@ -296,7 +296,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) zdev->aisb = bit; /* Create adapter interrupt vector */ - zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK); + zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | AIRQ_IV_BITLOCK, NULL); if (!zdev->aibv) return -ENOMEM; @@ -419,7 +419,7 @@ static int __init zpci_directed_irq_init(void) union zpci_sic_iib iib = {{0}}; unsigned int cpu; - zpci_sbv = airq_iv_create(num_possible_cpus(), 0); + zpci_sbv = airq_iv_create(num_possible_cpus(), 0, NULL); if (!zpci_sbv) return -ENOMEM; @@ -441,7 +441,7 @@ static int __init zpci_directed_irq_init(void) zpci_ibv[cpu] = airq_iv_create(cache_line_size() * BITS_PER_BYTE, AIRQ_IV_DATA | AIRQ_IV_CACHELINE | - (!cpu ? AIRQ_IV_ALLOC : 0)); + (!cpu ? AIRQ_IV_ALLOC : 0), NULL); if (!zpci_ibv[cpu]) return -ENOMEM; } @@ -458,7 +458,7 @@ static int __init zpci_floating_irq_init(void) if (!zpci_ibv) return -ENOMEM; - zpci_sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC); + zpci_sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC, NULL); if (!zpci_sbv) goto out_free; diff --git a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c index 230eb5b5b64e..34967e67249e 100644 --- a/drivers/s390/cio/airq.c +++ b/drivers/s390/cio/airq.c @@ -122,10 +122,12 @@ static inline unsigned long iv_size(unsigned long bits) * airq_iv_create - create an interrupt vector * @bits: number of bits in the interrupt vector * @flags: allocation flags + * @vec: pointer to pinned guest memory if AIRQ_IV_GUESTVEC * * Returns a pointer to an interrupt vector structure */ -struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags) +struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags, + unsigned long *vec) { struct airq_iv *iv; unsigned long size; @@ -146,6 +148,8 @@ struct airq_iv *airq_iv_create(unsigned long bits, unsigned long flags) &iv->vector_dma); if (!iv->vector) goto out_free; + } else if (flags & AIRQ_IV_GUESTVEC) { + iv->vector = vec; } else { iv->vector = cio_dma_zalloc(size); if (!iv->vector) @@ -185,7 +189,7 @@ out_free: kfree(iv->avail); if (iv->flags & AIRQ_IV_CACHELINE && iv->vector) dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma); - else + else if (!(iv->flags & AIRQ_IV_GUESTVEC)) cio_dma_free(iv->vector, size); kfree(iv); out: @@ -204,7 +208,7 @@ void airq_iv_release(struct airq_iv *iv) kfree(iv->bitlock); if (iv->flags & AIRQ_IV_CACHELINE) dma_pool_free(airq_iv_cache, iv->vector, iv->vector_dma); - else + else if (!(iv->flags & AIRQ_IV_GUESTVEC)) cio_dma_free(iv->vector, iv_size(iv->bits)); kfree(iv->avail); kfree(iv); diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 58cca50996ee..51bef226d33f 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -242,7 +242,7 @@ static struct airq_info *new_airq_info(int index) return NULL; rwlock_init(&info->lock); info->aiv = airq_iv_create(VIRTIO_IV_BITS, AIRQ_IV_ALLOC | AIRQ_IV_PTR - | AIRQ_IV_CACHELINE); + | AIRQ_IV_CACHELINE, NULL); if (!info->aiv) { kfree(info); return NULL; From 062f002485d4d5f26f9e8fbce831fd28c4b75ca5 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:11 -0400 Subject: [PATCH 0894/1436] s390/pci: externalize the SIC operation controls and routine A subsequent patch will be issuing SIC from KVM -- export the necessary routine and make the operation control definitions available from a header. Because the routine will now be exported, let's rename __zpci_set_irq_ctrl to zpci_set_irq_ctrl and get rid of the zero'd iib wrapper function of the same name. Reviewed-by: Niklas Schnelle Reviewed-by: Claudio Imbrenda Reviewed-by: Pierre Morel Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-8-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/pci_insn.h | 17 +++++++++-------- arch/s390/pci/pci_insn.c | 3 ++- arch/s390/pci/pci_irq.c | 26 ++++++++++++-------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h index 61cf9531f68f..5331082fa516 100644 --- a/arch/s390/include/asm/pci_insn.h +++ b/arch/s390/include/asm/pci_insn.h @@ -98,6 +98,14 @@ struct zpci_fib { u32 gd; } __packed __aligned(8); +/* Set Interruption Controls Operation Controls */ +#define SIC_IRQ_MODE_ALL 0 +#define SIC_IRQ_MODE_SINGLE 1 +#define SIC_IRQ_MODE_DIRECT 4 +#define SIC_IRQ_MODE_D_ALL 16 +#define SIC_IRQ_MODE_D_SINGLE 17 +#define SIC_IRQ_MODE_SET_CPU 18 + /* directed interruption information block */ struct zpci_diib { u32 : 1; @@ -134,13 +142,6 @@ int __zpci_store(u64 data, u64 req, u64 offset); int zpci_store(const volatile void __iomem *addr, u64 data, unsigned long len); int __zpci_store_block(const u64 *data, u64 req, u64 offset); void zpci_barrier(void); -int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib); - -static inline int zpci_set_irq_ctrl(u16 ctl, u8 isc) -{ - union zpci_sic_iib iib = {{0}}; - - return __zpci_set_irq_ctrl(ctl, isc, &iib); -} +int zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib); #endif diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c index 1a822b7799f8..5798178aec9d 100644 --- a/arch/s390/pci/pci_insn.c +++ b/arch/s390/pci/pci_insn.c @@ -138,7 +138,7 @@ int zpci_refresh_trans(u64 fn, u64 addr, u64 range) } /* Set Interruption Controls */ -int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib) +int zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib) { if (!test_facility(72)) return -EIO; @@ -149,6 +149,7 @@ int __zpci_set_irq_ctrl(u16 ctl, u8 isc, union zpci_sic_iib *iib) return 0; } +EXPORT_SYMBOL_GPL(zpci_set_irq_ctrl); /* PCI Load */ static inline int ____pcilg(u64 *data, u64 req, u64 offset, u8 *status) diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c index 87c7d121c255..f2b3145b6697 100644 --- a/arch/s390/pci/pci_irq.c +++ b/arch/s390/pci/pci_irq.c @@ -15,13 +15,6 @@ static enum {FLOATING, DIRECTED} irq_delivery; -#define SIC_IRQ_MODE_ALL 0 -#define SIC_IRQ_MODE_SINGLE 1 -#define SIC_IRQ_MODE_DIRECT 4 -#define SIC_IRQ_MODE_D_ALL 16 -#define SIC_IRQ_MODE_D_SINGLE 17 -#define SIC_IRQ_MODE_SET_CPU 18 - /* * summary bit vector * FLOATING - summary bit per function @@ -154,6 +147,7 @@ static struct irq_chip zpci_irq_chip = { static void zpci_handle_cpu_local_irq(bool rescan) { struct airq_iv *dibv = zpci_ibv[smp_processor_id()]; + union zpci_sic_iib iib = {{0}}; unsigned long bit; int irqs_on = 0; @@ -165,7 +159,7 @@ static void zpci_handle_cpu_local_irq(bool rescan) /* End of second scan with interrupts on. */ break; /* First scan complete, reenable interrupts. */ - if (zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC)) + if (zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC, &iib)) break; bit = 0; continue; @@ -193,6 +187,7 @@ static void zpci_handle_remote_irq(void *data) static void zpci_handle_fallback_irq(void) { struct cpu_irq_data *cpu_data; + union zpci_sic_iib iib = {{0}}; unsigned long cpu; int irqs_on = 0; @@ -203,7 +198,7 @@ static void zpci_handle_fallback_irq(void) /* End of second scan with interrupts on. */ break; /* First scan complete, reenable interrupts. */ - if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC)) + if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC, &iib)) break; cpu = 0; continue; @@ -234,6 +229,7 @@ static void zpci_directed_irq_handler(struct airq_struct *airq, static void zpci_floating_irq_handler(struct airq_struct *airq, struct tpi_info *tpi_info) { + union zpci_sic_iib iib = {{0}}; unsigned long si, ai; struct airq_iv *aibv; int irqs_on = 0; @@ -247,7 +243,7 @@ static void zpci_floating_irq_handler(struct airq_struct *airq, /* End of second scan with interrupts on. */ break; /* First scan complete, reenable interrupts. */ - if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC)) + if (zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC, &iib)) break; si = 0; continue; @@ -407,11 +403,12 @@ static struct airq_struct zpci_airq = { static void __init cpu_enable_directed_irq(void *unused) { union zpci_sic_iib iib = {{0}}; + union zpci_sic_iib ziib = {{0}}; iib.cdiib.dibv_addr = (u64) zpci_ibv[smp_processor_id()]->vector; - __zpci_set_irq_ctrl(SIC_IRQ_MODE_SET_CPU, 0, &iib); - zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC); + zpci_set_irq_ctrl(SIC_IRQ_MODE_SET_CPU, 0, &iib); + zpci_set_irq_ctrl(SIC_IRQ_MODE_D_SINGLE, PCI_ISC, &ziib); } static int __init zpci_directed_irq_init(void) @@ -426,7 +423,7 @@ static int __init zpci_directed_irq_init(void) iib.diib.isc = PCI_ISC; iib.diib.nr_cpus = num_possible_cpus(); iib.diib.disb_addr = virt_to_phys(zpci_sbv->vector); - __zpci_set_irq_ctrl(SIC_IRQ_MODE_DIRECT, 0, &iib); + zpci_set_irq_ctrl(SIC_IRQ_MODE_DIRECT, 0, &iib); zpci_ibv = kcalloc(num_possible_cpus(), sizeof(*zpci_ibv), GFP_KERNEL); @@ -471,6 +468,7 @@ out_free: int __init zpci_irq_init(void) { + union zpci_sic_iib iib = {{0}}; int rc; irq_delivery = sclp.has_dirq ? DIRECTED : FLOATING; @@ -502,7 +500,7 @@ int __init zpci_irq_init(void) * Enable floating IRQs (with suppression after one IRQ). When using * directed IRQs this enables the fallback path. */ - zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC); + zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, PCI_ISC, &iib); return 0; out_airq: From c68468ed3416ea88d7b14dabb1fa584c3a90cd85 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:12 -0400 Subject: [PATCH 0895/1436] s390/pci: stash associated GISA designation For passthrough devices, we will need to know the GISA designation of the guest if interpretation facilities are to be used. Setup to stash this in the zdev and set a default of 0 (no GISA designation) for now; a subsequent patch will set a valid GISA designation for passthrough devices. Also, extend mpcific routines to specify this stashed designation as part of the mpcific command. Reviewed-by: Pierre Morel Reviewed-by: Niklas Schnelle Reviewed-by: Christian Borntraeger Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-9-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/pci.h | 1 + arch/s390/include/asm/pci_clp.h | 3 ++- arch/s390/pci/pci.c | 6 ++++++ arch/s390/pci/pci_clp.c | 5 +++++ arch/s390/pci/pci_irq.c | 5 +++++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index fdb9745ee998..42a4a312a6dd 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -123,6 +123,7 @@ struct zpci_dev { enum zpci_state state; u32 fid; /* function ID, used by sclp */ u32 fh; /* function handle, used by insn's */ + u32 gisa; /* GISA designation for passthrough */ u16 vfn; /* virtual function number */ u16 pchid; /* physical channel ID */ u8 pfgid; /* function group ID */ diff --git a/arch/s390/include/asm/pci_clp.h b/arch/s390/include/asm/pci_clp.h index 1f4b666e85ee..f3286bc5ba6e 100644 --- a/arch/s390/include/asm/pci_clp.h +++ b/arch/s390/include/asm/pci_clp.h @@ -173,7 +173,8 @@ struct clp_req_set_pci { u16 reserved2; u8 oc; /* operation controls */ u8 ndas; /* number of dma spaces */ - u64 reserved3; + u32 reserved3; + u32 gisa; /* GISA designation */ } __packed; /* Set PCI function response */ diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index bc980fd313d5..c8b9d866434c 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -120,6 +120,7 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas, fib.pba = base; fib.pal = limit; fib.iota = iota | ZPCI_IOTA_RTTO_FLAG; + fib.gd = zdev->gisa; cc = zpci_mod_fc(req, &fib, &status); if (cc) zpci_dbg(3, "reg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, status); @@ -133,6 +134,8 @@ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas) struct zpci_fib fib = {0}; u8 cc, status; + fib.gd = zdev->gisa; + cc = zpci_mod_fc(req, &fib, &status); if (cc) zpci_dbg(3, "unreg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, status); @@ -160,6 +163,7 @@ int zpci_fmb_enable_device(struct zpci_dev *zdev) atomic64_set(&zdev->unmapped_pages, 0); fib.fmb_addr = virt_to_phys(zdev->fmb); + fib.gd = zdev->gisa; cc = zpci_mod_fc(req, &fib, &status); if (cc) { kmem_cache_free(zdev_fmb_cache, zdev->fmb); @@ -178,6 +182,8 @@ int zpci_fmb_disable_device(struct zpci_dev *zdev) if (!zdev->fmb) return -EINVAL; + fib.gd = zdev->gisa; + /* Function measurement is disabled if fmb address is zero */ cc = zpci_mod_fc(req, &fib, &status); if (cc == 3) /* Function already gone. */ diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index 375e0a5120bc..d058c83467ef 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c @@ -229,12 +229,16 @@ static int clp_set_pci_fn(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as, u8 comma { struct clp_req_rsp_set_pci *rrb; int rc, retries = 100; + u32 gisa = 0; *fh = 0; rrb = clp_alloc_block(GFP_KERNEL); if (!rrb) return -ENOMEM; + if (command != CLP_SET_DISABLE_PCI_FN) + gisa = zdev->gisa; + do { memset(rrb, 0, sizeof(*rrb)); rrb->request.hdr.len = sizeof(rrb->request); @@ -243,6 +247,7 @@ static int clp_set_pci_fn(struct zpci_dev *zdev, u32 *fh, u8 nr_dma_as, u8 comma rrb->request.fh = zdev->fh; rrb->request.oc = command; rrb->request.ndas = nr_dma_as; + rrb->request.gisa = gisa; rc = clp_req(rrb, CLP_LPS_PCI); if (rrb->response.hdr.rsp == CLP_RC_SETPCIFN_BUSY) { diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c index f2b3145b6697..a2b42a63a53b 100644 --- a/arch/s390/pci/pci_irq.c +++ b/arch/s390/pci/pci_irq.c @@ -43,6 +43,7 @@ static int zpci_set_airq(struct zpci_dev *zdev) fib.fmt0.aibvo = 0; /* each zdev has its own interrupt vector */ fib.fmt0.aisb = virt_to_phys(zpci_sbv->vector) + (zdev->aisb / 64) * 8; fib.fmt0.aisbo = zdev->aisb & 63; + fib.gd = zdev->gisa; return zpci_mod_fc(req, &fib, &status) ? -EIO : 0; } @@ -54,6 +55,8 @@ static int zpci_clear_airq(struct zpci_dev *zdev) struct zpci_fib fib = {0}; u8 cc, status; + fib.gd = zdev->gisa; + cc = zpci_mod_fc(req, &fib, &status); if (cc == 3 || (cc == 1 && status == 24)) /* Function already gone or IRQs already deregistered. */ @@ -72,6 +75,7 @@ static int zpci_set_directed_irq(struct zpci_dev *zdev) fib.fmt = 1; fib.fmt1.noi = zdev->msi_nr_irqs; fib.fmt1.dibvo = zdev->msi_first_bit; + fib.gd = zdev->gisa; return zpci_mod_fc(req, &fib, &status) ? -EIO : 0; } @@ -84,6 +88,7 @@ static int zpci_clear_directed_irq(struct zpci_dev *zdev) u8 cc, status; fib.fmt = 1; + fib.gd = zdev->gisa; cc = zpci_mod_fc(req, &fib, &status); if (cc == 3 || (cc == 1 && status == 24)) /* Function already gone or IRQs already deregistered. */ From d10384677630aa18c3ee0e8db915336c9ad9dec0 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:13 -0400 Subject: [PATCH 0896/1436] s390/pci: stash dtsm and maxstbl Store information about what IOAT designation types are supported by underlying hardware as well as the largest store block size allowed. These values will be needed by passthrough. Reviewed-by: Niklas Schnelle Reviewed-by: Pierre Morel Reviewed-by: Christian Borntraeger Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-10-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/pci.h | 2 ++ arch/s390/include/asm/pci_clp.h | 6 ++++-- arch/s390/pci/pci_clp.c | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 42a4a312a6dd..4c5b8fbc2079 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -126,9 +126,11 @@ struct zpci_dev { u32 gisa; /* GISA designation for passthrough */ u16 vfn; /* virtual function number */ u16 pchid; /* physical channel ID */ + u16 maxstbl; /* Maximum store block size */ u8 pfgid; /* function group ID */ u8 pft; /* pci function type */ u8 port; + u8 dtsm; /* Supported DT mask */ u8 rid_available : 1; u8 has_hp_slot : 1; u8 has_resources : 1; diff --git a/arch/s390/include/asm/pci_clp.h b/arch/s390/include/asm/pci_clp.h index f3286bc5ba6e..d6189ed14f84 100644 --- a/arch/s390/include/asm/pci_clp.h +++ b/arch/s390/include/asm/pci_clp.h @@ -153,9 +153,11 @@ struct clp_rsp_query_pci_grp { u8 : 6; u8 frame : 1; u8 refresh : 1; /* TLB refresh mode */ - u16 reserved2; + u16 : 3; + u16 maxstbl : 13; /* Maximum store block size */ u16 mui; - u16 : 16; + u8 dtsm; /* Supported DT mask */ + u8 reserved3; u16 maxfaal; u16 : 4; u16 dnoi : 12; diff --git a/arch/s390/pci/pci_clp.c b/arch/s390/pci/pci_clp.c index d058c83467ef..ee367798e388 100644 --- a/arch/s390/pci/pci_clp.c +++ b/arch/s390/pci/pci_clp.c @@ -106,6 +106,8 @@ static void clp_store_query_pci_fngrp(struct zpci_dev *zdev, zdev->max_msi = response->noi; zdev->fmb_update = response->mui; zdev->version = response->version; + zdev->maxstbl = response->maxstbl; + zdev->dtsm = response->dtsm; switch (response->version) { case 1: From c435c54639aa5513ab877c8b014dd83d4ce6b40e Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:14 -0400 Subject: [PATCH 0897/1436] vfio/pci: introduce CONFIG_VFIO_PCI_ZDEV_KVM The current contents of vfio-pci-zdev are today only useful in a KVM environment; let's tie everything currently under vfio-pci-zdev to this Kconfig statement and require KVM in this case, reducing complexity (e.g. symbol lookups). Signed-off-by: Matthew Rosato Acked-by: Alex Williamson Reviewed-by: Pierre Morel Link: https://lore.kernel.org/r/20220606203325.110625-11-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- drivers/vfio/pci/Kconfig | 11 +++++++++++ drivers/vfio/pci/Makefile | 2 +- include/linux/vfio_pci_core.h | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/vfio/pci/Kconfig b/drivers/vfio/pci/Kconfig index 4da1914425e1..f9d0c908e738 100644 --- a/drivers/vfio/pci/Kconfig +++ b/drivers/vfio/pci/Kconfig @@ -44,6 +44,17 @@ config VFIO_PCI_IGD To enable Intel IGD assignment through vfio-pci, say Y. endif +config VFIO_PCI_ZDEV_KVM + bool "VFIO PCI extensions for s390x KVM passthrough" + depends on S390 && KVM + default y + help + Support s390x-specific extensions to enable support for enhancements + to KVM passthrough capabilities, such as interpretive execution of + zPCI instructions. + + To enable s390x KVM vfio-pci extensions, say Y. + source "drivers/vfio/pci/mlx5/Kconfig" source "drivers/vfio/pci/hisilicon/Kconfig" diff --git a/drivers/vfio/pci/Makefile b/drivers/vfio/pci/Makefile index 7052ebd893e0..24c524224da5 100644 --- a/drivers/vfio/pci/Makefile +++ b/drivers/vfio/pci/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only vfio-pci-core-y := vfio_pci_core.o vfio_pci_intrs.o vfio_pci_rdwr.o vfio_pci_config.o -vfio-pci-core-$(CONFIG_S390) += vfio_pci_zdev.o +vfio-pci-core-$(CONFIG_VFIO_PCI_ZDEV_KVM) += vfio_pci_zdev.o obj-$(CONFIG_VFIO_PCI_CORE) += vfio-pci-core.o vfio-pci-y := vfio_pci.o diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index 23c176d4b073..63af2897939c 100644 --- a/include/linux/vfio_pci_core.h +++ b/include/linux/vfio_pci_core.h @@ -206,7 +206,7 @@ static inline int vfio_pci_igd_init(struct vfio_pci_core_device *vdev) } #endif -#ifdef CONFIG_S390 +#ifdef CONFIG_VFIO_PCI_ZDEV_KVM extern int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, struct vfio_info_cap *caps); #else From 6438e30714abd1bf7408356d3e86127d1fb379c0 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:15 -0400 Subject: [PATCH 0898/1436] KVM: s390: pci: add basic kvm_zdev structure This structure will be used to carry kvm passthrough information related to zPCI devices. Reviewed-by: Niklas Schnelle Reviewed-by: Pierre Morel Reviewed-by: Christian Borntraeger Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-12-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/pci.h | 3 +++ arch/s390/kvm/Makefile | 1 + arch/s390/kvm/pci.c | 36 ++++++++++++++++++++++++++++++++++++ arch/s390/kvm/pci.h | 21 +++++++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 arch/s390/kvm/pci.c create mode 100644 arch/s390/kvm/pci.h diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 4c5b8fbc2079..50f1851edfbe 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -97,6 +97,7 @@ struct zpci_bar_struct { }; struct s390_domain; +struct kvm_zdev; #define ZPCI_FUNCTIONS_PER_BUS 256 struct zpci_bus { @@ -189,7 +190,9 @@ struct zpci_dev { struct dentry *debugfs_dev; + /* IOMMU and passthrough */ struct s390_domain *s390_domain; /* s390 IOMMU domain data */ + struct kvm_zdev *kzdev; }; static inline bool zdev_enabled(struct zpci_dev *zdev) diff --git a/arch/s390/kvm/Makefile b/arch/s390/kvm/Makefile index 26f4a74e5ce4..02217fb4ae10 100644 --- a/arch/s390/kvm/Makefile +++ b/arch/s390/kvm/Makefile @@ -10,4 +10,5 @@ ccflags-y := -Ivirt/kvm -Iarch/s390/kvm kvm-y += kvm-s390.o intercept.o interrupt.o priv.o sigp.o kvm-y += diag.o gaccess.o guestdbg.o vsie.o pv.o +kvm-$(CONFIG_VFIO_PCI_ZDEV_KVM) += pci.o obj-$(CONFIG_KVM) += kvm.o diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c new file mode 100644 index 000000000000..e27191ea27c4 --- /dev/null +++ b/arch/s390/kvm/pci.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * s390 kvm PCI passthrough support + * + * Copyright IBM Corp. 2022 + * + * Author(s): Matthew Rosato + */ + +#include +#include +#include "pci.h" + +static int kvm_s390_pci_dev_open(struct zpci_dev *zdev) +{ + struct kvm_zdev *kzdev; + + kzdev = kzalloc(sizeof(struct kvm_zdev), GFP_KERNEL); + if (!kzdev) + return -ENOMEM; + + kzdev->zdev = zdev; + zdev->kzdev = kzdev; + + return 0; +} + +static void kvm_s390_pci_dev_release(struct zpci_dev *zdev) +{ + struct kvm_zdev *kzdev; + + kzdev = zdev->kzdev; + WARN_ON(kzdev->zdev != zdev); + zdev->kzdev = NULL; + kfree(kzdev); +} diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h new file mode 100644 index 000000000000..ce93978e8913 --- /dev/null +++ b/arch/s390/kvm/pci.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * s390 kvm PCI passthrough support + * + * Copyright IBM Corp. 2022 + * + * Author(s): Matthew Rosato + */ + +#ifndef __KVM_S390_PCI_H +#define __KVM_S390_PCI_H + +#include +#include + +struct kvm_zdev { + struct zpci_dev *zdev; + struct kvm *kvm; +}; + +#endif /* __KVM_S390_PCI_H */ From 98b1d33dac5fd09060486762c02fd1a78baeb1e0 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:16 -0400 Subject: [PATCH 0899/1436] KVM: s390: pci: do initial setup for AEN interpretation Initial setup for Adapter Event Notification Interpretation for zPCI passthrough devices. Specifically, allocate a structure for forwarding of adapter events and pass the address of this structure to firmware. Reviewed-by: Christian Borntraeger Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-13-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/pci.h | 4 + arch/s390/include/asm/pci_insn.h | 12 +++ arch/s390/kvm/interrupt.c | 14 +++ arch/s390/kvm/kvm-s390.c | 11 +++ arch/s390/kvm/pci.c | 160 +++++++++++++++++++++++++++++++ arch/s390/kvm/pci.h | 49 ++++++++++ arch/s390/pci/pci.c | 6 ++ 7 files changed, 256 insertions(+) diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 50f1851edfbe..322060a75d9f 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #define PCIBIOS_MIN_IO 0x1000 @@ -204,6 +205,9 @@ extern const struct attribute_group *zpci_attr_groups[]; extern unsigned int s390_pci_force_floating __initdata; extern unsigned int s390_pci_no_rid; +extern union zpci_sic_iib *zpci_aipb; +extern struct airq_iv *zpci_aif_sbv; + /* ----------------------------------------------------------------------------- Prototypes ----------------------------------------------------------------------------- */ diff --git a/arch/s390/include/asm/pci_insn.h b/arch/s390/include/asm/pci_insn.h index 5331082fa516..e5f57cfe1d45 100644 --- a/arch/s390/include/asm/pci_insn.h +++ b/arch/s390/include/asm/pci_insn.h @@ -101,6 +101,7 @@ struct zpci_fib { /* Set Interruption Controls Operation Controls */ #define SIC_IRQ_MODE_ALL 0 #define SIC_IRQ_MODE_SINGLE 1 +#define SIC_SET_AENI_CONTROLS 2 #define SIC_IRQ_MODE_DIRECT 4 #define SIC_IRQ_MODE_D_ALL 16 #define SIC_IRQ_MODE_D_SINGLE 17 @@ -127,9 +128,20 @@ struct zpci_cdiib { u64 : 64; } __packed __aligned(8); +/* adapter interruption parameters block */ +struct zpci_aipb { + u64 faisb; + u64 gait; + u16 : 13; + u16 afi : 3; + u32 : 32; + u16 faal; +} __packed __aligned(8); + union zpci_sic_iib { struct zpci_diib diib; struct zpci_cdiib cdiib; + struct zpci_aipb aipb; }; DECLARE_STATIC_KEY_FALSE(have_mio); diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 17ff475157d8..37ff4358121a 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -32,6 +32,7 @@ #include "kvm-s390.h" #include "gaccess.h" #include "trace-s390.h" +#include "pci.h" #define PFAULT_INIT 0x0600 #define PFAULT_DONE 0x0680 @@ -3328,6 +3329,11 @@ void kvm_s390_gib_destroy(void) { if (!gib) return; + if (kvm_s390_pci_interp_allowed() && aift) { + mutex_lock(&aift->aift_lock); + kvm_s390_pci_aen_exit(); + mutex_unlock(&aift->aift_lock); + } chsc_sgib(0); unregister_adapter_interrupt(&gib_alert_irq); free_page((unsigned long)gib); @@ -3365,6 +3371,14 @@ int kvm_s390_gib_init(u8 nisc) goto out_unreg_gal; } + if (kvm_s390_pci_interp_allowed()) { + if (kvm_s390_pci_aen_init(nisc)) { + pr_err("Initializing AEN for PCI failed\n"); + rc = -EIO; + goto out_unreg_gal; + } + } + KVM_EVENT(3, "gib 0x%pK (nisc=%d) initialized", gib, gib->nisc); goto out; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 8fcb56141689..251eaaff9c67 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -47,6 +47,7 @@ #include #include "kvm-s390.h" #include "gaccess.h" +#include "pci.h" #define CREATE_TRACE_POINTS #include "trace.h" @@ -502,6 +503,14 @@ int kvm_arch_init(void *opaque) goto out; } + if (kvm_s390_pci_interp_allowed()) { + rc = kvm_s390_pci_init(); + if (rc) { + pr_err("Unable to allocate AIFT for PCI\n"); + goto out; + } + } + rc = kvm_s390_gib_init(GAL_ISC); if (rc) goto out; @@ -516,6 +525,8 @@ out: void kvm_arch_exit(void) { kvm_s390_gib_destroy(); + if (kvm_s390_pci_interp_allowed()) + kvm_s390_pci_exit(); debug_unregister(kvm_s390_dbf); debug_unregister(kvm_s390_dbf_uv); } diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c index e27191ea27c4..d566551d3018 100644 --- a/arch/s390/kvm/pci.c +++ b/arch/s390/kvm/pci.c @@ -9,8 +9,149 @@ #include #include +#include +#include #include "pci.h" +struct zpci_aift *aift; + +static inline int __set_irq_noiib(u16 ctl, u8 isc) +{ + union zpci_sic_iib iib = {{0}}; + + return zpci_set_irq_ctrl(ctl, isc, &iib); +} + +void kvm_s390_pci_aen_exit(void) +{ + unsigned long flags; + struct kvm_zdev **gait_kzdev; + + lockdep_assert_held(&aift->aift_lock); + + /* + * Contents of the aipb remain registered for the life of the host + * kernel, the information preserved in zpci_aipb and zpci_aif_sbv + * in case we insert the KVM module again later. Clear the AIFT + * information and free anything not registered with underlying + * firmware. + */ + spin_lock_irqsave(&aift->gait_lock, flags); + gait_kzdev = aift->kzdev; + aift->gait = NULL; + aift->sbv = NULL; + aift->kzdev = NULL; + spin_unlock_irqrestore(&aift->gait_lock, flags); + + kfree(gait_kzdev); +} + +static int zpci_setup_aipb(u8 nisc) +{ + struct page *page; + int size, rc; + + zpci_aipb = kzalloc(sizeof(union zpci_sic_iib), GFP_KERNEL); + if (!zpci_aipb) + return -ENOMEM; + + aift->sbv = airq_iv_create(ZPCI_NR_DEVICES, AIRQ_IV_ALLOC, 0); + if (!aift->sbv) { + rc = -ENOMEM; + goto free_aipb; + } + zpci_aif_sbv = aift->sbv; + size = get_order(PAGE_ALIGN(ZPCI_NR_DEVICES * + sizeof(struct zpci_gaite))); + page = alloc_pages(GFP_KERNEL | __GFP_ZERO, size); + if (!page) { + rc = -ENOMEM; + goto free_sbv; + } + aift->gait = (struct zpci_gaite *)page_to_phys(page); + + zpci_aipb->aipb.faisb = virt_to_phys(aift->sbv->vector); + zpci_aipb->aipb.gait = virt_to_phys(aift->gait); + zpci_aipb->aipb.afi = nisc; + zpci_aipb->aipb.faal = ZPCI_NR_DEVICES; + + /* Setup Adapter Event Notification Interpretation */ + if (zpci_set_irq_ctrl(SIC_SET_AENI_CONTROLS, 0, zpci_aipb)) { + rc = -EIO; + goto free_gait; + } + + return 0; + +free_gait: + free_pages((unsigned long)aift->gait, size); +free_sbv: + airq_iv_release(aift->sbv); + zpci_aif_sbv = NULL; +free_aipb: + kfree(zpci_aipb); + zpci_aipb = NULL; + + return rc; +} + +static int zpci_reset_aipb(u8 nisc) +{ + /* + * AEN registration can only happen once per system boot. If + * an aipb already exists then AEN was already registered and + * we can re-use the aipb contents. This can only happen if + * the KVM module was removed and re-inserted. However, we must + * ensure that the same forwarding ISC is used as this is assigned + * during KVM module load. + */ + if (zpci_aipb->aipb.afi != nisc) + return -EINVAL; + + aift->sbv = zpci_aif_sbv; + aift->gait = (struct zpci_gaite *)zpci_aipb->aipb.gait; + + return 0; +} + +int kvm_s390_pci_aen_init(u8 nisc) +{ + int rc = 0; + + /* If already enabled for AEN, bail out now */ + if (aift->gait || aift->sbv) + return -EPERM; + + mutex_lock(&aift->aift_lock); + aift->kzdev = kcalloc(ZPCI_NR_DEVICES, sizeof(struct kvm_zdev), + GFP_KERNEL); + if (!aift->kzdev) { + rc = -ENOMEM; + goto unlock; + } + + if (!zpci_aipb) + rc = zpci_setup_aipb(nisc); + else + rc = zpci_reset_aipb(nisc); + if (rc) + goto free_zdev; + + /* Enable floating IRQs */ + if (__set_irq_noiib(SIC_IRQ_MODE_SINGLE, nisc)) { + rc = -EIO; + kvm_s390_pci_aen_exit(); + } + + goto unlock; + +free_zdev: + kfree(aift->kzdev); +unlock: + mutex_unlock(&aift->aift_lock); + return rc; +} + static int kvm_s390_pci_dev_open(struct zpci_dev *zdev) { struct kvm_zdev *kzdev; @@ -34,3 +175,22 @@ static void kvm_s390_pci_dev_release(struct zpci_dev *zdev) zdev->kzdev = NULL; kfree(kzdev); } + +int kvm_s390_pci_init(void) +{ + aift = kzalloc(sizeof(struct zpci_aift), GFP_KERNEL); + if (!aift) + return -ENOMEM; + + spin_lock_init(&aift->gait_lock); + mutex_init(&aift->aift_lock); + + return 0; +} + +void kvm_s390_pci_exit(void) +{ + mutex_destroy(&aift->aift_lock); + + kfree(aift); +} diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h index ce93978e8913..c357d900f8b0 100644 --- a/arch/s390/kvm/pci.h +++ b/arch/s390/kvm/pci.h @@ -12,10 +12,59 @@ #include #include +#include +#include +#include struct kvm_zdev { struct zpci_dev *zdev; struct kvm *kvm; }; +struct zpci_gaite { + u32 gisa; + u8 gisc; + u8 count; + u8 reserved; + u8 aisbo; + u64 aisb; +}; + +struct zpci_aift { + struct zpci_gaite *gait; + struct airq_iv *sbv; + struct kvm_zdev **kzdev; + spinlock_t gait_lock; /* Protects the gait, used during AEN forward */ + struct mutex aift_lock; /* Protects the other structures in aift */ +}; + +extern struct zpci_aift *aift; + +int kvm_s390_pci_aen_init(u8 nisc); +void kvm_s390_pci_aen_exit(void); + +int kvm_s390_pci_init(void); +void kvm_s390_pci_exit(void); + +static inline bool kvm_s390_pci_interp_allowed(void) +{ + struct cpuid cpu_id; + + get_cpu_id(&cpu_id); + switch (cpu_id.machine) { + case 0x2817: + case 0x2818: + case 0x2827: + case 0x2828: + case 0x2964: + case 0x2965: + /* No SHM on certain machines */ + return false; + default: + return (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM) && + sclp.has_zpci_lsi && sclp.has_aeni && sclp.has_aisi && + sclp.has_aisii); + } +} + #endif /* __KVM_S390_PCI_H */ diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index c8b9d866434c..86cd4d8446b1 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -61,6 +61,12 @@ DEFINE_STATIC_KEY_FALSE(have_mio); static struct kmem_cache *zdev_fmb_cache; +/* AEN structures that must be preserved over KVM module re-insertion */ +union zpci_sic_iib *zpci_aipb; +EXPORT_SYMBOL_GPL(zpci_aipb); +struct airq_iv *zpci_aif_sbv; +EXPORT_SYMBOL_GPL(zpci_aif_sbv); + struct zpci_dev *get_zdev_by_fid(u32 fid) { struct zpci_dev *tmp, *zdev = NULL; From 73f91b004321f2510fa79e66035dbbf1870fcf56 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:17 -0400 Subject: [PATCH 0900/1436] KVM: s390: pci: enable host forwarding of Adapter Event Notifications In cases where interrupts are not forwarded to the guest via firmware, KVM is responsible for ensuring delivery. When an interrupt presents with the forwarding bit, we must process the forwarding tables until all interrupts are delivered. Reviewed-by: Christian Borntraeger Reviewed-by: Pierre Morel Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-14-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 1 + arch/s390/include/asm/tpi.h | 13 ++++++ arch/s390/kvm/interrupt.c | 78 +++++++++++++++++++++++++++++++- arch/s390/kvm/kvm-s390.c | 3 +- arch/s390/kvm/pci.h | 10 ++++ 5 files changed, 103 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 766028d54a3e..c1518a505060 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -759,6 +759,7 @@ struct kvm_vm_stat { u64 inject_pfault_done; u64 inject_service_signal; u64 inject_virtio; + u64 aen_forward; }; struct kvm_arch_memory_slot { diff --git a/arch/s390/include/asm/tpi.h b/arch/s390/include/asm/tpi.h index 1ac538b8cbf5..f76e5fdff23a 100644 --- a/arch/s390/include/asm/tpi.h +++ b/arch/s390/include/asm/tpi.h @@ -19,6 +19,19 @@ struct tpi_info { u32 :12; } __packed __aligned(4); +/* I/O-Interruption Code as stored by TPI for an Adapter I/O */ +struct tpi_adapter_info { + u32 aism:8; + u32 :22; + u32 error:1; + u32 forward:1; + u32 reserved; + u32 adapter_IO:1; + u32 directed_irq:1; + u32 isc:3; + u32 :27; +} __packed __aligned(4); + #endif /* __ASSEMBLY__ */ #endif /* _ASM_S390_TPI_H */ diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index 37ff4358121a..d8e1fce78b7c 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -3313,11 +3313,87 @@ out: } EXPORT_SYMBOL_GPL(kvm_s390_gisc_unregister); +static void aen_host_forward(unsigned long si) +{ + struct kvm_s390_gisa_interrupt *gi; + struct zpci_gaite *gaite; + struct kvm *kvm; + + gaite = (struct zpci_gaite *)aift->gait + + (si * sizeof(struct zpci_gaite)); + if (gaite->count == 0) + return; + if (gaite->aisb != 0) + set_bit_inv(gaite->aisbo, (unsigned long *)gaite->aisb); + + kvm = kvm_s390_pci_si_to_kvm(aift, si); + if (!kvm) + return; + gi = &kvm->arch.gisa_int; + + if (!(gi->origin->g1.simm & AIS_MODE_MASK(gaite->gisc)) || + !(gi->origin->g1.nimm & AIS_MODE_MASK(gaite->gisc))) { + gisa_set_ipm_gisc(gi->origin, gaite->gisc); + if (hrtimer_active(&gi->timer)) + hrtimer_cancel(&gi->timer); + hrtimer_start(&gi->timer, 0, HRTIMER_MODE_REL); + kvm->stat.aen_forward++; + } +} + +static void aen_process_gait(u8 isc) +{ + bool found = false, first = true; + union zpci_sic_iib iib = {{0}}; + unsigned long si, flags; + + spin_lock_irqsave(&aift->gait_lock, flags); + + if (!aift->gait) { + spin_unlock_irqrestore(&aift->gait_lock, flags); + return; + } + + for (si = 0;;) { + /* Scan adapter summary indicator bit vector */ + si = airq_iv_scan(aift->sbv, si, airq_iv_end(aift->sbv)); + if (si == -1UL) { + if (first || found) { + /* Re-enable interrupts. */ + zpci_set_irq_ctrl(SIC_IRQ_MODE_SINGLE, isc, + &iib); + first = found = false; + } else { + /* Interrupts on and all bits processed */ + break; + } + found = false; + si = 0; + /* Scan again after re-enabling interrupts */ + continue; + } + found = true; + aen_host_forward(si); + } + + spin_unlock_irqrestore(&aift->gait_lock, flags); +} + static void gib_alert_irq_handler(struct airq_struct *airq, struct tpi_info *tpi_info) { + struct tpi_adapter_info *info = (struct tpi_adapter_info *)tpi_info; + inc_irq_stat(IRQIO_GAL); - process_gib_alert_list(); + + if ((info->forward || info->error) && + IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM)) { + aen_process_gait(info->isc); + if (info->aism != 0) + process_gib_alert_list(); + } else { + process_gib_alert_list(); + } } static struct airq_struct gib_alert_irq = { diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 251eaaff9c67..d96c9be0480b 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -64,7 +64,8 @@ const struct _kvm_stats_desc kvm_vm_stats_desc[] = { STATS_DESC_COUNTER(VM, inject_float_mchk), STATS_DESC_COUNTER(VM, inject_pfault_done), STATS_DESC_COUNTER(VM, inject_service_signal), - STATS_DESC_COUNTER(VM, inject_virtio) + STATS_DESC_COUNTER(VM, inject_virtio), + STATS_DESC_COUNTER(VM, aen_forward) }; const struct kvm_stats_header kvm_vm_stats_header = { diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h index c357d900f8b0..9f7828d97605 100644 --- a/arch/s390/kvm/pci.h +++ b/arch/s390/kvm/pci.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,15 @@ struct zpci_aift { extern struct zpci_aift *aift; +static inline struct kvm *kvm_s390_pci_si_to_kvm(struct zpci_aift *aift, + unsigned long si) +{ + if (!IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM) || aift->kzdev == 0 || + aift->kzdev[si] == 0) + return 0; + return aift->kzdev[si]->kvm; +}; + int kvm_s390_pci_aen_init(u8 nisc); void kvm_s390_pci_aen_exit(void); From 3f4bbb4342ec637b14d0e367e487fd38b31d8b48 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:18 -0400 Subject: [PATCH 0901/1436] KVM: s390: mechanism to enable guest zPCI Interpretation The guest must have access to certain facilities in order to allow interpretive execution of zPCI instructions and adapter event notifications. However, there are some cases where a guest might disable interpretation -- provide a mechanism via which we can defer enabling the associated zPCI interpretation facilities until the guest indicates it wishes to use them. Reviewed-by: Christian Borntraeger Reviewed-by: Pierre Morel Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-15-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 4 ++++ arch/s390/kvm/kvm-s390.c | 38 ++++++++++++++++++++++++++++++++ arch/s390/kvm/kvm-s390.h | 10 +++++++++ 3 files changed, 52 insertions(+) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index c1518a505060..8e381603b6a7 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -254,7 +254,10 @@ struct kvm_s390_sie_block { #define ECB2_IEP 0x20 #define ECB2_PFMFI 0x08 #define ECB2_ESCA 0x04 +#define ECB2_ZPCI_LSI 0x02 __u8 ecb2; /* 0x0062 */ +#define ECB3_AISI 0x20 +#define ECB3_AISII 0x10 #define ECB3_DEA 0x08 #define ECB3_AES 0x04 #define ECB3_RI 0x01 @@ -940,6 +943,7 @@ struct kvm_arch{ int use_cmma; int use_pfmfi; int use_skf; + int use_zpci_interp; int user_cpu_state_ctrl; int user_sigp; int user_stsi; diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index d96c9be0480b..a66da3f66114 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -1031,6 +1031,42 @@ static int kvm_s390_vm_set_crypto(struct kvm *kvm, struct kvm_device_attr *attr) return 0; } +static void kvm_s390_vcpu_pci_setup(struct kvm_vcpu *vcpu) +{ + /* Only set the ECB bits after guest requests zPCI interpretation */ + if (!vcpu->kvm->arch.use_zpci_interp) + return; + + vcpu->arch.sie_block->ecb2 |= ECB2_ZPCI_LSI; + vcpu->arch.sie_block->ecb3 |= ECB3_AISII + ECB3_AISI; +} + +void kvm_s390_vcpu_pci_enable_interp(struct kvm *kvm) +{ + struct kvm_vcpu *vcpu; + unsigned long i; + + lockdep_assert_held(&kvm->lock); + + if (!kvm_s390_pci_interp_allowed()) + return; + + /* + * If host is configured for PCI and the necessary facilities are + * available, turn on interpretation for the life of this guest + */ + kvm->arch.use_zpci_interp = 1; + + kvm_s390_vcpu_block_all(kvm); + + kvm_for_each_vcpu(i, vcpu, kvm) { + kvm_s390_vcpu_pci_setup(vcpu); + kvm_s390_sync_request(KVM_REQ_VSIE_RESTART, vcpu); + } + + kvm_s390_vcpu_unblock_all(kvm); +} + static void kvm_s390_sync_request_broadcast(struct kvm *kvm, int req) { unsigned long cx; @@ -3336,6 +3372,8 @@ static int kvm_s390_vcpu_setup(struct kvm_vcpu *vcpu) kvm_s390_vcpu_crypto_setup(vcpu); + kvm_s390_vcpu_pci_setup(vcpu); + mutex_lock(&vcpu->kvm->lock); if (kvm_s390_pv_is_protected(vcpu->kvm)) { rc = kvm_s390_pv_create_cpu(vcpu, &uvrc, &uvrrc); diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 497d52a83c78..975cffaf13de 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -507,6 +507,16 @@ void kvm_s390_reinject_machine_check(struct kvm_vcpu *vcpu, */ void kvm_s390_vcpu_crypto_reset_all(struct kvm *kvm); +/** + * kvm_s390_vcpu_pci_enable_interp + * + * Set the associated PCI attributes for each vcpu to allow for zPCI Load/Store + * interpretation as well as adapter interruption forwarding. + * + * @kvm: the KVM guest + */ +void kvm_s390_vcpu_pci_enable_interp(struct kvm *kvm); + /** * diag9c_forwarding_hz * From 3c5a1b6f0a18520a0edd0600fef6f1a8553b8fdc Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:19 -0400 Subject: [PATCH 0902/1436] KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding These routines will be wired into a kvm ioctl in order to respond to requests to enable / disable a device for Adapter Event Notifications / Adapter Interuption Forwarding. Reviewed-by: Christian Borntraeger Acked-by: Niklas Schnelle Signed-off-by: Matthew Rosato Link: https://lore.kernel.org/r/20220606203325.110625-16-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/kvm/pci.c | 247 +++++++++++++++++++++++++++++++++++++ arch/s390/kvm/pci.h | 1 + arch/s390/pci/pci_insn.c | 1 + include/linux/sched/user.h | 3 +- 4 files changed, 251 insertions(+), 1 deletion(-) diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c index d566551d3018..b232c8cbaa81 100644 --- a/arch/s390/kvm/pci.c +++ b/arch/s390/kvm/pci.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "pci.h" struct zpci_aift *aift; @@ -152,6 +153,252 @@ unlock: return rc; } +/* Modify PCI: Register floating adapter interruption forwarding */ +static int kvm_zpci_set_airq(struct zpci_dev *zdev) +{ + u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_REG_INT); + struct zpci_fib fib = {}; + u8 status; + + fib.fmt0.isc = zdev->kzdev->fib.fmt0.isc; + fib.fmt0.sum = 1; /* enable summary notifications */ + fib.fmt0.noi = airq_iv_end(zdev->aibv); + fib.fmt0.aibv = virt_to_phys(zdev->aibv->vector); + fib.fmt0.aibvo = 0; + fib.fmt0.aisb = virt_to_phys(aift->sbv->vector + (zdev->aisb / 64) * 8); + fib.fmt0.aisbo = zdev->aisb & 63; + fib.gd = zdev->gisa; + + return zpci_mod_fc(req, &fib, &status) ? -EIO : 0; +} + +/* Modify PCI: Unregister floating adapter interruption forwarding */ +static int kvm_zpci_clear_airq(struct zpci_dev *zdev) +{ + u64 req = ZPCI_CREATE_REQ(zdev->fh, 0, ZPCI_MOD_FC_DEREG_INT); + struct zpci_fib fib = {}; + u8 cc, status; + + fib.gd = zdev->gisa; + + cc = zpci_mod_fc(req, &fib, &status); + if (cc == 3 || (cc == 1 && status == 24)) + /* Function already gone or IRQs already deregistered. */ + cc = 0; + + return cc ? -EIO : 0; +} + +static inline void unaccount_mem(unsigned long nr_pages) +{ + struct user_struct *user = get_uid(current_user()); + + if (user) + atomic_long_sub(nr_pages, &user->locked_vm); + if (current->mm) + atomic64_sub(nr_pages, ¤t->mm->pinned_vm); +} + +static inline int account_mem(unsigned long nr_pages) +{ + struct user_struct *user = get_uid(current_user()); + unsigned long page_limit, cur_pages, new_pages; + + page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; + + do { + cur_pages = atomic_long_read(&user->locked_vm); + new_pages = cur_pages + nr_pages; + if (new_pages > page_limit) + return -ENOMEM; + } while (atomic_long_cmpxchg(&user->locked_vm, cur_pages, + new_pages) != cur_pages); + + atomic64_add(nr_pages, ¤t->mm->pinned_vm); + + return 0; +} + +static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib, + bool assist) +{ + struct page *pages[1], *aibv_page, *aisb_page = NULL; + unsigned int msi_vecs, idx; + struct zpci_gaite *gaite; + unsigned long hva, bit; + struct kvm *kvm; + phys_addr_t gaddr; + int rc = 0, gisc, npages, pcount = 0; + + /* + * Interrupt forwarding is only applicable if the device is already + * enabled for interpretation + */ + if (zdev->gisa == 0) + return -EINVAL; + + kvm = zdev->kzdev->kvm; + msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi); + + /* Get the associated forwarding ISC - if invalid, return the error */ + gisc = kvm_s390_gisc_register(kvm, fib->fmt0.isc); + if (gisc < 0) + return gisc; + + /* Replace AIBV address */ + idx = srcu_read_lock(&kvm->srcu); + hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aibv)); + npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM, pages); + srcu_read_unlock(&kvm->srcu, idx); + if (npages < 1) { + rc = -EIO; + goto out; + } + aibv_page = pages[0]; + pcount++; + gaddr = page_to_phys(aibv_page) + (fib->fmt0.aibv & ~PAGE_MASK); + fib->fmt0.aibv = gaddr; + + /* Pin the guest AISB if one was specified */ + if (fib->fmt0.sum == 1) { + idx = srcu_read_lock(&kvm->srcu); + hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aisb)); + npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM, + pages); + srcu_read_unlock(&kvm->srcu, idx); + if (npages < 1) { + rc = -EIO; + goto unpin1; + } + aisb_page = pages[0]; + pcount++; + } + + /* Account for pinned pages, roll back on failure */ + if (account_mem(pcount)) + goto unpin2; + + /* AISB must be allocated before we can fill in GAITE */ + mutex_lock(&aift->aift_lock); + bit = airq_iv_alloc_bit(aift->sbv); + if (bit == -1UL) + goto unlock; + zdev->aisb = bit; /* store the summary bit number */ + zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA | + AIRQ_IV_BITLOCK | + AIRQ_IV_GUESTVEC, + phys_to_virt(fib->fmt0.aibv)); + + spin_lock_irq(&aift->gait_lock); + gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb * + sizeof(struct zpci_gaite)); + + /* If assist not requested, host will get all alerts */ + if (assist) + gaite->gisa = (u32)virt_to_phys(&kvm->arch.sie_page2->gisa); + else + gaite->gisa = 0; + + gaite->gisc = fib->fmt0.isc; + gaite->count++; + gaite->aisbo = fib->fmt0.aisbo; + gaite->aisb = virt_to_phys(page_address(aisb_page) + (fib->fmt0.aisb & + ~PAGE_MASK)); + aift->kzdev[zdev->aisb] = zdev->kzdev; + spin_unlock_irq(&aift->gait_lock); + + /* Update guest FIB for re-issue */ + fib->fmt0.aisbo = zdev->aisb & 63; + fib->fmt0.aisb = virt_to_phys(aift->sbv->vector + (zdev->aisb / 64) * 8); + fib->fmt0.isc = gisc; + + /* Save some guest fib values in the host for later use */ + zdev->kzdev->fib.fmt0.isc = fib->fmt0.isc; + zdev->kzdev->fib.fmt0.aibv = fib->fmt0.aibv; + mutex_unlock(&aift->aift_lock); + + /* Issue the clp to setup the irq now */ + rc = kvm_zpci_set_airq(zdev); + return rc; + +unlock: + mutex_unlock(&aift->aift_lock); +unpin2: + if (fib->fmt0.sum == 1) + unpin_user_page(aisb_page); +unpin1: + unpin_user_page(aibv_page); +out: + return rc; +} + +static int kvm_s390_pci_aif_disable(struct zpci_dev *zdev, bool force) +{ + struct kvm_zdev *kzdev = zdev->kzdev; + struct zpci_gaite *gaite; + struct page *vpage = NULL, *spage = NULL; + int rc, pcount = 0; + u8 isc; + + if (zdev->gisa == 0) + return -EINVAL; + + mutex_lock(&aift->aift_lock); + + /* + * If the clear fails due to an error, leave now unless we know this + * device is about to go away (force) -- In that case clear the GAITE + * regardless. + */ + rc = kvm_zpci_clear_airq(zdev); + if (rc && !force) + goto out; + + if (zdev->kzdev->fib.fmt0.aibv == 0) + goto out; + spin_lock_irq(&aift->gait_lock); + gaite = (struct zpci_gaite *)aift->gait + (zdev->aisb * + sizeof(struct zpci_gaite)); + isc = gaite->gisc; + gaite->count--; + if (gaite->count == 0) { + /* Release guest AIBV and AISB */ + vpage = phys_to_page(kzdev->fib.fmt0.aibv); + if (gaite->aisb != 0) + spage = phys_to_page(gaite->aisb); + /* Clear the GAIT entry */ + gaite->aisb = 0; + gaite->gisc = 0; + gaite->aisbo = 0; + gaite->gisa = 0; + aift->kzdev[zdev->aisb] = 0; + /* Clear zdev info */ + airq_iv_free_bit(aift->sbv, zdev->aisb); + airq_iv_release(zdev->aibv); + zdev->aisb = 0; + zdev->aibv = NULL; + } + spin_unlock_irq(&aift->gait_lock); + kvm_s390_gisc_unregister(kzdev->kvm, isc); + kzdev->fib.fmt0.isc = 0; + kzdev->fib.fmt0.aibv = 0; + + if (vpage) { + unpin_user_page(vpage); + pcount++; + } + if (spage) { + unpin_user_page(spage); + pcount++; + } + if (pcount > 0) + unaccount_mem(pcount); +out: + mutex_unlock(&aift->aift_lock); + + return rc; +} + static int kvm_s390_pci_dev_open(struct zpci_dev *zdev) { struct kvm_zdev *kzdev; diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h index 9f7828d97605..9d091033fc02 100644 --- a/arch/s390/kvm/pci.h +++ b/arch/s390/kvm/pci.h @@ -20,6 +20,7 @@ struct kvm_zdev { struct zpci_dev *zdev; struct kvm *kvm; + struct zpci_fib fib; }; struct zpci_gaite { diff --git a/arch/s390/pci/pci_insn.c b/arch/s390/pci/pci_insn.c index 5798178aec9d..56480be48244 100644 --- a/arch/s390/pci/pci_insn.c +++ b/arch/s390/pci/pci_insn.c @@ -92,6 +92,7 @@ u8 zpci_mod_fc(u64 req, struct zpci_fib *fib, u8 *status) return cc; } +EXPORT_SYMBOL_GPL(zpci_mod_fc); /* Refresh PCI Translations */ static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status) diff --git a/include/linux/sched/user.h b/include/linux/sched/user.h index 00ed419dd464..f054d0360a75 100644 --- a/include/linux/sched/user.h +++ b/include/linux/sched/user.h @@ -24,7 +24,8 @@ struct user_struct { kuid_t uid; #if defined(CONFIG_PERF_EVENTS) || defined(CONFIG_BPF_SYSCALL) || \ - defined(CONFIG_NET) || defined(CONFIG_IO_URING) + defined(CONFIG_NET) || defined(CONFIG_IO_URING) || \ + defined(CONFIG_VFIO_PCI_ZDEV_KVM) atomic_long_t locked_vm; #endif #ifdef CONFIG_WATCH_QUEUE From 09340b2fca007509c3cbc34fdc97961e0abfc589 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:20 -0400 Subject: [PATCH 0903/1436] KVM: s390: pci: add routines to start/stop interpretive execution These routines will be invoked at the time an s390x vfio-pci device is associated with a KVM (or when the association is removed), allowing the zPCI device to enable or disable load/store intepretation mode; this requires the host zPCI device to inform firmware of the unique token (GISA designation) that is associated with the owning KVM. Signed-off-by: Matthew Rosato Acked-by: Pierre Morel Link: https://lore.kernel.org/r/20220606203325.110625-17-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- arch/s390/include/asm/kvm_host.h | 18 ++++ arch/s390/include/asm/pci.h | 1 + arch/s390/kvm/kvm-s390.c | 15 +++ arch/s390/kvm/pci.c | 162 +++++++++++++++++++++++++++++++ arch/s390/kvm/pci.h | 5 + arch/s390/pci/pci.c | 4 + 6 files changed, 205 insertions(+) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 8e381603b6a7..6e83d746bae2 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -967,6 +968,8 @@ struct kvm_arch{ DECLARE_BITMAP(idle_mask, KVM_MAX_VCPUS); struct kvm_s390_gisa_interrupt gisa_int; struct kvm_s390_pv pv; + struct list_head kzdev_list; + spinlock_t kzdev_list_lock; }; #define KVM_HVA_ERR_BAD (-1UL) @@ -1017,4 +1020,19 @@ static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm, static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} +#define __KVM_HAVE_ARCH_VM_FREE +void kvm_arch_free_vm(struct kvm *kvm); + +#ifdef CONFIG_VFIO_PCI_ZDEV_KVM +int kvm_s390_pci_register_kvm(struct zpci_dev *zdev, struct kvm *kvm); +void kvm_s390_pci_unregister_kvm(struct zpci_dev *zdev); +#else +static inline int kvm_s390_pci_register_kvm(struct zpci_dev *dev, + struct kvm *kvm) +{ + return -EPERM; +} +static inline void kvm_s390_pci_unregister_kvm(struct zpci_dev *dev) {} +#endif + #endif diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h index 322060a75d9f..85eb0ef9d4c3 100644 --- a/arch/s390/include/asm/pci.h +++ b/arch/s390/include/asm/pci.h @@ -194,6 +194,7 @@ struct zpci_dev { /* IOMMU and passthrough */ struct s390_domain *s390_domain; /* s390 IOMMU domain data */ struct kvm_zdev *kzdev; + struct mutex kzdev_lock; }; static inline bool zdev_enabled(struct zpci_dev *zdev) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index a66da3f66114..4758bb731199 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2790,6 +2790,14 @@ static void sca_dispose(struct kvm *kvm) kvm->arch.sca = NULL; } +void kvm_arch_free_vm(struct kvm *kvm) +{ + if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM)) + kvm_s390_pci_clear_list(kvm); + + __kvm_arch_free_vm(kvm); +} + int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) { gfp_t alloc_flags = GFP_KERNEL_ACCOUNT; @@ -2872,6 +2880,13 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) kvm_s390_crypto_init(kvm); + if (IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM)) { + mutex_lock(&kvm->lock); + kvm_s390_pci_init_list(kvm); + kvm_s390_vcpu_pci_enable_interp(kvm); + mutex_unlock(&kvm->lock); + } + mutex_init(&kvm->arch.float_int.ais_lock); spin_lock_init(&kvm->arch.float_int.lock); for (i = 0; i < FIRQ_LIST_COUNT; i++) diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c index b232c8cbaa81..24211741deb0 100644 --- a/arch/s390/kvm/pci.c +++ b/arch/s390/kvm/pci.c @@ -12,7 +12,9 @@ #include #include #include +#include #include "pci.h" +#include "kvm-s390.h" struct zpci_aift *aift; @@ -423,6 +425,166 @@ static void kvm_s390_pci_dev_release(struct zpci_dev *zdev) kfree(kzdev); } + +/* + * Register device with the specified KVM. If interpetation facilities are + * available, enable them and let userspace indicate whether or not they will + * be used (specify SHM bit to disable). + */ +int kvm_s390_pci_register_kvm(struct zpci_dev *zdev, struct kvm *kvm) +{ + int rc; + + if (!zdev) + return -EINVAL; + + mutex_lock(&zdev->kzdev_lock); + + if (zdev->kzdev || zdev->gisa != 0 || !kvm) { + mutex_unlock(&zdev->kzdev_lock); + return -EINVAL; + } + + kvm_get_kvm(kvm); + + mutex_lock(&kvm->lock); + + rc = kvm_s390_pci_dev_open(zdev); + if (rc) + goto err; + + /* + * If interpretation facilities aren't available, add the device to + * the kzdev list but don't enable for interpretation. + */ + if (!kvm_s390_pci_interp_allowed()) + goto out; + + /* + * If this is the first request to use an interpreted device, make the + * necessary vcpu changes + */ + if (!kvm->arch.use_zpci_interp) + kvm_s390_vcpu_pci_enable_interp(kvm); + + if (zdev_enabled(zdev)) { + rc = zpci_disable_device(zdev); + if (rc) + goto err; + } + + /* + * Store information about the identity of the kvm guest allowed to + * access this device via interpretation to be used by host CLP + */ + zdev->gisa = (u32)virt_to_phys(&kvm->arch.sie_page2->gisa); + + rc = zpci_enable_device(zdev); + if (rc) + goto clear_gisa; + + /* Re-register the IOMMU that was already created */ + rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, + virt_to_phys(zdev->dma_table)); + if (rc) + goto clear_gisa; + +out: + zdev->kzdev->kvm = kvm; + + spin_lock(&kvm->arch.kzdev_list_lock); + list_add_tail(&zdev->kzdev->entry, &kvm->arch.kzdev_list); + spin_unlock(&kvm->arch.kzdev_list_lock); + + mutex_unlock(&kvm->lock); + mutex_unlock(&zdev->kzdev_lock); + return 0; + +clear_gisa: + zdev->gisa = 0; +err: + if (zdev->kzdev) + kvm_s390_pci_dev_release(zdev); + mutex_unlock(&kvm->lock); + mutex_unlock(&zdev->kzdev_lock); + kvm_put_kvm(kvm); + return rc; +} +EXPORT_SYMBOL_GPL(kvm_s390_pci_register_kvm); + +void kvm_s390_pci_unregister_kvm(struct zpci_dev *zdev) +{ + struct kvm *kvm; + + if (!zdev) + return; + + mutex_lock(&zdev->kzdev_lock); + + if (WARN_ON(!zdev->kzdev)) { + mutex_unlock(&zdev->kzdev_lock); + return; + } + + kvm = zdev->kzdev->kvm; + mutex_lock(&kvm->lock); + + /* + * A 0 gisa means interpretation was never enabled, just remove the + * device from the list. + */ + if (zdev->gisa == 0) + goto out; + + /* Forwarding must be turned off before interpretation */ + if (zdev->kzdev->fib.fmt0.aibv != 0) + kvm_s390_pci_aif_disable(zdev, true); + + /* Remove the host CLP guest designation */ + zdev->gisa = 0; + + if (zdev_enabled(zdev)) { + if (zpci_disable_device(zdev)) + goto out; + } + + if (zpci_enable_device(zdev)) + goto out; + + /* Re-register the IOMMU that was already created */ + zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, + virt_to_phys(zdev->dma_table)); + +out: + spin_lock(&kvm->arch.kzdev_list_lock); + list_del(&zdev->kzdev->entry); + spin_unlock(&kvm->arch.kzdev_list_lock); + kvm_s390_pci_dev_release(zdev); + + mutex_unlock(&kvm->lock); + mutex_unlock(&zdev->kzdev_lock); + + kvm_put_kvm(kvm); +} +EXPORT_SYMBOL_GPL(kvm_s390_pci_unregister_kvm); + +void kvm_s390_pci_init_list(struct kvm *kvm) +{ + spin_lock_init(&kvm->arch.kzdev_list_lock); + INIT_LIST_HEAD(&kvm->arch.kzdev_list); +} + +void kvm_s390_pci_clear_list(struct kvm *kvm) +{ + /* + * This list should already be empty, either via vfio device closures + * or kvm fd cleanup. + */ + spin_lock(&kvm->arch.kzdev_list_lock); + WARN_ON_ONCE(!list_empty(&kvm->arch.kzdev_list)); + spin_unlock(&kvm->arch.kzdev_list_lock); +} + int kvm_s390_pci_init(void) { aift = kzalloc(sizeof(struct zpci_aift), GFP_KERNEL); diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h index 9d091033fc02..fb2b91b76e0c 100644 --- a/arch/s390/kvm/pci.h +++ b/arch/s390/kvm/pci.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ struct kvm_zdev { struct zpci_dev *zdev; struct kvm *kvm; struct zpci_fib fib; + struct list_head entry; }; struct zpci_gaite { @@ -54,6 +56,9 @@ static inline struct kvm *kvm_s390_pci_si_to_kvm(struct zpci_aift *aift, int kvm_s390_pci_aen_init(u8 nisc); void kvm_s390_pci_aen_exit(void); +void kvm_s390_pci_init_list(struct kvm *kvm); +void kvm_s390_pci_clear_list(struct kvm *kvm); + int kvm_s390_pci_init(void); void kvm_s390_pci_exit(void); diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index 86cd4d8446b1..73cdc5539384 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -132,6 +132,7 @@ int zpci_register_ioat(struct zpci_dev *zdev, u8 dmaas, zpci_dbg(3, "reg ioat fid:%x, cc:%d, status:%d\n", zdev->fid, cc, status); return cc; } +EXPORT_SYMBOL_GPL(zpci_register_ioat); /* Modify PCI: Unregister I/O address translation parameters */ int zpci_unregister_ioat(struct zpci_dev *zdev, u8 dmaas) @@ -712,6 +713,7 @@ int zpci_enable_device(struct zpci_dev *zdev) zpci_update_fh(zdev, fh); return rc; } +EXPORT_SYMBOL_GPL(zpci_enable_device); int zpci_disable_device(struct zpci_dev *zdev) { @@ -735,6 +737,7 @@ int zpci_disable_device(struct zpci_dev *zdev) } return rc; } +EXPORT_SYMBOL_GPL(zpci_disable_device); /** * zpci_hot_reset_device - perform a reset of the given zPCI function @@ -828,6 +831,7 @@ struct zpci_dev *zpci_create_device(u32 fid, u32 fh, enum zpci_state state) kref_init(&zdev->kref); mutex_init(&zdev->lock); + mutex_init(&zdev->kzdev_lock); rc = zpci_init_iommu(zdev); if (rc) From 8061d1c31f1a018281bc9877ecce44bfc779e21d Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:21 -0400 Subject: [PATCH 0904/1436] vfio-pci/zdev: add open/close device hooks During vfio-pci open_device, pass the KVM associated with the vfio group (if one exists). This is needed in order to pass a special indicator (GISA) to firmware to allow zPCI interpretation facilities to be used for only the specific KVM associated with the vfio-pci device. During vfio-pci close_device, unregister the notifier. Signed-off-by: Matthew Rosato Acked-by: Alex Williamson Reviewed-by: Pierre Morel Link: https://lore.kernel.org/r/20220606203325.110625-18-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- drivers/vfio/pci/vfio_pci_core.c | 10 +++++++++- drivers/vfio/pci/vfio_pci_zdev.c | 24 ++++++++++++++++++++++++ include/linux/vfio_pci_core.h | 10 ++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index a0d69ddaf90d..b1e5cfbadf38 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -316,10 +316,14 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) pci_write_config_word(pdev, PCI_COMMAND, cmd); } - ret = vfio_config_init(vdev); + ret = vfio_pci_zdev_open_device(vdev); if (ret) goto out_free_state; + ret = vfio_config_init(vdev); + if (ret) + goto out_free_zdev; + msix_pos = pdev->msix_cap; if (msix_pos) { u16 flags; @@ -340,6 +344,8 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) return 0; +out_free_zdev: + vfio_pci_zdev_close_device(vdev); out_free_state: kfree(vdev->pci_saved_state); vdev->pci_saved_state = NULL; @@ -418,6 +424,8 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev) vdev->needs_reset = true; + vfio_pci_zdev_close_device(vdev); + /* * If we have saved state, restore it. If we can reset the device, * even better. Resetting with current state seems better than diff --git a/drivers/vfio/pci/vfio_pci_zdev.c b/drivers/vfio/pci/vfio_pci_zdev.c index ea4c0d2b0663..686f2e75e392 100644 --- a/drivers/vfio/pci/vfio_pci_zdev.c +++ b/drivers/vfio/pci/vfio_pci_zdev.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -136,3 +137,26 @@ int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, return ret; } + +int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev) +{ + struct zpci_dev *zdev = to_zpci(vdev->pdev); + + if (!zdev) + return -ENODEV; + + if (!vdev->vdev.kvm) + return 0; + + return kvm_s390_pci_register_kvm(zdev, vdev->vdev.kvm); +} + +void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev) +{ + struct zpci_dev *zdev = to_zpci(vdev->pdev); + + if (!zdev || !vdev->vdev.kvm) + return; + + kvm_s390_pci_unregister_kvm(zdev); +} diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index 63af2897939c..d5d9e17f0156 100644 --- a/include/linux/vfio_pci_core.h +++ b/include/linux/vfio_pci_core.h @@ -209,12 +209,22 @@ static inline int vfio_pci_igd_init(struct vfio_pci_core_device *vdev) #ifdef CONFIG_VFIO_PCI_ZDEV_KVM extern int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, struct vfio_info_cap *caps); +int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev); +void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev); #else static inline int vfio_pci_info_zdev_add_caps(struct vfio_pci_core_device *vdev, struct vfio_info_cap *caps) { return -ENODEV; } + +static inline int vfio_pci_zdev_open_device(struct vfio_pci_core_device *vdev) +{ + return 0; +} + +static inline void vfio_pci_zdev_close_device(struct vfio_pci_core_device *vdev) +{} #endif /* Will be exported for vfio pci drivers usage */ From faf3bfcb895037ae2a8b89d1048090c9e1291cae Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:22 -0400 Subject: [PATCH 0905/1436] vfio-pci/zdev: add function handle to clp base capability The function handle is a system-wide unique identifier for a zPCI device. With zPCI instruction interpretation, the host will no longer be executing the zPCI instructions on behalf of the guest. As a result, the guest needs to use the real function handle in order for firmware to associate the instruction with the proper PCI function. Let's provide that handle to the guest. Reviewed-by: Christian Borntraeger Reviewed-by: Pierre Morel Signed-off-by: Matthew Rosato Acked-by: Alex Williamson Link: https://lore.kernel.org/r/20220606203325.110625-19-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- drivers/vfio/pci/vfio_pci_zdev.c | 5 +++-- include/uapi/linux/vfio_zdev.h | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_zdev.c b/drivers/vfio/pci/vfio_pci_zdev.c index 686f2e75e392..4f28cdd7ecd1 100644 --- a/drivers/vfio/pci/vfio_pci_zdev.c +++ b/drivers/vfio/pci/vfio_pci_zdev.c @@ -24,14 +24,15 @@ static int zpci_base_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) { struct vfio_device_info_cap_zpci_base cap = { .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_BASE, - .header.version = 1, + .header.version = 2, .start_dma = zdev->start_dma, .end_dma = zdev->end_dma, .pchid = zdev->pchid, .vfn = zdev->vfn, .fmb_length = zdev->fmb_length, .pft = zdev->pft, - .gid = zdev->pfgid + .gid = zdev->pfgid, + .fh = zdev->fh }; return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); diff --git a/include/uapi/linux/vfio_zdev.h b/include/uapi/linux/vfio_zdev.h index b4309397b6b2..78c022af3d29 100644 --- a/include/uapi/linux/vfio_zdev.h +++ b/include/uapi/linux/vfio_zdev.h @@ -29,6 +29,9 @@ struct vfio_device_info_cap_zpci_base { __u16 fmb_length; /* Measurement Block Length (in bytes) */ __u8 pft; /* PCI Function Type */ __u8 gid; /* PCI function group ID */ + /* End of version 1 */ + __u32 fh; /* PCI function handle */ + /* End of version 2 */ }; /** From ba6090ff8ae01b41288be87ed9f6bed3d8cf5961 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:23 -0400 Subject: [PATCH 0906/1436] vfio-pci/zdev: different maxstbl for interpreted devices When doing load/store interpretation, the maximum store block length is determined by the underlying firmware, not the host kernel API. Reflect that in the associated Query PCI Function Group clp capability and let userspace decide which is appropriate to present to the guest. Reviewed-by: Pierre Morel Signed-off-by: Matthew Rosato Acked-by: Alex Williamson Link: https://lore.kernel.org/r/20220606203325.110625-20-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- drivers/vfio/pci/vfio_pci_zdev.c | 6 ++++-- include/uapi/linux/vfio_zdev.h | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_zdev.c b/drivers/vfio/pci/vfio_pci_zdev.c index 4f28cdd7ecd1..e163aa9f6144 100644 --- a/drivers/vfio/pci/vfio_pci_zdev.c +++ b/drivers/vfio/pci/vfio_pci_zdev.c @@ -45,14 +45,16 @@ static int zpci_group_cap(struct zpci_dev *zdev, struct vfio_info_cap *caps) { struct vfio_device_info_cap_zpci_group cap = { .header.id = VFIO_DEVICE_INFO_CAP_ZPCI_GROUP, - .header.version = 1, + .header.version = 2, .dasm = zdev->dma_mask, .msi_addr = zdev->msi_addr, .flags = VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH, .mui = zdev->fmb_update, .noi = zdev->max_msi, .maxstbl = ZPCI_MAX_WRITE_SIZE, - .version = zdev->version + .version = zdev->version, + .reserved = 0, + .imaxstbl = zdev->maxstbl }; return vfio_info_add_capability(caps, &cap.header, sizeof(cap)); diff --git a/include/uapi/linux/vfio_zdev.h b/include/uapi/linux/vfio_zdev.h index 78c022af3d29..77f2aff1f27e 100644 --- a/include/uapi/linux/vfio_zdev.h +++ b/include/uapi/linux/vfio_zdev.h @@ -50,6 +50,10 @@ struct vfio_device_info_cap_zpci_group { __u16 noi; /* Maximum number of MSIs */ __u16 maxstbl; /* Maximum Store Block Length */ __u8 version; /* Supported PCI Version */ + /* End of version 1 */ + __u8 reserved; + __u16 imaxstbl; /* Maximum Interpreted Store Block Length */ + /* End of version 2 */ }; /** From db1c875e0539518e3d5fe9876ef50975cf4476bb Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:24 -0400 Subject: [PATCH 0907/1436] KVM: s390: add KVM_S390_ZPCI_OP to manage guest zPCI devices The KVM_S390_ZPCI_OP ioctl provides a mechanism for managing hardware-assisted virtualization features for s390x zPCI passthrough. Add the first 2 operations, which can be used to enable/disable the specified device for Adapter Event Notification interpretation. Signed-off-by: Matthew Rosato Acked-by: Pierre Morel Reviewed-by: Thomas Huth Link: https://lore.kernel.org/r/20220606203325.110625-21-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- Documentation/virt/kvm/api.rst | 47 +++++++++++++++++++ arch/s390/kvm/kvm-s390.c | 16 +++++++ arch/s390/kvm/pci.c | 85 ++++++++++++++++++++++++++++++++++ arch/s390/kvm/pci.h | 2 + include/uapi/linux/kvm.h | 31 +++++++++++++ 5 files changed, 181 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 11e00a46c610..d58354e9af8f 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -5802,6 +5802,53 @@ of CPUID leaf 0xD on the host. This ioctl injects an event channel interrupt directly to the guest vCPU. +4.137 KVM_S390_ZPCI_OP +-------------------- + +:Capability: KVM_CAP_S390_ZPCI_OP +:Architectures: s390 +:Type: vm ioctl +:Parameters: struct kvm_s390_zpci_op (in) +:Returns: 0 on success, <0 on error + +Used to manage hardware-assisted virtualization features for zPCI devices. + +Parameters are specified via the following structure:: + + struct kvm_s390_zpci_op { + /* in */ + __u32 fh; /* target device */ + __u8 op; /* operation to perform */ + __u8 pad[3]; + union { + /* for KVM_S390_ZPCIOP_REG_AEN */ + struct { + __u64 ibv; /* Guest addr of interrupt bit vector */ + __u64 sb; /* Guest addr of summary bit */ + __u32 flags; + __u32 noi; /* Number of interrupts */ + __u8 isc; /* Guest interrupt subclass */ + __u8 sbo; /* Offset of guest summary bit vector */ + __u16 pad; + } reg_aen; + __u64 reserved[8]; + } u; + }; + +The type of operation is specified in the "op" field. +KVM_S390_ZPCIOP_REG_AEN is used to register the VM for adapter event +notification interpretation, which will allow firmware delivery of adapter +events directly to the vm, with KVM providing a backup delivery mechanism; +KVM_S390_ZPCIOP_DEREG_AEN is used to subsequently disable interpretation of +adapter event notifications. + +The target zPCI function must also be specified via the "fh" field. For the +KVM_S390_ZPCIOP_REG_AEN operation, additional information to establish firmware +delivery must be provided via the "reg_aen" struct. + +The "pad" and "reserved" fields may be used for future extensions and should be +set to 0s by userspace. + 5. The kvm_run structure ======================== diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 4758bb731199..f214e0fc62ed 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -618,6 +618,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_S390_PROTECTED: r = is_prot_virt_host(); break; + case KVM_CAP_S390_ZPCI_OP: + r = kvm_s390_pci_interp_allowed(); + break; default: r = 0; } @@ -2629,6 +2632,19 @@ long kvm_arch_vm_ioctl(struct file *filp, r = -EFAULT; break; } + case KVM_S390_ZPCI_OP: { + struct kvm_s390_zpci_op args; + + r = -EINVAL; + if (!IS_ENABLED(CONFIG_VFIO_PCI_ZDEV_KVM)) + break; + if (copy_from_user(&args, argp, sizeof(args))) { + r = -EFAULT; + break; + } + r = kvm_s390_pci_zpci_op(kvm, &args); + break; + } default: r = -ENOTTY; } diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c index 24211741deb0..4946fb7757d6 100644 --- a/arch/s390/kvm/pci.c +++ b/arch/s390/kvm/pci.c @@ -585,6 +585,91 @@ void kvm_s390_pci_clear_list(struct kvm *kvm) spin_unlock(&kvm->arch.kzdev_list_lock); } +static struct zpci_dev *get_zdev_from_kvm_by_fh(struct kvm *kvm, u32 fh) +{ + struct zpci_dev *zdev = NULL; + struct kvm_zdev *kzdev; + + spin_lock(&kvm->arch.kzdev_list_lock); + list_for_each_entry(kzdev, &kvm->arch.kzdev_list, entry) { + if (kzdev->zdev->fh == fh) { + zdev = kzdev->zdev; + break; + } + } + spin_unlock(&kvm->arch.kzdev_list_lock); + + return zdev; +} + +static int kvm_s390_pci_zpci_reg_aen(struct zpci_dev *zdev, + struct kvm_s390_zpci_op *args) +{ + struct zpci_fib fib = {}; + bool hostflag; + + fib.fmt0.aibv = args->u.reg_aen.ibv; + fib.fmt0.isc = args->u.reg_aen.isc; + fib.fmt0.noi = args->u.reg_aen.noi; + if (args->u.reg_aen.sb != 0) { + fib.fmt0.aisb = args->u.reg_aen.sb; + fib.fmt0.aisbo = args->u.reg_aen.sbo; + fib.fmt0.sum = 1; + } else { + fib.fmt0.aisb = 0; + fib.fmt0.aisbo = 0; + fib.fmt0.sum = 0; + } + + hostflag = !(args->u.reg_aen.flags & KVM_S390_ZPCIOP_REGAEN_HOST); + return kvm_s390_pci_aif_enable(zdev, &fib, hostflag); +} + +int kvm_s390_pci_zpci_op(struct kvm *kvm, struct kvm_s390_zpci_op *args) +{ + struct kvm_zdev *kzdev; + struct zpci_dev *zdev; + int r; + + zdev = get_zdev_from_kvm_by_fh(kvm, args->fh); + if (!zdev) + return -ENODEV; + + mutex_lock(&zdev->kzdev_lock); + mutex_lock(&kvm->lock); + + kzdev = zdev->kzdev; + if (!kzdev) { + r = -ENODEV; + goto out; + } + if (kzdev->kvm != kvm) { + r = -EPERM; + goto out; + } + + switch (args->op) { + case KVM_S390_ZPCIOP_REG_AEN: + /* Fail on unknown flags */ + if (args->u.reg_aen.flags & ~KVM_S390_ZPCIOP_REGAEN_HOST) { + r = -EINVAL; + break; + } + r = kvm_s390_pci_zpci_reg_aen(zdev, args); + break; + case KVM_S390_ZPCIOP_DEREG_AEN: + r = kvm_s390_pci_aif_disable(zdev, false); + break; + default: + r = -EINVAL; + } + +out: + mutex_unlock(&kvm->lock); + mutex_unlock(&zdev->kzdev_lock); + return r; +} + int kvm_s390_pci_init(void) { aift = kzalloc(sizeof(struct zpci_aift), GFP_KERNEL); diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h index fb2b91b76e0c..0351382e990f 100644 --- a/arch/s390/kvm/pci.h +++ b/arch/s390/kvm/pci.h @@ -59,6 +59,8 @@ void kvm_s390_pci_aen_exit(void); void kvm_s390_pci_init_list(struct kvm *kvm); void kvm_s390_pci_clear_list(struct kvm *kvm); +int kvm_s390_pci_zpci_op(struct kvm *kvm, struct kvm_s390_zpci_op *args); + int kvm_s390_pci_init(void); void kvm_s390_pci_exit(void); diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 5088bd9f1922..2f302e2287d1 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1157,6 +1157,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_VM_TSC_CONTROL 214 #define KVM_CAP_SYSTEM_EVENT_DATA 215 #define KVM_CAP_ARM_SYSTEM_SUSPEND 216 +#define KVM_CAP_S390_ZPCI_OP 221 #ifdef KVM_CAP_IRQ_ROUTING @@ -2118,4 +2119,34 @@ struct kvm_stats_desc { /* Available with KVM_CAP_XSAVE2 */ #define KVM_GET_XSAVE2 _IOR(KVMIO, 0xcf, struct kvm_xsave) +/* Available with KVM_CAP_S390_ZPCI_OP */ +#define KVM_S390_ZPCI_OP _IOW(KVMIO, 0xd1, struct kvm_s390_zpci_op) + +struct kvm_s390_zpci_op { + /* in */ + __u32 fh; /* target device */ + __u8 op; /* operation to perform */ + __u8 pad[3]; + union { + /* for KVM_S390_ZPCIOP_REG_AEN */ + struct { + __u64 ibv; /* Guest addr of interrupt bit vector */ + __u64 sb; /* Guest addr of summary bit */ + __u32 flags; + __u32 noi; /* Number of interrupts */ + __u8 isc; /* Guest interrupt subclass */ + __u8 sbo; /* Offset of guest summary bit vector */ + __u16 pad; + } reg_aen; + __u64 reserved[8]; + } u; +}; + +/* types for kvm_s390_zpci_op->op */ +#define KVM_S390_ZPCIOP_REG_AEN 0 +#define KVM_S390_ZPCIOP_DEREG_AEN 1 + +/* flags for kvm_s390_zpci_op->u.reg_aen.flags */ +#define KVM_S390_ZPCIOP_REGAEN_HOST (1 << 0) + #endif /* __LINUX_KVM_H */ From 4ac34b94a5342544baa72ce09fc5e825a9d35070 Mon Sep 17 00:00:00 2001 From: Matthew Rosato Date: Mon, 6 Jun 2022 16:33:25 -0400 Subject: [PATCH 0908/1436] MAINTAINERS: additional files related kvm s390 pci passthrough Add entries from the s390 kvm subdirectory related to pci passthrough. Acked-by: Christian Borntraeger Signed-off-by: Matthew Rosato Reviewed-by: Thomas Huth Link: https://lore.kernel.org/r/20220606203325.110625-22-mjrosato@linux.ibm.com Signed-off-by: Christian Borntraeger --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index a6d3bd9d2a8d..3dd8657f5482 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17454,6 +17454,7 @@ M: Eric Farman L: linux-s390@vger.kernel.org L: kvm@vger.kernel.org S: Supported +F: arch/s390/kvm/pci* F: drivers/vfio/pci/vfio_pci_zdev.c F: include/uapi/linux/vfio_zdev.h From 6a0c054930d554ad8f8044ef1fc856d9da391c81 Mon Sep 17 00:00:00 2001 From: Duoming Zhou Date: Sun, 10 Jul 2022 18:30:02 +0800 Subject: [PATCH 0909/1436] staging: rtl8192u: Fix sleep in atomic context bug in dm_fsync_timer_callback There are sleep in atomic context bugs when dm_fsync_timer_callback is executing. The root cause is that the memory allocation functions with GFP_KERNEL or GFP_NOIO parameters are called in dm_fsync_timer_callback which is a timer handler. The call paths that could trigger bugs are shown below: (interrupt context) dm_fsync_timer_callback write_nic_byte kzalloc(sizeof(data), GFP_KERNEL); //may sleep usb_control_msg kmalloc(.., GFP_NOIO); //may sleep write_nic_dword kzalloc(sizeof(data), GFP_KERNEL); //may sleep usb_control_msg kmalloc(.., GFP_NOIO); //may sleep This patch uses delayed work to replace timer and moves the operations that may sleep into the delayed work in order to mitigate bugs. Fixes: 8fc8598e61f6 ("Staging: Added Realtek rtl8192u driver to staging") Signed-off-by: Duoming Zhou Link: https://lore.kernel.org/r/20220710103002.63283-1-duoming@zju.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192u/r8192U.h | 2 +- drivers/staging/rtl8192u/r8192U_dm.c | 38 +++++++++++++--------------- drivers/staging/rtl8192u/r8192U_dm.h | 2 +- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/staging/rtl8192u/r8192U.h b/drivers/staging/rtl8192u/r8192U.h index 14ca00a2789b..1942cb849374 100644 --- a/drivers/staging/rtl8192u/r8192U.h +++ b/drivers/staging/rtl8192u/r8192U.h @@ -1013,7 +1013,7 @@ typedef struct r8192_priv { bool bis_any_nonbepkts; bool bcurrent_turbo_EDCA; bool bis_cur_rdlstate; - struct timer_list fsync_timer; + struct delayed_work fsync_work; bool bfsync_processing; /* 500ms Fsync timer is active or not */ u32 rate_record; u32 rateCountDiffRecord; diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c index 916618ddc4b7..00fc8fd344db 100644 --- a/drivers/staging/rtl8192u/r8192U_dm.c +++ b/drivers/staging/rtl8192u/r8192U_dm.c @@ -2578,19 +2578,20 @@ static void dm_init_fsync(struct net_device *dev) priv->ieee80211->fsync_seconddiff_ratethreshold = 200; priv->ieee80211->fsync_state = Default_Fsync; priv->framesyncMonitor = 1; /* current default 0xc38 monitor on */ - timer_setup(&priv->fsync_timer, dm_fsync_timer_callback, 0); + INIT_DELAYED_WORK(&priv->fsync_work, dm_fsync_work_callback); } static void dm_deInit_fsync(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); - del_timer_sync(&priv->fsync_timer); + cancel_delayed_work_sync(&priv->fsync_work); } -void dm_fsync_timer_callback(struct timer_list *t) +void dm_fsync_work_callback(struct work_struct *work) { - struct r8192_priv *priv = from_timer(priv, t, fsync_timer); + struct r8192_priv *priv = + container_of(work, struct r8192_priv, fsync_work.work); struct net_device *dev = priv->ieee80211->dev; u32 rate_index, rate_count = 0, rate_count_diff = 0; bool bSwitchFromCountDiff = false; @@ -2657,17 +2658,16 @@ void dm_fsync_timer_callback(struct timer_list *t) } } if (bDoubleTimeInterval) { - if (timer_pending(&priv->fsync_timer)) - del_timer_sync(&priv->fsync_timer); - priv->fsync_timer.expires = jiffies + - msecs_to_jiffies(priv->ieee80211->fsync_time_interval*priv->ieee80211->fsync_multiple_timeinterval); - add_timer(&priv->fsync_timer); + cancel_delayed_work_sync(&priv->fsync_work); + schedule_delayed_work(&priv->fsync_work, + msecs_to_jiffies(priv + ->ieee80211->fsync_time_interval * + priv->ieee80211->fsync_multiple_timeinterval)); } else { - if (timer_pending(&priv->fsync_timer)) - del_timer_sync(&priv->fsync_timer); - priv->fsync_timer.expires = jiffies + - msecs_to_jiffies(priv->ieee80211->fsync_time_interval); - add_timer(&priv->fsync_timer); + cancel_delayed_work_sync(&priv->fsync_work); + schedule_delayed_work(&priv->fsync_work, + msecs_to_jiffies(priv + ->ieee80211->fsync_time_interval)); } } else { /* Let Register return to default value; */ @@ -2695,7 +2695,7 @@ static void dm_EndSWFsync(struct net_device *dev) struct r8192_priv *priv = ieee80211_priv(dev); RT_TRACE(COMP_HALDM, "%s\n", __func__); - del_timer_sync(&(priv->fsync_timer)); + cancel_delayed_work_sync(&priv->fsync_work); /* Let Register return to default value; */ if (priv->bswitch_fsync) { @@ -2736,11 +2736,9 @@ static void dm_StartSWFsync(struct net_device *dev) if (priv->ieee80211->fsync_rate_bitmap & rateBitmap) priv->rate_record += priv->stats.received_rate_histogram[1][rateIndex]; } - if (timer_pending(&priv->fsync_timer)) - del_timer_sync(&priv->fsync_timer); - priv->fsync_timer.expires = jiffies + - msecs_to_jiffies(priv->ieee80211->fsync_time_interval); - add_timer(&priv->fsync_timer); + cancel_delayed_work_sync(&priv->fsync_work); + schedule_delayed_work(&priv->fsync_work, + msecs_to_jiffies(priv->ieee80211->fsync_time_interval)); write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c12cd); } diff --git a/drivers/staging/rtl8192u/r8192U_dm.h b/drivers/staging/rtl8192u/r8192U_dm.h index 0b2a1c688597..2159018b4e38 100644 --- a/drivers/staging/rtl8192u/r8192U_dm.h +++ b/drivers/staging/rtl8192u/r8192U_dm.h @@ -166,7 +166,7 @@ void dm_force_tx_fw_info(struct net_device *dev, void dm_init_edca_turbo(struct net_device *dev); void dm_rf_operation_test_callback(unsigned long data); void dm_rf_pathcheck_workitemcallback(struct work_struct *work); -void dm_fsync_timer_callback(struct timer_list *t); +void dm_fsync_work_callback(struct work_struct *work); void dm_cck_txpower_adjust(struct net_device *dev, bool binch14); void dm_shadow_init(struct net_device *dev); void dm_initialize_txpower_tracking(struct net_device *dev); From ae9411408cf0263d08f8fe819380bb8ac90031af Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 9 Jul 2022 11:44:54 +0200 Subject: [PATCH 0910/1436] staging: r8188eu: remove HW_VAR_BASIC_RATE from SetHwReg8188EU() Remove the HW_VAR_BASIC_RATE case from SetHwReg8188EU() and move the functionality to a separate function. This is part of the ongoing effort to get rid of SetHwReg8188EU(). Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220709094458.9578-2-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 2 +- drivers/staging/r8188eu/core/rtw_wlan_util.c | 41 ++++++++++++++++++- drivers/staging/r8188eu/hal/usb_halinit.c | 37 ----------------- drivers/staging/r8188eu/include/hal_intf.h | 1 - .../staging/r8188eu/include/rtw_mlme_ext.h | 1 + 5 files changed, 42 insertions(+), 40 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 21485c57dc3f..a16996982b58 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -6681,7 +6681,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) /* update IOT-releated issue */ update_IOT_info(padapter); - SetHwReg8188EU(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates); + rtw_set_basic_rate(padapter, cur_network->SupportedRates); /* BCN interval */ rtw_write16(padapter, REG_BCN_INTERVAL, pmlmeinfo->bcn_interval); diff --git a/drivers/staging/r8188eu/core/rtw_wlan_util.c b/drivers/staging/r8188eu/core/rtw_wlan_util.c index aa6b549fd54d..60c49e161c12 100644 --- a/drivers/staging/r8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/r8188eu/core/rtw_wlan_util.c @@ -1265,6 +1265,45 @@ void set_sta_rate(struct adapter *padapter, struct sta_info *psta) enable_rate_adaptive(padapter, psta->mac_id); } +void rtw_set_basic_rate(struct adapter *adapter, u8 *rates) +{ + u16 BrateCfg = 0; + u8 RateIndex = 0; + int res; + u8 reg; + + /* 2007.01.16, by Emily */ + /* Select RRSR (in Legacy-OFDM and CCK) */ + /* For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. */ + /* We do not use other rates. */ + HalSetBrateCfg(adapter, rates, &BrateCfg); + + /* 2011.03.30 add by Luke Lee */ + /* CCK 2M ACK should be disabled for some BCM and Atheros AP IOT */ + /* because CCK 2M has poor TXEVM */ + /* CCK 5.5M & 11M ACK should be enabled for better performance */ + + BrateCfg = (BrateCfg | 0xd) & 0x15d; + + BrateCfg |= 0x01; /* default enable 1M ACK rate */ + /* Set RRSR rate table. */ + rtw_write8(adapter, REG_RRSR, BrateCfg & 0xff); + rtw_write8(adapter, REG_RRSR + 1, (BrateCfg >> 8) & 0xff); + res = rtw_read8(adapter, REG_RRSR + 2, ®); + if (res) + return; + + rtw_write8(adapter, REG_RRSR + 2, reg & 0xf0); + + /* Set RTS initial rate */ + while (BrateCfg > 0x1) { + BrateCfg = (BrateCfg >> 1); + RateIndex++; + } + /* Ziv - Check */ + rtw_write8(adapter, REG_INIRTS_RATE_SEL, RateIndex); +} + /* Update RRSR and Rate for USERATE */ void update_tx_basic_rate(struct adapter *padapter, u8 wirelessmode) { @@ -1290,7 +1329,7 @@ void update_tx_basic_rate(struct adapter *padapter, u8 wirelessmode) else update_mgnt_tx_rate(padapter, IEEE80211_OFDM_RATE_6MB); - SetHwReg8188EU(padapter, HW_VAR_BASIC_RATE, supported_rates); + rtw_set_basic_rate(padapter, supported_rates); } unsigned char check_assoc_AP(u8 *pframe, uint len) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 1a08de85a6ae..97893543d861 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -1071,43 +1071,6 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) case HW_VAR_SET_OPMODE: hw_var_set_opmode(Adapter, val); break; - case HW_VAR_BASIC_RATE: - { - u16 BrateCfg = 0; - u8 RateIndex = 0; - - /* 2007.01.16, by Emily */ - /* Select RRSR (in Legacy-OFDM and CCK) */ - /* For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M, and 1M from the Basic rate. */ - /* We do not use other rates. */ - HalSetBrateCfg(Adapter, val, &BrateCfg); - - /* 2011.03.30 add by Luke Lee */ - /* CCK 2M ACK should be disabled for some BCM and Atheros AP IOT */ - /* because CCK 2M has poor TXEVM */ - /* CCK 5.5M & 11M ACK should be enabled for better performance */ - - BrateCfg = (BrateCfg | 0xd) & 0x15d; - - BrateCfg |= 0x01; /* default enable 1M ACK rate */ - /* Set RRSR rate table. */ - rtw_write8(Adapter, REG_RRSR, BrateCfg & 0xff); - rtw_write8(Adapter, REG_RRSR + 1, (BrateCfg >> 8) & 0xff); - res = rtw_read8(Adapter, REG_RRSR + 2, ®); - if (res) - return; - - rtw_write8(Adapter, REG_RRSR + 2, reg & 0xf0); - - /* Set RTS initial rate */ - while (BrateCfg > 0x1) { - BrateCfg = (BrateCfg >> 1); - RateIndex++; - } - /* Ziv - Check */ - rtw_write8(Adapter, REG_INIRTS_RATE_SEL, RateIndex); - } - break; case HW_VAR_CORRECT_TSF: { u64 tsf; diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index b81144932d9a..3e0ee33aa131 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -10,7 +10,6 @@ enum hw_variables { HW_VAR_SET_OPMODE, - HW_VAR_BASIC_RATE, HW_VAR_CORRECT_TSF, HW_VAR_MLME_SITESURVEY, HW_VAR_DM_FLAG, diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h index 56c0e584bb6c..3cc475aa912a 100644 --- a/drivers/staging/r8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h @@ -455,6 +455,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len); void update_IOT_info(struct adapter *padapter); void update_capinfo(struct adapter *adapter, u16 updatecap); void update_wireless_mode(struct adapter *padapter); +void rtw_set_basic_rate(struct adapter *adapter, u8 *rates); void update_tx_basic_rate(struct adapter *padapter, u8 modulation); void update_bmc_sta_support_rate(struct adapter *padapter, u32 mac_id); int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, From 7644e877bab56223505ed3361d7cb287c0f34152 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 9 Jul 2022 11:44:55 +0200 Subject: [PATCH 0911/1436] staging: r8188eu: remove HW_VAR_DM_FUNC_OP from SetHwReg8188EU() Remove the HW_VAR_DM_FUNC_OP case from SetHwReg8188EU() and move the functionality to the functions that call SetHwReg8188EU() with HW_VAR_DM_FUNC_OP. This is part of the ongoing effort to get rid of SetHwReg8188EU(). Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220709094458.9578-3-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_wlan_util.c | 10 ++++++---- drivers/staging/r8188eu/hal/usb_halinit.c | 6 ------ drivers/staging/r8188eu/include/hal_intf.h | 1 - 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_wlan_util.c b/drivers/staging/r8188eu/core/rtw_wlan_util.c index 60c49e161c12..b48e0b9dfd7b 100644 --- a/drivers/staging/r8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/r8188eu/core/rtw_wlan_util.c @@ -264,16 +264,18 @@ void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen) void Save_DM_Func_Flag(struct adapter *padapter) { - u8 saveflag = true; + struct hal_data_8188e *haldata = &padapter->haldata; + struct odm_dm_struct *odmpriv = &haldata->odmpriv; - SetHwReg8188EU(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&saveflag)); + odmpriv->BK_SupportAbility = odmpriv->SupportAbility; } void Restore_DM_Func_Flag(struct adapter *padapter) { - u8 saveflag = false; + struct hal_data_8188e *haldata = &padapter->haldata; + struct odm_dm_struct *odmpriv = &haldata->odmpriv; - SetHwReg8188EU(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&saveflag)); + odmpriv->SupportAbility = odmpriv->BK_SupportAbility; } void Set_MSR(struct adapter *padapter, u8 type) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 97893543d861..0aae713d2c1c 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -1160,12 +1160,6 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) case HW_VAR_DM_FLAG: podmpriv->SupportAbility = *((u8 *)val); break; - case HW_VAR_DM_FUNC_OP: - if (val[0]) - podmpriv->BK_SupportAbility = podmpriv->SupportAbility; - else - podmpriv->SupportAbility = podmpriv->BK_SupportAbility; - break; case HW_VAR_DM_FUNC_RESET: podmpriv->SupportAbility = pdmpriv->InitODMFlag; break; diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index 3e0ee33aa131..261823e7e8e8 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -13,7 +13,6 @@ enum hw_variables { HW_VAR_CORRECT_TSF, HW_VAR_MLME_SITESURVEY, HW_VAR_DM_FLAG, - HW_VAR_DM_FUNC_OP, HW_VAR_DM_FUNC_RESET, HW_VAR_DM_FUNC_CLR, }; From f18ab26f7714b26db3f044891b0872847e1c30da Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 9 Jul 2022 11:44:56 +0200 Subject: [PATCH 0912/1436] staging: r8188eu: remove HW_VAR_DM_FLAG from SetHwReg8188EU() Remove the HW_VAR_DM_FLAG case from SetHwReg8188EU() and move its functionality to a static function. This is part of the ongoing effort to get rid of SetHwReg8188EU(). Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220709094458.9578-4-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/usb_halinit.c | 3 --- drivers/staging/r8188eu/include/hal_intf.h | 1 - drivers/staging/r8188eu/os_dep/ioctl_linux.c | 10 +++++++++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 0aae713d2c1c..ece57565b082 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -1157,9 +1157,6 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) rtw_write32(Adapter, REG_RCR, reg32 | RCR_CBSSID_BCN); } break; - case HW_VAR_DM_FLAG: - podmpriv->SupportAbility = *((u8 *)val); - break; case HW_VAR_DM_FUNC_RESET: podmpriv->SupportAbility = pdmpriv->InitODMFlag; break; diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index 261823e7e8e8..89aeb6c2229f 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -12,7 +12,6 @@ enum hw_variables { HW_VAR_SET_OPMODE, HW_VAR_CORRECT_TSF, HW_VAR_MLME_SITESURVEY, - HW_VAR_DM_FLAG, HW_VAR_DM_FUNC_RESET, HW_VAR_DM_FUNC_CLR, }; diff --git a/drivers/staging/r8188eu/os_dep/ioctl_linux.c b/drivers/staging/r8188eu/os_dep/ioctl_linux.c index 047e9c7d38c3..930bb4aea435 100644 --- a/drivers/staging/r8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/r8188eu/os_dep/ioctl_linux.c @@ -3221,6 +3221,14 @@ static void rtw_set_dynamic_functions(struct adapter *adapter, u8 dm_func) } } +static void rtw_set_dm_func_flag(struct adapter *adapter, u32 odm_flag) +{ + struct hal_data_8188e *haldata = &adapter->haldata; + struct odm_dm_struct *odmpriv = &haldata->odmpriv; + + odmpriv->SupportAbility = odm_flag; +} + static int rtw_dbg_port(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -3459,7 +3467,7 @@ static int rtw_dbg_port(struct net_device *dev, case 0x06: { u32 ODMFlag = (u32)(0x0f & arg); - SetHwReg8188EU(padapter, HW_VAR_DM_FLAG, (u8 *)(&ODMFlag)); + rtw_set_dm_func_flag(padapter, ODMFlag); } break; case 0x07: From 8ad697c3d7f89439fa203023a7d071f08f98157b Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 9 Jul 2022 11:44:57 +0200 Subject: [PATCH 0913/1436] staging: r8188eu: remove HW_VAR_DM_FUNC_RESET from SetHwReg8188EU() Remove the HW_VAR_DM_FUNC_RESET case from SetHwReg8188EU() and move its functionality to a static function. This is part of the ongoing effort to get rid of SetHwReg8188EU(). Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220709094458.9578-5-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 11 ++++++++++- drivers/staging/r8188eu/hal/usb_halinit.c | 4 ---- drivers/staging/r8188eu/include/hal_intf.h | 1 - 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index a16996982b58..31d936ad063a 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -6646,6 +6646,15 @@ void update_sta_info(struct adapter *padapter, struct sta_info *psta) psta->state = _FW_LINKED; } +static void rtw_reset_dm_func_flag(struct adapter *adapter) +{ + struct hal_data_8188e *haldata = &adapter->haldata; + struct dm_priv *dmpriv = &haldata->dmpriv; + struct odm_dm_struct *odmpriv = &haldata->odmpriv; + + odmpriv->SupportAbility = dmpriv->InitODMFlag; +} + void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) { struct sta_info *psta, *psta_bmc; @@ -6676,7 +6685,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) } /* turn on dynamic functions */ - SetHwReg8188EU(padapter, HW_VAR_DM_FUNC_RESET, NULL); + rtw_reset_dm_func_flag(padapter); /* update IOT-releated issue */ update_IOT_info(padapter); diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index ece57565b082..92446cd1a096 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -1062,7 +1062,6 @@ static void hw_var_set_opmode(struct adapter *Adapter, u8 *val) void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) { struct hal_data_8188e *haldata = &Adapter->haldata; - struct dm_priv *pdmpriv = &haldata->dmpriv; struct odm_dm_struct *podmpriv = &haldata->odmpriv; u8 reg; int res; @@ -1157,9 +1156,6 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) rtw_write32(Adapter, REG_RCR, reg32 | RCR_CBSSID_BCN); } break; - case HW_VAR_DM_FUNC_RESET: - podmpriv->SupportAbility = pdmpriv->InitODMFlag; - break; case HW_VAR_DM_FUNC_CLR: podmpriv->SupportAbility = 0; break; diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index 89aeb6c2229f..d33e75bcac74 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -12,7 +12,6 @@ enum hw_variables { HW_VAR_SET_OPMODE, HW_VAR_CORRECT_TSF, HW_VAR_MLME_SITESURVEY, - HW_VAR_DM_FUNC_RESET, HW_VAR_DM_FUNC_CLR, }; From 3782d959986f75cdedca317323b00910b9069d89 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sat, 9 Jul 2022 11:44:58 +0200 Subject: [PATCH 0914/1436] staging: r8188eu: remove HW_VAR_DM_FUNC_CLR from SetHwReg8188EU() Remove the HW_VAR_DM_FUNC_CLR case from SetHwReg8188EU() and move its functionality to a static function. This is part of the ongoing effort to get rid of SetHwReg8188EU(). Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220709094458.9578-6-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 12 ++++++++++-- drivers/staging/r8188eu/hal/usb_halinit.c | 5 ----- drivers/staging/r8188eu/include/hal_intf.h | 1 - 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 31d936ad063a..eecb00e41d6a 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -6655,6 +6655,14 @@ static void rtw_reset_dm_func_flag(struct adapter *adapter) odmpriv->SupportAbility = dmpriv->InitODMFlag; } +static void rtw_clear_dm_func_flag(struct adapter *adapter) +{ + struct hal_data_8188e *haldata = &adapter->haldata; + struct odm_dm_struct *odmpriv = &haldata->odmpriv; + + odmpriv->SupportAbility = 0; +} + void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) { struct sta_info *psta, *psta_bmc; @@ -7110,7 +7118,7 @@ u8 createbss_hdl(struct adapter *padapter, u8 *pbuf) /* disable dynamic functions, such as high power, DIG */ Save_DM_Func_Flag(padapter); - SetHwReg8188EU(padapter, HW_VAR_DM_FUNC_CLR, NULL); + rtw_clear_dm_func_flag(padapter); /* cancel link timer */ _cancel_timer_ex(&pmlmeext->link_timer); @@ -7380,7 +7388,7 @@ u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf) if ((pmlmeext->sitesurvey_res.state == SCAN_START) || (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) { /* disable dynamic functions, such as high power, DIG */ Save_DM_Func_Flag(padapter); - SetHwReg8188EU(padapter, HW_VAR_DM_FUNC_CLR, NULL); + rtw_clear_dm_func_flag(padapter); /* config the initial gain under scanning, need to write the BB registers */ if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 92446cd1a096..04beded95475 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -1061,8 +1061,6 @@ static void hw_var_set_opmode(struct adapter *Adapter, u8 *val) void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) { - struct hal_data_8188e *haldata = &Adapter->haldata; - struct odm_dm_struct *podmpriv = &haldata->odmpriv; u8 reg; int res; @@ -1156,9 +1154,6 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) rtw_write32(Adapter, REG_RCR, reg32 | RCR_CBSSID_BCN); } break; - case HW_VAR_DM_FUNC_CLR: - podmpriv->SupportAbility = 0; - break; default: break; } diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index d33e75bcac74..c1db7f834e20 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -12,7 +12,6 @@ enum hw_variables { HW_VAR_SET_OPMODE, HW_VAR_CORRECT_TSF, HW_VAR_MLME_SITESURVEY, - HW_VAR_DM_FUNC_CLR, }; typedef s32 (*c2h_id_filter)(u8 id); From ba68103d0f7af3e80286c74f7406b7b9a5334d3b Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:47 +0200 Subject: [PATCH 0915/1436] staging: r8188eu: remove unused eeprom defines Remove some eeprom-related defines which are not used by the r8188eu driver. This driver uses BOOT_FROM_EEPROM and EEPROM_EN instead of the defines that this patch removes. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-2-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/include/rtl8188e_spec.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/staging/r8188eu/include/rtl8188e_spec.h b/drivers/staging/r8188eu/include/rtl8188e_spec.h index ce5dd2e5b72a..9e7b1f89037c 100644 --- a/drivers/staging/r8188eu/include/rtl8188e_spec.h +++ b/drivers/staging/r8188eu/include/rtl8188e_spec.h @@ -426,12 +426,6 @@ #define MAX_MSS_DENSITY_2T 0x13 #define MAX_MSS_DENSITY_1T 0x0A -/* EEPROM enable when set 1 */ -#define CmdEEPROM_En BIT(5) -/* System EEPROM select, 0: boot from E-FUSE, 1: The EEPROM used is 9346 */ -#define CmdEERPOMSEL BIT(4) -#define Cmd9346CR_9356SEL BIT(4) - /* 8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) */ #define GPIOSEL_GPIO 0 #define GPIOSEL_ENBT BIT(5) From af4e6efda54da8520e6c7b73f34798fa3e5c088d Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:48 +0200 Subject: [PATCH 0916/1436] staging: r8188eu: remove EepromOrEfuse from struct eeprom_priv The EepromOrEfuse flag in struct eeprom_priv is used only in the ReadAdapterInfo8188EU function. We can remove EepromOrEfuse from struct eeprom_priv. As the meaning of EepromOrEfuse isn't obvious, there is a macro is_boot_from_eeprom that's used for checking the value. We don't need the macro, writing the check as !(eeValue & BOOT_FROM_EEPROM) makes it clear what is checked. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-3-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/usb_halinit.c | 3 +-- drivers/staging/r8188eu/include/hal_intf.h | 2 -- drivers/staging/r8188eu/include/rtw_eeprom.h | 1 - 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 04beded95475..2d5d81e96c8b 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -937,10 +937,9 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) if (res) return; - eeprom->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM); eeprom->bautoload_fail_flag = !(eeValue & EEPROM_EN); - if (!is_boot_from_eeprom(Adapter)) + if (!(eeValue & BOOT_FROM_EEPROM)) EFUSE_ShadowMapUpdate(Adapter); /* parse the eeprom/efuse content */ diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index c1db7f834e20..4e0a2a4f2f02 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -16,8 +16,6 @@ enum hw_variables { typedef s32 (*c2h_id_filter)(u8 id); -#define is_boot_from_eeprom(adapter) (adapter->eeprompriv.EepromOrEfuse) - void rtl8188eu_interface_configure(struct adapter *adapt); void ReadAdapterInfo8188EU(struct adapter *Adapter); void rtl8188eu_init_default_value(struct adapter *adapt); diff --git a/drivers/staging/r8188eu/include/rtw_eeprom.h b/drivers/staging/r8188eu/include/rtw_eeprom.h index d8d48ace356c..40c61f7a03be 100644 --- a/drivers/staging/r8188eu/include/rtw_eeprom.h +++ b/drivers/staging/r8188eu/include/rtw_eeprom.h @@ -12,7 +12,6 @@ struct eeprom_priv { u8 bautoload_fail_flag; u8 mac_addr[ETH_ALEN] __aligned(2); /* PermanentAddress */ - u8 EepromOrEfuse; u8 efuse_eeprom_data[HWSET_MAX_SIZE_512] __aligned(4); }; From 1c4d6546c3a4ee20e2f5ba525e35e779614954c8 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:49 +0200 Subject: [PATCH 0917/1436] staging: r8188eu: remove eeprom function prototypes Remove prototypes for non-existing eeprom functions. It seems that r8188eu has efuses but no eeprom. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-4-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/include/rtw_eeprom.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/staging/r8188eu/include/rtw_eeprom.h b/drivers/staging/r8188eu/include/rtw_eeprom.h index 40c61f7a03be..0a8792428927 100644 --- a/drivers/staging/r8188eu/include/rtw_eeprom.h +++ b/drivers/staging/r8188eu/include/rtw_eeprom.h @@ -15,10 +15,4 @@ struct eeprom_priv { u8 efuse_eeprom_data[HWSET_MAX_SIZE_512] __aligned(4); }; -void eeprom_write16(struct adapter *padapter, u16 reg, u16 data); -u16 eeprom_read16(struct adapter *padapter, u16 reg); -void read_eeprom_content(struct adapter *padapter); -void eeprom_read_sz(struct adapter *adapt, u16 reg, u8 *data, u32 sz); -void read_eeprom_content_by_attrib(struct adapter *padapter); - #endif /* __RTL871X_EEPROM_H__ */ From 14dbcfc4c9368d3a45db0d2d94f6b23708c72bf5 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:50 +0200 Subject: [PATCH 0918/1436] staging: r8188eu: merge EFUSE_ShadowMapUpdate with its caller Merge the EFUSE_ShadowMapUpdate function into ReadAdapterInfo8188EU, which is the only caller. Merging the two functions makes it clearer that eeprom->efuse_eeprom_data is in fact a temporary buffer that stores info read from efuses. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-5-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_efuse.c | 30 --------------------- drivers/staging/r8188eu/hal/usb_halinit.c | 11 ++++++-- drivers/staging/r8188eu/include/rtw_efuse.h | 2 -- 3 files changed, 9 insertions(+), 34 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_efuse.c b/drivers/staging/r8188eu/core/rtw_efuse.c index 8005ed8d3a20..df9534dd25cb 100644 --- a/drivers/staging/r8188eu/core/rtw_efuse.c +++ b/drivers/staging/r8188eu/core/rtw_efuse.c @@ -72,33 +72,3 @@ ReadEFuseByte( /* FIXME: return an error to caller */ } - -/*----------------------------------------------------------------------------- - * Function: EFUSE_ShadowMapUpdate - * - * Overview: Transfer current EFUSE content to shadow init and modify map. - * - * Input: NONE - * - * Output: NONE - * - * Return: NONE - * - * Revised History: - * When Who Remark - * 11/13/2008 MHC Create Version 0. - * - *---------------------------------------------------------------------------*/ -void EFUSE_ShadowMapUpdate(struct adapter *pAdapter) -{ - struct eeprom_priv *pEEPROM = &pAdapter->eeprompriv; - - if (pEEPROM->bautoload_fail_flag) { - memset(pEEPROM->efuse_eeprom_data, 0xFF, EFUSE_MAP_LEN_88E); - return; - } - - rtl8188e_EfusePowerSwitch(pAdapter, true); - rtl8188e_ReadEFuse(pAdapter, 0, EFUSE_MAP_LEN_88E, pEEPROM->efuse_eeprom_data); - rtl8188e_EfusePowerSwitch(pAdapter, false); -} diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 2d5d81e96c8b..8b9c3dea589b 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -939,8 +939,15 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) eeprom->bautoload_fail_flag = !(eeValue & EEPROM_EN); - if (!(eeValue & BOOT_FROM_EEPROM)) - EFUSE_ShadowMapUpdate(Adapter); + if (!(eeValue & BOOT_FROM_EEPROM)) { + if (eeprom->bautoload_fail_flag) { + memset(eeprom->efuse_eeprom_data, 0xFF, EFUSE_MAP_LEN_88E); + } else { + rtl8188e_EfusePowerSwitch(Adapter, true); + rtl8188e_ReadEFuse(Adapter, 0, EFUSE_MAP_LEN_88E, eeprom->efuse_eeprom_data); + rtl8188e_EfusePowerSwitch(Adapter, false); + } + } /* parse the eeprom/efuse content */ Hal_EfuseParseIDCode88E(Adapter, eeprom->efuse_eeprom_data); diff --git a/drivers/staging/r8188eu/include/rtw_efuse.h b/drivers/staging/r8188eu/include/rtw_efuse.h index 2daf69f554d5..3d688a0e6dfb 100644 --- a/drivers/staging/r8188eu/include/rtw_efuse.h +++ b/drivers/staging/r8188eu/include/rtw_efuse.h @@ -8,6 +8,4 @@ void ReadEFuseByte(struct adapter *adapter, u16 _offset, u8 *pbuf); -void EFUSE_ShadowMapUpdate(struct adapter *adapter); - #endif From 698bd81fe887ff66b9f4fb95b07da25fb1f06e3d Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:51 +0200 Subject: [PATCH 0919/1436] staging: r8188eu: use a local buffer for efuse data The efuse_eeprom_data array in struct eeprom_priv is used only by ReadAdapterInfo8188EU. We can remove efuse_eeprom_data and use a local buffer instead. Use EFUSE_MAP_LEN_88E as buffer size. Its value is the same as HWSET_MAX_SIZE_512. The functions that access the buffer use EFUSE_MAP_LEN_88E for its size. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-6-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/usb_halinit.c | 21 ++++++++++---------- drivers/staging/r8188eu/include/rtw_eeprom.h | 3 --- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 8b9c3dea589b..32f25312ffd7 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -929,6 +929,7 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) { struct eeprom_priv *eeprom = &Adapter->eeprompriv; struct led_priv *ledpriv = &Adapter->ledpriv; + u8 efuse_buf[EFUSE_MAP_LEN_88E] __aligned(4); u8 eeValue; int res; @@ -941,24 +942,24 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) if (!(eeValue & BOOT_FROM_EEPROM)) { if (eeprom->bautoload_fail_flag) { - memset(eeprom->efuse_eeprom_data, 0xFF, EFUSE_MAP_LEN_88E); + memset(efuse_buf, 0xFF, sizeof(efuse_buf)); } else { rtl8188e_EfusePowerSwitch(Adapter, true); - rtl8188e_ReadEFuse(Adapter, 0, EFUSE_MAP_LEN_88E, eeprom->efuse_eeprom_data); + rtl8188e_ReadEFuse(Adapter, 0, EFUSE_MAP_LEN_88E, efuse_buf); rtl8188e_EfusePowerSwitch(Adapter, false); } } /* parse the eeprom/efuse content */ - Hal_EfuseParseIDCode88E(Adapter, eeprom->efuse_eeprom_data); - Hal_EfuseParseMACAddr_8188EU(Adapter, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); + Hal_EfuseParseIDCode88E(Adapter, efuse_buf); + Hal_EfuseParseMACAddr_8188EU(Adapter, efuse_buf, eeprom->bautoload_fail_flag); - Hal_ReadPowerSavingMode88E(Adapter, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); - Hal_ReadTxPowerInfo88E(Adapter, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); - rtl8188e_EfuseParseChnlPlan(Adapter, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); - Hal_EfuseParseXtal_8188E(Adapter, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); - Hal_ReadAntennaDiversity88E(Adapter, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); - Hal_ReadThermalMeter_88E(Adapter, eeprom->efuse_eeprom_data, eeprom->bautoload_fail_flag); + Hal_ReadPowerSavingMode88E(Adapter, efuse_buf, eeprom->bautoload_fail_flag); + Hal_ReadTxPowerInfo88E(Adapter, efuse_buf, eeprom->bautoload_fail_flag); + rtl8188e_EfuseParseChnlPlan(Adapter, efuse_buf, eeprom->bautoload_fail_flag); + Hal_EfuseParseXtal_8188E(Adapter, efuse_buf, eeprom->bautoload_fail_flag); + Hal_ReadAntennaDiversity88E(Adapter, efuse_buf, eeprom->bautoload_fail_flag); + Hal_ReadThermalMeter_88E(Adapter, efuse_buf, eeprom->bautoload_fail_flag); ledpriv->bRegUseLed = true; } diff --git a/drivers/staging/r8188eu/include/rtw_eeprom.h b/drivers/staging/r8188eu/include/rtw_eeprom.h index 0a8792428927..94d735b1d0db 100644 --- a/drivers/staging/r8188eu/include/rtw_eeprom.h +++ b/drivers/staging/r8188eu/include/rtw_eeprom.h @@ -7,12 +7,9 @@ #include "osdep_service.h" #include "drv_types.h" -#define HWSET_MAX_SIZE_512 512 - struct eeprom_priv { u8 bautoload_fail_flag; u8 mac_addr[ETH_ALEN] __aligned(2); /* PermanentAddress */ - u8 efuse_eeprom_data[HWSET_MAX_SIZE_512] __aligned(4); }; #endif /* __RTL871X_EEPROM_H__ */ From 0fcae03da0d80af6138c911a127b3d9ab5dc7fe8 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:52 +0200 Subject: [PATCH 0920/1436] staging: r8188eu: always initialise efuse buffer with 0xff If BOOT_FROM_EEPROM is set, efuse_buf is not initialised before it is passed to functions that read from it. The buffer will be filled with 0x00 in this case like all local variables. However, the parsing functions expect the buffer to be filled with 0xFF if reading eeprom/efuse data failed. Fill the buffer with 0xFF before we try to read the data. Please note that this problem existed before we started using a local buffer. Adapter->eeprompriv->efuse_eeprom_data was allocated as a part of struct adapter by a vzalloc call in rtw_usb_if1_init. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-7-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/usb_halinit.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 32f25312ffd7..16ac5b49459a 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -940,14 +940,12 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) eeprom->bautoload_fail_flag = !(eeValue & EEPROM_EN); - if (!(eeValue & BOOT_FROM_EEPROM)) { - if (eeprom->bautoload_fail_flag) { - memset(efuse_buf, 0xFF, sizeof(efuse_buf)); - } else { - rtl8188e_EfusePowerSwitch(Adapter, true); - rtl8188e_ReadEFuse(Adapter, 0, EFUSE_MAP_LEN_88E, efuse_buf); - rtl8188e_EfusePowerSwitch(Adapter, false); - } + memset(efuse_buf, 0xFF, sizeof(efuse_buf)); + + if (!(eeValue & BOOT_FROM_EEPROM) && !eeprom->bautoload_fail_flag) { + rtl8188e_EfusePowerSwitch(Adapter, true); + rtl8188e_ReadEFuse(Adapter, 0, EFUSE_MAP_LEN_88E, efuse_buf); + rtl8188e_EfusePowerSwitch(Adapter, false); } /* parse the eeprom/efuse content */ From 3c1178680b37b5a5269f4db6e4e4b4981e202ff9 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:53 +0200 Subject: [PATCH 0921/1436] staging: r8188eu: use memcpy for fallback mac address Use memcpy to store the fallback mac address in eeprom->mac_addr. Do not copy byte by byte. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-8-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/usb_halinit.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 16ac5b49459a..3439a64f31ae 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -912,13 +912,11 @@ exit: static void Hal_EfuseParseMACAddr_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail) { - u16 i; u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x88, 0x02}; struct eeprom_priv *eeprom = &adapt->eeprompriv; if (AutoLoadFail) { - for (i = 0; i < 6; i++) - eeprom->mac_addr[i] = sMacAddr[i]; + memcpy(eeprom->mac_addr, sMacAddr, ETH_ALEN); } else { /* Read Permanent MAC address */ memcpy(eeprom->mac_addr, &hwinfo[EEPROM_MAC_ADDR_88EU], ETH_ALEN); From e1ebb0d6a163a318de9b9d6eb0a7f6343bb7255b Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:54 +0200 Subject: [PATCH 0922/1436] staging: r8188eu: merge ReadEFuseByIC into rtl8188e_ReadEFuse The rtl8188e_ReadEFuse function is just a wrapper to call ReadEFuseByIC. Copy ReadEFuseByIC into rtl8188e_ReadEFuse and remove ReadEFuseByIC. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-9-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/rtl8188e_hal_init.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index 5b65313e0b9d..0cb653002660 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -531,7 +531,7 @@ exit: kfree(eFuseWord); } -static void ReadEFuseByIC(struct adapter *Adapter, u16 _offset, u16 _size_byte, u8 *pbuf) +void rtl8188e_ReadEFuse(struct adapter *Adapter, u16 _offset, u16 _size_byte, u8 *pbuf) { int ret = _FAIL; if (rtw_IOL_applied(Adapter)) { @@ -548,11 +548,6 @@ static void ReadEFuseByIC(struct adapter *Adapter, u16 _offset, u16 _size_byte, Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf); } -void rtl8188e_ReadEFuse(struct adapter *Adapter, u16 _offset, u16 _size_byte, u8 *pbuf) -{ - ReadEFuseByIC(Adapter, _offset, _size_byte, pbuf); -} - void rtl8188e_read_chip_version(struct adapter *padapter) { u32 value32; From 36442aa73ba715da998d3a42a4a4d5f594cb6f0d Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:55 +0200 Subject: [PATCH 0923/1436] staging: r8188eu: txpktbuf_bndy is always 0 The only caller of iol_read_efuse sets the txpktbuf_bndy parameter to 0. Remove the parameter from iol_read_efuse and use 0 in the function body. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-10-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/rtl8188e_hal_init.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index 0cb653002660..24699e99edff 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -299,18 +299,18 @@ static int efuse_read_phymap_from_txpktbuf( return 0; } -static s32 iol_read_efuse(struct adapter *padapter, u8 txpktbuf_bndy, u16 offset, u16 size_byte, u8 *logical_map) +static s32 iol_read_efuse(struct adapter *padapter, u16 offset, u16 size_byte, u8 *logical_map) { s32 status = _FAIL; u8 physical_map[512]; u16 size = 512; - rtw_write8(padapter, REG_TDECTRL + 1, txpktbuf_bndy); + rtw_write8(padapter, REG_TDECTRL + 1, 0); memset(physical_map, 0xFF, 512); rtw_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); status = iol_execute(padapter, CMD_READ_EFUSE_MAP); if (status == _SUCCESS) - efuse_read_phymap_from_txpktbuf(padapter, txpktbuf_bndy, physical_map, &size); + efuse_read_phymap_from_txpktbuf(padapter, 0, physical_map, &size); efuse_phymap_to_logical(physical_map, offset, size_byte, logical_map); return status; } @@ -538,7 +538,7 @@ void rtl8188e_ReadEFuse(struct adapter *Adapter, u16 _offset, u16 _size_byte, u8 rtl8188eu_InitPowerOn(Adapter); iol_mode_enable(Adapter, 1); - ret = iol_read_efuse(Adapter, 0, _offset, _size_byte, pbuf); + ret = iol_read_efuse(Adapter, _offset, _size_byte, pbuf); iol_mode_enable(Adapter, 0); if (_SUCCESS == ret) From db9895b86b730c759749d7a6911cd966dd5b9aba Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:56 +0200 Subject: [PATCH 0924/1436] staging: r8188eu: offset is always 0 in rtl8188e_ReadEFuse The offset parameter of rtl8188e_ReadEFuse is always 0. Remove the parameter and use 0 in the function body. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-11-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/rtl8188e_hal_init.c | 6 +++--- drivers/staging/r8188eu/hal/usb_halinit.c | 2 +- drivers/staging/r8188eu/include/hal_intf.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index 24699e99edff..674ba420a272 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -531,21 +531,21 @@ exit: kfree(eFuseWord); } -void rtl8188e_ReadEFuse(struct adapter *Adapter, u16 _offset, u16 _size_byte, u8 *pbuf) +void rtl8188e_ReadEFuse(struct adapter *Adapter, u16 _size_byte, u8 *pbuf) { int ret = _FAIL; if (rtw_IOL_applied(Adapter)) { rtl8188eu_InitPowerOn(Adapter); iol_mode_enable(Adapter, 1); - ret = iol_read_efuse(Adapter, _offset, _size_byte, pbuf); + ret = iol_read_efuse(Adapter, 0, _size_byte, pbuf); iol_mode_enable(Adapter, 0); if (_SUCCESS == ret) return; } - Hal_EfuseReadEFuse88E(Adapter, _offset, _size_byte, pbuf); + Hal_EfuseReadEFuse88E(Adapter, 0, _size_byte, pbuf); } void rtl8188e_read_chip_version(struct adapter *padapter) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 3439a64f31ae..6b0337c09915 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -942,7 +942,7 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) if (!(eeValue & BOOT_FROM_EEPROM) && !eeprom->bautoload_fail_flag) { rtl8188e_EfusePowerSwitch(Adapter, true); - rtl8188e_ReadEFuse(Adapter, 0, EFUSE_MAP_LEN_88E, efuse_buf); + rtl8188e_ReadEFuse(Adapter, EFUSE_MAP_LEN_88E, efuse_buf); rtl8188e_EfusePowerSwitch(Adapter, false); } diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index 4e0a2a4f2f02..24bbba2cb7cf 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -22,7 +22,7 @@ void rtl8188eu_init_default_value(struct adapter *adapt); void rtl8188e_SetHalODMVar(struct adapter *Adapter, void *pValue1, bool bSet); u32 rtl8188eu_InitPowerOn(struct adapter *adapt); void rtl8188e_EfusePowerSwitch(struct adapter *pAdapter, u8 PwrState); -void rtl8188e_ReadEFuse(struct adapter *Adapter, u16 _offset, u16 _size_byte, u8 *pbuf); +void rtl8188e_ReadEFuse(struct adapter *Adapter, u16 _size_byte, u8 *pbuf); void hal_notch_filter_8188e(struct adapter *adapter, bool enable); From cda94a6b44f4eccd8581328f6e012db808f52905 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:57 +0200 Subject: [PATCH 0925/1436] staging: r8188eu: offset is always 0 in iol_read_efuse The offset parameter of iol_read_efuse is always 0. Remove the parameter and use 0 in the function body. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-12-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/rtl8188e_hal_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index 674ba420a272..f552b9adece3 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -299,7 +299,7 @@ static int efuse_read_phymap_from_txpktbuf( return 0; } -static s32 iol_read_efuse(struct adapter *padapter, u16 offset, u16 size_byte, u8 *logical_map) +static s32 iol_read_efuse(struct adapter *padapter, u16 size_byte, u8 *logical_map) { s32 status = _FAIL; u8 physical_map[512]; @@ -311,7 +311,7 @@ static s32 iol_read_efuse(struct adapter *padapter, u16 offset, u16 size_byte, u status = iol_execute(padapter, CMD_READ_EFUSE_MAP); if (status == _SUCCESS) efuse_read_phymap_from_txpktbuf(padapter, 0, physical_map, &size); - efuse_phymap_to_logical(physical_map, offset, size_byte, logical_map); + efuse_phymap_to_logical(physical_map, 0, size_byte, logical_map); return status; } @@ -538,7 +538,7 @@ void rtl8188e_ReadEFuse(struct adapter *Adapter, u16 _size_byte, u8 *pbuf) rtl8188eu_InitPowerOn(Adapter); iol_mode_enable(Adapter, 1); - ret = iol_read_efuse(Adapter, 0, _size_byte, pbuf); + ret = iol_read_efuse(Adapter, _size_byte, pbuf); iol_mode_enable(Adapter, 0); if (_SUCCESS == ret) From e2bd5dc33f037d627ecd3d688cd388131199ee7c Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:58 +0200 Subject: [PATCH 0926/1436] staging: r8188eu: _offset is always 0 in efuse_phymap_to_logical The _offset parameter of iol_read_efuse is always 0. Remove the parameter and use 0 in the function body. We can now replace the bytewise copy from efuseTbl to pbuf with memcpy. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-13-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/rtl8188e_hal_init.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index f552b9adece3..87ebfb013193 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -83,7 +83,7 @@ static s32 iol_InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy) } static void -efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf) +efuse_phymap_to_logical(u8 *phymap, u16 _size_byte, u8 *pbuf) { u8 *efuseTbl = NULL; u8 rtemp8; @@ -188,8 +188,7 @@ efuse_phymap_to_logical(u8 *phymap, u16 _offset, u16 _size_byte, u8 *pbuf) /* */ /* 4. Copy from Efuse map to output pointer memory!!! */ /* */ - for (i = 0; i < _size_byte; i++) - pbuf[i] = efuseTbl[_offset + i]; + memcpy(pbuf, efuseTbl, _size_byte); /* */ /* 5. Calculate Efuse utilization. */ @@ -311,7 +310,7 @@ static s32 iol_read_efuse(struct adapter *padapter, u16 size_byte, u8 *logical_m status = iol_execute(padapter, CMD_READ_EFUSE_MAP); if (status == _SUCCESS) efuse_read_phymap_from_txpktbuf(padapter, 0, physical_map, &size); - efuse_phymap_to_logical(physical_map, 0, size_byte, logical_map); + efuse_phymap_to_logical(physical_map, size_byte, logical_map); return status; } From c337bf6256316be5d74a27f6449363e10fda49a3 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:09:59 +0200 Subject: [PATCH 0927/1436] staging: r8188eu: efuse_utilized is never read The efuse_utilized variable in function efuse_phymap_to_logical is written to but never read. Remove it. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-14-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/rtl8188e_hal_init.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index 87ebfb013193..ddda3f994fa7 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -91,7 +91,6 @@ efuse_phymap_to_logical(u8 *phymap, u16 _size_byte, u8 *pbuf) u8 offset, wren; u16 i, j; u16 **eFuseWord = NULL; - u16 efuse_utilized = 0; u8 u1temp = 0; efuseTbl = kzalloc(EFUSE_MAP_LEN_88E, GFP_KERNEL); @@ -113,7 +112,6 @@ efuse_phymap_to_logical(u8 *phymap, u16 _size_byte, u8 *pbuf) /* */ rtemp8 = *(phymap + eFuse_Addr); if (rtemp8 != 0xFF) { - efuse_utilized++; eFuse_Addr++; } else { goto exit; @@ -151,13 +149,11 @@ efuse_phymap_to_logical(u8 *phymap, u16 _size_byte, u8 *pbuf) if (!(wren & 0x01)) { rtemp8 = *(phymap + eFuse_Addr); eFuse_Addr++; - efuse_utilized++; eFuseWord[offset][i] = (rtemp8 & 0xff); if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) break; rtemp8 = *(phymap + eFuse_Addr); eFuse_Addr++; - efuse_utilized++; eFuseWord[offset][i] |= (((u16)rtemp8 << 8) & 0xff00); if (eFuse_Addr >= EFUSE_REAL_CONTENT_LEN_88E) @@ -170,7 +166,6 @@ efuse_phymap_to_logical(u8 *phymap, u16 _size_byte, u8 *pbuf) rtemp8 = *(phymap + eFuse_Addr); if (rtemp8 != 0xFF && (eFuse_Addr < EFUSE_REAL_CONTENT_LEN_88E)) { - efuse_utilized++; eFuse_Addr++; } } @@ -190,10 +185,6 @@ efuse_phymap_to_logical(u8 *phymap, u16 _size_byte, u8 *pbuf) /* */ memcpy(pbuf, efuseTbl, _size_byte); - /* */ - /* 5. Calculate Efuse utilization. */ - /* */ - exit: kfree(efuseTbl); kfree(eFuseWord); From d4090520cde1f96ad66956ce1b24aa91e5210fa5 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 9 Jul 2022 19:10:00 +0200 Subject: [PATCH 0928/1436] staging: r8188eu: the bcnhead parameter is always 0 The only caller of efuse_read_phymap_from_txpktbuf sets bcnhead to 0. Remove this function parameter and simplify the function body. Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220709171000.180481-15-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/rtl8188e_hal_init.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index ddda3f994fa7..fe477438899e 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -193,13 +193,11 @@ exit: /* FIXME: add error handling in callers */ static int efuse_read_phymap_from_txpktbuf( struct adapter *adapter, - int bcnhead, /* beacon head, where FW store len(2-byte) and efuse physical map. */ u8 *content, /* buffer to store efuse physical map */ u16 *size /* for efuse content: the max byte to read. will update to byte read */ ) { unsigned long timeout; - u16 dbg_addr = 0; __le32 lo32 = 0, hi32 = 0; u16 len = 0, count = 0; int i = 0, res; @@ -208,20 +206,10 @@ static int efuse_read_phymap_from_txpktbuf( u8 *pos = content; u32 reg32; - if (bcnhead < 0) { /* if not valid */ - res = rtw_read8(adapter, REG_TDECTRL + 1, ®); - if (res) - return res; - - bcnhead = reg; - } - rtw_write8(adapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); - dbg_addr = bcnhead * 128 / 8; /* 8-bytes addressing */ - while (1) { - rtw_write16(adapter, REG_PKTBUF_DBG_ADDR, dbg_addr + i); + rtw_write16(adapter, REG_PKTBUF_DBG_ADDR, i); rtw_write8(adapter, REG_TXPKTBUF_DBG, 0); timeout = jiffies + msecs_to_jiffies(1000); @@ -300,7 +288,7 @@ static s32 iol_read_efuse(struct adapter *padapter, u16 size_byte, u8 *logical_m rtw_write8(padapter, REG_PKT_BUFF_ACCESS_CTRL, TXPKT_BUF_SELECT); status = iol_execute(padapter, CMD_READ_EFUSE_MAP); if (status == _SUCCESS) - efuse_read_phymap_from_txpktbuf(padapter, 0, physical_map, &size); + efuse_read_phymap_from_txpktbuf(padapter, physical_map, &size); efuse_phymap_to_logical(physical_map, size_byte, logical_map); return status; } From b9df116cb7656c7e7f869cf9d05b54b3fb3f944b Mon Sep 17 00:00:00 2001 From: Jiang Jian Date: Wed, 22 Jun 2022 22:07:20 +0800 Subject: [PATCH 0929/1436] KVM: s390: drop unexpected word 'and' in the comments there is an unexpected word 'and' in the comments that need to be dropped file: arch/s390/kvm/interrupt.c line: 705 * Subsystem damage are the only two and and are indicated by changed to: * Subsystem damage are the only two and are indicated by Signed-off-by: Jiang Jian Link: https://lore.kernel.org/lkml/20220622140720.7617-1-jiangjian@cdjrlc.com/ Signed-off-by: Janosch Frank --- arch/s390/kvm/interrupt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index d8e1fce78b7c..b9c944b262c7 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -704,7 +704,7 @@ static int __must_check __deliver_machine_check(struct kvm_vcpu *vcpu) /* * We indicate floating repressible conditions along with * other pending conditions. Channel Report Pending and Channel - * Subsystem damage are the only two and and are indicated by + * Subsystem damage are the only two and are indicated by * bits in mcic and masked in cr14. */ if (test_and_clear_bit(IRQ_PEND_MCHK_REP, &fi->pending_irqs)) { From 1b6abe95b522b313569469498c8c648a5ee535ba Mon Sep 17 00:00:00 2001 From: Steffen Eiden Date: Wed, 18 May 2022 13:59:08 +0000 Subject: [PATCH 0930/1436] s390: Add attestation query information We have information about the supported attestation header version and plaintext attestation flag bits. Let's expose it via the sysfs files. Signed-off-by: Steffen Eiden Reviewed-by: Claudio Imbrenda Reviewed-by: Janosch Frank Link: https://lore.kernel.org/lkml/20220601100245.3189993-1-seiden@linux.ibm.com/ Signed-off-by: Janosch Frank --- arch/s390/boot/uv.c | 2 ++ arch/s390/include/asm/uv.h | 7 ++++++- arch/s390/kernel/uv.c | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/arch/s390/boot/uv.c b/arch/s390/boot/uv.c index 67c737c1e580..a5fa667160b2 100644 --- a/arch/s390/boot/uv.c +++ b/arch/s390/boot/uv.c @@ -45,6 +45,8 @@ void uv_query_info(void) uv_info.supp_se_hdr_pcf = uvcb.supp_se_hdr_pcf; uv_info.conf_dump_storage_state_len = uvcb.conf_dump_storage_state_len; uv_info.conf_dump_finalize_len = uvcb.conf_dump_finalize_len; + uv_info.supp_att_req_hdr_ver = uvcb.supp_att_req_hdr_ver; + uv_info.supp_att_pflags = uvcb.supp_att_pflags; } #ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index 3e597bb634bd..18fe04c8547e 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -124,7 +124,10 @@ struct uv_cb_qui { u64 reservedc0; /* 0x00c0 */ u64 conf_dump_storage_state_len; /* 0x00c8 */ u64 conf_dump_finalize_len; /* 0x00d0 */ - u8 reservedd8[256 - 216]; /* 0x00d8 */ + u64 reservedd8; /* 0x00d8 */ + u64 supp_att_req_hdr_ver; /* 0x00e0 */ + u64 supp_att_pflags; /* 0x00e8 */ + u8 reservedf0[256 - 240]; /* 0x00f0 */ } __packed __aligned(8); /* Initialize Ultravisor */ @@ -350,6 +353,8 @@ struct uv_info { unsigned long supp_se_hdr_pcf; unsigned long conf_dump_storage_state_len; unsigned long conf_dump_finalize_len; + unsigned long supp_att_req_hdr_ver; + unsigned long supp_att_pflags; }; extern struct uv_info uv_info; diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index 84fe33b6af4d..c13d5a7b71f0 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -479,6 +479,24 @@ static ssize_t uv_query_max_guest_addr(struct kobject *kobj, static struct kobj_attribute uv_query_max_guest_addr_attr = __ATTR(max_address, 0444, uv_query_max_guest_addr, NULL); +static ssize_t uv_query_supp_att_req_hdr_ver(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return scnprintf(page, PAGE_SIZE, "%lx\n", uv_info.supp_att_req_hdr_ver); +} + +static struct kobj_attribute uv_query_supp_att_req_hdr_ver_attr = + __ATTR(supp_att_req_hdr_ver, 0444, uv_query_supp_att_req_hdr_ver, NULL); + +static ssize_t uv_query_supp_att_pflags(struct kobject *kobj, + struct kobj_attribute *attr, char *page) +{ + return scnprintf(page, PAGE_SIZE, "%lx\n", uv_info.supp_att_pflags); +} + +static struct kobj_attribute uv_query_supp_att_pflags_attr = + __ATTR(supp_att_pflags, 0444, uv_query_supp_att_pflags, NULL); + static struct attribute *uv_query_attrs[] = { &uv_query_facilities_attr.attr, &uv_query_feature_indications_attr.attr, @@ -490,6 +508,8 @@ static struct attribute *uv_query_attrs[] = { &uv_query_dump_storage_state_len_attr.attr, &uv_query_dump_finalize_len_attr.attr, &uv_query_dump_cpu_len_attr.attr, + &uv_query_supp_att_req_hdr_ver_attr.attr, + &uv_query_supp_att_pflags_attr.attr, NULL, }; From a8dd214ff58cd835aa61b7c800b161b98032e71d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 6 Jul 2022 15:20:34 -0600 Subject: [PATCH 0931/1436] dt-bindings: arm: nvidia,tegra20-pmc: Move fixed string property names under 'properties' Fixed string property names should be under 'properties' rather than 'patternProperties'. Additionally, without beginning and end of line anchors, any prefix or suffix is allowed on the specified property names. As all the nvidia,tegra20-pmc powergates child node properties are fixed strings, change 'patternProperties' to 'properties'. Signed-off-by: Rob Herring Acked-by: Thierry Reding Link: https://lore.kernel.org/r/20220706212034.568861-1-robh@kernel.org --- .../devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.yaml b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.yaml index 564ae6aaccf7..7fd8d47b1be4 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.yaml +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.yaml @@ -208,7 +208,7 @@ properties: "^[a-z0-9]+$": type: object - patternProperties: + properties: clocks: minItems: 1 maxItems: 8 From 6e44e0dc5806b614f1a683fc8d91f677f18bf2f4 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Thu, 7 Jul 2022 17:27:53 +0900 Subject: [PATCH 0932/1436] dt-bindings: arm: cpus: add cortex-a78ae compatible Cortex A78AE's MPIDR has been added since commit 83bea32ac7ed ("arm64: Add part number for Arm Cortex-A78AE") We also need to add the compatible. Signed-off-by: Chanho Park Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220707082753.28862-1-chanho61.park@samsung.com --- Documentation/devicetree/bindings/arm/cpus.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/arm/cpus.yaml b/Documentation/devicetree/bindings/arm/cpus.yaml index ed04650291a8..f565cc4c9d79 100644 --- a/Documentation/devicetree/bindings/arm/cpus.yaml +++ b/Documentation/devicetree/bindings/arm/cpus.yaml @@ -138,6 +138,7 @@ properties: - arm,cortex-a76 - arm,cortex-a77 - arm,cortex-a78 + - arm,cortex-a78ae - arm,cortex-a510 - arm,cortex-a710 - arm,cortex-m0 From 912cbf13a5445ca4a89d35b638795058dab61cce Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 29 Jun 2022 12:50:30 -0600 Subject: [PATCH 0933/1436] dt-bindings: mtd/partitions: Convert arm-firmware-suite to DT schema Convert the arm,arm-firmware-suite partition binding to DT schema format. Simple conversion as there's only a compatible property. Reviewed-by: Linus Walleij Signed-off-by: Rob Herring Reviewed-by: Miquel Raynal Link: https://lore.kernel.org/r/20220629185031.23826-1-robh@kernel.org --- .../mtd/partitions/arm,arm-firmware-suite.txt | 17 ----------- .../partitions/arm,arm-firmware-suite.yaml | 28 +++++++++++++++++++ 2 files changed, 28 insertions(+), 17 deletions(-) delete mode 100644 Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt create mode 100644 Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml diff --git a/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt b/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt deleted file mode 100644 index d5c5616f6db5..000000000000 --- a/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.txt +++ /dev/null @@ -1,17 +0,0 @@ -ARM AFS - ARM Firmware Suite Partitions -======================================= - -The ARM Firmware Suite is a flash partitioning system found on the -ARM reference designs: Integrator AP, Integrator CP, Versatile AB, -Versatile PB, the RealView family, Versatile Express and Juno. - -Required properties: -- compatible : (required) must be "arm,arm-firmware-suite" - -Example: - -flash@0 { - partitions { - compatible = "arm,arm-firmware-suite"; - }; -}; diff --git a/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml b/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml new file mode 100644 index 000000000000..76c88027b6d2 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/partitions/arm,arm-firmware-suite.yaml @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mtd/partitions/arm,arm-firmware-suite.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ARM Firmware Suite (AFS) Partitions + +maintainers: + - Linus Walleij + +description: | + The ARM Firmware Suite is a flash partitioning system found on the + ARM reference designs: Integrator AP, Integrator CP, Versatile AB, + Versatile PB, the RealView family, Versatile Express and Juno. + +properties: + compatible: + const: arm,arm-firmware-suite + +additionalProperties: false + +examples: + - | + partitions { + compatible = "arm,arm-firmware-suite"; + }; +... From 652081b3c64e03ae3229dd33923d295f9f3115db Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 9 Jul 2022 00:45:38 +0300 Subject: [PATCH 0934/1436] of: unittest: Switch to use fwnode instead of of_node The OF node in the GPIO library is deprecated and soon will be removed. GPIO library now accepts fwnode as a firmware node, so switch the module to use it instead. Signed-off-by: Andy Shevchenko Reviewed-by: Bartosz Golaszewski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220708214539.7254-1-andriy.shevchenko@linux.intel.com --- drivers/of/unittest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 7f6bba18c515..5a842dfc27e8 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1602,7 +1602,7 @@ static int unittest_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, devptr); - devptr->chip.of_node = pdev->dev.of_node; + devptr->chip.fwnode = dev_fwnode(&pdev->dev); devptr->chip.label = "of-unittest-gpio"; devptr->chip.base = -1; /* dynamic allocation */ devptr->chip.ngpio = 5; @@ -1611,7 +1611,7 @@ static int unittest_gpio_probe(struct platform_device *pdev) ret = gpiochip_add_data(&devptr->chip, NULL); unittest(!ret, - "gpiochip_add_data() for node @%pOF failed, ret = %d\n", devptr->chip.of_node, ret); + "gpiochip_add_data() for node @%pfw failed, ret = %d\n", devptr->chip.fwnode, ret); if (!ret) unittest_gpio_probe_pass_count++; From 9465a98458fe2a05015bc90d7587fb891cd0c0cc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sat, 9 Jul 2022 00:45:39 +0300 Subject: [PATCH 0935/1436] of: unittest: make unittest_gpio_remove() consistent with unittest_gpio_probe() On the ->remove() stage the callback uses physical device node instead of one from GPIO chip and the variable name which is different to one used in unittest_gpio_probe(). Make these consistent with unittest_gpio_probe(). Signed-off-by: Andy Shevchenko Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220708214539.7254-2-andriy.shevchenko@linux.intel.com --- drivers/of/unittest.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 5a842dfc27e8..eafa8ffefbd0 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -1620,20 +1620,19 @@ static int unittest_gpio_probe(struct platform_device *pdev) static int unittest_gpio_remove(struct platform_device *pdev) { - struct unittest_gpio_dev *gdev = platform_get_drvdata(pdev); + struct unittest_gpio_dev *devptr = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; - struct device_node *np = pdev->dev.of_node; - dev_dbg(dev, "%s for node @%pOF\n", __func__, np); + dev_dbg(dev, "%s for node @%pfw\n", __func__, devptr->chip.fwnode); - if (!gdev) + if (!devptr) return -EINVAL; - if (gdev->chip.base != -1) - gpiochip_remove(&gdev->chip); + if (devptr->chip.base != -1) + gpiochip_remove(&devptr->chip); platform_set_drvdata(pdev, NULL); - kfree(gdev); + kfree(devptr); return 0; } From 6c3c267e5fbc637c8fc4b1d075e3c43e328550a6 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Mon, 11 Jul 2022 11:10:58 -0700 Subject: [PATCH 0936/1436] Documentation/process: Add embargoed HW contact for LLVM Should the need for toolchain mitigations ever be necessary, add a group for toolchain ambassadors. Add Nick Desaulniers as LLVM's ambassador for the embargoed hardware issues process. Signed-off-by: Nick Desaulniers Link: https://lore.kernel.org/r/20220711181101.1559558-1-ndesaulniers@google.com Signed-off-by: Greg Kroah-Hartman --- Documentation/process/embargoed-hardware-issues.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/process/embargoed-hardware-issues.rst b/Documentation/process/embargoed-hardware-issues.rst index 95999302d279..48bd249d96b9 100644 --- a/Documentation/process/embargoed-hardware-issues.rst +++ b/Documentation/process/embargoed-hardware-issues.rst @@ -264,6 +264,9 @@ an involved disclosed party. The current ambassadors list: Amazon Google Kees Cook + + GCC + LLVM Nick Desaulniers ============= ======================================================== If you want your organization to be added to the ambassadors list, please From 042f1a6f434ad1fb49fca59d76b5203ce432c36c Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Mon, 11 Jul 2022 19:44:17 +0200 Subject: [PATCH 0937/1436] staging: r8188eu: remove HW_VAR_MLME_SITESURVEY from SetHwReg8188EU() Remove the HW_VAR_MLME_SITESURVEY case from SetHwReg8188EU() and move the functionality to two new functions in rtw_mlme_ext.c. This is part of the ongoing effort to get rid of SetHwReg8188EU(). Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220711174417.10721-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 70 +++++++++++++++++-- drivers/staging/r8188eu/core/rtw_p2p.c | 9 +-- drivers/staging/r8188eu/hal/usb_halinit.c | 53 -------------- drivers/staging/r8188eu/include/hal_intf.h | 1 - .../staging/r8188eu/include/rtw_mlme_ext.h | 3 + 5 files changed, 70 insertions(+), 66 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index eecb00e41d6a..771910763fec 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5695,9 +5695,70 @@ static void rtw_set_initial_gain(struct adapter *adapter, u8 gain) } } +void rtw_mlme_under_site_survey(struct adapter *adapter) +{ + /* config RCR to receive different BSSID & not to receive data frame */ + + int res; + u8 reg; + u32 v; + + res = rtw_read32(adapter, REG_RCR, &v); + if (res) + return; + + v &= ~(RCR_CBSSID_BCN); + rtw_write32(adapter, REG_RCR, v); + /* reject all data frame */ + rtw_write16(adapter, REG_RXFLTMAP2, 0x00); + + /* disable update TSF */ + res = rtw_read8(adapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(adapter, REG_BCN_CTRL, reg | BIT(4)); +} + +void rtw_mlme_site_survey_done(struct adapter *adapter) +{ + struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u32 reg32; + int res; + u8 reg; + + if ((is_client_associated_to_ap(adapter)) || + ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) { + /* enable to rx data frame */ + rtw_write16(adapter, REG_RXFLTMAP2, 0xFFFF); + + /* enable update TSF */ + res = rtw_read8(adapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(adapter, REG_BCN_CTRL, reg & (~BIT(4))); + } else if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { + rtw_write16(adapter, REG_RXFLTMAP2, 0xFFFF); + /* enable update TSF */ + res = rtw_read8(adapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(adapter, REG_BCN_CTRL, reg & (~BIT(4))); + } + + res = rtw_read32(adapter, REG_RCR, ®32); + if (res) + return; + + rtw_write32(adapter, REG_RCR, reg32 | RCR_CBSSID_BCN); +} + void site_survey(struct adapter *padapter) { - unsigned char survey_channel = 0, val8; + unsigned char survey_channel = 0; enum rt_scan_type ScanType = SCAN_PASSIVE; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -5821,8 +5882,7 @@ void site_survey(struct adapter *padapter) if (is_client_associated_to_ap(padapter)) issue_nulldata(padapter, NULL, 0, 3, 500); - val8 = 0; /* survey done */ - SetHwReg8188EU(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + rtw_mlme_site_survey_done(padapter); report_surveydone_event(padapter); @@ -7343,7 +7403,6 @@ u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf) struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf; u8 bdelayscan = false; - u8 val8; u32 i; struct wifidirect_info *pwdinfo = &padapter->wdinfo; @@ -7400,8 +7459,7 @@ u8 sitesurvey_cmd_hdl(struct adapter *padapter, u8 *pbuf) /* set MSR to no link state */ Set_MSR(padapter, _HW_STATE_NOLINK_); - val8 = 1; /* under site survey */ - SetHwReg8188EU(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + rtw_mlme_under_site_survey(padapter); pmlmeext->sitesurvey_res.state = SCAN_PROCESS; } diff --git a/drivers/staging/r8188eu/core/rtw_p2p.c b/drivers/staging/r8188eu/core/rtw_p2p.c index beffe5b16f1e..c306aafa183b 100644 --- a/drivers/staging/r8188eu/core/rtw_p2p.c +++ b/drivers/staging/r8188eu/core/rtw_p2p.c @@ -1450,10 +1450,9 @@ static void restore_p2p_state_handler(struct adapter *padapter) static void pre_tx_invitereq_handler(struct adapter *padapter) { struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 val8 = 1; set_channel_bwmode(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); - SetHwReg8188EU(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + rtw_mlme_under_site_survey(padapter); issue_probereq_p2p(padapter, NULL); _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); @@ -1462,10 +1461,9 @@ static void pre_tx_invitereq_handler(struct adapter *padapter) static void pre_tx_provdisc_handler(struct adapter *padapter) { struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 val8 = 1; set_channel_bwmode(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); - SetHwReg8188EU(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + rtw_mlme_under_site_survey(padapter); issue_probereq_p2p(padapter, NULL); _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); @@ -1474,10 +1472,9 @@ static void pre_tx_provdisc_handler(struct adapter *padapter) static void pre_tx_negoreq_handler(struct adapter *padapter) { struct wifidirect_info *pwdinfo = &padapter->wdinfo; - u8 val8 = 1; set_channel_bwmode(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20); - SetHwReg8188EU(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8)); + rtw_mlme_under_site_survey(padapter); issue_probereq_p2p(padapter, NULL); _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 6b0337c09915..68d012a442a8 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -1104,59 +1104,6 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) ResumeTxBeacon(Adapter); } break; - case HW_VAR_MLME_SITESURVEY: - if (*((u8 *)val)) { /* under sitesurvey */ - /* config RCR to receive different BSSID & not to receive data frame */ - u32 v; - - res = rtw_read32(Adapter, REG_RCR, &v); - if (res) - return; - - v &= ~(RCR_CBSSID_BCN); - rtw_write32(Adapter, REG_RCR, v); - /* reject all data frame */ - rtw_write16(Adapter, REG_RXFLTMAP2, 0x00); - - /* disable update TSF */ - res = rtw_read8(Adapter, REG_BCN_CTRL, ®); - if (res) - return; - - rtw_write8(Adapter, REG_BCN_CTRL, reg | BIT(4)); - } else { /* sitesurvey done */ - struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - u32 reg32; - - if ((is_client_associated_to_ap(Adapter)) || - ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE)) { - /* enable to rx data frame */ - rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); - - /* enable update TSF */ - res = rtw_read8(Adapter, REG_BCN_CTRL, ®); - if (res) - return; - - rtw_write8(Adapter, REG_BCN_CTRL, reg & (~BIT(4))); - } else if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) { - rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); - /* enable update TSF */ - res = rtw_read8(Adapter, REG_BCN_CTRL, ®); - if (res) - return; - - rtw_write8(Adapter, REG_BCN_CTRL, reg & (~BIT(4))); - } - - res = rtw_read32(Adapter, REG_RCR, ®32); - if (res) - return; - - rtw_write32(Adapter, REG_RCR, reg32 | RCR_CBSSID_BCN); - } - break; default: break; } diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index 24bbba2cb7cf..819d0dc6e6dc 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -11,7 +11,6 @@ enum hw_variables { HW_VAR_SET_OPMODE, HW_VAR_CORRECT_TSF, - HW_VAR_MLME_SITESURVEY, }; typedef s32 (*c2h_id_filter)(u8 id); diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h index 3cc475aa912a..c630700ea657 100644 --- a/drivers/staging/r8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h @@ -424,6 +424,9 @@ void invalidate_cam_all(struct adapter *padapter); int allocate_fw_sta_entry(struct adapter *padapter); void flush_all_cam_entry(struct adapter *padapter); +void rtw_mlme_under_site_survey(struct adapter *adapter); +void rtw_mlme_site_survey_done(struct adapter *adapter); + void site_survey(struct adapter *padapter); u8 collect_bss_info(struct adapter *padapter, struct recv_frame *precv_frame, struct wlan_bssid_ex *bssid); From d17e37c41b7ed38459957a5d2968ba61516fd5c2 Mon Sep 17 00:00:00 2001 From: Liang He Date: Sat, 2 Jul 2022 09:44:49 +0800 Subject: [PATCH 0938/1436] of: device: Fix missing of_node_put() in of_dma_set_restricted_buffer We should use of_node_put() for the reference 'node' returned by of_parse_phandle() which will increase the refcount. Fixes: fec9b625095f ("of: Add plumbing for restricted DMA pool") Co-authored-by: Miaoqian Lin Signed-off-by: Liang He Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220702014449.263772-1-windhl@126.com --- drivers/of/device.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/of/device.c b/drivers/of/device.c index 874f031442dc..75b6cbffa755 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -81,8 +81,11 @@ of_dma_set_restricted_buffer(struct device *dev, struct device_node *np) * restricted-dma-pool region is allowed. */ if (of_device_is_compatible(node, "restricted-dma-pool") && - of_device_is_available(node)) + of_device_is_available(node)) { + of_node_put(node); break; + } + of_node_put(node); } /* From 156b9d76e8822f2956c15029acf2d4b171502f3a Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 12 Jul 2022 15:50:09 +0200 Subject: [PATCH 0939/1436] KVM: nVMX: Always enable TSC scaling for L2 when it was enabled for L1 Windows 10/11 guests with Hyper-V role (WSL2) enabled are observed to hang upon boot or shortly after when a non-default TSC frequency was set for L1. The issue is observed on a host where TSC scaling is supported. The problem appears to be that Windows doesn't use TSC scaling for its guests, even when the feature is advertised, and KVM filters SECONDARY_EXEC_TSC_SCALING out when creating L2 controls from L1's VMCS. This leads to L2 running with the default frequency (matching host's) while L1 is running with an altered one. Keep SECONDARY_EXEC_TSC_SCALING in secondary exec controls for L2 when it was set for L1. TSC_MULTIPLIER is already correctly computed and written by prepare_vmcs02(). Signed-off-by: Vitaly Kuznetsov Fixes: d041b5ea93352b ("KVM: nVMX: Enable nested TSC scaling") Cc: stable@vger.kernel.org Reviewed-by: Maxim Levitsky Link: https://lore.kernel.org/r/20220712135009.952805-1-vkuznets@redhat.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/nested.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 778f82015f03..bfa366938c49 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -2284,7 +2284,6 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0 SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | SECONDARY_EXEC_APIC_REGISTER_VIRT | SECONDARY_EXEC_ENABLE_VMFUNC | - SECONDARY_EXEC_TSC_SCALING | SECONDARY_EXEC_DESC); if (nested_cpu_has(vmcs12, From 6e1d2a3f25d518cc3d9703115c6fbec704a6c5bb Mon Sep 17 00:00:00 2001 From: Hou Wenlong Date: Fri, 1 Jul 2022 17:24:13 +0800 Subject: [PATCH 0940/1436] KVM: x86/mmu: Replace UNMAPPED_GVA with INVALID_GPA for gva_to_gpa() The result of gva_to_gpa() is physical address not virtual address, it is odd that UNMAPPED_GVA macro is used as the result for physical address. Replace UNMAPPED_GVA with INVALID_GPA and drop UNMAPPED_GVA macro. No functional change intended. Signed-off-by: Hou Wenlong Reviewed-by: Sean Christopherson Link: https://lore.kernel.org/r/6104978956449467d3c68f1ad7f2c2f6d771d0ee.1656667239.git.houwenlong.hwl@antgroup.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 1 - arch/x86/kvm/mmu/paging_tmpl.h | 6 +++--- arch/x86/kvm/vmx/sgx.c | 2 +- arch/x86/kvm/x86.c | 18 +++++++++--------- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index de5a149d0971..dd6a26f7d46c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -129,7 +129,6 @@ #define INVALID_PAGE (~(hpa_t)0) #define VALID_PAGE(x) ((x) != INVALID_PAGE) -#define UNMAPPED_GVA (~(gpa_t)0) #define INVALID_GPA (~(gpa_t)0) /* KVM Hugepage definitions for x86 */ diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 2448fa8d8438..94bfd5f723ba 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -378,7 +378,7 @@ retry_walk: * information to fix the exit_qualification or exit_info_1 * fields. */ - if (unlikely(real_gpa == UNMAPPED_GVA)) + if (unlikely(real_gpa == INVALID_GPA)) return 0; host_addr = kvm_vcpu_gfn_to_hva_prot(vcpu, gpa_to_gfn(real_gpa), @@ -431,7 +431,7 @@ retry_walk: #endif real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(gfn), access, &walker->fault); - if (real_gpa == UNMAPPED_GVA) + if (real_gpa == INVALID_GPA) return 0; walker->gfn = real_gpa >> PAGE_SHIFT; @@ -962,7 +962,7 @@ static gpa_t FNAME(gva_to_gpa)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, struct x86_exception *exception) { struct guest_walker walker; - gpa_t gpa = UNMAPPED_GVA; + gpa_t gpa = INVALID_GPA; int r; #ifndef CONFIG_X86_64 diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c index 35e7ec91ae86..7ae8aa73724c 100644 --- a/arch/x86/kvm/vmx/sgx.c +++ b/arch/x86/kvm/vmx/sgx.c @@ -79,7 +79,7 @@ static int sgx_gva_to_gpa(struct kvm_vcpu *vcpu, gva_t gva, bool write, else *gpa = kvm_mmu_gva_to_gpa_read(vcpu, gva, &ex); - if (*gpa == UNMAPPED_GVA) { + if (*gpa == INVALID_GPA) { kvm_inject_emulated_page_fault(vcpu, &ex); return -EFAULT; } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 759bcc0a3300..67dcaa670874 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -849,7 +849,7 @@ int load_pdptrs(struct kvm_vcpu *vcpu, unsigned long cr3) */ real_gpa = kvm_translate_gpa(vcpu, mmu, gfn_to_gpa(pdpt_gfn), PFERR_USER_MASK | PFERR_WRITE_MASK, NULL); - if (real_gpa == UNMAPPED_GVA) + if (real_gpa == INVALID_GPA) return 0; /* Note the offset, PDPTRs are 32 byte aligned when using PAE paging. */ @@ -7072,7 +7072,7 @@ static int kvm_read_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, unsigned toread = min(bytes, (unsigned)PAGE_SIZE - offset); int ret; - if (gpa == UNMAPPED_GVA) + if (gpa == INVALID_GPA) return X86EMUL_PROPAGATE_FAULT; ret = kvm_vcpu_read_guest_page(vcpu, gpa >> PAGE_SHIFT, data, offset, toread); @@ -7103,7 +7103,7 @@ static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt, /* Inline kvm_read_guest_virt_helper for speed. */ gpa_t gpa = mmu->gva_to_gpa(vcpu, mmu, addr, access|PFERR_FETCH_MASK, exception); - if (unlikely(gpa == UNMAPPED_GVA)) + if (unlikely(gpa == INVALID_GPA)) return X86EMUL_PROPAGATE_FAULT; offset = addr & (PAGE_SIZE-1); @@ -7173,7 +7173,7 @@ static int kvm_write_guest_virt_helper(gva_t addr, void *val, unsigned int bytes unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); int ret; - if (gpa == UNMAPPED_GVA) + if (gpa == INVALID_GPA) return X86EMUL_PROPAGATE_FAULT; ret = kvm_vcpu_write_guest(vcpu, gpa, data, towrite); if (ret < 0) { @@ -7284,7 +7284,7 @@ static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva, *gpa = mmu->gva_to_gpa(vcpu, mmu, gva, access, exception); - if (*gpa == UNMAPPED_GVA) + if (*gpa == INVALID_GPA) return -1; return vcpu_is_mmio_gpa(vcpu, gva, *gpa, write); @@ -7521,7 +7521,7 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt, gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, NULL); - if (gpa == UNMAPPED_GVA || + if (gpa == INVALID_GPA || (gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE) goto emul_write; @@ -8338,7 +8338,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, * If the mapping is invalid in guest, let cpu retry * it to generate fault. */ - if (gpa == UNMAPPED_GVA) + if (gpa == INVALID_GPA) return true; } @@ -11378,7 +11378,7 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, gpa = kvm_mmu_gva_to_gpa_system(vcpu, vaddr, NULL); srcu_read_unlock(&vcpu->kvm->srcu, idx); tr->physical_address = gpa; - tr->valid = gpa != UNMAPPED_GVA; + tr->valid = gpa != INVALID_GPA; tr->writeable = 1; tr->usermode = 0; @@ -12983,7 +12983,7 @@ void kvm_fixup_and_inject_pf_error(struct kvm_vcpu *vcpu, gva_t gva, u16 error_c (PFERR_WRITE_MASK | PFERR_FETCH_MASK | PFERR_USER_MASK); if (!(error_code & PFERR_PRESENT_MASK) || - mmu->gva_to_gpa(vcpu, mmu, gva, access, &fault) != UNMAPPED_GVA) { + mmu->gva_to_gpa(vcpu, mmu, gva, access, &fault) != INVALID_GPA) { /* * If vcpu->arch.walk_mmu->gva_to_gpa succeeded, the page * tables probably do not match the TLB. Just proceed From 79f772b9e8004c542cc88aaf680189c3f6e9a0f2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 22:56:15 +0000 Subject: [PATCH 0941/1436] KVM: x86: Query vcpu->vcpu_idx directly and drop its accessor, again Read vcpu->vcpu_idx directly instead of bouncing through the one-line wrapper, kvm_vcpu_get_idx(), and drop the wrapper. The wrapper is a remnant of the original implementation and serves no purpose; remove it (again) before it gains more users. kvm_vcpu_get_idx() was removed in the not-too-distant past by commit 4eeef2424153 ("KVM: x86: Query vcpu->vcpu_idx directly and drop its accessor"), but was unintentionally re-introduced by commit a54d806688fe ("KVM: Keep memslots in tree-based structures instead of array-based ones"), likely due to a rebase goof. The wrapper then managed to gain users in KVM's Xen code. No functional change intended. Signed-off-by: Sean Christopherson Reviewed-by: Jim Mattson Link: https://lore.kernel.org/r/20220614225615.3843835-1-seanjc@google.com --- arch/x86/kvm/xen.c | 10 +++++----- include/linux/kvm_host.h | 5 ----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 610beba35907..a0c05ccbf4b1 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -1049,7 +1049,7 @@ static bool kvm_xen_schedop_poll(struct kvm_vcpu *vcpu, bool longmode, else vcpu->arch.xen.poll_evtchn = -1; - set_bit(kvm_vcpu_get_idx(vcpu), vcpu->kvm->arch.xen.poll_mask); + set_bit(vcpu->vcpu_idx, vcpu->kvm->arch.xen.poll_mask); if (!wait_pending_event(vcpu, sched_poll.nr_ports, ports)) { vcpu->arch.mp_state = KVM_MP_STATE_HALTED; @@ -1071,7 +1071,7 @@ static bool kvm_xen_schedop_poll(struct kvm_vcpu *vcpu, bool longmode, *r = 0; out: /* Really, this is only needed in case of timeout */ - clear_bit(kvm_vcpu_get_idx(vcpu), vcpu->kvm->arch.xen.poll_mask); + clear_bit(vcpu->vcpu_idx, vcpu->kvm->arch.xen.poll_mask); if (unlikely(sched_poll.nr_ports > 1)) kfree(ports); @@ -1311,7 +1311,7 @@ static void kvm_xen_check_poller(struct kvm_vcpu *vcpu, int port) int poll_evtchn = vcpu->arch.xen.poll_evtchn; if ((poll_evtchn == port || poll_evtchn == -1) && - test_and_clear_bit(kvm_vcpu_get_idx(vcpu), vcpu->kvm->arch.xen.poll_mask)) { + test_and_clear_bit(vcpu->vcpu_idx, vcpu->kvm->arch.xen.poll_mask)) { kvm_make_request(KVM_REQ_UNBLOCK, vcpu); kvm_vcpu_kick(vcpu); } @@ -1344,7 +1344,7 @@ int kvm_xen_set_evtchn_fast(struct kvm_xen_evtchn *xe, struct kvm *kvm) vcpu = kvm_get_vcpu_by_id(kvm, xe->vcpu_id); if (!vcpu) return -EINVAL; - WRITE_ONCE(xe->vcpu_idx, kvm_vcpu_get_idx(vcpu)); + WRITE_ONCE(xe->vcpu_idx, vcpu->vcpu_idx); } if (!vcpu->arch.xen.vcpu_info_cache.active) @@ -1540,7 +1540,7 @@ int kvm_xen_setup_evtchn(struct kvm *kvm, */ vcpu = kvm_get_vcpu_by_id(kvm, ue->u.xen_evtchn.vcpu); if (vcpu) - e->xen_evtchn.vcpu_idx = kvm_vcpu_get_idx(vcpu); + e->xen_evtchn.vcpu_idx = vcpu->vcpu_idx; else e->xen_evtchn.vcpu_idx = -1; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 3b40f8d68fbb..cb8168cc9755 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -907,11 +907,6 @@ static inline struct kvm_vcpu *kvm_get_vcpu_by_id(struct kvm *kvm, int id) return NULL; } -static inline int kvm_vcpu_get_idx(struct kvm_vcpu *vcpu) -{ - return vcpu->vcpu_idx; -} - void kvm_destroy_vcpus(struct kvm *kvm); void vcpu_load(struct kvm_vcpu *vcpu); From 874190fd4ee894bbbcc0d4df4c55ebf93af9c011 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 11 Jul 2022 22:57:51 +0000 Subject: [PATCH 0942/1436] KVM: selftests: Test MONITOR and MWAIT, not just MONITOR for quirk Fix a copy+paste error in monitor_mwait_test by switching one of the two "monitor" instructions to an "mwait". The intent of the test is very much to verify the quirk handles both MONITOR and MWAIT. Fixes: 2325d4dd7321 ("KVM: selftests: Add MONITOR/MWAIT quirk test") Reported-by: Yuan Yao Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220711225753.1073989-2-seanjc@google.com --- tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c index 49f2ed1c53fe..f5c09cb528ae 100644 --- a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c @@ -34,7 +34,7 @@ static void guest_monitor_wait(int testcase) else GUEST_ASSERT_2(!vector, testcase, vector); - vector = kvm_asm_safe("monitor"); + vector = kvm_asm_safe("mwait"); if (fault_wanted) GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector); else From b624ae35418ce9424f639f8ffa2568e7674c262b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 11 Jul 2022 22:57:52 +0000 Subject: [PATCH 0943/1436] KVM: selftests: Provide valid inputs for MONITOR/MWAIT regs Provide valid inputs for RAX, RCX, and RDX when testing whether or not KVM injects a #UD on MONITOR/MWAIT. SVM has a virtualization hole and checks for _all_ faults before checking for intercepts, e.g. MONITOR with an unsupported RCX will #GP before KVM gets a chance to intercept and emulate. Fixes: 2325d4dd7321 ("KVM: selftests: Add MONITOR/MWAIT quirk test") Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220711225753.1073989-3-seanjc@google.com --- tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c index f5c09cb528ae..6a4ebcdfa374 100644 --- a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c @@ -28,13 +28,17 @@ static void guest_monitor_wait(int testcase) GUEST_SYNC(testcase); - vector = kvm_asm_safe("monitor"); + /* + * Arbitrarily MONITOR this function, SVM performs fault checks before + * intercept checks, so the inputs for MONITOR and MWAIT must be valid. + */ + vector = kvm_asm_safe("monitor", "a"(guest_monitor_wait), "c"(0), "d"(0)); if (fault_wanted) GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector); else GUEST_ASSERT_2(!vector, testcase, vector); - vector = kvm_asm_safe("mwait"); + vector = kvm_asm_safe("mwait", "a"(guest_monitor_wait), "c"(0), "d"(0)); if (fault_wanted) GUEST_ASSERT_2(vector == UD_VECTOR, testcase, vector); else From f41e16ac606216c7ad01c21e01a1004ca5650a8f Mon Sep 17 00:00:00 2001 From: Zhang Jiaming Date: Wed, 29 Jun 2022 14:41:53 +0800 Subject: [PATCH 0944/1436] USB: serial: io_edgeport: fix spelling mistakes Change 'paramater' to 'parameter'. Change 'timedout' to 'timeout'. Signed-off-by: Zhang Jiaming Signed-off-by: Johan Hovold --- drivers/usb/serial/io_edgeport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index bdee78cc4a07..ffa622539a25 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -220,7 +220,7 @@ struct edgeport_serial { __u8 rxHeader3; /* receive header byte 3 */ __u8 rxPort; /* the port that we are currently receiving data for */ __u8 rxStatusCode; /* the receive status code */ - __u8 rxStatusParam; /* the receive status paramater */ + __u8 rxStatusParam; /* the receive status parameter */ __s16 rxBytesRemaining; /* the number of port bytes left to read */ struct usb_serial *serial; /* loop back to the owner of this object */ }; @@ -901,7 +901,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port) if (!edge_port->open) { /* open timed out */ - dev_dbg(dev, "%s - open timedout\n", __func__); + dev_dbg(dev, "%s - open timeout\n", __func__); edge_port->openPending = false; return -ENODEV; } From 9ec7e8d5fae34b3da52b4b0a7a47877bc6aa8416 Mon Sep 17 00:00:00 2001 From: Jiang Jian Date: Wed, 22 Jun 2022 18:42:17 +0800 Subject: [PATCH 0945/1436] USB: serial: fix repeated word "the" in comments There is a repeated word "the" in two comments that should be replaced or removed. Signed-off-by: Jiang Jian [ johan: replace one "the" with "that", merge the two cleanups, amend commit message ] Signed-off-by: Johan Hovold --- drivers/usb/serial/cypress_m8.c | 2 +- drivers/usb/serial/mos7720.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 6924fa95f6bd..5fbcc155e8f5 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -256,7 +256,7 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate) /* * Mike Isely 2-Feb-2008: The * Cypress app note that describes this mechanism - * states the the low-speed part can't handle more + * states that the low-speed part can't handle more * than 800 bytes/sec, in which case 4800 baud is the * safest speed for a part like that. */ diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 1e12b5f30dcc..23ccbba716c7 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -826,7 +826,7 @@ static int mos77xx_calc_num_ports(struct usb_serial *serial, /* * The 7715 uses the first bulk in/out endpoint pair for the * parallel port, and the second for the serial port. We swap - * the endpoint descriptors here so that the the first and + * the endpoint descriptors here so that the first and * only registered port structure uses the serial-port * endpoints. */ From 6131fd198099d9cfde4cbcd6d60a07aa634a358c Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Tue, 12 Jul 2022 11:31:40 +0200 Subject: [PATCH 0946/1436] KVM: s390/pci: fix include duplicates remove the duplicate includes. While at it sort the includes. Reported-by: kernel test robot Fixes: 73f91b004321 ("KVM: s390: pci: enable host forwarding of Adapter Event Notifications") Signed-off-by: Christian Borntraeger --- arch/s390/kvm/pci.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h index 0351382e990f..3a3606c3a0fe 100644 --- a/arch/s390/kvm/pci.h +++ b/arch/s390/kvm/pci.h @@ -10,11 +10,10 @@ #ifndef __KVM_S390_PCI_H #define __KVM_S390_PCI_H -#include -#include -#include #include #include +#include +#include #include #include From 5efab5cdf06b932ba7a53264b60f7d5c6ec87edf Mon Sep 17 00:00:00 2001 From: Bagas Sanjaya Date: Tue, 12 Jul 2022 16:29:54 +0700 Subject: [PATCH 0947/1436] Documentation: kvm: extend KVM_S390_ZPCI_OP subheading underline Stephen Rothwell reported the htmldocs warning: Documentation/virt/kvm/api.rst:5959: WARNING: Title underline too short. 4.137 KVM_S390_ZPCI_OP -------------------- The warning is due to subheading underline on KVM_S390_ZPCI_OP section is short of 2 dashes. Extend the underline to fix the warning. Link: https://lore.kernel.org/linux-next/20220711205557.183c3b14@canb.auug.org.au/ Fixes: a0c4d1109d6cc5 ("KVM: s390: add KVM_S390_ZPCI_OP to manage guest zPCI devices") Reported-by: Stephen Rothwell Cc: Paolo Bonzini Cc: Jonathan Corbet Cc: Pierre Morel Cc: Thomas Huth Cc: Matthew Rosato Cc: Christian Borntraeger Cc: Janosch Frank Cc: kvm@vger.kernel.org Cc: linux-s390@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Bagas Sanjaya Link: https://lore.kernel.org/r/20220712092954.142027-4-bagasdotme@gmail.com Signed-off-by: Christian Borntraeger --- Documentation/virt/kvm/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 5abc0c1a5aff..5be5cc59869d 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -5956,7 +5956,7 @@ KVM_PV_DUMP_CPU The length of the returned data is provided by uv_info.guest_cpu_stor_len. 4.137 KVM_S390_ZPCI_OP --------------------- +---------------------- :Capability: KVM_CAP_S390_ZPCI_OP :Architectures: s390 From c0da6efc74b47a4dd3e722dfb9e664a253bc597a Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Mon, 11 Jul 2022 13:51:08 +0200 Subject: [PATCH 0948/1436] KVM: s390: Add facility 197 to the allow list z16 also provides facility 197 (The processor-activity-instrumentation extension 1). Let's add it to KVM. Signed-off-by: Christian Borntraeger Link: https://lore.kernel.org/r/20220711115108.6494-1-borntraeger@linux.ibm.com Acked-by: Thomas Huth Reviewed-by: Claudio Imbrenda --- arch/s390/tools/gen_facilities.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/tools/gen_facilities.c b/arch/s390/tools/gen_facilities.c index 530dd941d140..cb0aff5c0187 100644 --- a/arch/s390/tools/gen_facilities.c +++ b/arch/s390/tools/gen_facilities.c @@ -111,6 +111,7 @@ static struct facility_def facility_defs[] = { 193, /* bear enhancement facility */ 194, /* rdp enhancement facility */ 196, /* processor activity instrumentation facility */ + 197, /* processor activity instrumentation extension 1 */ -1 /* END */ } }, From faa2f72cb3569256480c5540d242c84e99965160 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:02 +0200 Subject: [PATCH 0949/1436] KVM: s390: pv: leak the topmost page table when destroy fails Each secure guest must have a unique ASCE (address space control element); we must avoid that new guests use the same page for their ASCE, to avoid errors. Since the ASCE mostly consists of the address of the topmost page table (plus some flags), we must not return that memory to the pool unless the ASCE is no longer in use. Only a successful Destroy Secure Configuration UVC will make the ASCE reusable again. If the Destroy Configuration UVC fails, the ASCE cannot be reused for a secure guest (either for the ASCE or for other memory areas). To avoid a collision, it must not be used again. This is a permanent error and the page becomes in practice unusable, so we set it aside and leak it. On failure we already leak other memory that belongs to the ultravisor (i.e. the variable and base storage for a guest) and not leaking the topmost page table was an oversight. This error (and thus the leakage) should not happen unless the hardware is broken or KVM has some unknown serious bug. Signed-off-by: Claudio Imbrenda Fixes: 29b40f105ec8d55 ("KVM: s390: protvirt: Add initial vm and cpu lifecycle handling") Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20220628135619.32410-2-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-2-imbrenda@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/include/asm/gmap.h | 2 + arch/s390/kvm/pv.c | 9 ++-- arch/s390/mm/gmap.c | 86 ++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h index 40264f60b0da..f4073106e1f3 100644 --- a/arch/s390/include/asm/gmap.h +++ b/arch/s390/include/asm/gmap.h @@ -148,4 +148,6 @@ void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4], unsigned long gaddr, unsigned long vmaddr); int gmap_mark_unmergeable(void); void s390_reset_acc(struct mm_struct *mm); +void s390_unlist_old_asce(struct gmap *gmap); +int s390_replace_asce(struct gmap *gmap); #endif /* _ASM_S390_GMAP_H */ diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index b4a499b10b67..f1733812a263 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -162,10 +162,13 @@ int kvm_s390_pv_deinit_vm(struct kvm *kvm, u16 *rc, u16 *rrc) atomic_set(&kvm->mm->context.is_protected, 0); KVM_UV_EVENT(kvm, 3, "PROTVIRT DESTROY VM: rc %x rrc %x", *rc, *rrc); WARN_ONCE(cc, "protvirt destroy vm failed rc %x rrc %x", *rc, *rrc); - /* Inteded memory leak on "impossible" error */ - if (!cc) + /* Intended memory leak on "impossible" error */ + if (!cc) { kvm_s390_pv_dealloc_vm(kvm); - return cc ? -EIO : 0; + return 0; + } + s390_replace_asce(kvm->arch.gmap); + return -EIO; } int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc) diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index b8ae4a4aa2ba..85cab61d87a9 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -2735,3 +2735,89 @@ void s390_reset_acc(struct mm_struct *mm) mmput(mm); } EXPORT_SYMBOL_GPL(s390_reset_acc); + +/** + * s390_unlist_old_asce - Remove the topmost level of page tables from the + * list of page tables of the gmap. + * @gmap: the gmap whose table is to be removed + * + * On s390x, KVM keeps a list of all pages containing the page tables of the + * gmap (the CRST list). This list is used at tear down time to free all + * pages that are now not needed anymore. + * + * This function removes the topmost page of the tree (the one pointed to by + * the ASCE) from the CRST list. + * + * This means that it will not be freed when the VM is torn down, and needs + * to be handled separately by the caller, unless a leak is actually + * intended. Notice that this function will only remove the page from the + * list, the page will still be used as a top level page table (and ASCE). + */ +void s390_unlist_old_asce(struct gmap *gmap) +{ + struct page *old; + + old = virt_to_page(gmap->table); + spin_lock(&gmap->guest_table_lock); + list_del(&old->lru); + /* + * Sometimes the topmost page might need to be "removed" multiple + * times, for example if the VM is rebooted into secure mode several + * times concurrently, or if s390_replace_asce fails after calling + * s390_remove_old_asce and is attempted again later. In that case + * the old asce has been removed from the list, and therefore it + * will not be freed when the VM terminates, but the ASCE is still + * in use and still pointed to. + * A subsequent call to replace_asce will follow the pointer and try + * to remove the same page from the list again. + * Therefore it's necessary that the page of the ASCE has valid + * pointers, so list_del can work (and do nothing) without + * dereferencing stale or invalid pointers. + */ + INIT_LIST_HEAD(&old->lru); + spin_unlock(&gmap->guest_table_lock); +} +EXPORT_SYMBOL_GPL(s390_unlist_old_asce); + +/** + * s390_replace_asce - Try to replace the current ASCE of a gmap with a copy + * @gmap: the gmap whose ASCE needs to be replaced + * + * If the allocation of the new top level page table fails, the ASCE is not + * replaced. + * In any case, the old ASCE is always removed from the gmap CRST list. + * Therefore the caller has to make sure to save a pointer to it + * beforehand, unless a leak is actually intended. + */ +int s390_replace_asce(struct gmap *gmap) +{ + unsigned long asce; + struct page *page; + void *table; + + s390_unlist_old_asce(gmap); + + page = alloc_pages(GFP_KERNEL_ACCOUNT, CRST_ALLOC_ORDER); + if (!page) + return -ENOMEM; + table = page_to_virt(page); + memcpy(table, gmap->table, 1UL << (CRST_ALLOC_ORDER + PAGE_SHIFT)); + + /* + * The caller has to deal with the old ASCE, but here we make sure + * the new one is properly added to the CRST list, so that + * it will be freed when the VM is torn down. + */ + spin_lock(&gmap->guest_table_lock); + list_add(&page->lru, &gmap->crst_list); + spin_unlock(&gmap->guest_table_lock); + + /* Set new table origin while preserving existing ASCE control bits */ + asce = (gmap->asce & ~_ASCE_ORIGIN) | __pa(table); + WRITE_ONCE(gmap->asce, asce); + WRITE_ONCE(gmap->mm->context.gmap_asce, asce); + WRITE_ONCE(gmap->table, table); + + return 0; +} +EXPORT_SYMBOL_GPL(s390_replace_asce); From a52c25848e3143fbced80e6835de4034cc461fec Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:03 +0200 Subject: [PATCH 0950/1436] KVM: s390: pv: handle secure storage violations for protected guests A secure storage violation is triggered when a protected guest tries to access secure memory that has been mapped erroneously, or that belongs to a different protected guest or to the ultravisor. With upcoming patches, protected guests will be able to trigger secure storage violations in normal operation. This happens for example if a protected guest is rebooted with deferred destroy enabled and the new guest is also protected. When the new protected guest touches pages that have not yet been destroyed, and thus are accounted to the previous protected guest, a secure storage violation is raised. This patch adds handling of secure storage violations for protected guests. This exception is handled by first trying to destroy the page, because it is expected to belong to a defunct protected guest where a destroy should be possible. Note that a secure page can only be destroyed if its protected VM does not have any CPUs, which only happens when the protected VM is being terminated. If that fails, a normal export of the page is attempted. This means that pages that trigger the exception will be made non-secure (in one way or another) before attempting to use them again for a different secure guest. Signed-off-by: Claudio Imbrenda Acked-by: Janosch Frank Link: https://lore.kernel.org/r/20220628135619.32410-3-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-3-imbrenda@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/include/asm/uv.h | 1 + arch/s390/kernel/uv.c | 55 ++++++++++++++++++++++++++++++++++++++ arch/s390/mm/fault.c | 10 +++++++ 3 files changed, 66 insertions(+) diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h index 18fe04c8547e..be3ef9dd6972 100644 --- a/arch/s390/include/asm/uv.h +++ b/arch/s390/include/asm/uv.h @@ -426,6 +426,7 @@ static inline int is_prot_virt_host(void) } int gmap_make_secure(struct gmap *gmap, unsigned long gaddr, void *uvcb); +int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr); int uv_destroy_owned_page(unsigned long paddr); int uv_convert_from_secure(unsigned long paddr); int uv_convert_owned_from_secure(unsigned long paddr); diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index c13d5a7b71f0..4c91a3dbc05b 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -334,6 +334,61 @@ int gmap_convert_to_secure(struct gmap *gmap, unsigned long gaddr) } EXPORT_SYMBOL_GPL(gmap_convert_to_secure); +/** + * gmap_destroy_page - Destroy a guest page. + * @gmap: the gmap of the guest + * @gaddr: the guest address to destroy + * + * An attempt will be made to destroy the given guest page. If the attempt + * fails, an attempt is made to export the page. If both attempts fail, an + * appropriate error is returned. + */ +int gmap_destroy_page(struct gmap *gmap, unsigned long gaddr) +{ + struct vm_area_struct *vma; + unsigned long uaddr; + struct page *page; + int rc; + + rc = -EFAULT; + mmap_read_lock(gmap->mm); + + uaddr = __gmap_translate(gmap, gaddr); + if (IS_ERR_VALUE(uaddr)) + goto out; + vma = vma_lookup(gmap->mm, uaddr); + if (!vma) + goto out; + /* + * Huge pages should not be able to become secure + */ + if (is_vm_hugetlb_page(vma)) + goto out; + + rc = 0; + /* we take an extra reference here */ + page = follow_page(vma, uaddr, FOLL_WRITE | FOLL_GET); + if (IS_ERR_OR_NULL(page)) + goto out; + rc = uv_destroy_owned_page(page_to_phys(page)); + /* + * Fault handlers can race; it is possible that two CPUs will fault + * on the same secure page. One CPU can destroy the page, reboot, + * re-enter secure mode and import it, while the second CPU was + * stuck at the beginning of the handler. At some point the second + * CPU will be able to progress, and it will not be able to destroy + * the page. In that case we do not want to terminate the process, + * we instead try to export the page. + */ + if (rc) + rc = uv_convert_owned_from_secure(page_to_phys(page)); + put_page(page); +out: + mmap_read_unlock(gmap->mm); + return rc; +} +EXPORT_SYMBOL_GPL(gmap_destroy_page); + /* * To be called with the page locked or with an extra reference! This will * prevent gmap_make_secure from touching the page concurrently. Having 2 diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index e173b6187ad5..af1ac49168fb 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -837,6 +837,16 @@ NOKPROBE_SYMBOL(do_non_secure_storage_access); void do_secure_storage_violation(struct pt_regs *regs) { + unsigned long gaddr = regs->int_parm_long & __FAIL_ADDR_MASK; + struct gmap *gmap = (struct gmap *)S390_lowcore.gmap; + + /* + * If the VM has been rebooted, its address space might still contain + * secure pages from the previous boot. + * Clear the page so it can be reused. + */ + if (!gmap_destroy_page(gmap, gaddr)) + return; /* * Either KVM messed up the secure guest mapping or the same * page is mapped into multiple secure guests. From b108f7f0a29b24a94e0c4f9af20f84afaa6ef245 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:04 +0200 Subject: [PATCH 0951/1436] KVM: s390: pv: handle secure storage exceptions for normal guests With upcoming patches, normal guests might touch secure pages. This patch extends the existing exception handler to convert the pages to non secure also when the exception is triggered by a normal guest. This can happen for example when a secure guest reboots; the first stage of a secure guest is non secure, and in general a secure guest can reboot into non-secure mode. If the secure memory of the previous boot has not been cleared up completely yet (which will be allowed to happen in an upcoming patch), a non-secure guest might touch secure memory, which will need to be handled properly. This means that gmap faults must be handled and not cause termination of the process. The handling is the same as userspace accesses, it's enough to translate the gmap address to a user address and then let the normal user fault code handle it. Signed-off-by: Claudio Imbrenda Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20220628135619.32410-4-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-4-imbrenda@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/mm/fault.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index af1ac49168fb..ee7871f770fb 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -754,6 +754,7 @@ void do_secure_storage_access(struct pt_regs *regs) struct vm_area_struct *vma; struct mm_struct *mm; struct page *page; + struct gmap *gmap; int rc; /* @@ -783,6 +784,17 @@ void do_secure_storage_access(struct pt_regs *regs) } switch (get_fault_type(regs)) { + case GMAP_FAULT: + mm = current->mm; + gmap = (struct gmap *)S390_lowcore.gmap; + mmap_read_lock(mm); + addr = __gmap_translate(gmap, addr); + mmap_read_unlock(mm); + if (IS_ERR_VALUE(addr)) { + do_fault_error(regs, VM_ACCESS_FLAGS, VM_FAULT_BADMAP); + break; + } + fallthrough; case USER_FAULT: mm = current->mm; mmap_read_lock(mm); @@ -811,7 +823,6 @@ void do_secure_storage_access(struct pt_regs *regs) if (rc) BUG(); break; - case GMAP_FAULT: default: do_fault_error(regs, VM_READ | VM_WRITE, VM_FAULT_BADMAP); WARN_ON_ONCE(1); From 6f73517d0a99ba8ec972bf053456f1c2932598c0 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:05 +0200 Subject: [PATCH 0952/1436] KVM: s390: pv: refactor s390_reset_acc Refactor s390_reset_acc so that it can be reused in upcoming patches. We don't want to hold all the locks used in a walk_page_range for too long, and the destroy page UVC does take some time to complete. Therefore we quickly gather the pages to destroy, and then destroy them without holding all the locks. The new refactored function optionally allows to return early without completing if a fatal signal is pending (and return and appropriate error code). Two wrappers are provided to call the new function. Signed-off-by: Claudio Imbrenda Reviewed-by: Janosch Frank Reviewed-by: Nico Boehr Link: https://lore.kernel.org/r/20220628135619.32410-5-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-5-imbrenda@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/include/asm/gmap.h | 37 +++++++++++- arch/s390/kvm/pv.c | 12 +++- arch/s390/mm/gmap.c | 107 ++++++++++++++++++++++++----------- 3 files changed, 120 insertions(+), 36 deletions(-) diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h index f4073106e1f3..5cc46e0dde62 100644 --- a/arch/s390/include/asm/gmap.h +++ b/arch/s390/include/asm/gmap.h @@ -147,7 +147,42 @@ int gmap_mprotect_notify(struct gmap *, unsigned long start, void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4], unsigned long gaddr, unsigned long vmaddr); int gmap_mark_unmergeable(void); -void s390_reset_acc(struct mm_struct *mm); void s390_unlist_old_asce(struct gmap *gmap); int s390_replace_asce(struct gmap *gmap); +void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns); +int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start, + unsigned long end, bool interruptible); + +/** + * s390_uv_destroy_range - Destroy a range of pages in the given mm. + * @mm: the mm on which to operate on + * @start: the start of the range + * @end: the end of the range + * + * This function will call cond_sched, so it should not generate stalls, but + * it will otherwise only return when it completed. + */ +static inline void s390_uv_destroy_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + (void)__s390_uv_destroy_range(mm, start, end, false); +} + +/** + * s390_uv_destroy_range_interruptible - Destroy a range of pages in the + * given mm, but stop when a fatal signal is received. + * @mm: the mm on which to operate on + * @start: the start of the range + * @end: the end of the range + * + * This function will call cond_sched, so it should not generate stalls. If + * a fatal signal is received, it will return with -EINTR immediately, + * without finishing destroying the whole range. Upon successful + * completion, 0 is returned. + */ +static inline int s390_uv_destroy_range_interruptible(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + return __s390_uv_destroy_range(mm, start, end, true); +} #endif /* _ASM_S390_GMAP_H */ diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index f1733812a263..a556db3912a1 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "kvm-s390.h" int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc) @@ -153,8 +155,14 @@ int kvm_s390_pv_deinit_vm(struct kvm *kvm, u16 *rc, u16 *rrc) { int cc; - /* make all pages accessible before destroying the guest */ - s390_reset_acc(kvm->mm); + /* + * if the mm still has a mapping, make all its pages accessible + * before destroying the guest + */ + if (mmget_not_zero(kvm->mm)) { + s390_uv_destroy_range(kvm->mm, 0, TASK_SIZE); + mmput(kvm->mm); + } cc = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm), UVC_CMD_DESTROY_SEC_CONF, rc, rrc); diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index 85cab61d87a9..62758cb5872f 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -2697,44 +2697,85 @@ void s390_reset_cmma(struct mm_struct *mm) } EXPORT_SYMBOL_GPL(s390_reset_cmma); -/* - * make inaccessible pages accessible again - */ -static int __s390_reset_acc(pte_t *ptep, unsigned long addr, - unsigned long next, struct mm_walk *walk) -{ - pte_t pte = READ_ONCE(*ptep); +#define GATHER_GET_PAGES 32 - /* There is a reference through the mapping */ - if (pte_present(pte)) - WARN_ON_ONCE(uv_destroy_owned_page(pte_val(pte) & PAGE_MASK)); - - return 0; -} - -static const struct mm_walk_ops reset_acc_walk_ops = { - .pte_entry = __s390_reset_acc, +struct reset_walk_state { + unsigned long next; + unsigned long count; + unsigned long pfns[GATHER_GET_PAGES]; }; -#include -void s390_reset_acc(struct mm_struct *mm) +static int s390_gather_pages(pte_t *ptep, unsigned long addr, + unsigned long next, struct mm_walk *walk) { - if (!mm_is_protected(mm)) - return; - /* - * we might be called during - * reset: we walk the pages and clear - * close of all kvm file descriptors: we walk the pages and clear - * exit of process on fd closure: vma already gone, do nothing - */ - if (!mmget_not_zero(mm)) - return; - mmap_read_lock(mm); - walk_page_range(mm, 0, TASK_SIZE, &reset_acc_walk_ops, NULL); - mmap_read_unlock(mm); - mmput(mm); + struct reset_walk_state *p = walk->private; + pte_t pte = READ_ONCE(*ptep); + + if (pte_present(pte)) { + /* we have a reference from the mapping, take an extra one */ + get_page(phys_to_page(pte_val(pte))); + p->pfns[p->count] = phys_to_pfn(pte_val(pte)); + p->next = next; + p->count++; + } + return p->count >= GATHER_GET_PAGES; } -EXPORT_SYMBOL_GPL(s390_reset_acc); + +static const struct mm_walk_ops gather_pages_ops = { + .pte_entry = s390_gather_pages, +}; + +/* + * Call the Destroy secure page UVC on each page in the given array of PFNs. + * Each page needs to have an extra reference, which will be released here. + */ +void s390_uv_destroy_pfns(unsigned long count, unsigned long *pfns) +{ + unsigned long i; + + for (i = 0; i < count; i++) { + /* we always have an extra reference */ + uv_destroy_owned_page(pfn_to_phys(pfns[i])); + /* get rid of the extra reference */ + put_page(pfn_to_page(pfns[i])); + cond_resched(); + } +} +EXPORT_SYMBOL_GPL(s390_uv_destroy_pfns); + +/** + * __s390_uv_destroy_range - Call the destroy secure page UVC on each page + * in the given range of the given address space. + * @mm: the mm to operate on + * @start: the start of the range + * @end: the end of the range + * @interruptible: if not 0, stop when a fatal signal is received + * + * Walk the given range of the given address space and call the destroy + * secure page UVC on each page. Optionally exit early if a fatal signal is + * pending. + * + * Return: 0 on success, -EINTR if the function stopped before completing + */ +int __s390_uv_destroy_range(struct mm_struct *mm, unsigned long start, + unsigned long end, bool interruptible) +{ + struct reset_walk_state state = { .next = start }; + int r = 1; + + while (r > 0) { + state.count = 0; + mmap_read_lock(mm); + r = walk_page_range(mm, state.next, end, &gather_pages_ops, &state); + mmap_read_unlock(mm); + cond_resched(); + s390_uv_destroy_pfns(state.count, state.pfns); + if (interruptible && fatal_signal_pending(current)) + return -EINTR; + } + return 0; +} +EXPORT_SYMBOL_GPL(__s390_uv_destroy_range); /** * s390_unlist_old_asce - Remove the topmost level of page tables from the From 07fbdf7f934795a9e1728fcb3bdce6e0d8039e0c Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:06 +0200 Subject: [PATCH 0953/1436] KVM: s390: pv: usage counter instead of flag Use the new protected_count field as a counter instead of the old is_protected flag. This will be used in upcoming patches. Increment the counter when a secure configuration is created, and decrement it when it is destroyed. Previously the flag was set when the set secure parameters UVC was performed. Signed-off-by: Claudio Imbrenda Acked-by: Janosch Frank Link: https://lore.kernel.org/r/20220628135619.32410-6-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-6-imbrenda@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/include/asm/mmu.h | 2 +- arch/s390/include/asm/mmu_context.h | 2 +- arch/s390/include/asm/pgtable.h | 2 +- arch/s390/kvm/pv.c | 12 +++++++----- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h index 82aae78e1315..1572b3634cdd 100644 --- a/arch/s390/include/asm/mmu.h +++ b/arch/s390/include/asm/mmu.h @@ -18,7 +18,7 @@ typedef struct { unsigned long asce_limit; unsigned long vdso_base; /* The mmu context belongs to a secure guest. */ - atomic_t is_protected; + atomic_t protected_count; /* * The following bitfields need a down_write on the mm * semaphore when they are written to. As they are only diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h index c7937f369e62..2a38af5a00c2 100644 --- a/arch/s390/include/asm/mmu_context.h +++ b/arch/s390/include/asm/mmu_context.h @@ -26,7 +26,7 @@ static inline int init_new_context(struct task_struct *tsk, INIT_LIST_HEAD(&mm->context.gmap_list); cpumask_clear(&mm->context.cpu_attach_mask); atomic_set(&mm->context.flush_count, 0); - atomic_set(&mm->context.is_protected, 0); + atomic_set(&mm->context.protected_count, 0); mm->context.gmap_asce = 0; mm->context.flush_mm = 0; #ifdef CONFIG_PGSTE diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index a397b072a580..f16403ba81ec 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -525,7 +525,7 @@ static inline int mm_has_pgste(struct mm_struct *mm) static inline int mm_is_protected(struct mm_struct *mm) { #ifdef CONFIG_PGSTE - if (unlikely(atomic_read(&mm->context.is_protected))) + if (unlikely(atomic_read(&mm->context.protected_count))) return 1; #endif return 0; diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index a556db3912a1..59e0d5399113 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -167,7 +167,8 @@ int kvm_s390_pv_deinit_vm(struct kvm *kvm, u16 *rc, u16 *rrc) cc = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm), UVC_CMD_DESTROY_SEC_CONF, rc, rrc); WRITE_ONCE(kvm->arch.gmap->guest_handle, 0); - atomic_set(&kvm->mm->context.is_protected, 0); + if (!cc) + atomic_dec(&kvm->mm->context.protected_count); KVM_UV_EVENT(kvm, 3, "PROTVIRT DESTROY VM: rc %x rrc %x", *rc, *rrc); WARN_ONCE(cc, "protvirt destroy vm failed rc %x rrc %x", *rc, *rrc); /* Intended memory leak on "impossible" error */ @@ -209,11 +210,14 @@ int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc) /* Outputs */ kvm->arch.pv.handle = uvcb.guest_handle; + atomic_inc(&kvm->mm->context.protected_count); if (cc) { - if (uvcb.header.rc & UVC_RC_NEED_DESTROY) + if (uvcb.header.rc & UVC_RC_NEED_DESTROY) { kvm_s390_pv_deinit_vm(kvm, &dummy, &dummy); - else + } else { + atomic_dec(&kvm->mm->context.protected_count); kvm_s390_pv_dealloc_vm(kvm); + } return -EIO; } kvm->arch.gmap->guest_handle = uvcb.guest_handle; @@ -236,8 +240,6 @@ int kvm_s390_pv_set_sec_parms(struct kvm *kvm, void *hdr, u64 length, u16 *rc, *rrc = uvcb.header.rrc; KVM_UV_EVENT(kvm, 3, "PROTVIRT VM SET PARMS: rc %x rrc %x", *rc, *rrc); - if (!cc) - atomic_set(&kvm->mm->context.is_protected, 1); return cc ? -EINVAL : 0; } From 72b1daff2671cef2c8cccc6c4e52f8d5ce4ebe58 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:07 +0200 Subject: [PATCH 0954/1436] KVM: s390: pv: add export before import Due to upcoming changes, it will be possible to temporarily have multiple protected VMs in the same address space, although only one will be actually active. In that scenario, it is necessary to perform an export of every page that is to be imported, since the hardware does not allow a page belonging to a protected guest to be imported into a different protected guest. This also applies to pages that are shared, and thus accessible by the host. Signed-off-by: Claudio Imbrenda Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20220628135619.32410-7-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-7-imbrenda@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/kernel/uv.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/arch/s390/kernel/uv.c b/arch/s390/kernel/uv.c index 4c91a3dbc05b..f9810d2a267c 100644 --- a/arch/s390/kernel/uv.c +++ b/arch/s390/kernel/uv.c @@ -234,6 +234,32 @@ static int make_secure_pte(pte_t *ptep, unsigned long addr, return uvcb->rc == 0x10a ? -ENXIO : -EINVAL; } +/** + * should_export_before_import - Determine whether an export is needed + * before an import-like operation + * @uvcb: the Ultravisor control block of the UVC to be performed + * @mm: the mm of the process + * + * Returns whether an export is needed before every import-like operation. + * This is needed for shared pages, which don't trigger a secure storage + * exception when accessed from a different guest. + * + * Although considered as one, the Unpin Page UVC is not an actual import, + * so it is not affected. + * + * No export is needed also when there is only one protected VM, because the + * page cannot belong to the wrong VM in that case (there is no "other VM" + * it can belong to). + * + * Return: true if an export is needed before every import, otherwise false. + */ +static bool should_export_before_import(struct uv_cb_header *uvcb, struct mm_struct *mm) +{ + if (uvcb->cmd == UVC_CMD_UNPIN_PAGE_SHARED) + return false; + return atomic_read(&mm->context.protected_count) > 1; +} + /* * Requests the Ultravisor to make a page accessible to a guest. * If it's brought in the first time, it will be cleared. If @@ -277,6 +303,8 @@ again: lock_page(page); ptep = get_locked_pte(gmap->mm, uaddr, &ptelock); + if (should_export_before_import(uvcb, gmap->mm)) + uv_convert_from_secure(page_to_phys(page)); rc = make_secure_pte(ptep, uaddr, page, uvcb); pte_unmap_unlock(ptep, ptelock); unlock_page(page); From e40df9efd68a621734fe03efc68b8f3e8da47cf8 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:08 +0200 Subject: [PATCH 0955/1436] KVM: s390: pv: clear the state without memset Do not use memset to clean the whole struct kvm_s390_pv; instead, explicitly clear the fields that need to be cleared. Upcoming patches will introduce new fields in the struct kvm_s390_pv that will not need to be cleared. Signed-off-by: Claudio Imbrenda Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20220628135619.32410-8-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-8-imbrenda@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/kvm/pv.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index 59e0d5399113..d18c5ccfa5dc 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -17,6 +17,14 @@ #include #include "kvm-s390.h" +static void kvm_s390_clear_pv_state(struct kvm *kvm) +{ + kvm->arch.pv.handle = 0; + kvm->arch.pv.guest_len = 0; + kvm->arch.pv.stor_base = 0; + kvm->arch.pv.stor_var = NULL; +} + int kvm_s390_pv_destroy_cpu(struct kvm_vcpu *vcpu, u16 *rc, u16 *rrc) { int cc; @@ -111,7 +119,7 @@ static void kvm_s390_pv_dealloc_vm(struct kvm *kvm) vfree(kvm->arch.pv.stor_var); free_pages(kvm->arch.pv.stor_base, get_order(uv_info.guest_base_stor_len)); - memset(&kvm->arch.pv, 0, sizeof(kvm->arch.pv)); + kvm_s390_clear_pv_state(kvm); } static int kvm_s390_pv_alloc_vm(struct kvm *kvm) From be48d86f77f0cbceecadf10fda6330d82a0a77b7 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:09 +0200 Subject: [PATCH 0956/1436] KVM: s390: pv: Add kvm_s390_cpus_from_pv to kvm-s390.h and add documentation Future changes make it necessary to call this function from pv.c. While we are at it, let's properly document kvm_s390_cpus_from_pv() and kvm_s390_cpus_to_pv(). Signed-off-by: Claudio Imbrenda Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20220628135619.32410-9-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-9-imbrenda@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/kvm/kvm-s390.c | 36 ++++++++++++++++++++++++++++++------ arch/s390/kvm/kvm-s390.h | 1 + 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 18b0a6f0cd9c..d10c3b163cdc 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -2237,12 +2237,25 @@ out: return r; } -static int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rcp, u16 *rrcp) +/** + * kvm_s390_cpus_from_pv - Convert all protected vCPUs in a protected VM to + * non protected. + * @kvm: the VM whose protected vCPUs are to be converted + * @rc: return value for the RC field of the UVC (in case of error) + * @rrc: return value for the RRC field of the UVC (in case of error) + * + * Does not stop in case of error, tries to convert as many + * CPUs as possible. In case of error, the RC and RRC of the last error are + * returned. + * + * Return: 0 in case of success, otherwise -EIO + */ +int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rc, u16 *rrc) { struct kvm_vcpu *vcpu; - u16 rc, rrc; - int ret = 0; unsigned long i; + u16 _rc, _rrc; + int ret = 0; /* * We ignore failures and try to destroy as many CPUs as possible. @@ -2254,9 +2267,9 @@ static int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rcp, u16 *rrcp) */ kvm_for_each_vcpu(i, vcpu, kvm) { mutex_lock(&vcpu->mutex); - if (kvm_s390_pv_destroy_cpu(vcpu, &rc, &rrc) && !ret) { - *rcp = rc; - *rrcp = rrc; + if (kvm_s390_pv_destroy_cpu(vcpu, &_rc, &_rrc) && !ret) { + *rc = _rc; + *rrc = _rrc; ret = -EIO; } mutex_unlock(&vcpu->mutex); @@ -2267,6 +2280,17 @@ static int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rcp, u16 *rrcp) return ret; } +/** + * kvm_s390_cpus_to_pv - Convert all non-protected vCPUs in a protected VM + * to protected. + * @kvm: the VM whose protected vCPUs are to be converted + * @rc: return value for the RC field of the UVC (in case of error) + * @rrc: return value for the RRC field of the UVC (in case of error) + * + * Tries to undo the conversion in case of error. + * + * Return: 0 in case of success, otherwise -EIO + */ static int kvm_s390_cpus_to_pv(struct kvm *kvm, u16 *rc, u16 *rrc) { unsigned long i; diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index cf4f4d1713ea..f6fd668f887e 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h @@ -379,6 +379,7 @@ int kvm_s390_vcpu_setup_cmma(struct kvm_vcpu *vcpu); void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu); void kvm_s390_set_cpu_timer(struct kvm_vcpu *vcpu, __u64 cputm); __u64 kvm_s390_get_cpu_timer(struct kvm_vcpu *vcpu); +int kvm_s390_cpus_from_pv(struct kvm *kvm, u16 *rc, u16 *rrc); /* implemented in diag.c */ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu); From ce838f7dc7957afb2846c3bc537db56e4c513390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Tue, 12 Jul 2022 17:45:54 -0400 Subject: [PATCH 0957/1436] platform/chrome: cros_ec_typec: Use dev_err_probe on port register fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The typec_register_port() can fail with EPROBE_DEFER if the endpoint node hasn't probed yet. In order to avoid spamming the log with errors in that case, log using dev_err_probe(). Signed-off-by: Nícolas F. R. A. Prado Reviewed-by: Guenter Roeck Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20220712214554.545035-1-nfraprado@collabora.com Signed-off-by: Prashant Malani --- drivers/platform/chrome/cros_ec_typec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index d6088ba447af..8c0ca3c128ee 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -352,8 +352,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec) cros_port->port = typec_register_port(dev, cap); if (IS_ERR(cros_port->port)) { - dev_err(dev, "Failed to register port %d\n", port_num); ret = PTR_ERR(cros_port->port); + dev_err_probe(dev, ret, "Failed to register port %d\n", port_num); goto unregister_ports; } From 14fd95bf145ddb8201406b89c83faf24e7e3d52f Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Thu, 14 Jul 2022 01:11:15 +0000 Subject: [PATCH 0958/1436] KVM: selftests: Use "a" and "d" to set EAX/EDX for wrmsr_safe() Do not use GCC's "A" constraint to load EAX:EDX in wrmsr_safe(). Per GCC's documenation on x86-specific constraints, "A" will not actually load a 64-bit value into EAX:EDX on x86-64. The a and d registers. This class is used for instructions that return double word results in the ax:dx register pair. Single word values will be allocated either in ax or dx. For example on i386 the following implements rdtsc: unsigned long long rdtsc (void) { unsigned long long tick; __asm__ __volatile__("rdtsc":"=A"(tick)); return tick; } This is not correct on x86-64 as it would allocate tick in either ax or dx. You have to use the following variant instead: unsigned long long rdtsc (void) { unsigned int tickl, tickh; __asm__ __volatile__("rdtsc":"=a"(tickl),"=d"(tickh)); return ((unsigned long long)tickh << 32)|tickl; } Because a u64 fits in a single 64-bit register, using "A" for selftests, which are 64-bit only, results in GCC loading the value into either RAX or RDX instead of splitting it across EAX:EDX. E.g.: kvm_exit: reason MSR_WRITE rip 0x402919 info 0 0 kvm_msr: msr_write 40000118 = 0x60000000001 (#GP) ... With "A": 48 8b 43 08 mov 0x8(%rbx),%rax 49 b9 ba da ca ba 0a movabs $0xabacadaba,%r9 00 00 00 4c 8d 15 07 00 00 00 lea 0x7(%rip),%r10 # 402f44 4c 8d 1d 06 00 00 00 lea 0x6(%rip),%r11 # 402f4a 0f 30 wrmsr With "a"/"d": 48 8b 53 08 mov 0x8(%rbx),%rdx 89 d0 mov %edx,%eax 48 c1 ea 20 shr $0x20,%rdx 49 b9 ba da ca ba 0a movabs $0xabacadaba,%r9 00 00 00 4c 8d 15 07 00 00 00 lea 0x7(%rip),%r10 # 402fc3 4c 8d 1d 06 00 00 00 lea 0x6(%rip),%r11 # 402fc9 0f 30 wrmsr Fixes: 3b23054cd3f5 ("KVM: selftests: Add x86-64 support for exception fixup") Signed-off-by: Vitaly Kuznetsov Link: https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints [sean: use "& -1u", provide GCC blurb and link to documentation] Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220714011115.3135828-1-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/processor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 79dcf6be1b47..71e942ffac77 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -612,7 +612,7 @@ static inline uint8_t rdmsr_safe(uint32_t msr, uint64_t *val) static inline uint8_t wrmsr_safe(uint32_t msr, uint64_t val) { - return kvm_asm_safe("wrmsr", "A"(val), "c"(msr)); + return kvm_asm_safe("wrmsr", "a"(val & -1u), "d"(val >> 32), "c"(msr)); } uint64_t vm_get_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, From 43bb9e000ea4c62154c01844771fea25b8b83520 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 11 Jul 2022 22:57:53 +0000 Subject: [PATCH 0959/1436] KVM: x86: Tweak name of MONITOR/MWAIT #UD quirk to make it #UD specific Add a "UD" clause to KVM_X86_QUIRK_MWAIT_NEVER_FAULTS to make it clear that the quirk only controls the #UD behavior of MONITOR/MWAIT. KVM doesn't currently enforce fault checks when MONITOR/MWAIT are supported, but that could change in the future. SVM also has a virtualization hole in that it checks all faults before intercepts, and so "never faults" is already a lie when running on SVM. Fixes: bfbcc81bb82c ("KVM: x86: Add a quirk for KVM's "MONITOR/MWAIT are NOPs!" behavior") Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220711225753.1073989-4-seanjc@google.com --- Documentation/virt/kvm/api.rst | 2 +- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/include/uapi/asm/kvm.h | 2 +- arch/x86/kvm/x86.c | 2 +- tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index bafaeedd455c..cd9361f22530 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -7523,7 +7523,7 @@ The valid bits in cap.args[0] are: incorrect hypercall instruction will generate a #UD within the guest. -KVM_X86_QUIRK_MWAIT_NEVER_FAULTS By default, KVM emulates MONITOR/MWAIT (if +KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS By default, KVM emulates MONITOR/MWAIT (if they are intercepted) as NOPs regardless of whether or not MONITOR/MWAIT are supported according to guest CPUID. When this quirk diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index dd6a26f7d46c..d4ece7bf2124 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2096,6 +2096,6 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages); KVM_X86_QUIRK_OUT_7E_INC_RIP | \ KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT | \ KVM_X86_QUIRK_FIX_HYPERCALL_INSN | \ - KVM_X86_QUIRK_MWAIT_NEVER_FAULTS) + KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS) #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kvm.h index ee3896416c68..a0c0ab0c898e 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -439,7 +439,7 @@ struct kvm_sync_regs { #define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3) #define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4) #define KVM_X86_QUIRK_FIX_HYPERCALL_INSN (1 << 5) -#define KVM_X86_QUIRK_MWAIT_NEVER_FAULTS (1 << 6) +#define KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS (1 << 6) #define KVM_STATE_NESTED_FORMAT_VMX 0 #define KVM_STATE_NESTED_FORMAT_SVM 1 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 67dcaa670874..db46c060acb5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2046,7 +2046,7 @@ EXPORT_SYMBOL_GPL(kvm_handle_invalid_op); static int kvm_emulate_monitor_mwait(struct kvm_vcpu *vcpu, const char *insn) { - if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MWAIT_NEVER_FAULTS) && + if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS) && !guest_cpuid_has(vcpu, X86_FEATURE_MWAIT)) return kvm_handle_invalid_op(vcpu); diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c index 6a4ebcdfa374..094c68d744c0 100644 --- a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c @@ -113,7 +113,7 @@ int main(int argc, char *argv[]) disabled_quirks = 0; if (testcase & MWAIT_QUIRK_DISABLED) - disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_FAULTS; + disabled_quirks |= KVM_X86_QUIRK_MWAIT_NEVER_UD_FAULTS; if (testcase & MISC_ENABLES_QUIRK_DISABLED) disabled_quirks |= KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT; vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, disabled_quirks); From ec6e4d863258d4bfb36d48d5e3ef68140234d688 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 11 Jul 2022 23:27:48 +0000 Subject: [PATCH 0960/1436] KVM: x86: Mark TSS busy during LTR emulation _after_ all fault checks Wait to mark the TSS as busy during LTR emulation until after all fault checks for the LTR have passed. Specifically, don't mark the TSS busy if the new TSS base is non-canonical. Opportunistically drop the one-off !seg_desc.PRESENT check for TR as the only reason for the early check was to avoid marking a !PRESENT TSS as busy, i.e. the common !PRESENT is now done before setting the busy bit. Fixes: e37a75a13cda ("KVM: x86: Emulator ignores LDTR/TR extended base on LLDT/LTR") Reported-by: syzbot+760a73552f47a8cd0fd9@syzkaller.appspotmail.com Cc: stable@vger.kernel.org Cc: Tetsuo Handa Cc: Hou Wenlong Signed-off-by: Sean Christopherson Reviewed-by: Maxim Levitsky Link: https://lore.kernel.org/r/20220711232750.1092012-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/emulate.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 39ea9138224c..09e4b67b881f 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1699,16 +1699,6 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, case VCPU_SREG_TR: if (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9)) goto exception; - if (!seg_desc.p) { - err_vec = NP_VECTOR; - goto exception; - } - old_desc = seg_desc; - seg_desc.type |= 2; /* busy */ - ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc, - sizeof(seg_desc), &ctxt->exception); - if (ret != X86EMUL_CONTINUE) - return ret; break; case VCPU_SREG_LDTR: if (seg_desc.s || seg_desc.type != 2) @@ -1749,6 +1739,15 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, ((u64)base3 << 32), ctxt)) return emulate_gp(ctxt, 0); } + + if (seg == VCPU_SREG_TR) { + old_desc = seg_desc; + seg_desc.type |= 2; /* busy */ + ret = ctxt->ops->cmpxchg_emulated(ctxt, desc_addr, &old_desc, &seg_desc, + sizeof(seg_desc), &ctxt->exception); + if (ret != X86EMUL_CONTINUE) + return ret; + } load: ctxt->ops->set_segment(ctxt, selector, &seg_desc, base3, seg); if (desc) From 2626206963ace9e8bf92b6eea5ff78dd674c555c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 11 Jul 2022 23:27:49 +0000 Subject: [PATCH 0961/1436] KVM: x86: Set error code to segment selector on LLDT/LTR non-canonical #GP When injecting a #GP on LLDT/LTR due to a non-canonical LDT/TSS base, set the error code to the selector. Intel SDM's says nothing about the #GP, but AMD's APM explicitly states that both LLDT and LTR set the error code to the selector, not zero. Note, a non-canonical memory operand on LLDT/LTR does generate a #GP(0), but the KVM code in question is specific to the base from the descriptor. Fixes: e37a75a13cda ("KVM: x86: Emulator ignores LDTR/TR extended base on LLDT/LTR") Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Reviewed-by: Maxim Levitsky Link: https://lore.kernel.org/r/20220711232750.1092012-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/emulate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 09e4b67b881f..bd9e9c5627d0 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -1736,8 +1736,8 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (ret != X86EMUL_CONTINUE) return ret; if (emul_is_noncanonical_address(get_desc_base(&seg_desc) | - ((u64)base3 << 32), ctxt)) - return emulate_gp(ctxt, 0); + ((u64)base3 << 32), ctxt)) + return emulate_gp(ctxt, err_code); } if (seg == VCPU_SREG_TR) { From 0bc273266112937cd6560f7d447b6aa9cfd9134a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Mon, 11 Jul 2022 23:27:50 +0000 Subject: [PATCH 0962/1436] KVM: x86: WARN only once if KVM leaves a dangling userspace I/O request Change a WARN_ON() to separate WARN_ON_ONCE() if KVM has an outstanding PIO or MMIO request without an associated callback, i.e. if KVM queued a userspace I/O exit but didn't actually exit to userspace before moving on to something else. Warning on every KVM_RUN risks spamming the kernel if KVM gets into a bad state. Opportunistically split the WARNs so that it's easier to triage failures when a WARN fires. Deliberately do not use KVM_BUG_ON(), i.e. don't kill the VM. While the WARN is all but guaranteed to fire if and only if there's a KVM bug, a dangling I/O request does not present a danger to KVM (that flag is truly truly consumed only in a single emulator path), and any such bug is unlikely to be fatal to the VM (KVM essentially failed to do something it shouldn't have tried to do in the first place). In other words, note the bug, but let the VM keep running. Signed-off-by: Sean Christopherson Reviewed-by: Maxim Levitsky Link: https://lore.kernel.org/r/20220711232750.1092012-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index db46c060acb5..0729e434c51b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -10849,8 +10849,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) r = cui(vcpu); if (r <= 0) goto out; - } else - WARN_ON(vcpu->arch.pio.count || vcpu->mmio_needed); + } else { + WARN_ON_ONCE(vcpu->arch.pio.count); + WARN_ON_ONCE(vcpu->mmio_needed); + } if (kvm_run->immediate_exit) { r = -EINTR; From 8fb2638a568d8ef635bbef4f61eb6587d2ebd8da Mon Sep 17 00:00:00 2001 From: Colton Lewis Date: Wed, 15 Jun 2022 19:31:13 +0000 Subject: [PATCH 0963/1436] KVM: selftests: enumerate GUEST_ASSERT arguments Enumerate GUEST_ASSERT arguments to avoid magic indices to ucall.args. Signed-off-by: Colton Lewis Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20220615193116.806312-2-coltonlewis@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/ucall_common.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index 98562f685151..dbe872870b83 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -32,6 +32,14 @@ uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc); ucall(UCALL_SYNC, 6, "hello", stage, arg1, arg2, arg3, arg4) #define GUEST_SYNC(stage) ucall(UCALL_SYNC, 2, "hello", stage) #define GUEST_DONE() ucall(UCALL_DONE, 0) + +enum guest_assert_builtin_args { + GUEST_ERROR_STRING, + GUEST_FILE, + GUEST_LINE, + GUEST_ASSERT_BUILTIN_NARGS +}; + #define __GUEST_ASSERT(_condition, _condstr, _nargs, _args...) do { \ if (!(_condition)) \ ucall(UCALL_ABORT, 2 + _nargs, \ From fc573fa4f38aa0cecace00d00cc60109ae947834 Mon Sep 17 00:00:00 2001 From: Colton Lewis Date: Wed, 15 Jun 2022 19:31:14 +0000 Subject: [PATCH 0964/1436] KVM: selftests: Increase UCALL_MAX_ARGS to 7 Increase UCALL_MAX_ARGS to 7 to allow GUEST_ASSERT_4 to pass 3 builtin ucall arguments specified in guest_assert_builtin_args plus 4 user-specified arguments. Signed-off-by: Colton Lewis Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20220615193116.806312-3-coltonlewis@google.com Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/include/ucall_common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index dbe872870b83..568c562f14cd 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -16,7 +16,7 @@ enum { UCALL_UNHANDLED, }; -#define UCALL_MAX_ARGS 6 +#define UCALL_MAX_ARGS 7 struct ucall { uint64_t cmd; From ddcb57afd5815191f02aec12f18b4d1bbad5fb9d Mon Sep 17 00:00:00 2001 From: Colton Lewis Date: Wed, 15 Jun 2022 19:31:15 +0000 Subject: [PATCH 0965/1436] KVM: selftests: Write REPORT_GUEST_ASSERT macros to pair with GUEST_ASSERT Write REPORT_GUEST_ASSERT macros to pair with GUEST_ASSERT to abstract and make consistent all guest assertion reporting. Every report includes an explanatory string, a filename, and a line number. Signed-off-by: Colton Lewis Reviewed-by: Andrew Jones Link: https://lore.kernel.org/r/20220615193116.806312-4-coltonlewis@google.com Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/ucall_common.h | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index 568c562f14cd..e8af3b4fef6d 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -6,6 +6,7 @@ */ #ifndef SELFTEST_KVM_UCALL_COMMON_H #define SELFTEST_KVM_UCALL_COMMON_H +#include "test_util.h" /* Common ucalls */ enum { @@ -64,4 +65,45 @@ enum guest_assert_builtin_args { #define GUEST_ASSERT_EQ(a, b) __GUEST_ASSERT((a) == (b), #a " == " #b, 2, a, b) +#define __REPORT_GUEST_ASSERT(_ucall, fmt, _args...) \ + TEST_FAIL("%s at %s:%ld\n" fmt, \ + (const char *)(_ucall).args[GUEST_ERROR_STRING], \ + (const char *)(_ucall).args[GUEST_FILE], \ + (_ucall).args[GUEST_LINE], \ + ##_args) + +#define GUEST_ASSERT_ARG(ucall, i) ((ucall).args[GUEST_ASSERT_BUILTIN_NARGS + i]) + +#define REPORT_GUEST_ASSERT(ucall) \ + __REPORT_GUEST_ASSERT((ucall), "") + +#define REPORT_GUEST_ASSERT_1(ucall, fmt) \ + __REPORT_GUEST_ASSERT((ucall), \ + fmt, \ + GUEST_ASSERT_ARG((ucall), 0)) + +#define REPORT_GUEST_ASSERT_2(ucall, fmt) \ + __REPORT_GUEST_ASSERT((ucall), \ + fmt, \ + GUEST_ASSERT_ARG((ucall), 0), \ + GUEST_ASSERT_ARG((ucall), 1)) + +#define REPORT_GUEST_ASSERT_3(ucall, fmt) \ + __REPORT_GUEST_ASSERT((ucall), \ + fmt, \ + GUEST_ASSERT_ARG((ucall), 0), \ + GUEST_ASSERT_ARG((ucall), 1), \ + GUEST_ASSERT_ARG((ucall), 2)) + +#define REPORT_GUEST_ASSERT_4(ucall, fmt) \ + __REPORT_GUEST_ASSERT((ucall), \ + fmt, \ + GUEST_ASSERT_ARG((ucall), 0), \ + GUEST_ASSERT_ARG((ucall), 1), \ + GUEST_ASSERT_ARG((ucall), 2), \ + GUEST_ASSERT_ARG((ucall), 3)) + +#define REPORT_GUEST_ASSERT_N(ucall, fmt, args...) \ + __REPORT_GUEST_ASSERT((ucall), fmt, ##args) + #endif /* SELFTEST_KVM_UCALL_COMMON_H */ From 594a1c271c159c9c5f0ff2d92ebfda469e94e48d Mon Sep 17 00:00:00 2001 From: Colton Lewis Date: Wed, 15 Jun 2022 19:31:16 +0000 Subject: [PATCH 0966/1436] KVM: selftests: Fix filename reporting in guest asserts Fix filename reporting in guest asserts by ensuring the GUEST_ASSERT macro records __FILE__ and substituting REPORT_GUEST_ASSERT for many repetitive calls to TEST_FAIL. Previously filename was reported by using __FILE__ directly in the selftest, wrongly assuming it would always be the same as where the assertion failed. Signed-off-by: Colton Lewis Reported-by: Ricardo Koller Fixes: 4e18bccc2e5544f0be28fc1c4e6be47a469d6c60 Link: https://lore.kernel.org/r/20220615193116.806312-5-coltonlewis@google.com [sean: convert more TEST_FAIL => REPORT_GUEST_ASSERT instances] Signed-off-by: Sean Christopherson --- .../selftests/kvm/aarch64/arch_timer.c | 11 +++++--- .../selftests/kvm/aarch64/debug-exceptions.c | 4 +-- .../selftests/kvm/aarch64/hypercalls.c | 7 ++--- .../testing/selftests/kvm/aarch64/psci_test.c | 3 +-- .../testing/selftests/kvm/aarch64/vgic_irq.c | 4 +-- .../selftests/kvm/include/ucall_common.h | 11 ++++---- .../testing/selftests/kvm/memslot_perf_test.c | 4 +-- tools/testing/selftests/kvm/s390x/tprot.c | 26 +++++++++---------- .../selftests/kvm/set_memory_region_test.c | 3 +-- tools/testing/selftests/kvm/steal_time.c | 3 +-- .../kvm/system_counter_offset_test.c | 3 +-- tools/testing/selftests/kvm/x86_64/amx_test.c | 3 +-- .../testing/selftests/kvm/x86_64/cpuid_test.c | 3 +-- .../kvm/x86_64/cr4_cpuid_sync_test.c | 2 +- .../kvm/x86_64/emulator_error_test.c | 3 +-- .../testing/selftests/kvm/x86_64/evmcs_test.c | 3 +-- .../selftests/kvm/x86_64/fix_hypercall_test.c | 2 +- .../selftests/kvm/x86_64/hyperv_clock.c | 3 +-- .../selftests/kvm/x86_64/hyperv_features.c | 8 ++---- .../selftests/kvm/x86_64/hyperv_svm_test.c | 3 +-- .../selftests/kvm/x86_64/kvm_clock_test.c | 3 +-- .../selftests/kvm/x86_64/kvm_pv_test.c | 4 +-- .../selftests/kvm/x86_64/monitor_mwait_test.c | 4 +-- .../selftests/kvm/x86_64/set_boot_cpu_id.c | 4 +-- .../testing/selftests/kvm/x86_64/state_test.c | 3 +-- .../selftests/kvm/x86_64/svm_int_ctl_test.c | 2 +- .../kvm/x86_64/svm_nested_soft_inject_test.c | 3 +-- .../selftests/kvm/x86_64/svm_vmcall_test.c | 2 +- .../kvm/x86_64/triple_fault_event_test.c | 2 +- .../selftests/kvm/x86_64/tsc_msrs_test.c | 4 +-- .../selftests/kvm/x86_64/userspace_io_test.c | 4 +-- .../kvm/x86_64/userspace_msr_exit_test.c | 5 ++-- .../kvm/x86_64/vmx_apic_access_test.c | 3 +-- .../kvm/x86_64/vmx_close_while_nested_test.c | 2 +- .../selftests/kvm/x86_64/vmx_dirty_log_test.c | 3 +-- .../x86_64/vmx_invalid_nested_guest_state.c | 2 +- .../kvm/x86_64/vmx_nested_tsc_scaling_test.c | 2 +- .../kvm/x86_64/vmx_preemption_timer_test.c | 3 +-- .../kvm/x86_64/vmx_tsc_adjust_test.c | 2 +- .../selftests/kvm/x86_64/xen_shinfo_test.c | 2 +- .../selftests/kvm/x86_64/xen_vmcall_test.c | 2 +- 41 files changed, 68 insertions(+), 102 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/arch_timer.c b/tools/testing/selftests/kvm/aarch64/arch_timer.c index f68019be67c0..574eb73f0e90 100644 --- a/tools/testing/selftests/kvm/aarch64/arch_timer.c +++ b/tools/testing/selftests/kvm/aarch64/arch_timer.c @@ -231,10 +231,13 @@ static void *test_vcpu_run(void *arg) break; case UCALL_ABORT: sync_global_from_guest(vm, *shared_data); - TEST_FAIL("%s at %s:%ld\n\tvalues: %lu, %lu; %lu, vcpu: %u; stage: %u; iter: %u", - (const char *)uc.args[0], __FILE__, uc.args[1], - uc.args[2], uc.args[3], uc.args[4], vcpu_idx, - shared_data->guest_stage, shared_data->nr_iter); + REPORT_GUEST_ASSERT_N(uc, "values: %lu, %lu; %lu, vcpu %u; stage; %u; iter: %u", + GUEST_ASSERT_ARG(uc, 0), + GUEST_ASSERT_ARG(uc, 1), + GUEST_ASSERT_ARG(uc, 2), + vcpu_idx, + shared_data->guest_stage, + shared_data->nr_iter); break; default: TEST_FAIL("Unexpected guest exit\n"); diff --git a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c index b8072b40ccc8..2ee35cf9801e 100644 --- a/tools/testing/selftests/kvm/aarch64/debug-exceptions.c +++ b/tools/testing/selftests/kvm/aarch64/debug-exceptions.c @@ -283,9 +283,7 @@ int main(int argc, char *argv[]) stage, (ulong)uc.args[1]); break; case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld\n\tvalues: %#lx, %#lx", - (const char *)uc.args[0], - __FILE__, uc.args[1], uc.args[2], uc.args[3]); + REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); break; case UCALL_DONE: goto done; diff --git a/tools/testing/selftests/kvm/aarch64/hypercalls.c b/tools/testing/selftests/kvm/aarch64/hypercalls.c index 5fce4969cbb9..a39da3fe4952 100644 --- a/tools/testing/selftests/kvm/aarch64/hypercalls.c +++ b/tools/testing/selftests/kvm/aarch64/hypercalls.c @@ -291,9 +291,10 @@ static void test_run(void) guest_done = true; break; case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld\n\tvalues: 0x%lx, 0x%lx; 0x%lx, stage: %u", - (const char *)uc.args[0], __FILE__, uc.args[1], - uc.args[2], uc.args[3], uc.args[4], stage); + REPORT_GUEST_ASSERT_N(uc, "values: 0x%lx, 0x%lx; 0x%lx, stage: %u", + GUEST_ASSERT_ARG(uc, 0), + GUEST_ASSERT_ARG(uc, 1), + GUEST_ASSERT_ARG(uc, 2), stage); break; default: TEST_FAIL("Unexpected guest exit\n"); diff --git a/tools/testing/selftests/kvm/aarch64/psci_test.c b/tools/testing/selftests/kvm/aarch64/psci_test.c index b665b534cb78..f7621f6e938e 100644 --- a/tools/testing/selftests/kvm/aarch64/psci_test.c +++ b/tools/testing/selftests/kvm/aarch64/psci_test.c @@ -94,8 +94,7 @@ static void enter_guest(struct kvm_vcpu *vcpu) vcpu_run(vcpu); if (get_ucall(vcpu, &uc) == UCALL_ABORT) - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, - uc.args[1]); + REPORT_GUEST_ASSERT(uc); } static void assert_vcpu_reset(struct kvm_vcpu *vcpu) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_irq.c b/tools/testing/selftests/kvm/aarch64/vgic_irq.c index 046ba4fde648..17417220a083 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_irq.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_irq.c @@ -782,9 +782,7 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split) run_guest_cmd(vcpu, gic_fd, &inject_args, &args); break; case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld\n\tvalues: %#lx, %#lx", - (const char *)uc.args[0], - __FILE__, uc.args[1], uc.args[2], uc.args[3]); + REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); break; case UCALL_DONE: goto done; diff --git a/tools/testing/selftests/kvm/include/ucall_common.h b/tools/testing/selftests/kvm/include/ucall_common.h index e8af3b4fef6d..ee79d180e07e 100644 --- a/tools/testing/selftests/kvm/include/ucall_common.h +++ b/tools/testing/selftests/kvm/include/ucall_common.h @@ -41,11 +41,12 @@ enum guest_assert_builtin_args { GUEST_ASSERT_BUILTIN_NARGS }; -#define __GUEST_ASSERT(_condition, _condstr, _nargs, _args...) do { \ - if (!(_condition)) \ - ucall(UCALL_ABORT, 2 + _nargs, \ - "Failed guest assert: " \ - _condstr, __LINE__, _args); \ +#define __GUEST_ASSERT(_condition, _condstr, _nargs, _args...) \ +do { \ + if (!(_condition)) \ + ucall(UCALL_ABORT, GUEST_ASSERT_BUILTIN_NARGS + _nargs, \ + "Failed guest assert: " _condstr, \ + __FILE__, __LINE__, ##_args); \ } while (0) #define GUEST_ASSERT(_condition) \ diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c index 5f98489e4f4d..44995446d942 100644 --- a/tools/testing/selftests/kvm/memslot_perf_test.c +++ b/tools/testing/selftests/kvm/memslot_perf_test.c @@ -162,9 +162,7 @@ static void *vcpu_worker(void *__data) goto done; break; case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld, val = %lu", - (const char *)uc.args[0], - __FILE__, uc.args[1], uc.args[2]); + REPORT_GUEST_ASSERT_1(uc, "val = %lu"); break; case UCALL_DONE: goto done; diff --git a/tools/testing/selftests/kvm/s390x/tprot.c b/tools/testing/selftests/kvm/s390x/tprot.c index 015a13056503..a9a0b76e5fa4 100644 --- a/tools/testing/selftests/kvm/s390x/tprot.c +++ b/tools/testing/selftests/kvm/s390x/tprot.c @@ -181,20 +181,18 @@ static void guest_code(void) GUEST_SYNC(perform_next_stage(&i, mapped_0)); } -#define HOST_SYNC_NO_TAP(vcpup, stage) \ -({ \ - struct kvm_vcpu *__vcpu = (vcpup); \ - struct ucall uc; \ - int __stage = (stage); \ - \ - vcpu_run(__vcpu); \ - get_ucall(__vcpu, &uc); \ - if (uc.cmd == UCALL_ABORT) { \ - TEST_FAIL("line %lu: %s, hints: %lu, %lu", uc.args[1], \ - (const char *)uc.args[0], uc.args[2], uc.args[3]); \ - } \ - ASSERT_EQ(uc.cmd, UCALL_SYNC); \ - ASSERT_EQ(uc.args[1], __stage); \ +#define HOST_SYNC_NO_TAP(vcpup, stage) \ +({ \ + struct kvm_vcpu *__vcpu = (vcpup); \ + struct ucall uc; \ + int __stage = (stage); \ + \ + vcpu_run(__vcpu); \ + get_ucall(__vcpu, &uc); \ + if (uc.cmd == UCALL_ABORT) \ + REPORT_GUEST_ASSERT_2(uc, "hints: %lu, %lu"); \ + ASSERT_EQ(uc.cmd, UCALL_SYNC); \ + ASSERT_EQ(uc.args[1], __stage); \ }) #define HOST_SYNC(vcpu, stage) \ diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index 47b219dd60e4..0d55f508d595 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -88,8 +88,7 @@ static void *vcpu_worker(void *data) } if (run->exit_reason == KVM_EXIT_IO && cmd == UCALL_ABORT) - TEST_FAIL("%s at %s:%ld, val = %lu", (const char *)uc.args[0], - __FILE__, uc.args[1], uc.args[2]); + REPORT_GUEST_ASSERT_1(uc, "val = %lu"); return NULL; } diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index d122f1e05cdd..9866a71463d7 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -234,8 +234,7 @@ static void run_vcpu(struct kvm_vcpu *vcpu) case UCALL_DONE: break; case UCALL_ABORT: - TEST_ASSERT(false, "%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); default: TEST_ASSERT(false, "Unexpected exit: %s", exit_reason_str(vcpu->run->exit_reason)); diff --git a/tools/testing/selftests/kvm/system_counter_offset_test.c b/tools/testing/selftests/kvm/system_counter_offset_test.c index 862a8e93e070..1c274933912b 100644 --- a/tools/testing/selftests/kvm/system_counter_offset_test.c +++ b/tools/testing/selftests/kvm/system_counter_offset_test.c @@ -83,8 +83,7 @@ static void handle_sync(struct ucall *uc, uint64_t start, uint64_t end) static void handle_abort(struct ucall *uc) { - TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], - __FILE__, uc->args[1]); + REPORT_GUEST_ASSERT(*uc); } static void enter_guest(struct kvm_vcpu *vcpu) diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index dab4ca16a2df..b71763b11b78 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -373,8 +373,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: switch (uc.args[1]) { diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index 4aa784932597..3767a0cc694b 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -132,8 +132,7 @@ static void run_vcpu(struct kvm_vcpu *vcpu, int stage) case UCALL_DONE: return; case UCALL_ABORT: - TEST_ASSERT(false, "%s at %s:%ld\n\tvalues: %#lx, %#lx", (const char *)uc.args[0], - __FILE__, uc.args[1], uc.args[2], uc.args[3]); + REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); default: TEST_ASSERT(false, "Unexpected exit: %s", exit_reason_str(vcpu->run->exit_reason)); diff --git a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c index a80940ac420f..56d8ab92eed4 100644 --- a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c +++ b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c @@ -94,7 +94,7 @@ int main(int argc, char *argv[]) vcpu_sregs_set(vcpu, &sregs); break; case UCALL_ABORT: - TEST_FAIL("Guest CR4 bit (OSXSAVE) unsynchronized with CPUID bit."); + REPORT_GUEST_ASSERT(uc); break; case UCALL_DONE: goto done; diff --git a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c index bfff2d271c48..3aa3d17f230f 100644 --- a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c +++ b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c @@ -92,8 +92,7 @@ static void process_exit_on_emulation_error(struct kvm_vcpu *vcpu) static void do_guest_assert(struct ucall *uc) { - TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], __FILE__, - uc->args[1]); + REPORT_GUEST_ASSERT(*uc); } static void check_for_guest_assert(struct kvm_vcpu *vcpu) diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c index 8dda527cc080..aacad86d90e1 100644 --- a/tools/testing/selftests/kvm/x86_64/evmcs_test.c +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c @@ -236,8 +236,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: break; diff --git a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c index f6f251ce59e1..b1905d280ef5 100644 --- a/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c +++ b/tools/testing/selftests/kvm/x86_64/fix_hypercall_test.c @@ -112,7 +112,7 @@ static void enter_guest(struct kvm_vcpu *vcpu) case UCALL_DONE: return; case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); default: TEST_FAIL("Unhandled ucall: %ld\nexit_reason: %u (%s)", uc.cmd, run->exit_reason, exit_reason_str(run->exit_reason)); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c index f7a9e29ff0c7..d576bc8ce823 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_clock.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_clock.c @@ -234,8 +234,7 @@ int main(void) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: break; diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index c05acd78548f..2070ba0d6392 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -447,9 +447,7 @@ static void guest_test_msrs_access(void) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld, MSR = %lx, vector = %lx", - (const char *)uc.args[0], __FILE__, - uc.args[1], uc.args[2], uc.args[3]); + REPORT_GUEST_ASSERT_2(uc, "MSR = %lx, vector = %lx"); return; case UCALL_DONE: break; @@ -618,9 +616,7 @@ static void guest_test_hcalls_access(void) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld, arg1 = %lx, arg2 = %lx", - (const char *)uc.args[0], __FILE__, - uc.args[1], uc.args[2], uc.args[3]); + REPORT_GUEST_ASSERT_2(uc, "arg1 = %lx, arg2 = %lx"); return; case UCALL_DONE: break; diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c index c5cd9835dbd6..b7dc243ab8d5 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c @@ -145,8 +145,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: break; diff --git a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c index 138455575a11..813ce282cf56 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_clock_test.c @@ -71,8 +71,7 @@ static void handle_sync(struct ucall *uc, struct kvm_clock_data *start, static void handle_abort(struct ucall *uc) { - TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], - __FILE__, uc->args[1]); + REPORT_GUEST_ASSERT(*uc); } static void setup_clock(struct kvm_vm *vm, struct test_case *test_case) diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index feff85e43be3..ea452444f4af 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -137,9 +137,7 @@ static void enter_guest(struct kvm_vcpu *vcpu) pr_hcall(&uc); break; case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld, vector = %lu", - (const char *)uc.args[0], __FILE__, - uc.args[1], uc.args[2]); + REPORT_GUEST_ASSERT_1(uc, "vector = %lu"); return; case UCALL_DONE: return; diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c index 094c68d744c0..2bf6851b4f42 100644 --- a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c @@ -100,9 +100,7 @@ int main(int argc, char *argv[]) testcase = uc.args[1]; break; case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld, testcase = %lx, vector = %ld", - (const char *)uc.args[0], __FILE__, - uc.args[1], uc.args[2], uc.args[3]); + REPORT_GUEST_ASSERT_2(uc, "testcase = %lx, vector = %ld"); goto done; case UCALL_DONE: goto done; diff --git a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c index 7ef713fdd0a5..b25d7556b638 100644 --- a/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c +++ b/tools/testing/selftests/kvm/x86_64/set_boot_cpu_id.c @@ -65,9 +65,7 @@ static void run_vcpu(struct kvm_vcpu *vcpu) stage); break; case UCALL_ABORT: - TEST_ASSERT(false, "%s at %s:%ld\n\tvalues: %#lx, %#lx", - (const char *)uc.args[0], __FILE__, - uc.args[1], uc.args[2], uc.args[3]); + REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); default: TEST_ASSERT(false, "Unexpected exit: %s", exit_reason_str(vcpu->run->exit_reason)); diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index e2f1f35e51ff..2b0de1598ab8 100644 --- a/tools/testing/selftests/kvm/x86_64/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -190,8 +190,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: break; diff --git a/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c b/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c index 9c68a47b69e1..d978d1697f5a 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c @@ -113,7 +113,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s", (const char *)uc.args[0]); + REPORT_GUEST_ASSERT(uc); break; /* NOT REACHED */ case UCALL_DONE: diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c index 1c3f457aa3aa..07253e22defd 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -181,8 +181,7 @@ static void run_test(bool is_nmi) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld, vals = 0x%lx 0x%lx 0x%lx", (const char *)uc.args[0], - __FILE__, uc.args[1], uc.args[2], uc.args[3], uc.args[4]); + REPORT_GUEST_ASSERT_3(uc, "vals = 0x%lx 0x%lx 0x%lx"); break; /* NOT REACHED */ case UCALL_DONE: diff --git a/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c index e6d7191866a5..d53b1f7abb56 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c @@ -58,7 +58,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s", (const char *)uc.args[0]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: break; diff --git a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c index 5a202ecb8ea0..d1274c097b36 100644 --- a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c +++ b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c @@ -82,7 +82,7 @@ int main(void) case UCALL_DONE: break; case UCALL_ABORT: - TEST_FAIL("%s", (const char *)uc.args[0]); + REPORT_GUEST_ASSERT(uc); default: TEST_FAIL("Unexpected ucall: %lu", uc.cmd); } diff --git a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c index 3165d3f7e065..22d366c697f7 100644 --- a/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c +++ b/tools/testing/selftests/kvm/x86_64/tsc_msrs_test.c @@ -79,9 +79,7 @@ static void run_vcpu(struct kvm_vcpu *vcpu, int stage) case UCALL_DONE: return; case UCALL_ABORT: - TEST_ASSERT(false, "%s at %s:%ld\n" \ - "\tvalues: %#lx, %#lx", (const char *)uc.args[0], - __FILE__, uc.args[1], uc.args[2], uc.args[3]); + REPORT_GUEST_ASSERT_2(uc, "values: %#lx, %#lx"); default: TEST_ASSERT(false, "Unexpected exit: %s", exit_reason_str(vcpu->run->exit_reason)); diff --git a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c index 7538d57a41d5..7316521428f8 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_io_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_io_test.c @@ -98,9 +98,7 @@ int main(int argc, char *argv[]) case UCALL_DONE: break; case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld : argN+1 = 0x%lx, argN+2 = 0x%lx", - (const char *)uc.args[0], __FILE__, uc.args[1], - uc.args[2], uc.args[3]); + REPORT_GUEST_ASSERT_2(uc, "argN+1 = 0x%lx, argN+2 = 0x%lx"); default: TEST_FAIL("Unknown ucall %lu", uc.cmd); } diff --git a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c index f84dc37426f5..a4f06370a245 100644 --- a/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c +++ b/tools/testing/selftests/kvm/x86_64/userspace_msr_exit_test.c @@ -400,8 +400,7 @@ static void check_for_guest_assert(struct kvm_vcpu *vcpu) if (vcpu->run->exit_reason == KVM_EXIT_IO && get_ucall(vcpu, &uc) == UCALL_ABORT) { - TEST_FAIL("%s at %s:%ld", - (const char *)uc.args[0], __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); } } @@ -610,7 +609,7 @@ static int handle_ucall(struct kvm_vcpu *vcpu) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("Guest assertion not met"); + REPORT_GUEST_ASSERT(uc); break; case UCALL_SYNC: vm_ioctl(vcpu->vm, KVM_X86_SET_MSR_FILTER, &no_filter_deny); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c index ccb05ef7234e..d3582cea1258 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c @@ -114,8 +114,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: apic_access_addr = uc.args[1]; diff --git a/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c b/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c index 40c77bb706a1..e69e8963ed08 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c @@ -74,7 +74,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s", (const char *)uc.args[0]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ default: TEST_FAIL("Unknown ucall %lu", uc.cmd); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c index 215ffa0589d4..f378960299c0 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c @@ -123,8 +123,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: /* diff --git a/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c index 683f4f0a1616..8c854738f2cc 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c @@ -98,7 +98,7 @@ int main(int argc, char *argv[]) case UCALL_DONE: break; case UCALL_ABORT: - TEST_FAIL("%s", (const char *)uc.args[0]); + REPORT_GUEST_ASSERT(uc); default: TEST_FAIL("Unexpected ucall: %lu", uc.cmd); } diff --git a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c index ff4644038c55..6bfef77b87b7 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c @@ -194,7 +194,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s", (const char *) uc.args[0]); + REPORT_GUEST_ASSERT(uc); case UCALL_SYNC: switch (uc.args[0]) { case USLEEP: diff --git a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c index 99e57b0cc2c9..0a8e989d4200 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c @@ -189,8 +189,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: break; diff --git a/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c index e32bfb102699..2e75eef926ca 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c @@ -147,7 +147,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s", (const char *)uc.args[0]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: report(uc.args[1]); diff --git a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c index a4a78637c35a..8a5cb800f50e 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c @@ -542,7 +542,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s", (const char *)uc.args[0]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: { struct kvm_xen_vcpu_attr rst; diff --git a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c index 8b76cade9bcd..88914d48c65e 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_vmcall_test.c @@ -129,7 +129,7 @@ int main(int argc, char *argv[]) switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s", (const char *)uc.args[0]); + REPORT_GUEST_ASSERT(uc); /* NOT REACHED */ case UCALL_SYNC: break; From 4c16fa3ee945183a2f4718a45035e1835c19205b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:26 +0000 Subject: [PATCH 0967/1436] KVM: selftests: Set KVM's supported CPUID as vCPU's CPUID during recreate On x86-64, set KVM's supported CPUID as the vCPU's CPUID when recreating a VM+vCPU to deduplicate code for state save/restore tests, and to provide symmetry of sorts with respect to vm_create_with_one_vcpu(). The extra KVM_SET_CPUID2 call is wasteful for Hyper-V, but ultimately is nothing more than an expensive nop, and overriding the vCPU's CPUID with the Hyper-V CPUID information is the only known scenario where a state save/restore test wouldn't need/want the default CPUID. Opportunistically use __weak for the default vm_compute_max_gfn(), it's provided by tools' compiler.h. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-2-seanjc@google.com --- tools/testing/selftests/kvm/include/kvm_util_base.h | 9 +++++++++ tools/testing/selftests/kvm/lib/kvm_util.c | 10 ++++++++-- tools/testing/selftests/kvm/lib/x86_64/processor.c | 9 +++++++++ tools/testing/selftests/kvm/x86_64/amx_test.c | 1 - tools/testing/selftests/kvm/x86_64/smm_test.c | 1 - tools/testing/selftests/kvm/x86_64/state_test.c | 1 - .../selftests/kvm/x86_64/vmx_preemption_timer_test.c | 2 -- 7 files changed, 26 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index b78e3c7a2566..19f7b33a1e58 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -739,6 +739,15 @@ static inline struct kvm_vcpu *vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, return vm_arch_vcpu_add(vm, vcpu_id, guest_code); } +/* Re-create a vCPU after restarting a VM, e.g. for state save/restore tests. */ +struct kvm_vcpu *vm_arch_vcpu_recreate(struct kvm_vm *vm, uint32_t vcpu_id); + +static inline struct kvm_vcpu *vm_vcpu_recreate(struct kvm_vm *vm, + uint32_t vcpu_id) +{ + return vm_arch_vcpu_recreate(vm, vcpu_id); +} + void virt_arch_pgd_alloc(struct kvm_vm *vm); static inline void virt_pgd_alloc(struct kvm_vm *vm) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 768f3bce0161..49c189878af3 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -388,11 +388,17 @@ void kvm_vm_restart(struct kvm_vm *vmp) } } +__weak struct kvm_vcpu *vm_arch_vcpu_recreate(struct kvm_vm *vm, + uint32_t vcpu_id) +{ + return __vm_vcpu_add(vm, vcpu_id); +} + struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm) { kvm_vm_restart(vm); - return __vm_vcpu_add(vm, 0); + return vm_vcpu_recreate(vm, 0); } /* @@ -1812,7 +1818,7 @@ void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva) return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); } -unsigned long __attribute__((weak)) vm_compute_max_gfn(struct kvm_vm *vm) +unsigned long __weak vm_compute_max_gfn(struct kvm_vm *vm) { return ((1ULL << vm->pa_bits) >> vm->page_shift) - 1; } diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 1a32b1c75e9a..909ac12e5ec5 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -663,6 +663,15 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, return vcpu; } +struct kvm_vcpu *vm_arch_vcpu_recreate(struct kvm_vm *vm, uint32_t vcpu_id) +{ + struct kvm_vcpu *vcpu = __vm_vcpu_add(vm, vcpu_id); + + vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); + + return vcpu; +} + /* * Allocate an instance of struct kvm_cpuid2 * diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index b71763b11b78..4c59923f454f 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -424,7 +424,6 @@ int main(int argc, char *argv[]) /* Restore state in a new VM. */ vcpu = vm_recreate_with_one_vcpu(vm); - vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); vcpu_load_state(vcpu, state); run = vcpu->run; kvm_x86_state_cleanup(state); diff --git a/tools/testing/selftests/kvm/x86_64/smm_test.c b/tools/testing/selftests/kvm/x86_64/smm_test.c index 921cbf117329..d29aefb4d7d3 100644 --- a/tools/testing/selftests/kvm/x86_64/smm_test.c +++ b/tools/testing/selftests/kvm/x86_64/smm_test.c @@ -205,7 +205,6 @@ int main(int argc, char *argv[]) kvm_vm_release(vm); vcpu = vm_recreate_with_one_vcpu(vm); - vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); vcpu_load_state(vcpu, state); run = vcpu->run; kvm_x86_state_cleanup(state); diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index 2b0de1598ab8..3f1a13f28115 100644 --- a/tools/testing/selftests/kvm/x86_64/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -213,7 +213,6 @@ int main(int argc, char *argv[]) /* Restore state in a new VM. */ vcpu = vm_recreate_with_one_vcpu(vm); - vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); vcpu_load_state(vcpu, state); run = vcpu->run; kvm_x86_state_cleanup(state); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c index 0a8e989d4200..8504c6ce0cad 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c @@ -236,8 +236,6 @@ int main(int argc, char *argv[]) /* Restore state in a new VM. */ vcpu = vm_recreate_with_one_vcpu(vm); - - vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); vcpu_load_state(vcpu, state); run = vcpu->run; kvm_x86_state_cleanup(state); From 683edfd42bc222daf17388afb0c752e38712fa05 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:27 +0000 Subject: [PATCH 0968/1436] KVM: sefltests: Use CPUID_* instead of X86_FEATURE_* for one-off usage Rename X86_FEATURE_* macros to CPUID_* in various tests to free up the X86_FEATURE_* names for KVM-Unit-Tests style CPUID automagic where the function, leaf, register, and bit for the feature is embedded in its macro value. No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-3-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/processor.h | 4 ++++ tools/testing/selftests/kvm/x86_64/amx_test.c | 9 +++------ tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c | 7 ++----- tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c | 4 ++-- .../selftests/kvm/x86_64/svm_nested_soft_inject_test.c | 3 +-- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 71e942ffac77..776817a454bf 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -50,6 +50,7 @@ #define CPUID_SMX (1ul << 6) #define CPUID_PCID (1ul << 17) #define CPUID_XSAVE (1ul << 26) +#define CPUID_OSXSAVE (1ul << 27) /* CPUID.7.EBX */ #define CPUID_FSGSBASE (1ul << 0) @@ -64,6 +65,9 @@ /* CPUID.0x8000_0001.EDX */ #define CPUID_GBPAGES (1ul << 26) +/* CPUID.0x8000_000A.EDX */ +#define CPUID_NRIPS BIT(3) + /* Page table bitfield declarations */ #define PTE_PRESENT_MASK BIT_ULL(0) #define PTE_WRITABLE_MASK BIT_ULL(1) diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index 4c59923f454f..8024562016bc 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -25,9 +25,6 @@ # error This test is 64-bit only #endif -#define X86_FEATURE_XSAVE (1 << 26) -#define X86_FEATURE_OSXSAVE (1 << 27) - #define NUM_TILES 8 #define TILE_SIZE 1024 #define XSAVE_SIZE ((NUM_TILES * TILE_SIZE) + PAGE_SIZE) @@ -128,9 +125,9 @@ static inline void check_cpuid_xsave(void) eax = 1; ecx = 0; cpuid(&eax, &ebx, &ecx, &edx); - if (!(ecx & X86_FEATURE_XSAVE)) + if (!(ecx & CPUID_XSAVE)) GUEST_ASSERT(!"cpuid: no CPU xsave support!"); - if (!(ecx & X86_FEATURE_OSXSAVE)) + if (!(ecx & CPUID_OSXSAVE)) GUEST_ASSERT(!"cpuid: no OS xsave support!"); } @@ -333,7 +330,7 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); entry = kvm_get_supported_cpuid_entry(1); - TEST_REQUIRE(entry->ecx & X86_FEATURE_XSAVE); + TEST_REQUIRE(entry->ecx & CPUID_XSAVE); TEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xd); diff --git a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c index 56d8ab92eed4..f4d3a042ec1c 100644 --- a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c +++ b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c @@ -19,9 +19,6 @@ #include "kvm_util.h" #include "processor.h" -#define X86_FEATURE_XSAVE (1<<26) -#define X86_FEATURE_OSXSAVE (1<<27) - static inline bool cr4_cpuid_is_sync(void) { int func, subfunc; @@ -36,7 +33,7 @@ static inline bool cr4_cpuid_is_sync(void) cr4 = get_cr4(); - return (!!(ecx & X86_FEATURE_OSXSAVE)) == (!!(cr4 & X86_CR4_OSXSAVE)); + return (!!(ecx & CPUID_OSXSAVE)) == (!!(cr4 & X86_CR4_OSXSAVE)); } static void guest_code(void) @@ -70,7 +67,7 @@ int main(int argc, char *argv[]) struct ucall uc; entry = kvm_get_supported_cpuid_entry(1); - TEST_REQUIRE(entry->ecx & X86_FEATURE_XSAVE); + TEST_REQUIRE(entry->ecx & CPUID_XSAVE); /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c index 2bf6851b4f42..c804f6f04134 100644 --- a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c @@ -8,7 +8,7 @@ #include "kvm_util.h" #include "processor.h" -#define X86_FEATURE_MWAIT (1u << 3) +#define CPUID_MWAIT (1u << 3) enum monitor_mwait_testcases { MWAIT_QUIRK_DISABLED = BIT(0), @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) cpuid = kvm_get_supported_cpuid(); entry = kvm_get_supported_cpuid_index(1, 0); - entry->ecx &= ~X86_FEATURE_MWAIT; + entry->ecx &= ~CPUID_MWAIT; set_cpuid(cpuid, entry); vm = vm_create_with_one_vcpu(&vcpu, guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c index 07253e22defd..bf7eda7722fe 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -19,7 +19,6 @@ #include "test_util.h" #define INT_NR 0x20 -#define X86_FEATURE_NRIPS BIT(3) static_assert(ATOMIC_INT_LOCK_FREE == 2, "atomic int is not lockless"); @@ -203,7 +202,7 @@ int main(int argc, char *argv[]) nested_svm_check_supported(); cpuid = kvm_get_supported_cpuid_entry(0x8000000a); - TEST_ASSERT(cpuid->edx & X86_FEATURE_NRIPS, + TEST_ASSERT(cpuid->edx & CPUID_NRIPS, "KVM with nSVM is supposed to unconditionally advertise nRIP Save\n"); atomic_init(&nmi_stage, 0); From 61d76b8a6943cd12b89029f9b04a75ce97f01d96 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:28 +0000 Subject: [PATCH 0969/1436] KVM: selftests: Add framework to query KVM CPUID bits Add X86_FEATURE_* magic in the style of KVM-Unit-Tests' implementation, where the CPUID function, index, output register, and output bit position are embedded in the macro value. Add kvm_cpu_has() to query KVM's supported CPUID and use it set_sregs_test, which is the most prolific user of manual feature querying. Opportunstically rename calc_cr4_feature_bits() to calc_supported_cr4_feature_bits() to better capture how the CR4 bits are chosen. Link: https://lore.kernel.org/all/20210422005626.564163-1-ricarkol@google.com Suggested-by: Paolo Bonzini Suggested-by: Jim Mattson Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-4-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 106 ++++++++++++++++-- .../selftests/kvm/lib/x86_64/processor.c | 22 ++++ .../selftests/kvm/x86_64/set_sregs_test.c | 28 ++--- 3 files changed, 128 insertions(+), 28 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 776817a454bf..f5b935f112f5 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -45,23 +45,96 @@ #define X86_CR4_SMAP (1ul << 21) #define X86_CR4_PKE (1ul << 22) +/* Note, these are ordered alphabetically to match kvm_cpuid_entry2. Eww. */ +enum cpuid_output_regs { + KVM_CPUID_EAX, + KVM_CPUID_EBX, + KVM_CPUID_ECX, + KVM_CPUID_EDX +}; + +/* + * Pack the information into a 64-bit value so that each X86_FEATURE_XXX can be + * passed by value with no overhead. + */ +struct kvm_x86_cpu_feature { + u32 function; + u16 index; + u8 reg; + u8 bit; +}; +#define KVM_X86_CPU_FEATURE(fn, idx, gpr, __bit) \ +({ \ + struct kvm_x86_cpu_feature feature = { \ + .function = fn, \ + .index = idx, \ + .reg = KVM_CPUID_##gpr, \ + .bit = __bit, \ + }; \ + \ + feature; \ +}) + +/* + * Basic Leafs, a.k.a. Intel defined + */ +#define X86_FEATURE_MWAIT KVM_X86_CPU_FEATURE(0x1, 0, ECX, 3) +#define X86_FEATURE_VMX KVM_X86_CPU_FEATURE(0x1, 0, ECX, 5) +#define X86_FEATURE_SMX KVM_X86_CPU_FEATURE(0x1, 0, ECX, 6) +#define X86_FEATURE_PCID KVM_X86_CPU_FEATURE(0x1, 0, ECX, 17) +#define X86_FEATURE_MOVBE KVM_X86_CPU_FEATURE(0x1, 0, ECX, 22) +#define X86_FEATURE_TSC_DEADLINE_TIMER KVM_X86_CPU_FEATURE(0x1, 0, ECX, 24) +#define X86_FEATURE_XSAVE KVM_X86_CPU_FEATURE(0x1, 0, ECX, 26) +#define X86_FEATURE_OSXSAVE KVM_X86_CPU_FEATURE(0x1, 0, ECX, 27) +#define X86_FEATURE_RDRAND KVM_X86_CPU_FEATURE(0x1, 0, ECX, 30) +#define X86_FEATURE_MCE KVM_X86_CPU_FEATURE(0x1, 0, EDX, 7) +#define X86_FEATURE_APIC KVM_X86_CPU_FEATURE(0x1, 0, EDX, 9) +#define X86_FEATURE_CLFLUSH KVM_X86_CPU_FEATURE(0x1, 0, EDX, 19) +#define X86_FEATURE_XMM KVM_X86_CPU_FEATURE(0x1, 0, EDX, 25) +#define X86_FEATURE_XMM2 KVM_X86_CPU_FEATURE(0x1, 0, EDX, 26) +#define X86_FEATURE_FSGSBASE KVM_X86_CPU_FEATURE(0x7, 0, EBX, 0) +#define X86_FEATURE_TSC_ADJUST KVM_X86_CPU_FEATURE(0x7, 0, EBX, 1) +#define X86_FEATURE_HLE KVM_X86_CPU_FEATURE(0x7, 0, EBX, 4) +#define X86_FEATURE_SMEP KVM_X86_CPU_FEATURE(0x7, 0, EBX, 7) +#define X86_FEATURE_INVPCID KVM_X86_CPU_FEATURE(0x7, 0, EBX, 10) +#define X86_FEATURE_RTM KVM_X86_CPU_FEATURE(0x7, 0, EBX, 11) +#define X86_FEATURE_SMAP KVM_X86_CPU_FEATURE(0x7, 0, EBX, 20) +#define X86_FEATURE_PCOMMIT KVM_X86_CPU_FEATURE(0x7, 0, EBX, 22) +#define X86_FEATURE_CLFLUSHOPT KVM_X86_CPU_FEATURE(0x7, 0, EBX, 23) +#define X86_FEATURE_CLWB KVM_X86_CPU_FEATURE(0x7, 0, EBX, 24) +#define X86_FEATURE_UMIP KVM_X86_CPU_FEATURE(0x7, 0, ECX, 2) +#define X86_FEATURE_PKU KVM_X86_CPU_FEATURE(0x7, 0, ECX, 3) +#define X86_FEATURE_LA57 KVM_X86_CPU_FEATURE(0x7, 0, ECX, 16) +#define X86_FEATURE_RDPID KVM_X86_CPU_FEATURE(0x7, 0, ECX, 22) +#define X86_FEATURE_SHSTK KVM_X86_CPU_FEATURE(0x7, 0, ECX, 7) +#define X86_FEATURE_IBT KVM_X86_CPU_FEATURE(0x7, 0, EDX, 20) +#define X86_FEATURE_SPEC_CTRL KVM_X86_CPU_FEATURE(0x7, 0, EDX, 26) +#define X86_FEATURE_ARCH_CAPABILITIES KVM_X86_CPU_FEATURE(0x7, 0, EDX, 29) +#define X86_FEATURE_PKS KVM_X86_CPU_FEATURE(0x7, 0, ECX, 31) + +/* + * Extended Leafs, a.k.a. AMD defined + */ +#define X86_FEATURE_SVM KVM_X86_CPU_FEATURE(0x80000001, 0, ECX, 2) +#define X86_FEATURE_NX KVM_X86_CPU_FEATURE(0x80000001, 0, EDX, 20) +#define X86_FEATURE_GBPAGES KVM_X86_CPU_FEATURE(0x80000001, 0, EDX, 26) +#define X86_FEATURE_RDTSCP KVM_X86_CPU_FEATURE(0x80000001, 0, EDX, 27) +#define X86_FEATURE_LM KVM_X86_CPU_FEATURE(0x80000001, 0, EDX, 29) +#define X86_FEATURE_RDPRU KVM_X86_CPU_FEATURE(0x80000008, 0, EBX, 4) +#define X86_FEATURE_AMD_IBPB KVM_X86_CPU_FEATURE(0x80000008, 0, EBX, 12) +#define X86_FEATURE_NPT KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 0) +#define X86_FEATURE_LBRV KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 1) +#define X86_FEATURE_NRIPS KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 3) +#define X86_FEATURE_TSCRATEMSR KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 4) +#define X86_FEATURE_PAUSEFILTER KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 10) +#define X86_FEATURE_PFTHRESHOLD KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 12) +#define X86_FEATURE_VGIF KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 16) + /* CPUID.1.ECX */ #define CPUID_VMX (1ul << 5) -#define CPUID_SMX (1ul << 6) -#define CPUID_PCID (1ul << 17) #define CPUID_XSAVE (1ul << 26) #define CPUID_OSXSAVE (1ul << 27) -/* CPUID.7.EBX */ -#define CPUID_FSGSBASE (1ul << 0) -#define CPUID_SMEP (1ul << 7) -#define CPUID_SMAP (1ul << 20) - -/* CPUID.7.ECX */ -#define CPUID_UMIP (1ul << 2) -#define CPUID_PKU (1ul << 3) -#define CPUID_LA57 (1ul << 16) - /* CPUID.0x8000_0001.EDX */ #define CPUID_GBPAGES (1ul << 26) @@ -490,6 +563,15 @@ static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs) } struct kvm_cpuid2 *kvm_get_supported_cpuid(void); + +bool kvm_cpuid_has(const struct kvm_cpuid2 *cpuid, + struct kvm_x86_cpu_feature feature); + +static inline bool kvm_cpu_has(struct kvm_x86_cpu_feature feature) +{ + return kvm_cpuid_has(kvm_get_supported_cpuid(), feature); +} + struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu); static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu, diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 909ac12e5ec5..10038496fff6 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -734,6 +734,28 @@ struct kvm_cpuid2 *kvm_get_supported_cpuid(void) return cpuid; } +bool kvm_cpuid_has(const struct kvm_cpuid2 *cpuid, + struct kvm_x86_cpu_feature feature) +{ + const struct kvm_cpuid_entry2 *entry; + int i; + + for (i = 0; i < cpuid->nent; i++) { + entry = &cpuid->entries[i]; + + /* + * The output registers in kvm_cpuid_entry2 are in alphabetical + * order, but kvm_x86_cpu_feature matches that mess, so yay + * pointer shenanigans! + */ + if (entry->function == feature.function && + entry->index == feature.index) + return (&entry->eax)[feature.reg] & BIT(feature.bit); + } + + return false; +} + uint64_t kvm_get_feature_msr(uint64_t msr_index) { struct { diff --git a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c index dd344439ad33..2bb08bf2125d 100644 --- a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c +++ b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c @@ -43,36 +43,32 @@ static void test_cr4_feature_bit(struct kvm_vcpu *vcpu, struct kvm_sregs *orig, TEST_ASSERT(!memcmp(&sregs, orig, sizeof(sregs)), "KVM modified sregs"); } -static uint64_t calc_cr4_feature_bits(struct kvm_vm *vm) +static uint64_t calc_supported_cr4_feature_bits(void) { - struct kvm_cpuid_entry2 *cpuid_1, *cpuid_7; uint64_t cr4; - cpuid_1 = kvm_get_supported_cpuid_entry(1); - cpuid_7 = kvm_get_supported_cpuid_entry(7); - cr4 = X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE | X86_CR4_PGE | X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT; - if (cpuid_7->ecx & CPUID_UMIP) + if (kvm_cpu_has(X86_FEATURE_UMIP)) cr4 |= X86_CR4_UMIP; - if (cpuid_7->ecx & CPUID_LA57) + if (kvm_cpu_has(X86_FEATURE_LA57)) cr4 |= X86_CR4_LA57; - if (cpuid_1->ecx & CPUID_VMX) + if (kvm_cpu_has(X86_FEATURE_VMX)) cr4 |= X86_CR4_VMXE; - if (cpuid_1->ecx & CPUID_SMX) + if (kvm_cpu_has(X86_FEATURE_SMX)) cr4 |= X86_CR4_SMXE; - if (cpuid_7->ebx & CPUID_FSGSBASE) + if (kvm_cpu_has(X86_FEATURE_FSGSBASE)) cr4 |= X86_CR4_FSGSBASE; - if (cpuid_1->ecx & CPUID_PCID) + if (kvm_cpu_has(X86_FEATURE_PCID)) cr4 |= X86_CR4_PCIDE; - if (cpuid_1->ecx & CPUID_XSAVE) + if (kvm_cpu_has(X86_FEATURE_XSAVE)) cr4 |= X86_CR4_OSXSAVE; - if (cpuid_7->ebx & CPUID_SMEP) + if (kvm_cpu_has(X86_FEATURE_SMEP)) cr4 |= X86_CR4_SMEP; - if (cpuid_7->ebx & CPUID_SMAP) + if (kvm_cpu_has(X86_FEATURE_SMAP)) cr4 |= X86_CR4_SMAP; - if (cpuid_7->ecx & CPUID_PKU) + if (kvm_cpu_has(X86_FEATURE_PKU)) cr4 |= X86_CR4_PKE; return cr4; @@ -99,7 +95,7 @@ int main(int argc, char *argv[]) vcpu_sregs_get(vcpu, &sregs); - sregs.cr4 |= calc_cr4_feature_bits(vm); + sregs.cr4 |= calc_supported_cr4_feature_bits(); cr4 = sregs.cr4; rc = _vcpu_sregs_set(vcpu, &sregs); From c5c5b827f129734602b796eceb4342b17858dc01 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:29 +0000 Subject: [PATCH 0970/1436] KVM: selftests: Use kvm_cpu_has() in the SEV migration test Use kvm_cpu_has() in the SEV migration test instead of open coding equivalent functionality using kvm_get_supported_cpuid_entry(). No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-5-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 2 ++ .../selftests/kvm/x86_64/sev_migrate_tests.c | 13 ++----------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index f5b935f112f5..57fefd9e8ae9 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -129,6 +129,8 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_PAUSEFILTER KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 10) #define X86_FEATURE_PFTHRESHOLD KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 12) #define X86_FEATURE_VGIF KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 16) +#define X86_FEATURE_SEV KVM_X86_CPU_FEATURE(0x8000001F, 0, EAX, 1) +#define X86_FEATURE_SEV_ES KVM_X86_CPU_FEATURE(0x8000001F, 0, EAX, 3) /* CPUID.1.ECX */ #define CPUID_VMX (1ul << 5) diff --git a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c index 46018b247a04..c7ef97561038 100644 --- a/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c +++ b/tools/testing/selftests/kvm/x86_64/sev_migrate_tests.c @@ -393,23 +393,14 @@ static void test_sev_move_copy(void) kvm_vm_free(sev_vm); } -#define X86_FEATURE_SEV (1 << 1) -#define X86_FEATURE_SEV_ES (1 << 3) - int main(int argc, char *argv[]) { - struct kvm_cpuid_entry2 *cpuid; - TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)); - cpuid = kvm_get_supported_cpuid_entry(0x80000000); - TEST_REQUIRE(cpuid->eax >= 0x8000001f); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV)); - cpuid = kvm_get_supported_cpuid_entry(0x8000001f); - TEST_REQUIRE(cpuid->eax & X86_FEATURE_SEV); - - have_sev_es = !!(cpuid->eax & X86_FEATURE_SEV_ES); + have_sev_es = kvm_cpu_has(X86_FEATURE_SEV_ES); if (kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM)) { test_sev_migrate_from(/* es= */ false); From f21940a3bb5c6a6cd075f589d9405efc5718690c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:30 +0000 Subject: [PATCH 0971/1436] KVM: selftests: Use kvm_cpu_has() for nested SVM checks Use kvm_cpu_has() to check for nested SVM support, and drop the helpers now that their functionality is trivial to implement. No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-6-seanjc@google.com --- .../testing/selftests/kvm/include/x86_64/svm_util.h | 2 -- tools/testing/selftests/kvm/lib/x86_64/svm.c | 13 ------------- .../testing/selftests/kvm/x86_64/hyperv_svm_test.c | 2 +- tools/testing/selftests/kvm/x86_64/smm_test.c | 2 +- tools/testing/selftests/kvm/x86_64/state_test.c | 2 +- .../testing/selftests/kvm/x86_64/svm_int_ctl_test.c | 2 +- .../kvm/x86_64/svm_nested_soft_inject_test.c | 2 +- .../testing/selftests/kvm/x86_64/svm_vmcall_test.c | 2 +- 8 files changed, 6 insertions(+), 21 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/svm_util.h b/tools/testing/selftests/kvm/include/x86_64/svm_util.h index 136ba6a5d027..f48806d26989 100644 --- a/tools/testing/selftests/kvm/include/x86_64/svm_util.h +++ b/tools/testing/selftests/kvm/include/x86_64/svm_util.h @@ -51,8 +51,6 @@ struct svm_test_data { struct svm_test_data *vcpu_alloc_svm(struct kvm_vm *vm, vm_vaddr_t *p_svm_gva); void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_rsp); void run_guest(struct vmcb *vmcb, uint64_t vmcb_gpa); -bool nested_svm_supported(void); -void nested_svm_check_supported(void); static inline bool cpu_has_svm(void) { diff --git a/tools/testing/selftests/kvm/lib/x86_64/svm.c b/tools/testing/selftests/kvm/lib/x86_64/svm.c index 37e9c0a923e0..6d445886e16c 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/svm.c +++ b/tools/testing/selftests/kvm/lib/x86_64/svm.c @@ -164,19 +164,6 @@ void run_guest(struct vmcb *vmcb, uint64_t vmcb_gpa) : "r15", "memory"); } -bool nested_svm_supported(void) -{ - struct kvm_cpuid_entry2 *entry = - kvm_get_supported_cpuid_entry(0x80000001); - - return entry->ecx & CPUID_SVM; -} - -void nested_svm_check_supported(void) -{ - TEST_REQUIRE(nested_svm_supported()); -} - /* * Open SEV_DEV_PATH if available, otherwise exit the entire program. * diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c index b7dc243ab8d5..a380ad7bb9b3 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_svm_test.c @@ -127,7 +127,7 @@ int main(int argc, char *argv[]) struct ucall uc; int stage; - TEST_REQUIRE(nested_svm_supported()); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM)); /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/smm_test.c b/tools/testing/selftests/kvm/x86_64/smm_test.c index d29aefb4d7d3..fde3fe925686 100644 --- a/tools/testing/selftests/kvm/x86_64/smm_test.c +++ b/tools/testing/selftests/kvm/x86_64/smm_test.c @@ -154,7 +154,7 @@ int main(int argc, char *argv[]) vcpu_set_msr(vcpu, MSR_IA32_SMBASE, SMRAM_GPA); if (kvm_has_cap(KVM_CAP_NESTED_STATE)) { - if (nested_svm_supported()) + if (kvm_cpu_has(X86_FEATURE_SVM)) vcpu_alloc_svm(vm, &nested_gva); else if (nested_vmx_supported()) vcpu_alloc_vmx(vm, &nested_gva); diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index 3f1a13f28115..ae01d32624ec 100644 --- a/tools/testing/selftests/kvm/x86_64/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -170,7 +170,7 @@ int main(int argc, char *argv[]) vcpu_regs_get(vcpu, ®s1); if (kvm_has_cap(KVM_CAP_NESTED_STATE)) { - if (nested_svm_supported()) + if (kvm_cpu_has(X86_FEATURE_SVM)) vcpu_alloc_svm(vm, &nested_gva); else if (nested_vmx_supported()) vcpu_alloc_vmx(vm, &nested_gva); diff --git a/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c b/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c index d978d1697f5a..4a07ba227b99 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_int_ctl_test.c @@ -90,7 +90,7 @@ int main(int argc, char *argv[]) struct kvm_vm *vm; struct ucall uc; - nested_svm_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM)); vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c index bf7eda7722fe..2cc09ab41570 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -199,7 +199,7 @@ int main(int argc, char *argv[]) /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); - nested_svm_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM)); cpuid = kvm_get_supported_cpuid_entry(0x8000000a); TEST_ASSERT(cpuid->edx & CPUID_NRIPS, diff --git a/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c b/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c index d53b1f7abb56..c3ac45df7483 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_vmcall_test.c @@ -39,7 +39,7 @@ int main(int argc, char *argv[]) vm_vaddr_t svm_gva; struct kvm_vm *vm; - nested_svm_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM)); vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); From 1ecbb337fa107c6a08800d34ba4f3296ad01103e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:31 +0000 Subject: [PATCH 0972/1436] KVM: selftests: Use kvm_cpu_has() for nested VMX checks Use kvm_cpu_has() to check for nested VMX support, and drop the helpers now that their functionality is trivial to implement. No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-7-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/vmx.h | 2 -- .../selftests/kvm/lib/x86_64/perf_test_util.c | 2 +- tools/testing/selftests/kvm/lib/x86_64/vmx.c | 12 ------------ tools/testing/selftests/kvm/x86_64/evmcs_test.c | 2 +- tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c | 4 ++-- tools/testing/selftests/kvm/x86_64/smm_test.c | 2 +- tools/testing/selftests/kvm/x86_64/state_test.c | 2 +- .../selftests/kvm/x86_64/triple_fault_event_test.c | 2 +- .../selftests/kvm/x86_64/vmx_apic_access_test.c | 2 +- .../kvm/x86_64/vmx_close_while_nested_test.c | 2 +- .../selftests/kvm/x86_64/vmx_dirty_log_test.c | 2 +- .../kvm/x86_64/vmx_invalid_nested_guest_state.c | 2 +- .../kvm/x86_64/vmx_nested_tsc_scaling_test.c | 2 +- .../selftests/kvm/x86_64/vmx_preemption_timer_test.c | 2 +- .../selftests/kvm/x86_64/vmx_set_nested_state_test.c | 2 +- .../selftests/kvm/x86_64/vmx_tsc_adjust_test.c | 2 +- 16 files changed, 15 insertions(+), 29 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/vmx.h b/tools/testing/selftests/kvm/include/x86_64/vmx.h index cc3604f8f1d3..99fa1410964c 100644 --- a/tools/testing/selftests/kvm/include/x86_64/vmx.h +++ b/tools/testing/selftests/kvm/include/x86_64/vmx.h @@ -607,8 +607,6 @@ bool prepare_for_vmx_operation(struct vmx_pages *vmx); void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp); bool load_vmcs(struct vmx_pages *vmx); -bool nested_vmx_supported(void); -void nested_vmx_check_supported(void); bool ept_1g_pages_supported(void); void nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm, diff --git a/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c b/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c index bfe85c8c2f6e..0f344a7c89c4 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c +++ b/tools/testing/selftests/kvm/lib/x86_64/perf_test_util.c @@ -84,7 +84,7 @@ void perf_test_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vc vm_vaddr_t vmx_gva; int vcpu_id; - nested_vmx_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) { vmx = vcpu_alloc_vmx(vm, &vmx_gva); diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c index 381432741df4..80a568c439b8 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c @@ -382,18 +382,6 @@ void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp) init_vmcs_guest_state(guest_rip, guest_rsp); } -bool nested_vmx_supported(void) -{ - struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1); - - return entry->ecx & CPUID_VMX; -} - -void nested_vmx_check_supported(void) -{ - TEST_REQUIRE(nested_vmx_supported()); -} - static void nested_create_pte(struct kvm_vm *vm, struct eptPageTableEntry *pte, uint64_t nested_paddr, diff --git a/tools/testing/selftests/kvm/x86_64/evmcs_test.c b/tools/testing/selftests/kvm/x86_64/evmcs_test.c index aacad86d90e1..99bc202243d2 100644 --- a/tools/testing/selftests/kvm/x86_64/evmcs_test.c +++ b/tools/testing/selftests/kvm/x86_64/evmcs_test.c @@ -208,7 +208,7 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); - TEST_REQUIRE(nested_vmx_supported()); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c index cbd4a7d36189..c406b95cba9b 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c @@ -148,7 +148,7 @@ int main(int argc, char *argv[]) test_hv_cpuid(hv_cpuid_entries, false); free(hv_cpuid_entries); - if (!nested_vmx_supported() || + if (!kvm_cpu_has(X86_FEATURE_VMX) || !kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { print_skip("Enlightened VMCS is unsupported"); goto do_sys; @@ -168,7 +168,7 @@ do_sys: test_hv_cpuid_e2big(vm, NULL); hv_cpuid_entries = kvm_get_supported_hv_cpuid(); - test_hv_cpuid(hv_cpuid_entries, nested_vmx_supported()); + test_hv_cpuid(hv_cpuid_entries, kvm_cpu_has(X86_FEATURE_VMX)); out: kvm_vm_free(vm); diff --git a/tools/testing/selftests/kvm/x86_64/smm_test.c b/tools/testing/selftests/kvm/x86_64/smm_test.c index fde3fe925686..17bb2397ea38 100644 --- a/tools/testing/selftests/kvm/x86_64/smm_test.c +++ b/tools/testing/selftests/kvm/x86_64/smm_test.c @@ -156,7 +156,7 @@ int main(int argc, char *argv[]) if (kvm_has_cap(KVM_CAP_NESTED_STATE)) { if (kvm_cpu_has(X86_FEATURE_SVM)) vcpu_alloc_svm(vm, &nested_gva); - else if (nested_vmx_supported()) + else if (kvm_cpu_has(X86_FEATURE_VMX)) vcpu_alloc_vmx(vm, &nested_gva); } diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index ae01d32624ec..8ab81a3b561f 100644 --- a/tools/testing/selftests/kvm/x86_64/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -172,7 +172,7 @@ int main(int argc, char *argv[]) if (kvm_has_cap(KVM_CAP_NESTED_STATE)) { if (kvm_cpu_has(X86_FEATURE_SVM)) vcpu_alloc_svm(vm, &nested_gva); - else if (nested_vmx_supported()) + else if (kvm_cpu_has(X86_FEATURE_VMX)) vcpu_alloc_vmx(vm, &nested_gva); } diff --git a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c index d1274c097b36..70b44f0b52fe 100644 --- a/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c +++ b/tools/testing/selftests/kvm/x86_64/triple_fault_event_test.c @@ -46,7 +46,7 @@ int main(void) vm_vaddr_t vmx_pages_gva; struct ucall uc; - nested_vmx_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_X86_TRIPLE_FAULT_EVENT)); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c index d3582cea1258..5abecf06329e 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_apic_access_test.c @@ -80,7 +80,7 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu; struct kvm_vm *vm; - nested_vmx_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c b/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c index e69e8963ed08..d79651b02740 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_close_while_nested_test.c @@ -51,7 +51,7 @@ int main(int argc, char *argv[]) struct kvm_vcpu *vcpu; struct kvm_vm *vm; - nested_vmx_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c index f378960299c0..2d8c23d639f7 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_dirty_log_test.c @@ -77,7 +77,7 @@ int main(int argc, char *argv[]) struct ucall uc; bool done = false; - nested_vmx_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c index 8c854738f2cc..6bfb4bb471ca 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_invalid_nested_guest_state.c @@ -58,7 +58,7 @@ int main(int argc, char *argv[]) struct kvm_run *run; struct ucall uc; - nested_vmx_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c index 6bfef77b87b7..465a9434d61c 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_nested_tsc_scaling_test.c @@ -150,7 +150,7 @@ int main(int argc, char *argv[]) uint64_t l1_tsc_freq = 0; uint64_t l2_tsc_freq = 0; - nested_vmx_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL)); stable_tsc_check_supported(); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c index 8504c6ce0cad..0efdc05969a5 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_preemption_timer_test.c @@ -167,7 +167,7 @@ int main(int argc, char *argv[]) * AMD currently does not implement any VMX features, so for now we * just early out. */ - nested_vmx_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE)); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c index b564b86dfc1d..66cb2d0054e6 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c @@ -273,7 +273,7 @@ int main(int argc, char *argv[]) * AMD currently does not implement set_nested_state, so for now we * just early out. */ - nested_vmx_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); vm = vm_create_with_one_vcpu(&vcpu, NULL); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c index 2e75eef926ca..5943187e8594 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_tsc_adjust_test.c @@ -127,7 +127,7 @@ int main(int argc, char *argv[]) vm_vaddr_t vmx_pages_gva; struct kvm_vcpu *vcpu; - nested_vmx_check_supported(); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); vm = vm_create_with_one_vcpu(&vcpu, (void *) l1_guest_code); From ea129d22541ecd2bf4c8769d33f48e3105eca5f9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:32 +0000 Subject: [PATCH 0973/1436] KVM: selftests: Use kvm_cpu_has() to query PDCM in PMU selftest Use kvm_cpu_has() in the PMU test to query PDCM support instead of open coding equivalent functionality using kvm_get_supported_cpuid_index(). No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-8-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/processor.h | 1 + tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 57fefd9e8ae9..ad10c8787892 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -81,6 +81,7 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_MWAIT KVM_X86_CPU_FEATURE(0x1, 0, ECX, 3) #define X86_FEATURE_VMX KVM_X86_CPU_FEATURE(0x1, 0, ECX, 5) #define X86_FEATURE_SMX KVM_X86_CPU_FEATURE(0x1, 0, ECX, 6) +#define X86_FEATURE_PDCM KVM_X86_CPU_FEATURE(0x1, 0, ECX, 15) #define X86_FEATURE_PCID KVM_X86_CPU_FEATURE(0x1, 0, ECX, 17) #define X86_FEATURE_MOVBE KVM_X86_CPU_FEATURE(0x1, 0, ECX, 22) #define X86_FEATURE_TSC_DEADLINE_TIMER KVM_X86_CPU_FEATURE(0x1, 0, ECX, 24) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c index eb592fae44ef..667d48e8c1e0 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c @@ -17,7 +17,6 @@ #include "kvm_util.h" #include "vmx.h" -#define X86_FEATURE_PDCM (1<<15) #define PMU_CAP_FW_WRITES (1ULL << 13) #define PMU_CAP_LBR_FMT 0x3f @@ -55,7 +54,6 @@ static void guest_code(void) int main(int argc, char *argv[]) { struct kvm_cpuid2 *cpuid; - struct kvm_cpuid_entry2 *entry_1_0; struct kvm_cpuid_entry2 *entry_a_0; struct kvm_vm *vm; struct kvm_vcpu *vcpu; @@ -70,11 +68,10 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); cpuid = kvm_get_supported_cpuid(); - TEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xa); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM)); - entry_1_0 = kvm_get_supported_cpuid_index(1, 0); + TEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xa); entry_a_0 = kvm_get_supported_cpuid_index(0xa, 0); - TEST_REQUIRE(entry_1_0->ecx & X86_FEATURE_PDCM); eax.full = entry_a_0->eax; __TEST_REQUIRE(eax.split.version_id, "PMU is not supported by the vCPU"); From 50445ea2337a5f8df2242f795f45b6cf8c959c77 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:33 +0000 Subject: [PATCH 0974/1436] KVM: selftests: Drop redundant vcpu_set_cpuid() from PMU selftest Drop a redundant vcpu_set_cpuid() from the PMU test. The vCPU's CPUID is set to KVM's supported CPUID by vm_create_with_one_vcpu(), which was also true back when the helper was named vm_create_default(). Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-9-seanjc@google.com --- tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c index 667d48e8c1e0..dc3869d5aff0 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c @@ -53,7 +53,6 @@ static void guest_code(void) int main(int argc, char *argv[]) { - struct kvm_cpuid2 *cpuid; struct kvm_cpuid_entry2 *entry_a_0; struct kvm_vm *vm; struct kvm_vcpu *vcpu; @@ -66,7 +65,6 @@ int main(int argc, char *argv[]) /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, guest_code); - cpuid = kvm_get_supported_cpuid(); TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM)); @@ -77,7 +75,6 @@ int main(int argc, char *argv[]) __TEST_REQUIRE(eax.split.version_id, "PMU is not supported by the vCPU"); /* testcase 1, set capabilities when we have PDCM bit */ - vcpu_set_cpuid(vcpu, cpuid); vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, PMU_CAP_FW_WRITES); /* check capabilities can be retrieved with KVM_GET_MSR */ From fdd1e2788c41e9b420a3744e022b5ff85b7e5fc0 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:34 +0000 Subject: [PATCH 0975/1436] KVM: selftests: Use kvm_cpu_has() for XSAVES in XSS MSR test Use kvm_cpu_has() in the XSS MSR test instead of open coding equivalent functionality using kvm_get_supported_cpuid_index(). No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-10-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/processor.h | 1 + tools/testing/selftests/kvm/x86_64/xss_msr_test.c | 8 +------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index ad10c8787892..227473ab8ec6 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -112,6 +112,7 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_SPEC_CTRL KVM_X86_CPU_FEATURE(0x7, 0, EDX, 26) #define X86_FEATURE_ARCH_CAPABILITIES KVM_X86_CPU_FEATURE(0x7, 0, EDX, 29) #define X86_FEATURE_PKS KVM_X86_CPU_FEATURE(0x7, 0, ECX, 31) +#define X86_FEATURE_XSAVES KVM_X86_CPU_FEATURE(0xD, 1, EAX, 3) /* * Extended Leafs, a.k.a. AMD defined diff --git a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c index 4e2e08059b95..e0ddf47362e7 100644 --- a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c +++ b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c @@ -14,11 +14,8 @@ #define MSR_BITS 64 -#define X86_FEATURE_XSAVES (1<<3) - int main(int argc, char *argv[]) { - struct kvm_cpuid_entry2 *entry; bool xss_in_msr_list; struct kvm_vm *vm; struct kvm_vcpu *vcpu; @@ -28,10 +25,7 @@ int main(int argc, char *argv[]) /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, NULL); - TEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xd); - - entry = kvm_get_supported_cpuid_index(0xd, 1); - TEST_REQUIRE(entry->eax & X86_FEATURE_XSAVES); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XSAVES)); xss_val = vcpu_get_msr(vcpu, MSR_IA32_XSS); TEST_ASSERT(xss_val == 0, From 2697646bd343e3e04004f49a3673975729ef9f01 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:35 +0000 Subject: [PATCH 0976/1436] KVM: selftests: Check for _both_ XTILE data and cfg in AMX test Check for _both_ XTILE data and cfg support in the AMX test instead of checking for _either_ feature. Practically speaking, no sane CPU or vCPU will support one but not the other, but the effective "or" behavior is subtle and technically incorrect. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-11-seanjc@google.com --- tools/testing/selftests/kvm/x86_64/amx_test.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index 8024562016bc..6fc4e652b38f 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -335,7 +335,8 @@ int main(int argc, char *argv[]) TEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xd); entry = kvm_get_supported_cpuid_index(0xd, 0); - TEST_REQUIRE(entry->eax & XFEATURE_MASK_XTILE); + TEST_REQUIRE(entry->eax & XFEATURE_MASK_XTILECFG); + TEST_REQUIRE(entry->eax & XFEATURE_MASK_XTILEDATA); /* Get xsave/restore max size */ xsave_restore_size = entry->ecx; From 8fea056eeb0c4840593bf2ed1e4cab5030d0b5b5 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:36 +0000 Subject: [PATCH 0977/1436] KVM: selftests: Use kvm_cpu_has() in AMX test Use kvm_cpu_has() in the AMX test instead of open coding equivalent functionality using kvm_get_supported_cpuid_entry() and kvm_get_supported_cpuid_index(). No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-12-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 3 +++ tools/testing/selftests/kvm/x86_64/amx_test.c | 17 ++++++----------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 227473ab8ec6..3b819bf673ac 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -109,9 +109,12 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_RDPID KVM_X86_CPU_FEATURE(0x7, 0, ECX, 22) #define X86_FEATURE_SHSTK KVM_X86_CPU_FEATURE(0x7, 0, ECX, 7) #define X86_FEATURE_IBT KVM_X86_CPU_FEATURE(0x7, 0, EDX, 20) +#define X86_FEATURE_AMX_TILE KVM_X86_CPU_FEATURE(0x7, 0, EDX, 24) #define X86_FEATURE_SPEC_CTRL KVM_X86_CPU_FEATURE(0x7, 0, EDX, 26) #define X86_FEATURE_ARCH_CAPABILITIES KVM_X86_CPU_FEATURE(0x7, 0, EDX, 29) #define X86_FEATURE_PKS KVM_X86_CPU_FEATURE(0x7, 0, ECX, 31) +#define X86_FEATURE_XTILECFG KVM_X86_CPU_FEATURE(0xD, 0, EAX, 17) +#define X86_FEATURE_XTILEDATA KVM_X86_CPU_FEATURE(0xD, 0, EAX, 18) #define X86_FEATURE_XSAVES KVM_X86_CPU_FEATURE(0xD, 1, EAX, 3) /* diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index 6fc4e652b38f..c8f98331a807 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -312,13 +312,12 @@ void guest_nm_handler(struct ex_regs *regs) int main(int argc, char *argv[]) { - struct kvm_cpuid_entry2 *entry; struct kvm_regs regs1, regs2; struct kvm_vcpu *vcpu; struct kvm_vm *vm; struct kvm_run *run; struct kvm_x86_state *state; - int xsave_restore_size = 0; + int xsave_restore_size; vm_vaddr_t amx_cfg, tiledata, xsavedata; struct ucall uc; u32 amx_offset; @@ -329,17 +328,13 @@ int main(int argc, char *argv[]) /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, guest_code); - entry = kvm_get_supported_cpuid_entry(1); - TEST_REQUIRE(entry->ecx & CPUID_XSAVE); - - TEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xd); - - entry = kvm_get_supported_cpuid_index(0xd, 0); - TEST_REQUIRE(entry->eax & XFEATURE_MASK_XTILECFG); - TEST_REQUIRE(entry->eax & XFEATURE_MASK_XTILEDATA); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XSAVE)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_AMX_TILE)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XTILECFG)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XTILEDATA)); /* Get xsave/restore max size */ - xsave_restore_size = entry->ecx; + xsave_restore_size = kvm_get_supported_cpuid_index(0xd, 0)->ecx; run = vcpu->run; vcpu_regs_get(vcpu, ®s1); From 045520e4755bbdf2f2983309c8eab6176a97a13d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:37 +0000 Subject: [PATCH 0978/1436] KVM: selftests: Use kvm_cpu_has() for XSAVE in cr4_cpuid_sync_test Use kvm_cpu_has() in the CR4/CPUID sync test instead of open coding equivalent functionality using kvm_get_supported_cpuid_entry(). No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-13-seanjc@google.com --- tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c index f4d3a042ec1c..611febdc2128 100644 --- a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c +++ b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c @@ -63,11 +63,9 @@ int main(int argc, char *argv[]) struct kvm_run *run; struct kvm_vm *vm; struct kvm_sregs sregs; - struct kvm_cpuid_entry2 *entry; struct ucall uc; - entry = kvm_get_supported_cpuid_entry(1); - TEST_REQUIRE(entry->ecx & CPUID_XSAVE); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XSAVE)); /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); From b046f4ee9cb60da285e1d45a1fe8dc6bb5fc446e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:38 +0000 Subject: [PATCH 0979/1436] KVM: selftests: Remove the obsolete/dead MMU role test Remove the MMU role test, which was made obsolete by KVM commit feb627e8d6f6 ("KVM: x86: Forbid KVM_SET_CPUID{,2} after KVM_RUN"). The ongoing costs of keeping the test updated far outweigh any benefits, e.g. the test _might_ be useful as an example or for documentation purposes, but otherwise the test is dead weight. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-14-seanjc@google.com --- tools/testing/selftests/kvm/.gitignore | 1 - tools/testing/selftests/kvm/Makefile | 1 - .../selftests/kvm/include/x86_64/processor.h | 3 - .../selftests/kvm/x86_64/mmu_role_test.c | 137 ------------------ 4 files changed, 142 deletions(-) delete mode 100644 tools/testing/selftests/kvm/x86_64/mmu_role_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index f44ebf401310..91429330faea 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -27,7 +27,6 @@ /x86_64/hyperv_svm_test /x86_64/max_vcpuid_cap_test /x86_64/mmio_warning_test -/x86_64/mmu_role_test /x86_64/monitor_mwait_test /x86_64/nx_huge_pages_test /x86_64/platform_info_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 4d6753aadfa0..6b22fb1ce2b9 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -87,7 +87,6 @@ TEST_GEN_PROGS_x86_64 += x86_64/hyperv_svm_test TEST_GEN_PROGS_x86_64 += x86_64/kvm_clock_test TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test -TEST_GEN_PROGS_x86_64 += x86_64/mmu_role_test TEST_GEN_PROGS_x86_64 += x86_64/monitor_mwait_test TEST_GEN_PROGS_x86_64 += x86_64/platform_info_test TEST_GEN_PROGS_x86_64 += x86_64/pmu_event_filter_test diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 3b819bf673ac..14342e68e0b5 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -142,9 +142,6 @@ struct kvm_x86_cpu_feature { #define CPUID_XSAVE (1ul << 26) #define CPUID_OSXSAVE (1ul << 27) -/* CPUID.0x8000_0001.EDX */ -#define CPUID_GBPAGES (1ul << 26) - /* CPUID.0x8000_000A.EDX */ #define CPUID_NRIPS BIT(3) diff --git a/tools/testing/selftests/kvm/x86_64/mmu_role_test.c b/tools/testing/selftests/kvm/x86_64/mmu_role_test.c deleted file mode 100644 index 383fff2c9587..000000000000 --- a/tools/testing/selftests/kvm/x86_64/mmu_role_test.c +++ /dev/null @@ -1,137 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include "kvm_util.h" -#include "processor.h" - -#define MMIO_GPA 0x100000000ull - -static void guest_code(void) -{ - (void)READ_ONCE(*((uint64_t *)MMIO_GPA)); - (void)READ_ONCE(*((uint64_t *)MMIO_GPA)); - - GUEST_ASSERT(0); -} - -static void guest_pf_handler(struct ex_regs *regs) -{ - /* PFEC == RSVD | PRESENT (read, kernel). */ - GUEST_ASSERT(regs->error_code == 0x9); - GUEST_DONE(); -} - -static void mmu_role_test(u32 *cpuid_reg, u32 evil_cpuid_val) -{ - u32 good_cpuid_val = *cpuid_reg; - struct kvm_vcpu *vcpu; - struct kvm_run *run; - struct kvm_vm *vm; - uint64_t cmd; - - /* Create VM */ - vm = vm_create_with_one_vcpu(&vcpu, guest_code); - run = vcpu->run; - - /* Map 1gb page without a backing memlot. */ - __virt_pg_map(vm, MMIO_GPA, MMIO_GPA, PG_LEVEL_1G); - - vcpu_run(vcpu); - - /* Guest access to the 1gb page should trigger MMIO. */ - TEST_ASSERT(run->exit_reason == KVM_EXIT_MMIO, - "Unexpected exit reason: %u (%s), expected MMIO exit (1gb page w/o memslot)\n", - run->exit_reason, exit_reason_str(run->exit_reason)); - - TEST_ASSERT(run->mmio.len == 8, "Unexpected exit mmio size = %u", run->mmio.len); - - TEST_ASSERT(run->mmio.phys_addr == MMIO_GPA, - "Unexpected exit mmio address = 0x%llx", run->mmio.phys_addr); - - /* - * Effect the CPUID change for the guest and re-enter the guest. Its - * access should now #PF due to the PAGE_SIZE bit being reserved or - * the resulting GPA being invalid. Note, kvm_get_supported_cpuid() - * returns the struct that contains the entry being modified. Eww. - */ - *cpuid_reg = evil_cpuid_val; - vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); - - /* - * Add a dummy memslot to coerce KVM into bumping the MMIO generation. - * KVM does not "officially" support mucking with CPUID after KVM_RUN, - * and will incorrectly reuse MMIO SPTEs. Don't delete the memslot! - * KVM x86 zaps all shadow pages on memslot deletion. - */ - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, - MMIO_GPA << 1, 10, 1, 0); - - /* Set up a #PF handler to eat the RSVD #PF and signal all done! */ - vm_init_descriptor_tables(vm); - vcpu_init_descriptor_tables(vcpu); - vm_install_exception_handler(vm, PF_VECTOR, guest_pf_handler); - - vcpu_run(vcpu); - - cmd = get_ucall(vcpu, NULL); - TEST_ASSERT(cmd == UCALL_DONE, - "Unexpected guest exit, exit_reason=%s, ucall.cmd = %lu\n", - exit_reason_str(run->exit_reason), cmd); - - /* - * Restore the happy CPUID value for the next test. Yes, changes are - * indeed persistent across VM destruction. - */ - *cpuid_reg = good_cpuid_val; - - kvm_vm_free(vm); -} - -int main(int argc, char *argv[]) -{ - struct kvm_cpuid_entry2 *entry; - int opt; - - /* - * All tests are opt-in because TDP doesn't play nice with reserved #PF - * in the GVA->GPA translation. The hardware page walker doesn't let - * software change GBPAGES or MAXPHYADDR, and KVM doesn't manually walk - * the GVA on fault for performance reasons. - */ - bool do_gbpages = false; - bool do_maxphyaddr = false; - - setbuf(stdout, NULL); - - while ((opt = getopt(argc, argv, "gm")) != -1) { - switch (opt) { - case 'g': - do_gbpages = true; - break; - case 'm': - do_maxphyaddr = true; - break; - case 'h': - default: - printf("usage: %s [-g (GBPAGES)] [-m (MAXPHYADDR)]\n", argv[0]); - break; - } - } - - __TEST_REQUIRE(do_gbpages || do_maxphyaddr, "No sub-tests selected"); - - entry = kvm_get_supported_cpuid_entry(0x80000001); - TEST_REQUIRE(entry->edx & CPUID_GBPAGES); - - if (do_gbpages) { - pr_info("Test MMIO after toggling CPUID.GBPAGES\n\n"); - mmu_role_test(&entry->edx, entry->edx & ~CPUID_GBPAGES); - } - - if (do_maxphyaddr) { - pr_info("Test MMIO after changing CPUID.MAXPHYADDR\n\n"); - entry = kvm_get_supported_cpuid_entry(0x80000008); - mmu_role_test(&entry->eax, (entry->eax & ~0xff) | 0x20); - } - - return 0; -} From 601c067f381532105d01db9257b69eb9cfa8945e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:39 +0000 Subject: [PATCH 0980/1436] KVM: selftests: Use kvm_cpu_has() for KVM's PV steal time Use kvm_cpu_has() in the stea-ltime test instead of open coding equivalent functionality using kvm_get_supported_cpuid_entry(). Opportunistically define all of KVM's paravirt CPUID-based features. No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-15-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 22 +++++++++++++++++++ tools/testing/selftests/kvm/steal_time.c | 4 +--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 14342e68e0b5..15bccdd6d78c 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -137,6 +137,28 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_SEV KVM_X86_CPU_FEATURE(0x8000001F, 0, EAX, 1) #define X86_FEATURE_SEV_ES KVM_X86_CPU_FEATURE(0x8000001F, 0, EAX, 3) +/* + * KVM defined paravirt features. + */ +#define X86_FEATURE_KVM_CLOCKSOURCE KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 0) +#define X86_FEATURE_KVM_NOP_IO_DELAY KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 1) +#define X86_FEATURE_KVM_MMU_OP KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 2) +#define X86_FEATURE_KVM_CLOCKSOURCE2 KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 3) +#define X86_FEATURE_KVM_ASYNC_PF KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 4) +#define X86_FEATURE_KVM_STEAL_TIME KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 5) +#define X86_FEATURE_KVM_PV_EOI KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 6) +#define X86_FEATURE_KVM_PV_UNHALT KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 7) +/* Bit 8 apparently isn't used?!?! */ +#define X86_FEATURE_KVM_PV_TLB_FLUSH KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 9) +#define X86_FEATURE_KVM_ASYNC_PF_VMEXIT KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 10) +#define X86_FEATURE_KVM_PV_SEND_IPI KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 11) +#define X86_FEATURE_KVM_POLL_CONTROL KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 12) +#define X86_FEATURE_KVM_PV_SCHED_YIELD KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 13) +#define X86_FEATURE_KVM_ASYNC_PF_INT KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 14) +#define X86_FEATURE_KVM_MSI_EXT_DEST_ID KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 15) +#define X86_FEATURE_KVM_HC_MAP_GPA_RANGE KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 16) +#define X86_FEATURE_KVM_MIGRATION_CONTROL KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 17) + /* CPUID.1.ECX */ #define CPUID_VMX (1ul << 5) #define CPUID_XSAVE (1ul << 26) diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c index 9866a71463d7..db8967f1a17b 100644 --- a/tools/testing/selftests/kvm/steal_time.c +++ b/tools/testing/selftests/kvm/steal_time.c @@ -60,9 +60,7 @@ static void guest_code(int cpu) static bool is_steal_time_supported(struct kvm_vcpu *vcpu) { - struct kvm_cpuid_entry2 *cpuid = kvm_get_supported_cpuid_entry(KVM_CPUID_FEATURES); - - return cpuid && (cpuid->eax & KVM_FEATURE_STEAL_TIME); + return kvm_cpu_has(X86_FEATURE_KVM_STEAL_TIME); } static void steal_time_init(struct kvm_vcpu *vcpu, uint32_t i) From 3c67f8208451a864478b9bf049782159fc925e11 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:40 +0000 Subject: [PATCH 0981/1436] KVM: selftests: Use kvm_cpu_has() for nSVM soft INT injection test Use kvm_cpu_has() to query for NRIPS support instead of open coding equivalent functionality using kvm_get_supported_cpuid_entry(). Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-16-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/processor.h | 3 --- .../selftests/kvm/x86_64/svm_nested_soft_inject_test.c | 7 ++----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 15bccdd6d78c..a66d625da3d4 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -164,9 +164,6 @@ struct kvm_x86_cpu_feature { #define CPUID_XSAVE (1ul << 26) #define CPUID_OSXSAVE (1ul << 27) -/* CPUID.0x8000_000A.EDX */ -#define CPUID_NRIPS BIT(3) - /* Page table bitfield declarations */ #define PTE_PRESENT_MASK BIT_ULL(0) #define PTE_WRITABLE_MASK BIT_ULL(1) diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c index 2cc09ab41570..e637d7736012 100644 --- a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -194,16 +194,13 @@ done: int main(int argc, char *argv[]) { - struct kvm_cpuid_entry2 *cpuid; - /* Tell stdout not to buffer its content */ setbuf(stdout, NULL); TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SVM)); - cpuid = kvm_get_supported_cpuid_entry(0x8000000a); - TEST_ASSERT(cpuid->edx & CPUID_NRIPS, - "KVM with nSVM is supposed to unconditionally advertise nRIP Save\n"); + TEST_ASSERT(kvm_cpu_has(X86_FEATURE_NRIPS), + "KVM with nSVM is supposed to unconditionally advertise nRIP Save"); atomic_init(&nmi_stage, 0); From 71bcb951c68b422ca65f55dc7ae7be01735ae48e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:41 +0000 Subject: [PATCH 0982/1436] KVM: selftests: Verify that kvm_cpuid2.entries layout is unchanged by KVM In the CPUID test, verify that KVM doesn't modify the kvm_cpuid2.entries layout, i.e. that the order of entries and their flags is identical between what the test provides via KVM_SET_CPUID2 and what KVM returns via KVM_GET_CPUID2. Asserting that the layouts match simplifies the test as there's no need to iterate over both arrays. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-17-seanjc@google.com --- .../testing/selftests/kvm/x86_64/cpuid_test.c | 53 ++++++++----------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index 3767a0cc694b..59dcdf5a1220 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -79,41 +79,34 @@ static bool is_cpuid_mangled(struct kvm_cpuid_entry2 *entrie) return false; } -static void check_cpuid(struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 *entrie) -{ - int i; - - for (i = 0; i < cpuid->nent; i++) { - if (cpuid->entries[i].function == entrie->function && - cpuid->entries[i].index == entrie->index) { - if (is_cpuid_mangled(entrie)) - return; - - TEST_ASSERT(cpuid->entries[i].eax == entrie->eax && - cpuid->entries[i].ebx == entrie->ebx && - cpuid->entries[i].ecx == entrie->ecx && - cpuid->entries[i].edx == entrie->edx, - "CPUID 0x%x.%x differ: 0x%x:0x%x:0x%x:0x%x vs 0x%x:0x%x:0x%x:0x%x", - entrie->function, entrie->index, - cpuid->entries[i].eax, cpuid->entries[i].ebx, - cpuid->entries[i].ecx, cpuid->entries[i].edx, - entrie->eax, entrie->ebx, entrie->ecx, entrie->edx); - return; - } - } - - TEST_ASSERT(false, "CPUID 0x%x.%x not found", entrie->function, entrie->index); -} - static void compare_cpuids(struct kvm_cpuid2 *cpuid1, struct kvm_cpuid2 *cpuid2) { + struct kvm_cpuid_entry2 *e1, *e2; int i; - for (i = 0; i < cpuid1->nent; i++) - check_cpuid(cpuid2, &cpuid1->entries[i]); + TEST_ASSERT(cpuid1->nent == cpuid2->nent, + "CPUID nent mismatch: %d vs. %d", cpuid1->nent, cpuid2->nent); - for (i = 0; i < cpuid2->nent; i++) - check_cpuid(cpuid1, &cpuid2->entries[i]); + for (i = 0; i < cpuid1->nent; i++) { + e1 = &cpuid1->entries[i]; + e2 = &cpuid2->entries[i]; + + TEST_ASSERT(e1->function == e2->function && + e1->index == e2->index && e1->flags == e2->flags, + "CPUID entries[%d] mismtach: 0x%x.%d.%x vs. 0x%x.%d.%x\n", + i, e1->function, e1->index, e1->flags, + e2->function, e2->index, e2->flags); + + if (is_cpuid_mangled(e1)) + continue; + + TEST_ASSERT(e1->eax == e2->eax && e1->ebx == e2->ebx && + e1->ecx == e2->ecx && e1->edx == e2->edx, + "CPUID 0x%x.%x differ: 0x%x:0x%x:0x%x:0x%x vs 0x%x:0x%x:0x%x:0x%x", + e1->function, e1->index, + e1->eax, e1->ebx, e1->ecx, e1->edx, + e2->eax, e2->ebx, e2->ecx, e2->edx); + } } static void run_vcpu(struct kvm_vcpu *vcpu, int stage) From fc66963d7b01e00ef0482bd7adbc8918343f81d9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:42 +0000 Subject: [PATCH 0983/1436] KVM: selftests: Split out kvm_cpuid2_size() from allocate_kvm_cpuid2() Split out the computation of the effective size of a kvm_cpuid2 struct from allocate_kvm_cpuid2(), and modify both to take an arbitrary number of entries. Future commits will add caching of a vCPU's CPUID model, and will (a) be able to precisely size the entries array, and (b) will need to know the effective size of the struct in order to copy to/from the cache. Expose the helpers so that the Hyper-V Features test can use them in the (somewhat distant) future. The Hyper-V test very, very subtly relies on propagating CPUID info across vCPU instances, and will need to make a copy of the previous vCPU's CPUID information when it switches to using the per-vCPU cache. Alternatively, KVM could provide helpers to duplicate and/or copy a kvm_cpuid2 instance, but each is literally a single line of code if the helpers are exposed, and it's not like the size of kvm_cpuid2 is secret knowledge. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-18-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 23 +++++++++ .../selftests/kvm/lib/x86_64/processor.c | 48 +++---------------- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index a66d625da3d4..1326377f72b7 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -595,6 +595,29 @@ static inline bool kvm_cpu_has(struct kvm_x86_cpu_feature feature) return kvm_cpuid_has(kvm_get_supported_cpuid(), feature); } +static inline size_t kvm_cpuid2_size(int nr_entries) +{ + return sizeof(struct kvm_cpuid2) + + sizeof(struct kvm_cpuid_entry2) * nr_entries; +} + +/* + * Allocate a "struct kvm_cpuid2* instance, with the 0-length arrary of + * entries sized to hold @nr_entries. The caller is responsible for freeing + * the struct. + */ +static inline struct kvm_cpuid2 *allocate_kvm_cpuid2(int nr_entries) +{ + struct kvm_cpuid2 *cpuid; + + cpuid = malloc(kvm_cpuid2_size(nr_entries)); + TEST_ASSERT(cpuid, "-ENOMEM when allocating kvm_cpuid2"); + + cpuid->nent = nr_entries; + + return cpuid; +} + struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu); static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu, diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 10038496fff6..4d383dee30b7 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -16,6 +16,8 @@ #define DEFAULT_CODE_SELECTOR 0x8 #define DEFAULT_DATA_SELECTOR 0x10 +#define MAX_NR_CPUID_ENTRIES 100 + vm_vaddr_t exception_handlers; static void regs_dump(FILE *stream, struct kvm_regs *regs, uint8_t indent) @@ -672,40 +674,6 @@ struct kvm_vcpu *vm_arch_vcpu_recreate(struct kvm_vm *vm, uint32_t vcpu_id) return vcpu; } -/* - * Allocate an instance of struct kvm_cpuid2 - * - * Input Args: None - * - * Output Args: None - * - * Return: A pointer to the allocated struct. The caller is responsible - * for freeing this struct. - * - * Since kvm_cpuid2 uses a 0-length array to allow a the size of the - * array to be decided at allocation time, allocation is slightly - * complicated. This function uses a reasonable default length for - * the array and performs the appropriate allocation. - */ -static struct kvm_cpuid2 *allocate_kvm_cpuid2(void) -{ - struct kvm_cpuid2 *cpuid; - int nent = 100; - size_t size; - - size = sizeof(*cpuid); - size += nent * sizeof(struct kvm_cpuid_entry2); - cpuid = malloc(size); - if (!cpuid) { - perror("malloc"); - abort(); - } - - cpuid->nent = nent; - - return cpuid; -} - /* * KVM Supported CPUID Get * @@ -725,7 +693,7 @@ struct kvm_cpuid2 *kvm_get_supported_cpuid(void) if (cpuid) return cpuid; - cpuid = allocate_kvm_cpuid2(); + cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES); kvm_fd = open_kvm_dev_path_or_exit(); kvm_ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); @@ -781,7 +749,7 @@ struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu) int max_ent; int rc = -1; - cpuid = allocate_kvm_cpuid2(); + cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES); max_ent = cpuid->nent; for (cpuid->nent = 1; cpuid->nent <= max_ent; cpuid->nent++) { @@ -1295,7 +1263,7 @@ struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void) if (cpuid) return cpuid; - cpuid = allocate_kvm_cpuid2(); + cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES); kvm_fd = open_kvm_dev_path_or_exit(); kvm_ioctl(kvm_fd, KVM_GET_SUPPORTED_HV_CPUID, cpuid); @@ -1314,9 +1282,7 @@ void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu) cpuid_sys = kvm_get_supported_cpuid(); cpuid_hv = kvm_get_supported_hv_cpuid(); - cpuid_full = malloc(sizeof(*cpuid_full) + - (cpuid_sys->nent + cpuid_hv->nent) * - sizeof(struct kvm_cpuid_entry2)); + cpuid_full = allocate_kvm_cpuid2(cpuid_sys->nent + cpuid_hv->nent); if (!cpuid_full) { perror("malloc"); abort(); @@ -1343,7 +1309,7 @@ struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu) { static struct kvm_cpuid2 *cpuid; - cpuid = allocate_kvm_cpuid2(); + cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES); vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, cpuid); From 7fbc6038acbaa4c0c0b374aac635038881143e84 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:43 +0000 Subject: [PATCH 0984/1436] KVM: selftests: Cache CPUID in struct kvm_vcpu Cache a vCPU's CPUID information in "struct kvm_vcpu" to allow fixing the mess where tests, often unknowingly, modify the global/static "cpuid" allocated by kvm_get_supported_cpuid(). Add vcpu_init_cpuid() to handle stuffing an entirely different CPUID model, e.g. during vCPU creation or when switching to the Hyper-V enabled CPUID model. Automatically refresh the cache on vcpu_set_cpuid() so that any adjustments made by KVM are always reflected in the cache. Drop vcpu_get_cpuid() entirely to force tests to use the cache, and to allow adding e.g. vcpu_get_cpuid_entry() in the future without creating a conflicting set of APIs where vcpu_get_cpuid() does KVM_GET_CPUID2, but vcpu_get_cpuid_entry() does not. Opportunistically convert the VMX nested state test and KVM PV test to manipulating the vCPU's CPUID (because it's easy), but use vcpu_init_cpuid() for the Hyper-V features test and "emulator error" test to effectively retain their current behavior as they're less trivial to convert. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-19-seanjc@google.com --- .../selftests/kvm/include/kvm_util_base.h | 5 +++ .../selftests/kvm/include/x86_64/processor.h | 25 +++++++---- tools/testing/selftests/kvm/lib/kvm_util.c | 7 ++++ .../selftests/kvm/lib/x86_64/processor.c | 42 +++++++++---------- .../testing/selftests/kvm/x86_64/cpuid_test.c | 18 ++++---- .../kvm/x86_64/emulator_error_test.c | 2 +- .../selftests/kvm/x86_64/hyperv_features.c | 2 +- .../selftests/kvm/x86_64/kvm_pv_test.c | 6 +-- .../selftests/kvm/x86_64/monitor_mwait_test.c | 2 +- .../kvm/x86_64/vmx_set_nested_state_test.c | 6 +-- .../selftests/kvm/x86_64/xapic_state_test.c | 4 +- 11 files changed, 69 insertions(+), 50 deletions(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 19f7b33a1e58..24fde97f6121 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -50,6 +50,9 @@ struct kvm_vcpu { int fd; struct kvm_vm *vm; struct kvm_run *run; +#ifdef __x86_64__ + struct kvm_cpuid2 *cpuid; +#endif struct kvm_dirty_gfn *dirty_gfns; uint32_t fetch_index; uint32_t dirty_gfns_count; @@ -748,6 +751,8 @@ static inline struct kvm_vcpu *vm_vcpu_recreate(struct kvm_vm *vm, return vm_arch_vcpu_recreate(vm, vcpu_id); } +void vcpu_arch_free(struct kvm_vcpu *vcpu); + void virt_arch_pgd_alloc(struct kvm_vm *vm); static inline void virt_pgd_alloc(struct kvm_vm *vm) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 1326377f72b7..c61b3aa4950f 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -618,18 +618,29 @@ static inline struct kvm_cpuid2 *allocate_kvm_cpuid2(int nr_entries) return cpuid; } -struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu); +void vcpu_init_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid); -static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu, - struct kvm_cpuid2 *cpuid) +static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu) { - return __vcpu_ioctl(vcpu, KVM_SET_CPUID2, cpuid); + int r; + + TEST_ASSERT(vcpu->cpuid, "Must do vcpu_init_cpuid() first"); + r = __vcpu_ioctl(vcpu, KVM_SET_CPUID2, vcpu->cpuid); + if (r) + return r; + + /* On success, refresh the cache to pick up adjustments made by KVM. */ + vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid); + return 0; } -static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu, - struct kvm_cpuid2 *cpuid) +static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu) { - vcpu_ioctl(vcpu, KVM_SET_CPUID2, cpuid); + TEST_ASSERT(vcpu->cpuid, "Must do vcpu_init_cpuid() first"); + vcpu_ioctl(vcpu, KVM_SET_CPUID2, vcpu->cpuid); + + /* Refresh the cache to pick up adjustments made by KVM. */ + vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid); } struct kvm_cpuid_entry2 * diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 49c189878af3..9889fe0d8919 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -472,6 +472,11 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, return ®ion->region; } +__weak void vcpu_arch_free(struct kvm_vcpu *vcpu) +{ + +} + /* * VM VCPU Remove * @@ -501,6 +506,8 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu) TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("close()", ret)); list_del(&vcpu->list); + + vcpu_arch_free(vcpu); free(vcpu); } diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 4d383dee30b7..4cbcc333bba0 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -648,7 +648,7 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id, DEFAULT_GUEST_STACK_VADDR_MIN); vcpu = __vm_vcpu_add(vm, vcpu_id); - vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); + vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid()); vcpu_setup(vm, vcpu); /* Setup guest general purpose registers */ @@ -669,11 +669,17 @@ struct kvm_vcpu *vm_arch_vcpu_recreate(struct kvm_vm *vm, uint32_t vcpu_id) { struct kvm_vcpu *vcpu = __vm_vcpu_add(vm, vcpu_id); - vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); + vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid()); return vcpu; } +void vcpu_arch_free(struct kvm_vcpu *vcpu) +{ + if (vcpu->cpuid) + free(vcpu->cpuid); +} + /* * KVM Supported CPUID Get * @@ -743,31 +749,23 @@ uint64_t kvm_get_feature_msr(uint64_t msr_index) return buffer.entry.data; } -struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu) +void vcpu_init_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) { - struct kvm_cpuid2 *cpuid; - int max_ent; - int rc = -1; + TEST_ASSERT(cpuid != vcpu->cpuid, "@cpuid can't be the vCPU's CPUID"); - cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES); - max_ent = cpuid->nent; - - for (cpuid->nent = 1; cpuid->nent <= max_ent; cpuid->nent++) { - rc = __vcpu_ioctl(vcpu, KVM_GET_CPUID2, cpuid); - if (!rc) - break; - - TEST_ASSERT(rc == -1 && errno == E2BIG, - "KVM_GET_CPUID2 should either succeed or give E2BIG: %d %d", - rc, errno); + /* Allow overriding the default CPUID. */ + if (vcpu->cpuid && vcpu->cpuid->nent < cpuid->nent) { + free(vcpu->cpuid); + vcpu->cpuid = NULL; } - TEST_ASSERT(!rc, KVM_IOCTL_ERROR(KVM_GET_CPUID2, rc)); - return cpuid; + if (!vcpu->cpuid) + vcpu->cpuid = allocate_kvm_cpuid2(cpuid->nent); + + memcpy(vcpu->cpuid, cpuid, kvm_cpuid2_size(cpuid->nent)); + vcpu_set_cpuid(vcpu); } - - /* * Locate a cpuid entry. * @@ -1302,7 +1300,7 @@ void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu) cpuid_full->nent = nent + cpuid_hv->nent; } - vcpu_set_cpuid(vcpu, cpuid_full); + vcpu_init_cpuid(vcpu, cpuid_full); } struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu) diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index 59dcdf5a1220..96f141a758ca 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -144,21 +144,22 @@ struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm, vm_vaddr_t *p_gva, struct return guest_cpuids; } -static void set_cpuid_after_run(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) +static void set_cpuid_after_run(struct kvm_vcpu *vcpu) { + struct kvm_cpuid2 *cpuid = vcpu->cpuid; struct kvm_cpuid_entry2 *ent; int rc; u32 eax, ebx, x; /* Setting unmodified CPUID is allowed */ - rc = __vcpu_set_cpuid(vcpu, cpuid); + rc = __vcpu_set_cpuid(vcpu); TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc); /* Changing CPU features is forbidden */ ent = get_cpuid(cpuid, 0x7, 0); ebx = ent->ebx; ent->ebx--; - rc = __vcpu_set_cpuid(vcpu, cpuid); + rc = __vcpu_set_cpuid(vcpu); TEST_ASSERT(rc, "Changing CPU features should fail"); ent->ebx = ebx; @@ -167,14 +168,14 @@ static void set_cpuid_after_run(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) eax = ent->eax; x = eax & 0xff; ent->eax = (eax & ~0xffu) | (x - 1); - rc = __vcpu_set_cpuid(vcpu, cpuid); + rc = __vcpu_set_cpuid(vcpu); TEST_ASSERT(rc, "Changing MAXPHYADDR should fail"); ent->eax = eax; } int main(void) { - struct kvm_cpuid2 *supp_cpuid, *cpuid2; + struct kvm_cpuid2 *supp_cpuid; struct kvm_vcpu *vcpu; vm_vaddr_t cpuid_gva; struct kvm_vm *vm; @@ -183,18 +184,17 @@ int main(void) vm = vm_create_with_one_vcpu(&vcpu, guest_main); supp_cpuid = kvm_get_supported_cpuid(); - cpuid2 = vcpu_get_cpuid(vcpu); - compare_cpuids(supp_cpuid, cpuid2); + compare_cpuids(supp_cpuid, vcpu->cpuid); - vcpu_alloc_cpuid(vm, &cpuid_gva, cpuid2); + vcpu_alloc_cpuid(vm, &cpuid_gva, vcpu->cpuid); vcpu_args_set(vcpu, 1, cpuid_gva); for (stage = 0; stage < 3; stage++) run_vcpu(vcpu, stage); - set_cpuid_after_run(vcpu, cpuid2); + set_cpuid_after_run(vcpu); kvm_vm_free(vm); } diff --git a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c index 3aa3d17f230f..d8dbed419638 100644 --- a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c +++ b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c @@ -171,7 +171,7 @@ int main(int argc, char *argv[]) entry->eax = (entry->eax & 0xffffff00) | MAXPHYADDR; set_cpuid(cpuid, entry); - vcpu_set_cpuid(vcpu, cpuid); + vcpu_init_cpuid(vcpu, cpuid); rc = kvm_check_cap(KVM_CAP_EXIT_ON_EMULATION_FAILURE); TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable"); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index 2070ba0d6392..86ce1f1e98ee 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -102,7 +102,7 @@ static void hv_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, "failed to set HYPERV_CPUID_ENLIGHTMENT_INFO leaf"); TEST_ASSERT(set_cpuid(cpuid, dbg), "failed to set HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES leaf"); - vcpu_set_cpuid(vcpu, cpuid); + vcpu_init_cpuid(vcpu, cpuid); } static void guest_test_msrs_access(void) diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index ea452444f4af..986ca7282a09 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -147,7 +147,6 @@ static void enter_guest(struct kvm_vcpu *vcpu) int main(void) { - struct kvm_cpuid2 *best; struct kvm_vcpu *vcpu; struct kvm_vm *vm; @@ -157,9 +156,8 @@ int main(void) vcpu_enable_cap(vcpu, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 1); - best = kvm_get_supported_cpuid(); - clear_kvm_cpuid_features(best); - vcpu_set_cpuid(vcpu, best); + clear_kvm_cpuid_features(vcpu->cpuid); + vcpu_set_cpuid(vcpu); vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c index c804f6f04134..0ac5bec1e3b7 100644 --- a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c @@ -80,7 +80,7 @@ int main(int argc, char *argv[]) set_cpuid(cpuid, entry); vm = vm_create_with_one_vcpu(&vcpu, guest_code); - vcpu_set_cpuid(vcpu, cpuid); + vcpu_set_cpuid(vcpu); run = vcpu->run; diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c index 66cb2d0054e6..1cf78ec007f2 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c @@ -121,7 +121,7 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu) test_nested_state(vcpu, state); /* Enable VMX in the guest CPUID. */ - vcpu_set_cpuid(vcpu, kvm_get_supported_cpuid()); + vcpu_set_cpuid(vcpu); /* * Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without @@ -245,7 +245,7 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu) void disable_vmx(struct kvm_vcpu *vcpu) { - struct kvm_cpuid2 *cpuid = kvm_get_supported_cpuid(); + struct kvm_cpuid2 *cpuid = vcpu->cpuid; int i; for (i = 0; i < cpuid->nent; ++i) @@ -255,7 +255,7 @@ void disable_vmx(struct kvm_vcpu *vcpu) TEST_ASSERT(i != cpuid->nent, "CPUID function 1 not found"); cpuid->entries[i].ecx &= ~CPUID_VMX; - vcpu_set_cpuid(vcpu, cpuid); + vcpu_set_cpuid(vcpu); cpuid->entries[i].ecx |= CPUID_VMX; } diff --git a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c index 87531623064f..52133bb4d85a 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c @@ -152,13 +152,13 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&x.vcpu, xapic_guest_code); x.is_x2apic = false; - cpuid = vcpu_get_cpuid(x.vcpu); + cpuid = x.vcpu->cpuid; for (i = 0; i < cpuid->nent; i++) { if (cpuid->entries[i].function == 1) break; } cpuid->entries[i].ecx &= ~BIT(21); - vcpu_set_cpuid(x.vcpu, cpuid); + vcpu_set_cpuid(x.vcpu); virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); test_icr(&x); From d838b313aadcf89d9b352ced1cd849d313971864 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:44 +0000 Subject: [PATCH 0985/1436] KVM: selftests: Don't use a static local in vcpu_get_supported_hv_cpuid() Don't use a static variable for the Hyper-V supported CPUID array, the helper unconditionally reallocates the array on every invocation (and all callers free the array immediately after use). The array is intentionally recreated and refilled because the set of supported CPUID features is dependent on vCPU state, e.g. whether or not eVMCS has been enabled. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-20-seanjc@google.com --- tools/testing/selftests/kvm/lib/x86_64/processor.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 4cbcc333bba0..09e51514e1b9 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1305,9 +1305,7 @@ void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu) struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu) { - static struct kvm_cpuid2 *cpuid; - - cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES); + struct kvm_cpuid2 *cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES); vcpu_ioctl(vcpu, KVM_GET_SUPPORTED_HV_CPUID, cpuid); From 8b02674103e6f09f9f9397bfb7bfd60a9323c9c2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:45 +0000 Subject: [PATCH 0986/1436] KVM: selftests: Rename and tweak get_cpuid() to get_cpuid_entry() Rename get_cpuid() to get_cpuid_entry() to better reflect its behavior. Leave set_cpuid() as is to avoid unnecessary churn, that helper will soon be removed entirely. Oppurtunistically tweak the implementation to avoid using a temporary variable in anticipation of taggin the input @cpuid with "const". No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-21-seanjc@google.com --- .../testing/selftests/kvm/include/x86_64/processor.h | 4 ++-- tools/testing/selftests/kvm/lib/x86_64/processor.c | 11 +++++------ tools/testing/selftests/kvm/x86_64/cpuid_test.c | 4 ++-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index c61b3aa4950f..1703e07f8b83 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -766,8 +766,8 @@ void vm_set_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, /* * get_cpuid() - find matching CPUID entry and return pointer to it. */ -struct kvm_cpuid_entry2 *get_cpuid(struct kvm_cpuid2 *cpuid, uint32_t function, - uint32_t index); +struct kvm_cpuid_entry2 *get_cpuid_entry(struct kvm_cpuid2 *cpuid, + uint32_t function, uint32_t index); /* * set_cpuid() - overwrites a matching cpuid entry with the provided value. * matches based on ent->function && ent->index. returns true diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 09e51514e1b9..fd8577a12678 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1207,16 +1207,15 @@ void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) } } -struct kvm_cpuid_entry2 *get_cpuid(struct kvm_cpuid2 *cpuid, uint32_t function, - uint32_t index) +struct kvm_cpuid_entry2 *get_cpuid_entry(struct kvm_cpuid2 *cpuid, + uint32_t function, uint32_t index) { int i; for (i = 0; i < cpuid->nent; i++) { - struct kvm_cpuid_entry2 *cur = &cpuid->entries[i]; - - if (cur->function == function && cur->index == index) - return cur; + if (cpuid->entries[i].function == function && + cpuid->entries[i].index == index) + return &cpuid->entries[i]; } TEST_FAIL("CPUID function 0x%x index 0x%x not found ", function, index); diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index 96f141a758ca..a9345cee9bbc 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -156,7 +156,7 @@ static void set_cpuid_after_run(struct kvm_vcpu *vcpu) TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc); /* Changing CPU features is forbidden */ - ent = get_cpuid(cpuid, 0x7, 0); + ent = get_cpuid_entry(cpuid, 0x7, 0); ebx = ent->ebx; ent->ebx--; rc = __vcpu_set_cpuid(vcpu); @@ -164,7 +164,7 @@ static void set_cpuid_after_run(struct kvm_vcpu *vcpu) ent->ebx = ebx; /* Changing MAXPHYADDR is forbidden */ - ent = get_cpuid(cpuid, 0x80000008, 0); + ent = get_cpuid_entry(cpuid, 0x80000008, 0); eax = ent->eax; x = eax & 0xff; ent->eax = (eax & ~0xffu) | (x - 1); From 662162fed26137651cc69971555c3f5a984345d7 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:46 +0000 Subject: [PATCH 0987/1436] KVM: selftests: Use get_cpuid_entry() in kvm_get_supported_cpuid_index() Use get_cpuid_entry() in kvm_get_supported_cpuid_index() to replace functionally identical code. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-22-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 14 ++++---- .../selftests/kvm/lib/x86_64/processor.c | 32 ------------------- 2 files changed, 7 insertions(+), 39 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 1703e07f8b83..db8d8a84fbc3 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -618,6 +618,8 @@ static inline struct kvm_cpuid2 *allocate_kvm_cpuid2(int nr_entries) return cpuid; } +struct kvm_cpuid_entry2 *get_cpuid_entry(struct kvm_cpuid2 *cpuid, + uint32_t function, uint32_t index); void vcpu_init_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid); static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu) @@ -643,8 +645,11 @@ static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu) vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid); } -struct kvm_cpuid_entry2 * -kvm_get_supported_cpuid_index(uint32_t function, uint32_t index); +static inline struct kvm_cpuid_entry2 *kvm_get_supported_cpuid_index(uint32_t function, + uint32_t index) +{ + return get_cpuid_entry(kvm_get_supported_cpuid(), function, index); +} static inline struct kvm_cpuid_entry2 * kvm_get_supported_cpuid_entry(uint32_t function) @@ -763,11 +768,6 @@ uint64_t vm_get_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, void vm_set_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, uint64_t vaddr, uint64_t pte); -/* - * get_cpuid() - find matching CPUID entry and return pointer to it. - */ -struct kvm_cpuid_entry2 *get_cpuid_entry(struct kvm_cpuid2 *cpuid, - uint32_t function, uint32_t index); /* * set_cpuid() - overwrites a matching cpuid entry with the provided value. * matches based on ent->function && ent->index. returns true diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index fd8577a12678..5f359314a6ec 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -766,38 +766,6 @@ void vcpu_init_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) vcpu_set_cpuid(vcpu); } -/* - * Locate a cpuid entry. - * - * Input Args: - * function: The function of the cpuid entry to find. - * index: The index of the cpuid entry. - * - * Output Args: None - * - * Return: A pointer to the cpuid entry. Never returns NULL. - */ -struct kvm_cpuid_entry2 * -kvm_get_supported_cpuid_index(uint32_t function, uint32_t index) -{ - struct kvm_cpuid2 *cpuid; - struct kvm_cpuid_entry2 *entry = NULL; - int i; - - cpuid = kvm_get_supported_cpuid(); - for (i = 0; i < cpuid->nent; i++) { - if (cpuid->entries[i].function == function && - cpuid->entries[i].index == index) { - entry = &cpuid->entries[i]; - break; - } - } - - TEST_ASSERT(entry, "Guest CPUID entry not found: (EAX=%x, ECX=%x).", - function, index); - return entry; -} - uint64_t vcpu_get_msr(struct kvm_vcpu *vcpu, uint64_t msr_index) { struct { From c41880b5f040120fc27eb2305a0ab3f179c89f9a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:47 +0000 Subject: [PATCH 0988/1436] KVM: selftests: Add helpers to get and modify a vCPU's CPUID entries Add helpers to get a specific CPUID entry for a given vCPU, and to toggle a specific CPUID-based feature for a vCPU. The helpers will reduce the amount of boilerplate code needed to tweak a vCPU's CPUID model, improve code clarity, and most importantly move tests away from modifying the static "cpuid" returned by kvm_get_supported_cpuid(). Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-23-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 30 +++++++++++++++++++ .../selftests/kvm/lib/x86_64/processor.c | 18 +++++++++++ 2 files changed, 48 insertions(+) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index db8d8a84fbc3..25b99eab7e71 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -622,6 +622,19 @@ struct kvm_cpuid_entry2 *get_cpuid_entry(struct kvm_cpuid2 *cpuid, uint32_t function, uint32_t index); void vcpu_init_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid); +static inline struct kvm_cpuid_entry2 *__vcpu_get_cpuid_entry(struct kvm_vcpu *vcpu, + uint32_t function, + uint32_t index) +{ + return get_cpuid_entry(vcpu->cpuid, function, index); +} + +static inline struct kvm_cpuid_entry2 *vcpu_get_cpuid_entry(struct kvm_vcpu *vcpu, + uint32_t function) +{ + return __vcpu_get_cpuid_entry(vcpu, function, 0); +} + static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu) { int r; @@ -645,6 +658,23 @@ static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu) vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid); } +void vcpu_set_or_clear_cpuid_feature(struct kvm_vcpu *vcpu, + struct kvm_x86_cpu_feature feature, + bool set); + +static inline void vcpu_set_cpuid_feature(struct kvm_vcpu *vcpu, + struct kvm_x86_cpu_feature feature) +{ + vcpu_set_or_clear_cpuid_feature(vcpu, feature, true); + +} + +static inline void vcpu_clear_cpuid_feature(struct kvm_vcpu *vcpu, + struct kvm_x86_cpu_feature feature) +{ + vcpu_set_or_clear_cpuid_feature(vcpu, feature, false); +} + static inline struct kvm_cpuid_entry2 *kvm_get_supported_cpuid_index(uint32_t function, uint32_t index) { diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 5f359314a6ec..72aac618e0e4 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -766,6 +766,24 @@ void vcpu_init_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) vcpu_set_cpuid(vcpu); } +void vcpu_set_or_clear_cpuid_feature(struct kvm_vcpu *vcpu, + struct kvm_x86_cpu_feature feature, + bool set) +{ + struct kvm_cpuid_entry2 *entry; + u32 *reg; + + entry = __vcpu_get_cpuid_entry(vcpu, feature.function, feature.index); + reg = (&entry->eax) + feature.reg; + + if (set) + *reg |= BIT(feature.bit); + else + *reg &= ~BIT(feature.bit); + + vcpu_set_cpuid(vcpu); +} + uint64_t vcpu_get_msr(struct kvm_vcpu *vcpu, uint64_t msr_index) { struct { From 7af7161d87383f84caec1e8aaf6366c31ce845ec Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:48 +0000 Subject: [PATCH 0989/1436] KVM: selftests: Use vm->pa_bits to generate reserved PA bits Use vm->pa_bits to generate the mask of physical address bits that are reserved in page table entries. vm->pa_bits is set when the VM is created, i.e. it's guaranteed to be valid when populating page tables. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-24-seanjc@google.com --- tools/testing/selftests/kvm/lib/x86_64/processor.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 72aac618e0e4..080480c397a4 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -221,16 +221,12 @@ static uint64_t *_vm_get_page_table_entry(struct kvm_vm *vm, uint16_t index[4]; uint64_t *pml4e, *pdpe, *pde; uint64_t *pte; - struct kvm_cpuid_entry2 *entry; struct kvm_sregs sregs; - int max_phy_addr; uint64_t rsvd_mask = 0; - entry = kvm_get_supported_cpuid_index(0x80000008, 0); - max_phy_addr = entry->eax & 0x000000ff; /* Set the high bits in the reserved mask. */ - if (max_phy_addr < 52) - rsvd_mask = GENMASK_ULL(51, max_phy_addr); + if (vm->pa_bits < 52) + rsvd_mask = GENMASK_ULL(51, vm->pa_bits); /* * SDM vol 3, fig 4-11 "Formats of CR3 and Paging-Structure Entries From 1940af0b8179ae2c2bd287fbd3edaab59df5fb55 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:49 +0000 Subject: [PATCH 0990/1436] KVM: selftests: Add and use helper to set vCPU's CPUID maxphyaddr Add a helper to set a vCPU's guest.MAXPHYADDR, and use it in the test that verifies the emulator returns an error on an unknown instruction when KVM emulates in response to an EPT violation with a GPA that is legal in hardware but illegal with respect to the guest's MAXPHYADDR. Add a helper even though there's only a single user at this time. Before its removal, mmu_role_test also stuffed guest.MAXPHYADDR, and the helper provides a small amount of clarity. More importantly, this eliminates a set_cpuid() user and an instance of modifying kvm_get_supported_cpuid()'s static "cpuid". Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-25-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/processor.h | 2 ++ tools/testing/selftests/kvm/lib/x86_64/processor.c | 8 ++++++++ .../testing/selftests/kvm/x86_64/emulator_error_test.c | 10 +--------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 25b99eab7e71..a3d61807d223 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -658,6 +658,8 @@ static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu) vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid); } +void vcpu_set_cpuid_maxphyaddr(struct kvm_vcpu *vcpu, uint8_t maxphyaddr); + void vcpu_set_or_clear_cpuid_feature(struct kvm_vcpu *vcpu, struct kvm_x86_cpu_feature feature, bool set); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 080480c397a4..27bf5dad6ec5 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -762,6 +762,14 @@ void vcpu_init_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) vcpu_set_cpuid(vcpu); } +void vcpu_set_cpuid_maxphyaddr(struct kvm_vcpu *vcpu, uint8_t maxphyaddr) +{ + struct kvm_cpuid_entry2 *entry = vcpu_get_cpuid_entry(vcpu, 0x80000008); + + entry->eax = (entry->eax & ~0xff) | maxphyaddr; + vcpu_set_cpuid(vcpu); +} + void vcpu_set_or_clear_cpuid_feature(struct kvm_vcpu *vcpu, struct kvm_x86_cpu_feature feature, bool set) diff --git a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c index d8dbed419638..236e11755ba6 100644 --- a/tools/testing/selftests/kvm/x86_64/emulator_error_test.c +++ b/tools/testing/selftests/kvm/x86_64/emulator_error_test.c @@ -150,8 +150,6 @@ static uint64_t process_ucall(struct kvm_vcpu *vcpu) int main(int argc, char *argv[]) { - struct kvm_cpuid_entry2 *entry; - struct kvm_cpuid2 *cpuid; struct kvm_vcpu *vcpu; struct kvm_vm *vm; uint64_t gpa, pte; @@ -165,13 +163,7 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&vcpu, guest_code); - cpuid = kvm_get_supported_cpuid(); - - entry = kvm_get_supported_cpuid_index(0x80000008, 0); - entry->eax = (entry->eax & 0xffffff00) | MAXPHYADDR; - set_cpuid(cpuid, entry); - - vcpu_init_cpuid(vcpu, cpuid); + vcpu_set_cpuid_maxphyaddr(vcpu, MAXPHYADDR); rc = kvm_check_cap(KVM_CAP_EXIT_ON_EMULATION_FAILURE); TEST_ASSERT(rc, "KVM_CAP_EXIT_ON_EMULATION_FAILURE is unavailable"); From b78843be77968b1e5a071c7ed7fd8f3094e8f0a2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 8 Jul 2022 14:42:49 -0700 Subject: [PATCH 0991/1436] KVM: selftests: Use vcpu_clear_cpuid_feature() in monitor_mwait_test Use vcpu_clear_cpuid_feature() to the MONITOR/MWAIT CPUID feature bit in the MONITOR/MWAIT quirk test. Signed-off-by: Sean Christopherson --- .../testing/selftests/kvm/x86_64/monitor_mwait_test.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c index 0ac5bec1e3b7..016070cad36e 100644 --- a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c @@ -63,8 +63,6 @@ static void guest_code(void) int main(int argc, char *argv[]) { uint64_t disabled_quirks; - struct kvm_cpuid2 *cpuid; - struct kvm_cpuid_entry2 *entry; struct kvm_vcpu *vcpu; struct kvm_run *run; struct kvm_vm *vm; @@ -73,14 +71,8 @@ int main(int argc, char *argv[]) TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2)); - cpuid = kvm_get_supported_cpuid(); - - entry = kvm_get_supported_cpuid_index(1, 0); - entry->ecx &= ~CPUID_MWAIT; - set_cpuid(cpuid, entry); - vm = vm_create_with_one_vcpu(&vcpu, guest_code); - vcpu_set_cpuid(vcpu); + vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_MWAIT); run = vcpu->run; From 3a5d36b32bd26d88d8dfe8f1eff702e138ea18cd Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:50 +0000 Subject: [PATCH 0992/1436] KVM: selftests: Use vcpu_get_cpuid_entry() in PV features test (sort of) Add a new helper, vcpu_clear_cpuid_entry(), to do a RMW operation on the vCPU's CPUID model to clear a given CPUID entry, and use it to clear KVM's paravirt feature instead of operating on kvm_get_supported_cpuid()'s static "cpuid" variable. This also eliminates a user of the soon-be-defunct set_cpuid() helper. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-26-seanjc@google.com --- .../testing/selftests/kvm/include/x86_64/processor.h | 1 + tools/testing/selftests/kvm/lib/x86_64/processor.c | 11 +++++++++++ tools/testing/selftests/kvm/x86_64/kvm_pv_test.c | 12 +----------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index a3d61807d223..c0d40474ef2d 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -660,6 +660,7 @@ static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu) void vcpu_set_cpuid_maxphyaddr(struct kvm_vcpu *vcpu, uint8_t maxphyaddr); +void vcpu_clear_cpuid_entry(struct kvm_vcpu *vcpu, uint32_t function); void vcpu_set_or_clear_cpuid_feature(struct kvm_vcpu *vcpu, struct kvm_x86_cpu_feature feature, bool set); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 27bf5dad6ec5..a41384863336 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -770,6 +770,17 @@ void vcpu_set_cpuid_maxphyaddr(struct kvm_vcpu *vcpu, uint8_t maxphyaddr) vcpu_set_cpuid(vcpu); } +void vcpu_clear_cpuid_entry(struct kvm_vcpu *vcpu, uint32_t function) +{ + struct kvm_cpuid_entry2 *entry = vcpu_get_cpuid_entry(vcpu, function); + + entry->eax = 0; + entry->ebx = 0; + entry->ecx = 0; + entry->edx = 0; + vcpu_set_cpuid(vcpu); +} + void vcpu_set_or_clear_cpuid_feature(struct kvm_vcpu *vcpu, struct kvm_x86_cpu_feature feature, bool set) diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c index 986ca7282a09..619655c1a1f3 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -95,15 +95,6 @@ static void guest_main(void) GUEST_DONE(); } -static void clear_kvm_cpuid_features(struct kvm_cpuid2 *cpuid) -{ - struct kvm_cpuid_entry2 ent = {0}; - - ent.function = KVM_CPUID_FEATURES; - TEST_ASSERT(set_cpuid(cpuid, &ent), - "failed to clear KVM_CPUID_FEATURES leaf"); -} - static void pr_msr(struct ucall *uc) { struct msr_data *msr = (struct msr_data *)uc->args[0]; @@ -156,8 +147,7 @@ int main(void) vcpu_enable_cap(vcpu, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 1); - clear_kvm_cpuid_features(vcpu->cpuid); - vcpu_set_cpuid(vcpu); + vcpu_clear_cpuid_entry(vcpu, KVM_CPUID_FEATURES); vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); From 4dcd130c9b3d64464b5c44aba071203095f77e63 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:51 +0000 Subject: [PATCH 0993/1436] KVM: selftests: Use vCPU's CPUID directly in Hyper-V test Use the vCPU's persistent CPUID array directly when manipulating the set of exposed Hyper-V CPUID features. Drop set_cpuid() to route all future modification through the vCPU helpers; the Hyper-V features test was the last user. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-27-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 9 -- .../selftests/kvm/lib/x86_64/processor.c | 18 --- .../selftests/kvm/x86_64/hyperv_features.c | 126 +++++++++--------- 3 files changed, 64 insertions(+), 89 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index c0d40474ef2d..50d68114ab86 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -801,15 +801,6 @@ uint64_t vm_get_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, void vm_set_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, uint64_t vaddr, uint64_t pte); -/* - * set_cpuid() - overwrites a matching cpuid entry with the provided value. - * matches based on ent->function && ent->index. returns true - * if a match was found and successfully overwritten. - * @cpuid: the kvm cpuid list to modify. - * @ent: cpuid entry to insert - */ -bool set_cpuid(struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 *ent); - uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index a41384863336..7cc0814f0b67 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1224,24 +1224,6 @@ struct kvm_cpuid_entry2 *get_cpuid_entry(struct kvm_cpuid2 *cpuid, return NULL; } -bool set_cpuid(struct kvm_cpuid2 *cpuid, - struct kvm_cpuid_entry2 *ent) -{ - int i; - - for (i = 0; i < cpuid->nent; i++) { - struct kvm_cpuid_entry2 *cur = &cpuid->entries[i]; - - if (cur->function != ent->function || cur->index != ent->index) - continue; - - memcpy(cur, ent, sizeof(struct kvm_cpuid_entry2)); - return true; - } - - return false; -} - uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) { diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/testing/selftests/kvm/x86_64/hyperv_features.c index 86ce1f1e98ee..79ab0152d281 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -91,37 +91,28 @@ static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) GUEST_DONE(); } -static void hv_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid, - struct kvm_cpuid_entry2 *feat, - struct kvm_cpuid_entry2 *recomm, - struct kvm_cpuid_entry2 *dbg) +static void vcpu_reset_hv_cpuid(struct kvm_vcpu *vcpu) { - TEST_ASSERT(set_cpuid(cpuid, feat), - "failed to set KVM_CPUID_FEATURES leaf"); - TEST_ASSERT(set_cpuid(cpuid, recomm), - "failed to set HYPERV_CPUID_ENLIGHTMENT_INFO leaf"); - TEST_ASSERT(set_cpuid(cpuid, dbg), - "failed to set HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES leaf"); - vcpu_init_cpuid(vcpu, cpuid); + /* + * Enable all supported Hyper-V features, then clear the leafs holding + * the features that will be tested one by one. + */ + vcpu_set_hv_cpuid(vcpu); + + vcpu_clear_cpuid_entry(vcpu, HYPERV_CPUID_FEATURES); + vcpu_clear_cpuid_entry(vcpu, HYPERV_CPUID_ENLIGHTMENT_INFO); + vcpu_clear_cpuid_entry(vcpu, HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES); } static void guest_test_msrs_access(void) { + struct kvm_cpuid2 *prev_cpuid = NULL; + struct kvm_cpuid_entry2 *feat, *dbg; struct kvm_vcpu *vcpu; struct kvm_run *run; struct kvm_vm *vm; struct ucall uc; int stage = 0; - struct kvm_cpuid_entry2 feat = { - .function = HYPERV_CPUID_FEATURES - }; - struct kvm_cpuid_entry2 recomm = { - .function = HYPERV_CPUID_ENLIGHTMENT_INFO - }; - struct kvm_cpuid_entry2 dbg = { - .function = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES - }; - struct kvm_cpuid2 *best; vm_vaddr_t msr_gva; struct msr_data *msr; @@ -135,9 +126,16 @@ static void guest_test_msrs_access(void) vcpu_args_set(vcpu, 1, msr_gva); vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); - vcpu_set_hv_cpuid(vcpu); + if (!prev_cpuid) { + vcpu_reset_hv_cpuid(vcpu); - best = kvm_get_supported_hv_cpuid(); + prev_cpuid = allocate_kvm_cpuid2(vcpu->cpuid->nent); + } else { + vcpu_init_cpuid(vcpu, prev_cpuid); + } + + feat = vcpu_get_cpuid_entry(vcpu, HYPERV_CPUID_FEATURES); + dbg = vcpu_get_cpuid_entry(vcpu, HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES); vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); @@ -163,7 +161,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 2: - feat.eax |= HV_MSR_HYPERCALL_AVAILABLE; + feat->eax |= HV_MSR_HYPERCALL_AVAILABLE; /* * HV_X64_MSR_GUEST_OS_ID has to be written first to make * HV_X64_MSR_HYPERCALL available. @@ -190,7 +188,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 6: - feat.eax |= HV_MSR_VP_RUNTIME_AVAILABLE; + feat->eax |= HV_MSR_VP_RUNTIME_AVAILABLE; msr->idx = HV_X64_MSR_VP_RUNTIME; msr->write = 0; msr->available = 1; @@ -209,7 +207,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 9: - feat.eax |= HV_MSR_TIME_REF_COUNT_AVAILABLE; + feat->eax |= HV_MSR_TIME_REF_COUNT_AVAILABLE; msr->idx = HV_X64_MSR_TIME_REF_COUNT; msr->write = 0; msr->available = 1; @@ -228,7 +226,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 12: - feat.eax |= HV_MSR_VP_INDEX_AVAILABLE; + feat->eax |= HV_MSR_VP_INDEX_AVAILABLE; msr->idx = HV_X64_MSR_VP_INDEX; msr->write = 0; msr->available = 1; @@ -247,7 +245,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 15: - feat.eax |= HV_MSR_RESET_AVAILABLE; + feat->eax |= HV_MSR_RESET_AVAILABLE; msr->idx = HV_X64_MSR_RESET; msr->write = 0; msr->available = 1; @@ -265,7 +263,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 18: - feat.eax |= HV_MSR_REFERENCE_TSC_AVAILABLE; + feat->eax |= HV_MSR_REFERENCE_TSC_AVAILABLE; msr->idx = HV_X64_MSR_REFERENCE_TSC; msr->write = 0; msr->available = 1; @@ -292,7 +290,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 22: - feat.eax |= HV_MSR_SYNIC_AVAILABLE; + feat->eax |= HV_MSR_SYNIC_AVAILABLE; msr->idx = HV_X64_MSR_EOM; msr->write = 0; msr->available = 1; @@ -310,7 +308,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 25: - feat.eax |= HV_MSR_SYNTIMER_AVAILABLE; + feat->eax |= HV_MSR_SYNTIMER_AVAILABLE; msr->idx = HV_X64_MSR_STIMER0_CONFIG; msr->write = 0; msr->available = 1; @@ -329,7 +327,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 28: - feat.edx |= HV_STIMER_DIRECT_MODE_AVAILABLE; + feat->edx |= HV_STIMER_DIRECT_MODE_AVAILABLE; msr->idx = HV_X64_MSR_STIMER0_CONFIG; msr->write = 1; msr->write_val = 1 << 12; @@ -342,7 +340,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 30: - feat.eax |= HV_MSR_APIC_ACCESS_AVAILABLE; + feat->eax |= HV_MSR_APIC_ACCESS_AVAILABLE; msr->idx = HV_X64_MSR_EOI; msr->write = 1; msr->write_val = 1; @@ -355,7 +353,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 32: - feat.eax |= HV_ACCESS_FREQUENCY_MSRS; + feat->eax |= HV_ACCESS_FREQUENCY_MSRS; msr->idx = HV_X64_MSR_TSC_FREQUENCY; msr->write = 0; msr->available = 1; @@ -374,7 +372,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 35: - feat.eax |= HV_ACCESS_REENLIGHTENMENT; + feat->eax |= HV_ACCESS_REENLIGHTENMENT; msr->idx = HV_X64_MSR_REENLIGHTENMENT_CONTROL; msr->write = 0; msr->available = 1; @@ -399,7 +397,7 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 39: - feat.edx |= HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE; + feat->edx |= HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE; msr->idx = HV_X64_MSR_CRASH_P0; msr->write = 0; msr->available = 1; @@ -417,8 +415,8 @@ static void guest_test_msrs_access(void) msr->available = 0; break; case 42: - feat.edx |= HV_FEATURE_DEBUG_MSRS_AVAILABLE; - dbg.eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; + feat->edx |= HV_FEATURE_DEBUG_MSRS_AVAILABLE; + dbg->eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; msr->idx = HV_X64_MSR_SYNDBG_STATUS; msr->write = 0; msr->available = 1; @@ -435,7 +433,9 @@ static void guest_test_msrs_access(void) return; } - hv_set_cpuid(vcpu, best, &feat, &recomm, &dbg); + vcpu_set_cpuid(vcpu); + + memcpy(prev_cpuid, vcpu->cpuid, kvm_cpuid2_size(vcpu->cpuid->nent)); pr_debug("Stage %d: testing msr: 0x%x for %s\n", stage, msr->idx, msr->write ? "write" : "read"); @@ -463,24 +463,15 @@ static void guest_test_msrs_access(void) static void guest_test_hcalls_access(void) { + struct kvm_cpuid_entry2 *feat, *recomm, *dbg; + struct kvm_cpuid2 *prev_cpuid = NULL; struct kvm_vcpu *vcpu; struct kvm_run *run; struct kvm_vm *vm; struct ucall uc; int stage = 0; - struct kvm_cpuid_entry2 feat = { - .function = HYPERV_CPUID_FEATURES, - .eax = HV_MSR_HYPERCALL_AVAILABLE - }; - struct kvm_cpuid_entry2 recomm = { - .function = HYPERV_CPUID_ENLIGHTMENT_INFO - }; - struct kvm_cpuid_entry2 dbg = { - .function = HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES - }; vm_vaddr_t hcall_page, hcall_params; struct hcall_data *hcall; - struct kvm_cpuid2 *best; while (true) { vm = vm_create_with_one_vcpu(&vcpu, guest_hcall); @@ -499,14 +490,23 @@ static void guest_test_hcalls_access(void) vcpu_args_set(vcpu, 2, addr_gva2gpa(vm, hcall_page), hcall_params); vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); - vcpu_set_hv_cpuid(vcpu); + if (!prev_cpuid) { + vcpu_reset_hv_cpuid(vcpu); - best = kvm_get_supported_hv_cpuid(); + prev_cpuid = allocate_kvm_cpuid2(vcpu->cpuid->nent); + } else { + vcpu_init_cpuid(vcpu, prev_cpuid); + } + + feat = vcpu_get_cpuid_entry(vcpu, HYPERV_CPUID_FEATURES); + recomm = vcpu_get_cpuid_entry(vcpu, HYPERV_CPUID_ENLIGHTMENT_INFO); + dbg = vcpu_get_cpuid_entry(vcpu, HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES); run = vcpu->run; switch (stage) { case 0: + feat->eax |= HV_MSR_HYPERCALL_AVAILABLE; hcall->control = 0xdeadbeef; hcall->expect = HV_STATUS_INVALID_HYPERCALL_CODE; break; @@ -516,7 +516,7 @@ static void guest_test_hcalls_access(void) hcall->expect = HV_STATUS_ACCESS_DENIED; break; case 2: - feat.ebx |= HV_POST_MESSAGES; + feat->ebx |= HV_POST_MESSAGES; hcall->control = HVCALL_POST_MESSAGE; hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT; break; @@ -526,7 +526,7 @@ static void guest_test_hcalls_access(void) hcall->expect = HV_STATUS_ACCESS_DENIED; break; case 4: - feat.ebx |= HV_SIGNAL_EVENTS; + feat->ebx |= HV_SIGNAL_EVENTS; hcall->control = HVCALL_SIGNAL_EVENT; hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT; break; @@ -536,12 +536,12 @@ static void guest_test_hcalls_access(void) hcall->expect = HV_STATUS_INVALID_HYPERCALL_CODE; break; case 6: - dbg.eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; + dbg->eax |= HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; hcall->control = HVCALL_RESET_DEBUG_SESSION; hcall->expect = HV_STATUS_ACCESS_DENIED; break; case 7: - feat.ebx |= HV_DEBUGGING; + feat->ebx |= HV_DEBUGGING; hcall->control = HVCALL_RESET_DEBUG_SESSION; hcall->expect = HV_STATUS_OPERATION_DENIED; break; @@ -551,7 +551,7 @@ static void guest_test_hcalls_access(void) hcall->expect = HV_STATUS_ACCESS_DENIED; break; case 9: - recomm.eax |= HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED; + recomm->eax |= HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED; hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE; hcall->expect = HV_STATUS_SUCCESS; break; @@ -560,7 +560,7 @@ static void guest_test_hcalls_access(void) hcall->expect = HV_STATUS_ACCESS_DENIED; break; case 11: - recomm.eax |= HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED; + recomm->eax |= HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED; hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX; hcall->expect = HV_STATUS_SUCCESS; break; @@ -570,7 +570,7 @@ static void guest_test_hcalls_access(void) hcall->expect = HV_STATUS_ACCESS_DENIED; break; case 13: - recomm.eax |= HV_X64_CLUSTER_IPI_RECOMMENDED; + recomm->eax |= HV_X64_CLUSTER_IPI_RECOMMENDED; hcall->control = HVCALL_SEND_IPI; hcall->expect = HV_STATUS_INVALID_HYPERCALL_INPUT; break; @@ -585,7 +585,7 @@ static void guest_test_hcalls_access(void) hcall->expect = HV_STATUS_ACCESS_DENIED; break; case 16: - recomm.ebx = 0xfff; + recomm->ebx = 0xfff; hcall->control = HVCALL_NOTIFY_LONG_SPIN_WAIT; hcall->expect = HV_STATUS_SUCCESS; break; @@ -595,7 +595,7 @@ static void guest_test_hcalls_access(void) hcall->ud_expected = true; break; case 18: - feat.edx |= HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE; + feat->edx |= HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE; hcall->control = HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE | HV_HYPERCALL_FAST_BIT; hcall->ud_expected = false; hcall->expect = HV_STATUS_SUCCESS; @@ -605,7 +605,9 @@ static void guest_test_hcalls_access(void) return; } - hv_set_cpuid(vcpu, best, &feat, &recomm, &dbg); + vcpu_set_cpuid(vcpu); + + memcpy(prev_cpuid, vcpu->cpuid, kvm_cpuid2_size(vcpu->cpuid->nent)); pr_debug("Stage %d: testing hcall: 0x%lx\n", stage, hcall->control); From 49f6876a2e1e7e8a4dc3f2b27f720502d62e4804 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:52 +0000 Subject: [PATCH 0994/1436] KVM: selftests: Use vcpu_get_cpuid_entry() in CPUID test Use vcpu_get_cpuid_entry() instead of an open coded equivalent in the CPUID test. No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-28-seanjc@google.com --- tools/testing/selftests/kvm/x86_64/cpuid_test.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index a9345cee9bbc..7bbc1837b389 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -146,7 +146,6 @@ struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm, vm_vaddr_t *p_gva, struct static void set_cpuid_after_run(struct kvm_vcpu *vcpu) { - struct kvm_cpuid2 *cpuid = vcpu->cpuid; struct kvm_cpuid_entry2 *ent; int rc; u32 eax, ebx, x; @@ -156,7 +155,7 @@ static void set_cpuid_after_run(struct kvm_vcpu *vcpu) TEST_ASSERT(!rc, "Setting unmodified CPUID after KVM_RUN failed: %d", rc); /* Changing CPU features is forbidden */ - ent = get_cpuid_entry(cpuid, 0x7, 0); + ent = vcpu_get_cpuid_entry(vcpu, 0x7); ebx = ent->ebx; ent->ebx--; rc = __vcpu_set_cpuid(vcpu); @@ -164,7 +163,7 @@ static void set_cpuid_after_run(struct kvm_vcpu *vcpu) ent->ebx = ebx; /* Changing MAXPHYADDR is forbidden */ - ent = get_cpuid_entry(cpuid, 0x80000008, 0); + ent = vcpu_get_cpuid_entry(vcpu, 0x80000008); eax = ent->eax; x = eax & 0xff; ent->eax = (eax & ~0xffu) | (x - 1); From 4ee315231e3d7f85ab672fe231421614cad8f68d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:53 +0000 Subject: [PATCH 0995/1436] KVM: selftests: Use vcpu_{set,clear}_cpuid_feature() in nVMX state test Use vcpu_{set,clear}_cpuid_feature() to toggle nested VMX support in the vCPU CPUID module in the nVMX state test. Drop CPUID_VMX as there are no longer any users. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-29-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 1 - .../kvm/x86_64/vmx_set_nested_state_test.c | 20 ++----------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 50d68114ab86..7c0396788f76 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -160,7 +160,6 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_KVM_MIGRATION_CONTROL KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 17) /* CPUID.1.ECX */ -#define CPUID_VMX (1ul << 5) #define CPUID_XSAVE (1ul << 26) #define CPUID_OSXSAVE (1ul << 27) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c index 1cf78ec007f2..41ea7028a1f8 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c @@ -121,7 +121,7 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu) test_nested_state(vcpu, state); /* Enable VMX in the guest CPUID. */ - vcpu_set_cpuid(vcpu); + vcpu_set_cpuid_feature(vcpu, X86_FEATURE_VMX); /* * Setting vmxon_pa == -1ull and vmcs_pa == -1ull exits early without @@ -243,22 +243,6 @@ void test_vmx_nested_state(struct kvm_vcpu *vcpu) free(state); } -void disable_vmx(struct kvm_vcpu *vcpu) -{ - struct kvm_cpuid2 *cpuid = vcpu->cpuid; - int i; - - for (i = 0; i < cpuid->nent; ++i) - if (cpuid->entries[i].function == 1 && - cpuid->entries[i].index == 0) - break; - TEST_ASSERT(i != cpuid->nent, "CPUID function 1 not found"); - - cpuid->entries[i].ecx &= ~CPUID_VMX; - vcpu_set_cpuid(vcpu); - cpuid->entries[i].ecx |= CPUID_VMX; -} - int main(int argc, char *argv[]) { struct kvm_vm *vm; @@ -280,7 +264,7 @@ int main(int argc, char *argv[]) /* * First run tests with VMX disabled to check error handling. */ - disable_vmx(vcpu); + vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_VMX); /* Passing a NULL kvm_nested_state causes a EFAULT. */ test_nested_state_expect_efault(vcpu, NULL); From 7ed5a54e8282edfb464ccce4d3cf3a6f1d79b14a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:54 +0000 Subject: [PATCH 0996/1436] KVM: selftests: Use vcpu_clear_cpuid_feature() to clear x2APIC Add X86_FEATURE_X2APIC and use vcpu_clear_cpuid_feature() to clear x2APIC support in the xAPIC state test. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-30-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/processor.h | 1 + tools/testing/selftests/kvm/x86_64/xapic_state_test.c | 10 +--------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 7c0396788f76..db90a80dd09a 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -83,6 +83,7 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_SMX KVM_X86_CPU_FEATURE(0x1, 0, ECX, 6) #define X86_FEATURE_PDCM KVM_X86_CPU_FEATURE(0x1, 0, ECX, 15) #define X86_FEATURE_PCID KVM_X86_CPU_FEATURE(0x1, 0, ECX, 17) +#define X86_FEATURE_X2APIC KVM_X86_CPU_FEATURE(0x1, 0, ECX, 21) #define X86_FEATURE_MOVBE KVM_X86_CPU_FEATURE(0x1, 0, ECX, 22) #define X86_FEATURE_TSC_DEADLINE_TIMER KVM_X86_CPU_FEATURE(0x1, 0, ECX, 24) #define X86_FEATURE_XSAVE KVM_X86_CPU_FEATURE(0x1, 0, ECX, 26) diff --git a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c index 52133bb4d85a..6f7a5ef66718 100644 --- a/tools/testing/selftests/kvm/x86_64/xapic_state_test.c +++ b/tools/testing/selftests/kvm/x86_64/xapic_state_test.c @@ -136,9 +136,7 @@ int main(int argc, char *argv[]) .vcpu = NULL, .is_x2apic = true, }; - struct kvm_cpuid2 *cpuid; struct kvm_vm *vm; - int i; vm = vm_create_with_one_vcpu(&x.vcpu, x2apic_guest_code); test_icr(&x); @@ -152,13 +150,7 @@ int main(int argc, char *argv[]) vm = vm_create_with_one_vcpu(&x.vcpu, xapic_guest_code); x.is_x2apic = false; - cpuid = x.vcpu->cpuid; - for (i = 0; i < cpuid->nent; i++) { - if (cpuid->entries[i].function == 1) - break; - } - cpuid->entries[i].ecx &= ~BIT(21); - vcpu_set_cpuid(x.vcpu); + vcpu_clear_cpuid_feature(x.vcpu, X86_FEATURE_X2APIC); virt_pg_map(vm, APIC_DEFAULT_GPA, APIC_DEFAULT_GPA); test_icr(&x); From 813e38cd6d7b4247314427a901015867e0534356 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:55 +0000 Subject: [PATCH 0997/1436] KVM: selftests: Make get_supported_cpuid() returns "const" Tag the returned CPUID pointers from kvm_get_supported_cpuid(), kvm_get_supported_hv_cpuid(), and vcpu_get_supported_hv_cpuid() "const" to prevent reintroducing the broken pattern of modifying the static "cpuid" variable used by kvm_get_supported_cpuid() to cache the results of KVM_GET_SUPPORTED_CPUID. Update downstream consumers as needed. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-31-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 24 ++++++++--------- .../selftests/kvm/lib/x86_64/processor.c | 27 ++++++------------- .../testing/selftests/kvm/x86_64/cpuid_test.c | 12 ++++----- .../selftests/kvm/x86_64/hyperv_cpuid.c | 10 +++---- .../kvm/x86_64/pmu_event_filter_test.c | 10 +++---- .../selftests/kvm/x86_64/vmx_pmu_caps_test.c | 2 +- 6 files changed, 36 insertions(+), 49 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index db90a80dd09a..d1c0cff24779 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -585,7 +585,9 @@ static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs) vcpu_ioctl(vcpu, KVM_SET_XCRS, xcrs); } -struct kvm_cpuid2 *kvm_get_supported_cpuid(void); +const struct kvm_cpuid2 *kvm_get_supported_cpuid(void); +const struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void); +const struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu); bool kvm_cpuid_has(const struct kvm_cpuid2 *cpuid, struct kvm_x86_cpu_feature feature); @@ -618,15 +620,17 @@ static inline struct kvm_cpuid2 *allocate_kvm_cpuid2(int nr_entries) return cpuid; } -struct kvm_cpuid_entry2 *get_cpuid_entry(struct kvm_cpuid2 *cpuid, - uint32_t function, uint32_t index); -void vcpu_init_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid); +const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid, + uint32_t function, uint32_t index); +void vcpu_init_cpuid(struct kvm_vcpu *vcpu, const struct kvm_cpuid2 *cpuid); +void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu); static inline struct kvm_cpuid_entry2 *__vcpu_get_cpuid_entry(struct kvm_vcpu *vcpu, uint32_t function, uint32_t index) { - return get_cpuid_entry(vcpu->cpuid, function, index); + return (struct kvm_cpuid_entry2 *)get_cpuid_entry(vcpu->cpuid, + function, index); } static inline struct kvm_cpuid_entry2 *vcpu_get_cpuid_entry(struct kvm_vcpu *vcpu, @@ -678,14 +682,13 @@ static inline void vcpu_clear_cpuid_feature(struct kvm_vcpu *vcpu, vcpu_set_or_clear_cpuid_feature(vcpu, feature, false); } -static inline struct kvm_cpuid_entry2 *kvm_get_supported_cpuid_index(uint32_t function, - uint32_t index) +static inline const struct kvm_cpuid_entry2 *kvm_get_supported_cpuid_index(uint32_t function, + uint32_t index) { return get_cpuid_entry(kvm_get_supported_cpuid(), function, index); } -static inline struct kvm_cpuid_entry2 * -kvm_get_supported_cpuid_entry(uint32_t function) +static inline const struct kvm_cpuid_entry2 *kvm_get_supported_cpuid_entry(uint32_t function) { return kvm_get_supported_cpuid_index(function, 0); } @@ -804,9 +807,6 @@ void vm_set_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3); -struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void); -void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu); -struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu); void vm_xsave_req_perm(int bit); enum pg_level { diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 7cc0814f0b67..8677c6063388 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -676,18 +676,7 @@ void vcpu_arch_free(struct kvm_vcpu *vcpu) free(vcpu->cpuid); } -/* - * KVM Supported CPUID Get - * - * Input Args: None - * - * Output Args: - * - * Return: The supported KVM CPUID - * - * Get the guest CPUID supported by KVM. - */ -struct kvm_cpuid2 *kvm_get_supported_cpuid(void) +const struct kvm_cpuid2 *kvm_get_supported_cpuid(void) { static struct kvm_cpuid2 *cpuid; int kvm_fd; @@ -745,7 +734,7 @@ uint64_t kvm_get_feature_msr(uint64_t msr_index) return buffer.entry.data; } -void vcpu_init_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid) +void vcpu_init_cpuid(struct kvm_vcpu *vcpu, const struct kvm_cpuid2 *cpuid) { TEST_ASSERT(cpuid != vcpu->cpuid, "@cpuid can't be the vCPU's CPUID"); @@ -1079,7 +1068,7 @@ uint32_t kvm_get_cpuid_max_extended(void) void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits) { - struct kvm_cpuid_entry2 *entry; + const struct kvm_cpuid_entry2 *entry; bool pae; /* SDM 4.1.4 */ @@ -1208,8 +1197,8 @@ void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) } } -struct kvm_cpuid_entry2 *get_cpuid_entry(struct kvm_cpuid2 *cpuid, - uint32_t function, uint32_t index) +const struct kvm_cpuid_entry2 *get_cpuid_entry(const struct kvm_cpuid2 *cpuid, + uint32_t function, uint32_t index) { int i; @@ -1235,7 +1224,7 @@ uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, return r; } -struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void) +const struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void) { static struct kvm_cpuid2 *cpuid; int kvm_fd; @@ -1255,7 +1244,7 @@ struct kvm_cpuid2 *kvm_get_supported_hv_cpuid(void) void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu) { static struct kvm_cpuid2 *cpuid_full; - struct kvm_cpuid2 *cpuid_sys, *cpuid_hv; + const struct kvm_cpuid2 *cpuid_sys, *cpuid_hv; int i, nent = 0; if (!cpuid_full) { @@ -1285,7 +1274,7 @@ void vcpu_set_hv_cpuid(struct kvm_vcpu *vcpu) vcpu_init_cpuid(vcpu, cpuid_full); } -struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu) +const struct kvm_cpuid2 *vcpu_get_supported_hv_cpuid(struct kvm_vcpu *vcpu) { struct kvm_cpuid2 *cpuid = allocate_kvm_cpuid2(MAX_NR_CPUID_ENTRIES); diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index 7bbc1837b389..d8ae4a0e00a4 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -66,7 +66,7 @@ static void guest_main(struct kvm_cpuid2 *guest_cpuid) GUEST_DONE(); } -static bool is_cpuid_mangled(struct kvm_cpuid_entry2 *entrie) +static bool is_cpuid_mangled(const struct kvm_cpuid_entry2 *entrie) { int i; @@ -79,9 +79,10 @@ static bool is_cpuid_mangled(struct kvm_cpuid_entry2 *entrie) return false; } -static void compare_cpuids(struct kvm_cpuid2 *cpuid1, struct kvm_cpuid2 *cpuid2) +static void compare_cpuids(const struct kvm_cpuid2 *cpuid1, + const struct kvm_cpuid2 *cpuid2) { - struct kvm_cpuid_entry2 *e1, *e2; + const struct kvm_cpuid_entry2 *e1, *e2; int i; TEST_ASSERT(cpuid1->nent == cpuid2->nent, @@ -174,7 +175,6 @@ static void set_cpuid_after_run(struct kvm_vcpu *vcpu) int main(void) { - struct kvm_cpuid2 *supp_cpuid; struct kvm_vcpu *vcpu; vm_vaddr_t cpuid_gva; struct kvm_vm *vm; @@ -182,9 +182,7 @@ int main(void) vm = vm_create_with_one_vcpu(&vcpu, guest_main); - supp_cpuid = kvm_get_supported_cpuid(); - - compare_cpuids(supp_cpuid, vcpu->cpuid); + compare_cpuids(kvm_get_supported_cpuid(), vcpu->cpuid); vcpu_alloc_cpuid(vm, &cpuid_gva, vcpu->cpuid); diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c index c406b95cba9b..e804eb08dff9 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_cpuid.c @@ -43,7 +43,7 @@ static bool smt_possible(void) return res; } -static void test_hv_cpuid(struct kvm_cpuid2 *hv_cpuid_entries, +static void test_hv_cpuid(const struct kvm_cpuid2 *hv_cpuid_entries, bool evmcs_expected) { int i; @@ -56,7 +56,7 @@ static void test_hv_cpuid(struct kvm_cpuid2 *hv_cpuid_entries, nent_expected, hv_cpuid_entries->nent); for (i = 0; i < hv_cpuid_entries->nent; i++) { - struct kvm_cpuid_entry2 *entry = &hv_cpuid_entries->entries[i]; + const struct kvm_cpuid_entry2 *entry = &hv_cpuid_entries->entries[i]; TEST_ASSERT((entry->function >= 0x40000000) && (entry->function <= 0x40000082), @@ -131,7 +131,7 @@ void test_hv_cpuid_e2big(struct kvm_vm *vm, struct kvm_vcpu *vcpu) int main(int argc, char *argv[]) { struct kvm_vm *vm; - struct kvm_cpuid2 *hv_cpuid_entries; + const struct kvm_cpuid2 *hv_cpuid_entries; struct kvm_vcpu *vcpu; /* Tell stdout not to buffer its content */ @@ -146,7 +146,7 @@ int main(int argc, char *argv[]) hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vcpu); test_hv_cpuid(hv_cpuid_entries, false); - free(hv_cpuid_entries); + free((void *)hv_cpuid_entries); if (!kvm_cpu_has(X86_FEATURE_VMX) || !kvm_has_cap(KVM_CAP_HYPERV_ENLIGHTENED_VMCS)) { @@ -156,7 +156,7 @@ int main(int argc, char *argv[]) vcpu_enable_evmcs(vcpu); hv_cpuid_entries = vcpu_get_supported_hv_cpuid(vcpu); test_hv_cpuid(hv_cpuid_entries, true); - free(hv_cpuid_entries); + free((void *)hv_cpuid_entries); do_sys: /* Test system ioctl version */ diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index 530a75fee92c..b4c4631891d5 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -384,7 +384,7 @@ static void test_pmu_config_disable(void (*guest_code)(void)) * counter per logical processor, an EBX bit vector of length greater * than 5, and EBX[5] clear. */ -static bool check_intel_pmu_leaf(struct kvm_cpuid_entry2 *entry) +static bool check_intel_pmu_leaf(const struct kvm_cpuid_entry2 *entry) { union cpuid10_eax eax = { .full = entry->eax }; union cpuid10_ebx ebx = { .full = entry->ebx }; @@ -400,10 +400,10 @@ static bool check_intel_pmu_leaf(struct kvm_cpuid_entry2 *entry) */ static bool use_intel_pmu(void) { - struct kvm_cpuid_entry2 *entry; + const struct kvm_cpuid_entry2 *entry; entry = kvm_get_supported_cpuid_index(0xa, 0); - return is_intel_cpu() && entry && check_intel_pmu_leaf(entry); + return is_intel_cpu() && check_intel_pmu_leaf(entry); } static bool is_zen1(uint32_t eax) @@ -432,10 +432,10 @@ static bool is_zen3(uint32_t eax) */ static bool use_amd_pmu(void) { - struct kvm_cpuid_entry2 *entry; + const struct kvm_cpuid_entry2 *entry; entry = kvm_get_supported_cpuid_index(1, 0); - return is_amd_cpu() && entry && + return is_amd_cpu() && (is_zen1(entry->eax) || is_zen2(entry->eax) || is_zen3(entry->eax)); diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c index dc3869d5aff0..689517f2aae6 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c @@ -53,7 +53,7 @@ static void guest_code(void) int main(int argc, char *argv[]) { - struct kvm_cpuid_entry2 *entry_a_0; + const struct kvm_cpuid_entry2 *entry_a_0; struct kvm_vm *vm; struct kvm_vcpu *vcpu; int ret; From 8fe09d6a91be94be6910d843bb21d60b1fc99cd2 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:56 +0000 Subject: [PATCH 0998/1436] KVM: selftests: Set input function/index in raw CPUID helper(s) Set the function/index for CPUID in the helper instead of relying on the caller to do so. In addition to reducing the risk of consuming an uninitialized ECX, having the function/index embedded in the call makes it easier to understand what is being checked. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-32-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 16 +++++++++++++--- .../selftests/kvm/lib/x86_64/processor.c | 13 ++++--------- tools/testing/selftests/kvm/x86_64/amx_test.c | 19 ++++--------------- .../testing/selftests/kvm/x86_64/cpuid_test.c | 11 +++++------ 4 files changed, 26 insertions(+), 33 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index d1c0cff24779..47e74beda155 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -404,10 +404,13 @@ static inline void outl(uint16_t port, uint32_t value) __asm__ __volatile__("outl %%eax, %%dx" : : "d"(port), "a"(value)); } -static inline void cpuid(uint32_t *eax, uint32_t *ebx, - uint32_t *ecx, uint32_t *edx) +static inline void __cpuid(uint32_t function, uint32_t index, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) { - /* ecx is often an input as well as an output. */ + *eax = function; + *ecx = index; + asm volatile("cpuid" : "=a" (*eax), "=b" (*ebx), @@ -417,6 +420,13 @@ static inline void cpuid(uint32_t *eax, uint32_t *ebx, : "memory"); } +static inline void cpuid(uint32_t function, + uint32_t *eax, uint32_t *ebx, + uint32_t *ecx, uint32_t *edx) +{ + return __cpuid(function, 0, eax, ebx, ecx, edx); +} + #define SET_XMM(__var, __xmm) \ asm volatile("movq %0, %%"#__xmm : : "r"(__var) : #__xmm) diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 8677c6063388..5f62b58433d3 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1301,9 +1301,7 @@ unsigned long vm_compute_max_gfn(struct kvm_vm *vm) /* Before family 17h, the HyperTransport area is just below 1T. */ ht_gfn = (1 << 28) - num_ht_pages; - eax = 1; - ecx = 0; - cpuid(&eax, &ebx, &ecx, &edx); + cpuid(1, &eax, &ebx, &ecx, &edx); if (x86_family(eax) < 0x17) goto done; @@ -1312,18 +1310,15 @@ unsigned long vm_compute_max_gfn(struct kvm_vm *vm) * reduced due to SME by bits 11:6 of CPUID[0x8000001f].EBX. Use * the old conservative value if MAXPHYADDR is not enumerated. */ - eax = 0x80000000; - cpuid(&eax, &ebx, &ecx, &edx); + cpuid(0x80000000, &eax, &ebx, &ecx, &edx); max_ext_leaf = eax; if (max_ext_leaf < 0x80000008) goto done; - eax = 0x80000008; - cpuid(&eax, &ebx, &ecx, &edx); + cpuid(0x80000008, &eax, &ebx, &ecx, &edx); max_pfn = (1ULL << ((eax & 0xff) - vm->page_shift)) - 1; if (max_ext_leaf >= 0x8000001f) { - eax = 0x8000001f; - cpuid(&eax, &ebx, &ecx, &edx); + cpuid(0x8000001f, &eax, &ebx, &ecx, &edx); max_pfn >>= (ebx >> 6) & 0x3f; } diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index c8f98331a807..cb5e20936cc1 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -122,9 +122,7 @@ static inline void check_cpuid_xsave(void) { uint32_t eax, ebx, ecx, edx; - eax = 1; - ecx = 0; - cpuid(&eax, &ebx, &ecx, &edx); + cpuid(1, &eax, &ebx, &ecx, &edx); if (!(ecx & CPUID_XSAVE)) GUEST_ASSERT(!"cpuid: no CPU xsave support!"); if (!(ecx & CPUID_OSXSAVE)) @@ -140,10 +138,7 @@ static bool enum_xtile_config(void) { u32 eax, ebx, ecx, edx; - eax = TILE_CPUID; - ecx = TILE_PALETTE_CPUID_SUBLEAVE; - - cpuid(&eax, &ebx, &ecx, &edx); + __cpuid(TILE_CPUID, TILE_PALETTE_CPUID_SUBLEAVE, &eax, &ebx, &ecx, &edx); if (!eax || !ebx || !ecx) return false; @@ -165,10 +160,7 @@ static bool enum_xsave_tile(void) { u32 eax, ebx, ecx, edx; - eax = XSTATE_CPUID; - ecx = XFEATURE_XTILEDATA; - - cpuid(&eax, &ebx, &ecx, &edx); + __cpuid(XSTATE_CPUID, XFEATURE_XTILEDATA, &eax, &ebx, &ecx, &edx); if (!eax || !ebx) return false; @@ -183,10 +175,7 @@ static bool check_xsave_size(void) u32 eax, ebx, ecx, edx; bool valid = false; - eax = XSTATE_CPUID; - ecx = XSTATE_USER_STATE_SUBLEAVE; - - cpuid(&eax, &ebx, &ecx, &edx); + __cpuid(XSTATE_CPUID, XSTATE_USER_STATE_SUBLEAVE, &eax, &ebx, &ecx, &edx); if (ebx && ebx <= XSAVE_SIZE) valid = true; diff --git a/tools/testing/selftests/kvm/x86_64/cpuid_test.c b/tools/testing/selftests/kvm/x86_64/cpuid_test.c index d8ae4a0e00a4..a6aeee2e62e4 100644 --- a/tools/testing/selftests/kvm/x86_64/cpuid_test.c +++ b/tools/testing/selftests/kvm/x86_64/cpuid_test.c @@ -31,10 +31,9 @@ static void test_guest_cpuids(struct kvm_cpuid2 *guest_cpuid) u32 eax, ebx, ecx, edx; for (i = 0; i < guest_cpuid->nent; i++) { - eax = guest_cpuid->entries[i].function; - ecx = guest_cpuid->entries[i].index; - - cpuid(&eax, &ebx, &ecx, &edx); + __cpuid(guest_cpuid->entries[i].function, + guest_cpuid->entries[i].index, + &eax, &ebx, &ecx, &edx); GUEST_ASSERT(eax == guest_cpuid->entries[i].eax && ebx == guest_cpuid->entries[i].ebx && @@ -46,9 +45,9 @@ static void test_guest_cpuids(struct kvm_cpuid2 *guest_cpuid) static void test_cpuid_40000000(struct kvm_cpuid2 *guest_cpuid) { - u32 eax = 0x40000000, ebx, ecx = 0, edx; + u32 eax, ebx, ecx, edx; - cpuid(&eax, &ebx, &ecx, &edx); + cpuid(0x40000000, &eax, &ebx, &ecx, &edx); GUEST_ASSERT(eax == 0x40000001); } From 48ce3ed052e8336a17c64ca1787648d9e17c54d9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:57 +0000 Subject: [PATCH 0999/1436] KVM: selftests: Add this_cpu_has() to query X86_FEATURE_* via cpuid() Add this_cpu_has() to query an X86_FEATURE_* via cpuid(), i.e. to query a feature from L1 (or L2) guest code. Arbitrarily select the AMX test to be the first user. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-33-seanjc@google.com --- .../testing/selftests/kvm/include/x86_64/processor.h | 12 +++++++++++- tools/testing/selftests/kvm/x86_64/amx_test.c | 9 ++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 47e74beda155..b065d6cadba1 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -161,7 +161,6 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_KVM_MIGRATION_CONTROL KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 17) /* CPUID.1.ECX */ -#define CPUID_XSAVE (1ul << 26) #define CPUID_OSXSAVE (1ul << 27) /* Page table bitfield declarations */ @@ -427,6 +426,17 @@ static inline void cpuid(uint32_t function, return __cpuid(function, 0, eax, ebx, ecx, edx); } +static inline bool this_cpu_has(struct kvm_x86_cpu_feature feature) +{ + uint32_t gprs[4]; + + __cpuid(feature.function, feature.index, + &gprs[KVM_CPUID_EAX], &gprs[KVM_CPUID_EBX], + &gprs[KVM_CPUID_ECX], &gprs[KVM_CPUID_EDX]); + + return gprs[feature.reg] & BIT(feature.bit); +} + #define SET_XMM(__var, __xmm) \ asm volatile("movq %0, %%"#__xmm : : "r"(__var) : #__xmm) diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index cb5e20936cc1..c867f10532af 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -120,13 +120,8 @@ static inline void __xsavec(struct xsave_data *data, uint64_t rfbm) static inline void check_cpuid_xsave(void) { - uint32_t eax, ebx, ecx, edx; - - cpuid(1, &eax, &ebx, &ecx, &edx); - if (!(ecx & CPUID_XSAVE)) - GUEST_ASSERT(!"cpuid: no CPU xsave support!"); - if (!(ecx & CPUID_OSXSAVE)) - GUEST_ASSERT(!"cpuid: no OS xsave support!"); + GUEST_ASSERT(this_cpu_has(X86_FEATURE_XSAVE)); + GUEST_ASSERT(this_cpu_has(X86_FEATURE_OSXSAVE)); } static bool check_xsave_supports_xtile(void) From 2b424a76d02cf6f8d94eeb253b1c0e4327b1718a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:58 +0000 Subject: [PATCH 1000/1436] KVM: selftests: Use this_cpu_has() in CR4/CPUID sync test Use this_cpu_has() to query OSXSAVE from the L1 guest in the CR4=>CPUID sync test. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-34-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 3 --- .../selftests/kvm/x86_64/cr4_cpuid_sync_test.c | 14 ++------------ 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index b065d6cadba1..8ce421471c4c 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -160,9 +160,6 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_KVM_HC_MAP_GPA_RANGE KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 16) #define X86_FEATURE_KVM_MIGRATION_CONTROL KVM_X86_CPU_FEATURE(0x40000001, 0, EAX, 17) -/* CPUID.1.ECX */ -#define CPUID_OSXSAVE (1ul << 27) - /* Page table bitfield declarations */ #define PTE_PRESENT_MASK BIT_ULL(0) #define PTE_WRITABLE_MASK BIT_ULL(1) diff --git a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c index 611febdc2128..4208487652f8 100644 --- a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c +++ b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c @@ -21,19 +21,9 @@ static inline bool cr4_cpuid_is_sync(void) { - int func, subfunc; - uint32_t eax, ebx, ecx, edx; - uint64_t cr4; + uint64_t cr4 = get_cr4(); - func = 0x1; - subfunc = 0x0; - __asm__ __volatile__("cpuid" - : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) - : "a"(func), "c"(subfunc)); - - cr4 = get_cr4(); - - return (!!(ecx & CPUID_OSXSAVE)) == (!!(cr4 & X86_CR4_OSXSAVE)); + return (this_cpu_has(X86_FEATURE_OSXSAVE) == !!(cr4 & X86_CR4_OSXSAVE)); } static void guest_code(void) From 05c2b6e5facc4f04e4df0cfedbcc8943318ed983 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:06:59 +0000 Subject: [PATCH 1001/1436] KVM: selftests: Use this_cpu_has() to detect SVM support in L1 Replace an evil open coded instance of querying CPUID from L1 with this_cpu_has(X86_FEATURE_SVM). No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-35-seanjc@google.com --- .../testing/selftests/kvm/include/x86_64/svm_util.h | 13 ------------- tools/testing/selftests/kvm/x86_64/smm_test.c | 4 ++-- tools/testing/selftests/kvm/x86_64/state_test.c | 2 +- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/svm_util.h b/tools/testing/selftests/kvm/include/x86_64/svm_util.h index f48806d26989..a339b537a575 100644 --- a/tools/testing/selftests/kvm/include/x86_64/svm_util.h +++ b/tools/testing/selftests/kvm/include/x86_64/svm_util.h @@ -13,9 +13,6 @@ #include "svm.h" #include "processor.h" -#define CPUID_SVM_BIT 2 -#define CPUID_SVM BIT_ULL(CPUID_SVM_BIT) - #define SVM_EXIT_EXCP_BASE 0x040 #define SVM_EXIT_HLT 0x078 #define SVM_EXIT_MSR 0x07c @@ -52,16 +49,6 @@ struct svm_test_data *vcpu_alloc_svm(struct kvm_vm *vm, vm_vaddr_t *p_svm_gva); void generic_svm_setup(struct svm_test_data *svm, void *guest_rip, void *guest_rsp); void run_guest(struct vmcb *vmcb, uint64_t vmcb_gpa); -static inline bool cpu_has_svm(void) -{ - u32 eax = 0x80000001, ecx; - - asm("cpuid" : - "=a" (eax), "=c" (ecx) : "0" (eax) : "ebx", "edx"); - - return ecx & CPUID_SVM; -} - int open_sev_dev_path_or_exit(void); #endif /* SELFTEST_KVM_SVM_UTILS_H */ diff --git a/tools/testing/selftests/kvm/x86_64/smm_test.c b/tools/testing/selftests/kvm/x86_64/smm_test.c index 17bb2397ea38..1f136a81858e 100644 --- a/tools/testing/selftests/kvm/x86_64/smm_test.c +++ b/tools/testing/selftests/kvm/x86_64/smm_test.c @@ -83,7 +83,7 @@ static void guest_code(void *arg) sync_with_host(4); if (arg) { - if (cpu_has_svm()) { + if (this_cpu_has(X86_FEATURE_SVM)) { generic_svm_setup(svm, l2_guest_code, &l2_guest_stack[L2_GUEST_STACK_SIZE]); } else { @@ -99,7 +99,7 @@ static void guest_code(void *arg) sync_with_host(7); - if (cpu_has_svm()) { + if (this_cpu_has(X86_FEATURE_SVM)) { run_guest(svm->vmcb, svm->vmcb_gpa); run_guest(svm->vmcb, svm->vmcb_gpa); } else { diff --git a/tools/testing/selftests/kvm/x86_64/state_test.c b/tools/testing/selftests/kvm/x86_64/state_test.c index 8ab81a3b561f..ea578971fb9f 100644 --- a/tools/testing/selftests/kvm/x86_64/state_test.c +++ b/tools/testing/selftests/kvm/x86_64/state_test.c @@ -142,7 +142,7 @@ static void __attribute__((__flatten__)) guest_code(void *arg) GUEST_SYNC(2); if (arg) { - if (cpu_has_svm()) + if (this_cpu_has(X86_FEATURE_SVM)) svm_l1_guest_code(arg); else vmx_l1_guest_code(arg); From 446ab76a0f7addb196c154636eb04c478ccecdcf Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:07:00 +0000 Subject: [PATCH 1002/1436] KVM: selftests: Drop unnecessary use of kvm_get_supported_cpuid_index() Use kvm_get_supported_cpuid_entry() instead of kvm_get_supported_cpuid_index() when passing in '0' for the index, which just so happens to be the case in all remaining users of kvm_get_supported_cpuid_index() except kvm_get_supported_cpuid_entry(). Keep the helper as there may be users in the future, and it's not doing any harm. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-36-seanjc@google.com --- tools/testing/selftests/kvm/x86_64/amx_test.c | 2 +- tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c | 4 ++-- tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index c867f10532af..08d5801cf858 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -318,7 +318,7 @@ int main(int argc, char *argv[]) TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XTILEDATA)); /* Get xsave/restore max size */ - xsave_restore_size = kvm_get_supported_cpuid_index(0xd, 0)->ecx; + xsave_restore_size = kvm_get_supported_cpuid_entry(0xd)->ecx; run = vcpu->run; vcpu_regs_get(vcpu, ®s1); diff --git a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c index b4c4631891d5..ea4e259a1e2e 100644 --- a/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c +++ b/tools/testing/selftests/kvm/x86_64/pmu_event_filter_test.c @@ -402,7 +402,7 @@ static bool use_intel_pmu(void) { const struct kvm_cpuid_entry2 *entry; - entry = kvm_get_supported_cpuid_index(0xa, 0); + entry = kvm_get_supported_cpuid_entry(0xa); return is_intel_cpu() && check_intel_pmu_leaf(entry); } @@ -434,7 +434,7 @@ static bool use_amd_pmu(void) { const struct kvm_cpuid_entry2 *entry; - entry = kvm_get_supported_cpuid_index(1, 0); + entry = kvm_get_supported_cpuid_entry(1); return is_amd_cpu() && (is_zen1(entry->eax) || is_zen2(entry->eax) || diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c index 689517f2aae6..6ec901dab61e 100644 --- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c +++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c @@ -69,7 +69,7 @@ int main(int argc, char *argv[]) TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_PDCM)); TEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xa); - entry_a_0 = kvm_get_supported_cpuid_index(0xa, 0); + entry_a_0 = kvm_get_supported_cpuid_entry(0xa); eax.full = entry_a_0->eax; __TEST_REQUIRE(eax.split.version_id, "PMU is not supported by the vCPU"); From 28e09d321035149b881ceb3253d0a6729b91d506 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:07:01 +0000 Subject: [PATCH 1003/1436] KVM: selftests: Rename kvm_get_supported_cpuid_index() to __..._entry() Rename kvm_get_supported_cpuid_index() to __kvm_get_supported_cpuid_entry() to better show its relationship to kvm_get_supported_cpuid_entry(), and because the helper returns a CPUID entry, not the index of an entry. No functional change intended. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-37-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/processor.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 8ce421471c4c..ba5cd86a8565 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -699,15 +699,15 @@ static inline void vcpu_clear_cpuid_feature(struct kvm_vcpu *vcpu, vcpu_set_or_clear_cpuid_feature(vcpu, feature, false); } -static inline const struct kvm_cpuid_entry2 *kvm_get_supported_cpuid_index(uint32_t function, - uint32_t index) +static inline const struct kvm_cpuid_entry2 *__kvm_get_supported_cpuid_entry(uint32_t function, + uint32_t index) { return get_cpuid_entry(kvm_get_supported_cpuid(), function, index); } static inline const struct kvm_cpuid_entry2 *kvm_get_supported_cpuid_entry(uint32_t function) { - return kvm_get_supported_cpuid_index(function, 0); + return __kvm_get_supported_cpuid_entry(function, 0); } uint64_t vcpu_get_msr(struct kvm_vcpu *vcpu, uint64_t msr_index); From d04019274d13301b413c28b85f1b1775a9d63062 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:07:02 +0000 Subject: [PATCH 1004/1436] KVM: selftests: Inline "get max CPUID leaf" helpers Make the "get max CPUID leaf" helpers static inline, there's no reason to bury the one liners in processor.c. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-38-seanjc@google.com --- .../testing/selftests/kvm/include/x86_64/processor.h | 11 +++++++++-- tools/testing/selftests/kvm/lib/x86_64/processor.c | 10 ---------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index ba5cd86a8565..ecf2ace952ab 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -721,9 +721,16 @@ static inline void vcpu_set_msr(struct kvm_vcpu *vcpu, uint64_t msr_index, TEST_ASSERT(r == 1, KVM_IOCTL_ERROR(KVM_SET_MSRS, r)); } +static inline uint32_t kvm_get_cpuid_max_basic(void) +{ + return kvm_get_supported_cpuid_entry(0)->eax; +} + +static inline uint32_t kvm_get_cpuid_max_extended(void) +{ + return kvm_get_supported_cpuid_entry(0x80000000)->eax; +} -uint32_t kvm_get_cpuid_max_basic(void); -uint32_t kvm_get_cpuid_max_extended(void); void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits); bool vm_is_unrestricted_guest(struct kvm_vm *vm); diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 5f62b58433d3..e2894b5bcfd1 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1056,16 +1056,6 @@ bool is_amd_cpu(void) return cpu_vendor_string_is("AuthenticAMD"); } -uint32_t kvm_get_cpuid_max_basic(void) -{ - return kvm_get_supported_cpuid_entry(0)->eax; -} - -uint32_t kvm_get_cpuid_max_extended(void) -{ - return kvm_get_supported_cpuid_entry(0x80000000)->eax; -} - void kvm_get_cpu_address_width(unsigned int *pa_bits, unsigned int *va_bits) { const struct kvm_cpuid_entry2 *entry; From 7fbb653e01fdd45b377674a9e77da473d49afd38 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:07:03 +0000 Subject: [PATCH 1005/1436] KVM: selftests: Check KVM's supported CPUID, not host CPUID, for XFD Use kvm_cpu_has() to check for XFD supported in vm_xsave_req_perm(), simply checking host CPUID doesn't guarantee KVM supports AMX/XFD. Opportunistically hoist the check above the bit check; if XFD isn't supported, it's far better to get a "not supported at all" message, as opposed to a "feature X isn't supported" message". Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-39-seanjc@google.com --- .../selftests/kvm/include/x86_64/processor.h | 1 + .../selftests/kvm/lib/x86_64/processor.c | 19 ++----------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index ecf2ace952ab..559840e47f01 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -117,6 +117,7 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_XTILECFG KVM_X86_CPU_FEATURE(0xD, 0, EAX, 17) #define X86_FEATURE_XTILEDATA KVM_X86_CPU_FEATURE(0xD, 0, EAX, 18) #define X86_FEATURE_XSAVES KVM_X86_CPU_FEATURE(0xD, 1, EAX, 3) +#define X86_FEATURE_XFD KVM_X86_CPU_FEATURE(0xD, 1, EAX, 4) /* * Extended Leafs, a.k.a. AMD defined diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index e2894b5bcfd1..6cb93bbd6130 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -578,21 +578,6 @@ static void vcpu_setup(struct kvm_vm *vm, struct kvm_vcpu *vcpu) vcpu_sregs_set(vcpu, &sregs); } -#define CPUID_XFD_BIT (1 << 4) -static bool is_xfd_supported(void) -{ - int eax, ebx, ecx, edx; - const int leaf = 0xd, subleaf = 0x1; - - __asm__ __volatile__( - "cpuid" - : /* output */ "=a"(eax), "=b"(ebx), - "=c"(ecx), "=d"(edx) - : /* input */ "0"(leaf), "2"(subleaf)); - - return !!(eax & CPUID_XFD_BIT); -} - void vm_xsave_req_perm(int bit) { int kvm_fd; @@ -604,6 +589,8 @@ void vm_xsave_req_perm(int bit) .addr = (unsigned long) &bitmask }; + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_XFD)); + kvm_fd = open_kvm_dev_path_or_exit(); rc = __kvm_ioctl(kvm_fd, KVM_GET_DEVICE_ATTR, &attr); close(kvm_fd); @@ -614,8 +601,6 @@ void vm_xsave_req_perm(int bit) TEST_REQUIRE(bitmask & (1ULL << bit)); - TEST_REQUIRE(is_xfd_supported()); - rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, bit); /* From d4c94ee8121cce64f2882f3bdcc346dc3d01bcdd Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:07:04 +0000 Subject: [PATCH 1006/1436] KVM: selftests: Skip AMX test if ARCH_REQ_XCOMP_GUEST_PERM isn't supported Skip the AMX test instead of silently returning if the host kernel doesn't support ARCH_REQ_XCOMP_GUEST_PERM. KVM didn't support XFD until v5.17, so it's extremely unlikely allowing the test to run on a pre-v5.15 kernel is the right thing to do. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-40-seanjc@google.com --- tools/testing/selftests/kvm/lib/x86_64/processor.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 6cb93bbd6130..912da2100f90 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -601,14 +601,7 @@ void vm_xsave_req_perm(int bit) TEST_REQUIRE(bitmask & (1ULL << bit)); - rc = syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, bit); - - /* - * The older kernel version(<5.15) can't support - * ARCH_REQ_XCOMP_GUEST_PERM and directly return. - */ - if (rc) - return; + TEST_REQUIRE(!syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, bit)); rc = syscall(SYS_arch_prctl, ARCH_GET_XCOMP_GUEST_PERM, &bitmask); TEST_ASSERT(rc == 0, "prctl(ARCH_GET_XCOMP_GUEST_PERM) error: %ld", rc); From 090cd45b21cd0d26297315d4bd9b83d9dcad10e1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:07:05 +0000 Subject: [PATCH 1007/1436] KVM: selftests: Clean up requirements for XFD-aware XSAVE features Provide informative error messages for the various checks related to requesting access to XSAVE features that are buried behind XSAVE Feature Disabling (XFD). Opportunistically rename the helper to have "require" in the name so that it's somewhat obvious that the helper may skip the test. Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-41-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/processor.h | 5 ++++- tools/testing/selftests/kvm/lib/x86_64/processor.c | 8 +++++--- tools/testing/selftests/kvm/x86_64/amx_test.c | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 559840e47f01..4060fe954d53 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -832,7 +832,10 @@ void vm_set_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3); -void vm_xsave_req_perm(int bit); +void __vm_xsave_require_permission(int bit, const char *name); + +#define vm_xsave_require_permission(perm) \ + __vm_xsave_require_permission(perm, #perm) enum pg_level { PG_LEVEL_NONE, diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 912da2100f90..92a047cd1cd5 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -578,7 +578,7 @@ static void vcpu_setup(struct kvm_vm *vm, struct kvm_vcpu *vcpu) vcpu_sregs_set(vcpu, &sregs); } -void vm_xsave_req_perm(int bit) +void __vm_xsave_require_permission(int bit, const char *name) { int kvm_fd; u64 bitmask; @@ -596,10 +596,12 @@ void vm_xsave_req_perm(int bit) close(kvm_fd); if (rc == -1 && (errno == ENXIO || errno == EINVAL)) - exit(KSFT_SKIP); + __TEST_REQUIRE(0, "KVM_X86_XCOMP_GUEST_SUPP not supported"); + TEST_ASSERT(rc == 0, "KVM_GET_DEVICE_ATTR(0, KVM_X86_XCOMP_GUEST_SUPP) error: %ld", rc); - TEST_REQUIRE(bitmask & (1ULL << bit)); + __TEST_REQUIRE(bitmask & (1ULL << bit), + "Required XSAVE feature '%s' not supported", name); TEST_REQUIRE(!syscall(SYS_arch_prctl, ARCH_REQ_XCOMP_GUEST_PERM, bit)); diff --git a/tools/testing/selftests/kvm/x86_64/amx_test.c b/tools/testing/selftests/kvm/x86_64/amx_test.c index 08d5801cf858..dadcbad10a1d 100644 --- a/tools/testing/selftests/kvm/x86_64/amx_test.c +++ b/tools/testing/selftests/kvm/x86_64/amx_test.c @@ -307,7 +307,7 @@ int main(int argc, char *argv[]) u32 amx_offset; int stage, ret; - vm_xsave_req_perm(XSTATE_XTILE_DATA_BIT); + vm_xsave_require_permission(XSTATE_XTILE_DATA_BIT); /* Create VM */ vm = vm_create_with_one_vcpu(&vcpu, guest_code); From 12a985aeb40691a27befb0ae99707d0322b4bd8e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:07:06 +0000 Subject: [PATCH 1008/1436] KVM: selftests: Use the common cpuid() helper in cpu_vendor_string_is() Use cpuid() to get CPUID.0x0 in cpu_vendor_string_is(), thus eliminating the last open coded usage of CPUID (ignoring debug_regs.c, which emits CPUID from the guest to trigger a VM-Exit and doesn't actually care about the results of CPUID). Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-42-seanjc@google.com --- tools/testing/selftests/kvm/lib/x86_64/processor.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index 92a047cd1cd5..f35626df1dea 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1011,15 +1011,9 @@ void kvm_x86_state_cleanup(struct kvm_x86_state *state) static bool cpu_vendor_string_is(const char *vendor) { const uint32_t *chunk = (const uint32_t *)vendor; - int eax, ebx, ecx, edx; - const int leaf = 0; - - __asm__ __volatile__( - "cpuid" - : /* output */ "=a"(eax), "=b"(ebx), - "=c"(ecx), "=d"(edx) - : /* input */ "0"(leaf), "2"(0)); + uint32_t eax, ebx, ecx, edx; + cpuid(0, &eax, &ebx, &ecx, &edx); return (ebx == chunk[0] && edx == chunk[1] && ecx == chunk[2]); } From 3d5f8d03786fee6aa7a4c59446c5356775aeb4d9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 14 Jun 2022 20:07:07 +0000 Subject: [PATCH 1009/1436] KVM: selftests: Drop unused SVM_CPUID_FUNC macro Drop SVM_CPUID_FUNC to reduce the probability of tests open coding CPUID checks instead of using kvm_cpu_has() or this_cpu_has(). Signed-off-by: Sean Christopherson Link: https://lore.kernel.org/r/20220614200707.3315957-43-seanjc@google.com --- tools/testing/selftests/kvm/include/x86_64/svm.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/svm.h b/tools/testing/selftests/kvm/include/x86_64/svm.h index 2225e5077350..c8343ff84f7f 100644 --- a/tools/testing/selftests/kvm/include/x86_64/svm.h +++ b/tools/testing/selftests/kvm/include/x86_64/svm.h @@ -218,8 +218,6 @@ struct __attribute__ ((__packed__)) vmcb { struct vmcb_save_area save; }; -#define SVM_CPUID_FUNC 0x8000000a - #define SVM_VM_CR_SVM_DISABLE 4 #define SVM_SELECTOR_S_SHIFT 4 From b184b35d06b2a3de65ff2ef4303f83535572266c Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 12 Jul 2022 01:58:38 +0000 Subject: [PATCH 1010/1436] KVM: VMX: Update PT MSR intercepts during filter change iff PT in host+guest Update the Processor Trace (PT) MSR intercepts during a filter change if and only if PT may be exposed to the guest, i.e. only if KVM is operating in the so called "host+guest" mode where PT can be used simultaneously by both the host and guest. If PT is in system mode, the host is the sole owner of PT and the MSRs should never be passed through to the guest. Luckily the missed check only results in unnecessary work, as select RTIT MSRs are passed through only when RTIT tracing is enabled "in" the guest, and tracing can't be enabled in the guest when KVM is in system mode (writes to guest.MSR_IA32_RTIT_CTL are disallowed). Cc: Xiaoyao Li Signed-off-by: Sean Christopherson Reviewed-by: Xiaoyao Li Link: https://lore.kernel.org/r/20220712015838.1253995-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/vmx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index c30115b9cb33..3842e121070a 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -4004,7 +4004,9 @@ static void vmx_msr_filter_changed(struct kvm_vcpu *vcpu) vmx_disable_intercept_for_msr(vcpu, msr, MSR_TYPE_W); } - pt_update_intercept_for_msr(vcpu); + /* PT MSRs can be passed through iff PT is exposed to the guest. */ + if (vmx_pt_mode_is_host_guest()) + pt_update_intercept_for_msr(vcpu); } static inline void kvm_vcpu_trigger_posted_interrupt(struct kvm_vcpu *vcpu, From 0391334907937f841f23e77d0e1c0a2eb26c15d5 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 6 Jul 2022 22:57:35 -0700 Subject: [PATCH 1011/1436] xtensa: iss/network: drop 'devices' list There are two per-device lists in the ISS network driver: command line parameters list and iss_net_private object list. The latter is only used for duplicate checking in the function iss_net_setup where the former should have been used. Drop iss_net_private object list and associated code and use command line parameters list in the iss_net_setup instead. Signed-off-by: Max Filippov --- arch/xtensa/platforms/iss/network.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index fd84d4891758..2d566231688f 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -37,10 +37,6 @@ #define ETH_HEADER_OTHER 14 #define ISS_NET_TIMER_VALUE (HZ / 10) - -static DEFINE_SPINLOCK(devices_lock); -static LIST_HEAD(devices); - /* ------------------------------------------------------------------------- */ /* We currently only support the TUNTAP transport protocol. */ @@ -70,8 +66,6 @@ struct iss_net_ops { /* This structure contains out private information for the driver. */ struct iss_net_private { - struct list_head device_list; - spinlock_t lock; struct net_device *dev; struct platform_device pdev; @@ -488,7 +482,6 @@ static int iss_net_configure(int index, char *init) lp = netdev_priv(dev); *lp = (struct iss_net_private) { - .device_list = LIST_HEAD_INIT(lp->device_list), .dev = dev, .index = index, }; @@ -521,10 +514,6 @@ static int iss_net_configure(int index, char *init) driver_registered = 1; } - spin_lock(&devices_lock); - list_add(&lp->device_list, &devices); - spin_unlock(&devices_lock); - lp->pdev.id = index; lp->pdev.name = DRIVER_NAME; platform_device_register(&lp->pdev); @@ -574,7 +563,7 @@ struct iss_net_init { static int __init iss_net_setup(char *str) { - struct iss_net_private *device = NULL; + struct iss_net_init *device = NULL; struct iss_net_init *new; struct list_head *ele; char *end; @@ -595,16 +584,12 @@ static int __init iss_net_setup(char *str) } str = end; - spin_lock(&devices_lock); - - list_for_each(ele, &devices) { - device = list_entry(ele, struct iss_net_private, device_list); + list_for_each(ele, ð_cmd_line) { + device = list_entry(ele, struct iss_net_init, list); if (device->index == n) break; } - spin_unlock(&devices_lock); - if (device && device->index == n) { pr_err("Device %u already configured\n", n); return 1; From 8864fb8359682912ee99235db7db916733a1fd7b Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Thu, 7 Jul 2022 00:23:16 -0700 Subject: [PATCH 1012/1436] xtensa: iss/network: provide release() callback Provide release() callback for the platform device embedded into struct iss_net_private and registered in the iss_net_configure so that platform_device_unregister could be called for it. Signed-off-by: Max Filippov --- arch/xtensa/platforms/iss/network.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index 2d566231688f..2a22e80a488d 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -466,6 +466,15 @@ static const struct net_device_ops iss_netdev_ops = { .ndo_set_rx_mode = iss_net_set_multicast_list, }; +static void iss_net_pdev_release(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct iss_net_private *lp = + container_of(pdev, struct iss_net_private, pdev); + + free_netdev(lp->dev); +} + static int iss_net_configure(int index, char *init) { struct net_device *dev; @@ -516,6 +525,7 @@ static int iss_net_configure(int index, char *init) lp->pdev.id = index; lp->pdev.name = DRIVER_NAME; + lp->pdev.dev.release = iss_net_pdev_release; platform_device_register(&lp->pdev); SET_NETDEV_DEV(dev, &lp->pdev.dev); From 628ccfc8f5f79dd548319408fcc53949fe97b258 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 7 Jul 2022 10:32:29 +0800 Subject: [PATCH 1013/1436] xtensa: iss: fix handling error cases in iss_net_configure() The 'pdev' and 'netdev' need to be released in error cases of iss_net_configure(). Change the return type of iss_net_configure() to void, because it's not used. Fixes: 7282bee78798 ("[PATCH] xtensa: Architecture support for Tensilica Xtensa Part 8") Reported-by: Hulk Robot Signed-off-by: Yang Yingliang Signed-off-by: Max Filippov --- arch/xtensa/platforms/iss/network.c | 32 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index 2a22e80a488d..9ac46ab3a296 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -475,16 +475,15 @@ static void iss_net_pdev_release(struct device *dev) free_netdev(lp->dev); } -static int iss_net_configure(int index, char *init) +static void iss_net_configure(int index, char *init) { struct net_device *dev; struct iss_net_private *lp; - int err; dev = alloc_etherdev(sizeof(*lp)); if (dev == NULL) { pr_err("eth_configure: failed to allocate device\n"); - return 1; + return; } /* Initialize private element. */ @@ -511,7 +510,7 @@ static int iss_net_configure(int index, char *init) if (!tuntap_probe(lp, index, init)) { pr_err("%s: invalid arguments. Skipping device!\n", dev->name); - goto errout; + goto err_free_netdev; } pr_info("Netdevice %d (%pM)\n", index, dev->dev_addr); @@ -519,14 +518,16 @@ static int iss_net_configure(int index, char *init) /* sysfs register */ if (!driver_registered) { - platform_driver_register(&iss_net_driver); + if (platform_driver_register(&iss_net_driver)) + goto err_free_netdev; driver_registered = 1; } lp->pdev.id = index; lp->pdev.name = DRIVER_NAME; lp->pdev.dev.release = iss_net_pdev_release; - platform_device_register(&lp->pdev); + if (platform_device_register(&lp->pdev)) + goto err_free_netdev; SET_NETDEV_DEV(dev, &lp->pdev.dev); dev->netdev_ops = &iss_netdev_ops; @@ -535,23 +536,20 @@ static int iss_net_configure(int index, char *init) dev->irq = -1; rtnl_lock(); - err = register_netdevice(dev); - rtnl_unlock(); - - if (err) { + if (register_netdevice(dev)) { + rtnl_unlock(); pr_err("%s: error registering net device!\n", dev->name); - /* XXX: should we call ->remove() here? */ - free_netdev(dev); - return 1; + platform_device_unregister(&lp->pdev); + return; } + rtnl_unlock(); timer_setup(&lp->tl, iss_net_user_timer_expire, 0); - return 0; + return; -errout: - /* FIXME: unregister; free, etc.. */ - return -EIO; +err_free_netdev: + free_netdev(dev); } /* ------------------------------------------------------------------------- */ From c49731a04e7c14b2ccd146a7fddf92e78ccae143 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 13 Jul 2022 20:14:25 -0700 Subject: [PATCH 1014/1436] xtensa: enable KCOV support Select ARCH_HAS_KCOV and set KCOV_INSTRUMENT = n inside arch/xtensa/boot/lib. Signed-off-by: Max Filippov --- Documentation/features/debug/kcov/arch-support.txt | 2 +- arch/xtensa/Kconfig | 1 + arch/xtensa/boot/lib/Makefile | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/features/debug/kcov/arch-support.txt b/Documentation/features/debug/kcov/arch-support.txt index afb90bebded2..0a91f5ce34a9 100644 --- a/Documentation/features/debug/kcov/arch-support.txt +++ b/Documentation/features/debug/kcov/arch-support.txt @@ -27,5 +27,5 @@ | sparc: | TODO | | um: | ok | | x86: | ok | - | xtensa: | TODO | + | xtensa: | ok | ----------------------- diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 0b0f0172cced..c4ef8e9c7249 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -6,6 +6,7 @@ config XTENSA select ARCH_HAS_CURRENT_STACK_POINTER select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DMA_PREP_COHERENT if MMU + select ARCH_HAS_KCOV select ARCH_HAS_SYNC_DMA_FOR_CPU if MMU select ARCH_HAS_SYNC_DMA_FOR_DEVICE if MMU select ARCH_HAS_DMA_SET_UNCACHED if MMU diff --git a/arch/xtensa/boot/lib/Makefile b/arch/xtensa/boot/lib/Makefile index 162d10af36f3..6f9a56a8ca85 100644 --- a/arch/xtensa/boot/lib/Makefile +++ b/arch/xtensa/boot/lib/Makefile @@ -17,6 +17,7 @@ endif KASAN_SANITIZE := n KCSAN_SANITIZE := n +KCOV_INSTRUMENT := n CFLAGS_REMOVE_inflate.o += -fstack-protector -fstack-protector-strong CFLAGS_REMOVE_zmem.o += -fstack-protector -fstack-protector-strong From 0847d167d0f9bdc8f61e5e5d32831fa8fdcd150f Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 13 Jul 2022 21:20:58 -0700 Subject: [PATCH 1015/1436] xtensa: enable ARCH_HAS_GCOV_PROFILE_ALL Select ARCH_HAS_GCOV_PROFILE_ALL and set GCOV_PROFILE = n inside arch/xtensa/boot/lib. Signed-off-by: Max Filippov --- Documentation/features/debug/gcov-profile-all/arch-support.txt | 2 +- arch/xtensa/Kconfig | 1 + arch/xtensa/boot/lib/Makefile | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/features/debug/gcov-profile-all/arch-support.txt b/Documentation/features/debug/gcov-profile-all/arch-support.txt index 502c1d409648..0b3ba2415fac 100644 --- a/Documentation/features/debug/gcov-profile-all/arch-support.txt +++ b/Documentation/features/debug/gcov-profile-all/arch-support.txt @@ -27,5 +27,5 @@ | sparc: | TODO | | um: | ok | | x86: | ok | - | xtensa: | TODO | + | xtensa: | ok | ----------------------- diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index c4ef8e9c7249..5fa1fd1aecff 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -6,6 +6,7 @@ config XTENSA select ARCH_HAS_CURRENT_STACK_POINTER select ARCH_HAS_DEBUG_VM_PGTABLE select ARCH_HAS_DMA_PREP_COHERENT if MMU + select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_KCOV select ARCH_HAS_SYNC_DMA_FOR_CPU if MMU select ARCH_HAS_SYNC_DMA_FOR_DEVICE if MMU diff --git a/arch/xtensa/boot/lib/Makefile b/arch/xtensa/boot/lib/Makefile index 6f9a56a8ca85..0378a22a08e3 100644 --- a/arch/xtensa/boot/lib/Makefile +++ b/arch/xtensa/boot/lib/Makefile @@ -18,6 +18,7 @@ endif KASAN_SANITIZE := n KCSAN_SANITIZE := n KCOV_INSTRUMENT := n +GCOV_PROFILE := n CFLAGS_REMOVE_inflate.o += -fstack-protector -fstack-protector-strong CFLAGS_REMOVE_zmem.o += -fstack-protector -fstack-protector-strong From 9745fb07474f4501eff62130a78a42a8b8c18b05 Mon Sep 17 00:00:00 2001 From: Jonathan Yong Date: Mon, 6 Jun 2022 19:41:27 +0300 Subject: [PATCH 1016/1436] platform/x86/intel: Add Primary to Sideband (P2SB) bridge support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SoC features such as GPIO are accessed via a reserved MMIO area, we don't know its address but can obtain it from the BAR of the P2SB device, that device is normally hidden so we have to temporarily unhide it, read address and hide it back. There are already a few users and at least one more is coming which require an access to Primary to Sideband (P2SB) bridge in order to get IO or MMIO BAR hidden by BIOS. Create a library to access P2SB for x86 devices in a unified way. Background information ====================== Note, the term "bridge" is used in the documentation and it has nothing to do with a PCI (host) bridge as per the PCI specifications. The P2SB is an interesting device by its nature and hardware design. First of all, it has several devices in the hardware behind it. These devices may or may not be represented as ACPI devices by a firmware. It also has a hardwired (to 0s) the least significant bits of the base address register which is represented by the only 64-bit BAR0. It means that OS mustn't reallocate the BAR. On top of that in some cases P2SB is represented by function 0 on PCI slot (in terms of B:D.F) and according to the PCI specification any other function can't be seen until function 0 is present and visible. In the PCI configuration space of P2SB device the full 32-bit register is allocated for the only purpose of hiding the entire P2SB device. As per [3]: 3.1.39 P2SB Control (P2SBC)—Offset E0h Hide Device (HIDE): When this bit is set, the P2SB will return 1s on any PCI Configuration Read on IOSF-P. All other transactions including PCI Configuration Writes on IOSF-P are unaffected by this. This does not affect reads performed on the IOSF-SB interface. This doesn't prevent MMIO accesses, although preventing the OS from assigning these addresses. The firmware on the affected platforms marks the region as unusable (by cutting it off from the PCI host bridge resources) as depicted in the Apollo Lake example below: PCI host bridge to bus 0000:00 pci_bus 0000:00: root bus resource [io 0x0070-0x0077] pci_bus 0000:00: root bus resource [io 0x0000-0x006f window] pci_bus 0000:00: root bus resource [io 0x0078-0x0cf7 window] pci_bus 0000:00: root bus resource [io 0x0d00-0xffff window] pci_bus 0000:00: root bus resource [mem 0x7c000001-0x7fffffff window] pci_bus 0000:00: root bus resource [mem 0x7b800001-0x7bffffff window] pci_bus 0000:00: root bus resource [mem 0x80000000-0xcfffffff window] pci_bus 0000:00: root bus resource [mem 0xe0000000-0xefffffff window] pci_bus 0000:00: root bus resource [bus 00-ff] The P2SB 16MB BAR is located at 0xd0000000-0xd0ffffff memory window. The generic solution ==================== The generic solution for all cases when we need to access to the information behind P2SB device is a library code where users ask for necessary resources by demand and hence those users take care of not being run on the systems where this access is not required. The library provides the p2sb_bar() API to retrieve the MMIO of the BAR0 of the device from P2SB device slot. P2SB unconditional unhiding awareness ===================================== Technically it's possible to unhide the P2SB device and devices on the same PCI slot and access them at any time as needed. But there are several potential issues with that: - the systems were never tested against such configuration and hence nobody knows what kind of bugs it may bring, especially when we talk about SPI NOR case which contains Intel FirmWare Image (IFWI) code (including BIOS) and already known to be problematic in the past for end users - the PCI by its nature is a hotpluggable bus and in case somebody attaches a driver to the functions of a P2SB slot device(s) the end user experience and system behaviour can be unpredictable - the kernel code would need some ugly hacks (or code looking as an ugly hack) under arch/x86/pci in order to enable these devices on only selected platforms (which may include CPU ID table followed by a potentially growing number of DMI strings The future improvements ======================= The future improvements with this code may go in order to gain some kind of cache, if it's possible at all, to prevent unhiding and hiding many times to take static information that may be saved once per boot. Links ===== [1]: https://lab.whitequark.org/notes/2017-11-08/accessing-intel-ich-pch-gpios/ [2]: https://cdrdv2.intel.com/v1/dl/getContent/332690?wapkw=332690 [3]: https://cdrdv2.intel.com/v1/dl/getContent/332691?wapkw=332691 [4]: https://medium.com/@jacksonchen_43335/bios-gpio-p2sb-70e9b829b403 Signed-off-by: Jonathan Yong Co-developed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko Tested-by: Henning Schild Acked-by: Hans de Goede Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/platform/x86/intel/Kconfig | 12 +++ drivers/platform/x86/intel/Makefile | 2 + drivers/platform/x86/intel/p2sb.c | 127 +++++++++++++++++++++++++ include/linux/platform_data/x86/p2sb.h | 28 ++++++ 4 files changed, 169 insertions(+) create mode 100644 drivers/platform/x86/intel/p2sb.c create mode 100644 include/linux/platform_data/x86/p2sb.h diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index 794968bda115..c9cfbaae436b 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -70,6 +70,18 @@ config INTEL_OAKTRAIL enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y here; it will only load on supported platforms. +config P2SB + bool "Primary to Sideband (P2SB) bridge access support" + depends on PCI + help + The Primary to Sideband (P2SB) bridge is an interface to some + PCI devices connected through it. In particular, SPI NOR controller + in Intel Apollo Lake SoC is one of such devices. + + The main purpose of this library is to unhide P2SB device in case + firmware kept it hidden on some platforms in order to access devices + behind it. + config INTEL_BXTWC_PMIC_TMU tristate "Intel Broxton Whiskey Cove TMU Driver" depends on INTEL_SOC_PMIC_BXTWC diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index 717933dd0cfd..741a9404db98 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -28,6 +28,8 @@ intel_int0002_vgpio-y := int0002_vgpio.o obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o intel_oaktrail-y := oaktrail.o obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o +intel_p2sb-y := p2sb.o +obj-$(CONFIG_P2SB) += intel_p2sb.o intel_sdsi-y := sdsi.o obj-$(CONFIG_INTEL_SDSI) += intel_sdsi.o intel_vsec-y := vsec.o diff --git a/drivers/platform/x86/intel/p2sb.c b/drivers/platform/x86/intel/p2sb.c new file mode 100644 index 000000000000..b598ef14dbc6 --- /dev/null +++ b/drivers/platform/x86/intel/p2sb.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Primary to Sideband (P2SB) bridge access support + * + * Copyright (c) 2017, 2021-2022 Intel Corporation. + * + * Authors: Andy Shevchenko + * Jonathan Yong + */ + +#include +#include +#include +#include + +#include +#include + +#define P2SBC 0xe0 +#define P2SBC_HIDE BIT(8) + +static const struct x86_cpu_id p2sb_cpu_ids[] = { + X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, PCI_DEVFN(13, 0)), + {} +}; + +static int p2sb_get_devfn(unsigned int *devfn) +{ + const struct x86_cpu_id *id; + + id = x86_match_cpu(p2sb_cpu_ids); + if (!id) + return -ENODEV; + + *devfn = (unsigned int)id->driver_data; + return 0; +} + +static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem) +{ + /* Copy resource from the first BAR of the device in question */ + *mem = pdev->resource[0]; + return 0; +} + +static int p2sb_scan_and_read(struct pci_bus *bus, unsigned int devfn, struct resource *mem) +{ + struct pci_dev *pdev; + int ret; + + pdev = pci_scan_single_device(bus, devfn); + if (!pdev) + return -ENODEV; + + ret = p2sb_read_bar0(pdev, mem); + + pci_stop_and_remove_bus_device(pdev); + return ret; +} + +/** + * p2sb_bar - Get Primary to Sideband (P2SB) bridge device BAR + * @bus: PCI bus to communicate with + * @devfn: PCI slot and function to communicate with + * @mem: memory resource to be filled in + * + * The BIOS prevents the P2SB device from being enumerated by the PCI + * subsystem, so we need to unhide and hide it back to lookup the BAR. + * + * if @bus is NULL, the bus 0 in domain 0 will be used. + * If @devfn is 0, it will be replaced by devfn of the P2SB device. + * + * Caller must provide a valid pointer to @mem. + * + * Locking is handled by pci_rescan_remove_lock mutex. + * + * Return: + * 0 on success or appropriate errno value on error. + */ +int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) +{ + struct pci_dev *pdev_p2sb; + unsigned int devfn_p2sb; + u32 value = P2SBC_HIDE; + int ret; + + /* Get devfn for P2SB device itself */ + ret = p2sb_get_devfn(&devfn_p2sb); + if (ret) + return ret; + + /* if @bus is NULL, use bus 0 in domain 0 */ + bus = bus ?: pci_find_bus(0, 0); + + /* + * Prevent concurrent PCI bus scan from seeing the P2SB device and + * removing via sysfs while it is temporarily exposed. + */ + pci_lock_rescan_remove(); + + /* Unhide the P2SB device, if needed */ + pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value); + if (value & P2SBC_HIDE) + pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, 0); + + pdev_p2sb = pci_scan_single_device(bus, devfn_p2sb); + if (devfn) + ret = p2sb_scan_and_read(bus, devfn, mem); + else + ret = p2sb_read_bar0(pdev_p2sb, mem); + pci_stop_and_remove_bus_device(pdev_p2sb); + + /* Hide the P2SB device, if it was hidden */ + if (value & P2SBC_HIDE) + pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, P2SBC_HIDE); + + pci_unlock_rescan_remove(); + + if (ret) + return ret; + + if (mem->flags == 0) + return -ENODEV; + + return 0; +} +EXPORT_SYMBOL_GPL(p2sb_bar); diff --git a/include/linux/platform_data/x86/p2sb.h b/include/linux/platform_data/x86/p2sb.h new file mode 100644 index 000000000000..a1d5fddc8f13 --- /dev/null +++ b/include/linux/platform_data/x86/p2sb.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Primary to Sideband (P2SB) bridge access support + */ + +#ifndef _PLATFORM_DATA_X86_P2SB_H +#define _PLATFORM_DATA_X86_P2SB_H + +#include +#include + +struct pci_bus; +struct resource; + +#if IS_BUILTIN(CONFIG_P2SB) + +int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem); + +#else /* CONFIG_P2SB */ + +static inline int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) +{ + return -ENODEV; +} + +#endif /* CONFIG_P2SB is not set */ + +#endif /* _PLATFORM_DATA_X86_P2SB_H */ From c551bd81d198bf1dcd4398d5454acdc0309dbe77 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 6 Jun 2022 19:41:28 +0300 Subject: [PATCH 1017/1436] pinctrl: intel: Check against matching data instead of ACPI companion In some cases we may get a platform device that has ACPI companion which is different to the pin control described in the ACPI tables. This is primarily happens when device is instantiated by board file. In order to allow this device being enumerated, refactor intel_pinctrl_get_soc_data() to check the matching data instead of ACPI companion. Reported-by: Henning Schild Signed-off-by: Andy Shevchenko Tested-by: Henning Schild Acked-by: Hans de Goede Acked-by: Mika Westerberg Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/pinctrl/intel/pinctrl-intel.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index ffc045f7bf00..fd093e36c3a8 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -1641,16 +1641,14 @@ EXPORT_SYMBOL_GPL(intel_pinctrl_probe_by_uid); const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev) { + const struct intel_pinctrl_soc_data * const *table; const struct intel_pinctrl_soc_data *data = NULL; - const struct intel_pinctrl_soc_data **table; - struct acpi_device *adev; - unsigned int i; - adev = ACPI_COMPANION(&pdev->dev); - if (adev) { - const void *match = device_get_match_data(&pdev->dev); + table = device_get_match_data(&pdev->dev); + if (table) { + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); + unsigned int i; - table = (const struct intel_pinctrl_soc_data **)match; for (i = 0; table[i]; i++) { if (!strcmp(adev->pnp.unique_id, table[i]->uid)) { data = table[i]; @@ -1664,7 +1662,7 @@ const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_ if (!id) return ERR_PTR(-ENODEV); - table = (const struct intel_pinctrl_soc_data **)id->driver_data; + table = (const struct intel_pinctrl_soc_data * const *)id->driver_data; data = table[pdev->id]; } From 6e3b29dbc119fa86bc25f822e8c6166552086531 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 6 Jun 2022 19:41:29 +0300 Subject: [PATCH 1018/1436] mfd: lpc_ich: Factor out lpc_ich_enable_spi_write() Factor out duplicate code to lpc_ich_enable_spi_write() helper function. Signed-off-by: Andy Shevchenko Tested-by: Henning Schild Acked-by: Hans de Goede Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/lpc_ich.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 9ffab9aafd81..d9175cb8a2d5 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -1100,35 +1100,32 @@ static bool lpc_ich_byt_set_writeable(void __iomem *base, void *data) return val & BYT_BCR_WPD; } -static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data) +static bool lpc_ich_set_writeable(struct pci_bus *bus, unsigned int devfn) { - struct pci_dev *pdev = data; u32 bcr; - pci_read_config_dword(pdev, BCR, &bcr); + pci_bus_read_config_dword(bus, devfn, BCR, &bcr); if (!(bcr & BCR_WPD)) { bcr |= BCR_WPD; - pci_write_config_dword(pdev, BCR, bcr); - pci_read_config_dword(pdev, BCR, &bcr); + pci_bus_write_config_dword(bus, devfn, BCR, bcr); + pci_bus_read_config_dword(bus, devfn, BCR, &bcr); } return bcr & BCR_WPD; } +static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data) +{ + struct pci_dev *pdev = data; + + return lpc_ich_set_writeable(pdev->bus, pdev->devfn); +} + static bool lpc_ich_bxt_set_writeable(void __iomem *base, void *data) { - unsigned int spi = PCI_DEVFN(13, 2); - struct pci_bus *bus = data; - u32 bcr; + struct pci_dev *pdev = data; - pci_bus_read_config_dword(bus, spi, BCR, &bcr); - if (!(bcr & BCR_WPD)) { - bcr |= BCR_WPD; - pci_bus_write_config_dword(bus, spi, BCR, bcr); - pci_bus_read_config_dword(bus, spi, BCR, &bcr); - } - - return bcr & BCR_WPD; + return lpc_ich_set_writeable(pdev->bus, PCI_DEVFN(13, 2)); } static int lpc_ich_init_spi(struct pci_dev *dev) @@ -1185,7 +1182,7 @@ static int lpc_ich_init_spi(struct pci_dev *dev) res->end = res->start + SPIBASE_APL_SZ - 1; info->set_writeable = lpc_ich_bxt_set_writeable; - info->data = bus; + info->data = dev; } pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1); From 559793198f9280cdd56c438f5258e315ed8a6cbc Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 6 Jun 2022 19:41:30 +0300 Subject: [PATCH 1019/1436] mfd: lpc_ich: Switch to generic p2sb_bar() Instead of open coding p2sb_bar() functionality we are going to use generic library. There is one more user en route. This is more than just a clean-up. It also fixes a potential issue seen when SPI BAR is 64-bit. The current code works if and only if the PCI BAR of the hidden device is inside 4G address space. In case when firmware decides to go above 4G, we will get a wrong address. Signed-off-by: Andy Shevchenko Tested-by: Henning Schild Acked-by: Hans de Goede Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 1 + drivers/mfd/lpc_ich.c | 27 ++++++++------------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3b59456f5545..9566341de470 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -572,6 +572,7 @@ config LPC_ICH tristate "Intel ICH LPC" depends on PCI select MFD_CORE + select P2SB if X86 help The LPC bridge function of the Intel ICH provides support for many functional units. This driver provides needed support for diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index d9175cb8a2d5..e360651c5406 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -45,6 +45,7 @@ #include #include #include +#include #define ACPIBASE 0x40 #define ACPIBASE_GPE_OFF 0x28 @@ -71,8 +72,6 @@ #define BCR 0xdc #define BCR_WPD BIT(0) -#define SPIBASE_APL_SZ 4096 - #define GPIOBASE_ICH0 0x58 #define GPIOCTRL_ICH0 0x5C #define GPIOBASE_ICH6 0x48 @@ -1134,6 +1133,7 @@ static int lpc_ich_init_spi(struct pci_dev *dev) struct resource *res = &intel_spi_res[0]; struct intel_spi_boardinfo *info; u32 spi_base, rcba; + int ret; info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL); if (!info) @@ -1164,30 +1164,19 @@ static int lpc_ich_init_spi(struct pci_dev *dev) } break; - case INTEL_SPI_BXT: { - unsigned int p2sb = PCI_DEVFN(13, 0); - unsigned int spi = PCI_DEVFN(13, 2); - struct pci_bus *bus = dev->bus; - + case INTEL_SPI_BXT: /* * The P2SB is hidden by BIOS and we need to unhide it in * order to read BAR of the SPI flash device. Once that is * done we hide it again. */ - pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x0); - pci_bus_read_config_dword(bus, spi, PCI_BASE_ADDRESS_0, - &spi_base); - if (spi_base != ~0) { - res->start = spi_base & 0xfffffff0; - res->end = res->start + SPIBASE_APL_SZ - 1; + ret = p2sb_bar(dev->bus, PCI_DEVFN(13, 2), res); + if (ret) + return ret; - info->set_writeable = lpc_ich_bxt_set_writeable; - info->data = dev; - } - - pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1); + info->set_writeable = lpc_ich_bxt_set_writeable; + info->data = dev; break; - } default: return -EINVAL; From 7064d7d88b83b6394ee833e805fd041c615acb13 Mon Sep 17 00:00:00 2001 From: Tan Jui Nee Date: Mon, 6 Jun 2022 19:41:31 +0300 Subject: [PATCH 1020/1436] mfd: lpc_ich: Add support for pinctrl in non-ACPI system Add support for non-ACPI systems, such as system that uses Advanced Boot Loader (ABL) whereby a platform device has to be created in order to bind with pin control and GPIO. At the moment, Intel Apollo Lake In-Vehicle Infotainment (IVI) system requires a driver to hide and unhide P2SB to lookup P2SB BAR and pass the PCI BAR address to GPIO. Signed-off-by: Tan Jui Nee Co-developed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko Tested-by: Henning Schild Acked-by: Hans de Goede Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/lpc_ich.c | 105 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index e360651c5406..650951f89f1c 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -8,7 +8,8 @@ * Configuration Registers. * * This driver is derived from lpc_sch. - + * + * Copyright (c) 2017, 2021-2022 Intel Corporation * Copyright (c) 2011 Extreme Engineering Solution, Inc. * Author: Aaron Sierra * @@ -42,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -142,6 +144,73 @@ static struct mfd_cell lpc_ich_gpio_cell = { .ignore_resource_conflicts = true, }; +#define APL_GPIO_NORTH 0 +#define APL_GPIO_NORTHWEST 1 +#define APL_GPIO_WEST 2 +#define APL_GPIO_SOUTHWEST 3 +#define APL_GPIO_NR_DEVICES 4 + +/* Offset data for Apollo Lake GPIO controllers */ +static resource_size_t apl_gpio_offsets[APL_GPIO_NR_DEVICES] = { + [APL_GPIO_NORTH] = 0xc50000, + [APL_GPIO_NORTHWEST] = 0xc40000, + [APL_GPIO_WEST] = 0xc70000, + [APL_GPIO_SOUTHWEST] = 0xc00000, +}; + +#define APL_GPIO_RESOURCE_SIZE 0x1000 + +#define APL_GPIO_IRQ 14 + +static struct resource apl_gpio_resources[APL_GPIO_NR_DEVICES][2] = { + [APL_GPIO_NORTH] = { + DEFINE_RES_MEM(0, 0), + DEFINE_RES_IRQ(APL_GPIO_IRQ), + }, + [APL_GPIO_NORTHWEST] = { + DEFINE_RES_MEM(0, 0), + DEFINE_RES_IRQ(APL_GPIO_IRQ), + }, + [APL_GPIO_WEST] = { + DEFINE_RES_MEM(0, 0), + DEFINE_RES_IRQ(APL_GPIO_IRQ), + }, + [APL_GPIO_SOUTHWEST] = { + DEFINE_RES_MEM(0, 0), + DEFINE_RES_IRQ(APL_GPIO_IRQ), + }, +}; + +static const struct mfd_cell apl_gpio_devices[APL_GPIO_NR_DEVICES] = { + [APL_GPIO_NORTH] = { + .name = "apollolake-pinctrl", + .id = APL_GPIO_NORTH, + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_NORTH]), + .resources = apl_gpio_resources[APL_GPIO_NORTH], + .ignore_resource_conflicts = true, + }, + [APL_GPIO_NORTHWEST] = { + .name = "apollolake-pinctrl", + .id = APL_GPIO_NORTHWEST, + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_NORTHWEST]), + .resources = apl_gpio_resources[APL_GPIO_NORTHWEST], + .ignore_resource_conflicts = true, + }, + [APL_GPIO_WEST] = { + .name = "apollolake-pinctrl", + .id = APL_GPIO_WEST, + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_WEST]), + .resources = apl_gpio_resources[APL_GPIO_WEST], + .ignore_resource_conflicts = true, + }, + [APL_GPIO_SOUTHWEST] = { + .name = "apollolake-pinctrl", + .id = APL_GPIO_SOUTHWEST, + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_SOUTHWEST]), + .resources = apl_gpio_resources[APL_GPIO_SOUTHWEST], + .ignore_resource_conflicts = true, + }, +}; static struct mfd_cell lpc_ich_spi_cell = { .name = "intel-spi", @@ -1085,6 +1154,34 @@ wdt_done: return ret; } +static int lpc_ich_init_pinctrl(struct pci_dev *dev) +{ + struct resource base; + unsigned int i; + int ret; + + /* Check, if GPIO has been exported as an ACPI device */ + if (acpi_dev_present("INT3452", NULL, -1)) + return -EEXIST; + + ret = p2sb_bar(dev->bus, 0, &base); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(apl_gpio_devices); i++) { + struct resource *mem = &apl_gpio_resources[i][0]; + resource_size_t offset = apl_gpio_offsets[i]; + + /* Fill MEM resource */ + mem->start = base.start + offset; + mem->end = base.start + offset + APL_GPIO_RESOURCE_SIZE - 1; + mem->flags = base.flags; + } + + return mfd_add_devices(&dev->dev, 0, apl_gpio_devices, + ARRAY_SIZE(apl_gpio_devices), NULL, 0, NULL); +} + static bool lpc_ich_byt_set_writeable(void __iomem *base, void *data) { u32 val; @@ -1235,6 +1332,12 @@ static int lpc_ich_probe(struct pci_dev *dev, cell_added = true; } + if (priv->chipset == LPC_APL) { + ret = lpc_ich_init_pinctrl(dev); + if (!ret) + cell_added = true; + } + if (lpc_chipset_info[priv->chipset].spi_type) { ret = lpc_ich_init_spi(dev); if (!ret) From 5c7b9167ddf89d2d845e09bfcdc9f677340b6a5c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 6 Jun 2022 19:41:32 +0300 Subject: [PATCH 1021/1436] i2c: i801: convert to use common P2SB accessor Since we have a common P2SB accessor in tree we may use it instead of open coded variants. Replace custom code by p2sb_bar() call. Signed-off-by: Andy Shevchenko Tested-by: Henning Schild Acked-by: Hans de Goede Acked-by: Linus Walleij Reviewed-by: Jean Delvare Acked-by: Wolfram Sang Signed-off-by: Lee Jones --- drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 39 +++++++------------------------ drivers/platform/x86/intel/p2sb.c | 6 +++++ 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a1bae59208e3..4d0a195ca3ef 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -108,6 +108,7 @@ config I2C_HIX5HD2 config I2C_I801 tristate "Intel 82801 (ICH/PCH)" depends on PCI + select P2SB if X86 select CHECK_SIGNATURE if X86 && DMI select I2C_SMBUS help diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index ff706349bdfb..f7a0bb372e8e 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -111,6 +111,7 @@ #include #include #include +#include #include #include @@ -140,7 +141,6 @@ #define TCOBASE 0x050 #define TCOCTL 0x054 -#define SBREG_BAR 0x10 #define SBREG_SMBCTRL 0xc6000c #define SBREG_SMBCTRL_DNV 0xcf000c @@ -1482,45 +1482,24 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, .version = 4, }; struct resource *res; - unsigned int devfn; - u64 base64_addr; - u32 base_addr; - u8 hidden; + int ret; /* * We must access the NO_REBOOT bit over the Primary to Sideband - * bridge (P2SB). The BIOS prevents the P2SB device from being - * enumerated by the PCI subsystem, so we need to unhide/hide it - * to lookup the P2SB BAR. + * (P2SB) bridge. */ - pci_lock_rescan_remove(); - - devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); - - /* Unhide the P2SB device, if it is hidden */ - pci_bus_read_config_byte(pci_dev->bus, devfn, 0xe1, &hidden); - if (hidden) - pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0); - - pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr); - base64_addr = base_addr & 0xfffffff0; - - pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr); - base64_addr |= (u64)base_addr << 32; - - /* Hide the P2SB device, if it was hidden before */ - if (hidden) - pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden); - pci_unlock_rescan_remove(); res = &tco_res[1]; + ret = p2sb_bar(pci_dev->bus, 0, res); + if (ret) + return ERR_PTR(ret); + if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) - res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV; + res->start += SBREG_SMBCTRL_DNV; else - res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; + res->start += SBREG_SMBCTRL; res->end = res->start + 3; - res->flags = IORESOURCE_MEM; return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, tco_res, 2, &pldata, sizeof(pldata)); diff --git a/drivers/platform/x86/intel/p2sb.c b/drivers/platform/x86/intel/p2sb.c index b598ef14dbc6..fb2e141f3eb8 100644 --- a/drivers/platform/x86/intel/p2sb.c +++ b/drivers/platform/x86/intel/p2sb.c @@ -21,6 +21,12 @@ static const struct x86_cpu_id p2sb_cpu_ids[] = { X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, PCI_DEVFN(13, 0)), + X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D, PCI_DEVFN(31, 1)), + X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_D, PCI_DEVFN(31, 1)), + X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, PCI_DEVFN(31, 1)), + X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, PCI_DEVFN(31, 1)), + X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, PCI_DEVFN(31, 1)), + X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, PCI_DEVFN(31, 1)), {} }; From 6adc32f58b9356ced575f9d820e8e3f1f629f830 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 6 Jun 2022 19:41:33 +0300 Subject: [PATCH 1022/1436] EDAC, pnd2: Use proper I/O accessors and address space annotation The driver uses rather voodoo kind of castings and I/O accessors. Replace it with proper __iomem annotation and readl()/readq() calls. Signed-off-by: Andy Shevchenko Tested-by: Henning Schild Reviewed-by: Tony Luck Signed-off-by: Lee Jones --- drivers/edac/pnd2_edac.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/edac/pnd2_edac.c b/drivers/edac/pnd2_edac.c index c94ca1f790c4..7d1df120e24c 100644 --- a/drivers/edac/pnd2_edac.c +++ b/drivers/edac/pnd2_edac.c @@ -265,7 +265,7 @@ static u64 get_sideband_reg_base_addr(void) static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *name) { struct pci_dev *pdev; - char *base; + void __iomem *base; u64 addr; unsigned long size; @@ -297,8 +297,9 @@ static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *na return -ENODEV; if (sz == 8) - *(u32 *)(data + 4) = *(u32 *)(base + off + 4); - *(u32 *)data = *(u32 *)(base + off); + *(u64 *)data = readq(base + off); + else + *(u32 *)data = readl(base + off); iounmap(base); } From 7b2db7049bb9e55efb7e0c8a7169d5a021b50284 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 6 Jun 2022 19:41:34 +0300 Subject: [PATCH 1023/1436] EDAC, pnd2: convert to use common P2SB accessor Since we have a common P2SB accessor in tree we may use it instead of open coded variants. Replace custom code by p2sb_bar() call. Signed-off-by: Andy Shevchenko Tested-by: Henning Schild Reviewed-by: Tony Luck Signed-off-by: Lee Jones --- drivers/edac/Kconfig | 1 + drivers/edac/pnd2_edac.c | 55 ++++++++++++---------------------------- 2 files changed, 17 insertions(+), 39 deletions(-) diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index d3e2477948c8..17562cf1fe97 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -263,6 +263,7 @@ config EDAC_I10NM config EDAC_PND2 tristate "Intel Pondicherry2" depends on PCI && X86_64 && X86_MCE_INTEL + select P2SB if X86 help Support for error detection and correction on the Intel Pondicherry2 Integrated Memory Controller. This SoC IP is diff --git a/drivers/edac/pnd2_edac.c b/drivers/edac/pnd2_edac.c index 7d1df120e24c..a20b299f1202 100644 --- a/drivers/edac/pnd2_edac.c +++ b/drivers/edac/pnd2_edac.c @@ -28,6 +28,8 @@ #include #include #include +#include + #include #include #include @@ -232,42 +234,14 @@ static u64 get_mem_ctrl_hub_base_addr(void) return U64_LSHIFT(hi.base, 32) | U64_LSHIFT(lo.base, 15); } -static u64 get_sideband_reg_base_addr(void) -{ - struct pci_dev *pdev; - u32 hi, lo; - u8 hidden; - - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x19dd, NULL); - if (pdev) { - /* Unhide the P2SB device, if it's hidden */ - pci_read_config_byte(pdev, 0xe1, &hidden); - if (hidden) - pci_write_config_byte(pdev, 0xe1, 0); - - pci_read_config_dword(pdev, 0x10, &lo); - pci_read_config_dword(pdev, 0x14, &hi); - lo &= 0xfffffff0; - - /* Hide the P2SB device, if it was hidden before */ - if (hidden) - pci_write_config_byte(pdev, 0xe1, hidden); - - pci_dev_put(pdev); - return (U64_LSHIFT(hi, 32) | U64_LSHIFT(lo, 0)); - } else { - return 0xfd000000; - } -} - #define DNV_MCHBAR_SIZE 0x8000 #define DNV_SB_PORT_SIZE 0x10000 static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *name) { struct pci_dev *pdev; void __iomem *base; - u64 addr; - unsigned long size; + struct resource r; + int ret; if (op == 4) { pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x1980, NULL); @@ -279,20 +253,23 @@ static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *na } else { /* MMIO via memory controller hub base address */ if (op == 0 && port == 0x4c) { - addr = get_mem_ctrl_hub_base_addr(); - if (!addr) + memset(&r, 0, sizeof(r)); + + r.start = get_mem_ctrl_hub_base_addr(); + if (!r.start) return -ENODEV; - size = DNV_MCHBAR_SIZE; + r.end = r.start + DNV_MCHBAR_SIZE - 1; } else { /* MMIO via sideband register base address */ - addr = get_sideband_reg_base_addr(); - if (!addr) - return -ENODEV; - addr += (port << 16); - size = DNV_SB_PORT_SIZE; + ret = p2sb_bar(NULL, 0, &r); + if (ret) + return ret; + + r.start += (port << 16); + r.end = r.start + DNV_SB_PORT_SIZE - 1; } - base = ioremap((resource_size_t)addr, size); + base = ioremap(r.start, resource_size(&r)); if (!base) return -ENODEV; From e38da7d30f56ec6f9fae505a80561d4357cc7024 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Mon, 6 Jun 2022 19:41:35 +0300 Subject: [PATCH 1024/1436] watchdog: simatic-ipc-wdt: convert to use P2SB accessor Since we have a common P2SB accessor in tree we may use it instead of open coded variants. Replace custom code by p2sb_bar() call. Signed-off-by: Henning Schild Acked-by: Guenter Roeck Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/watchdog/Kconfig | 1 + drivers/watchdog/simatic-ipc-wdt.c | 15 ++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 32fd37698932..0796f6a9e8ff 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1647,6 +1647,7 @@ config SIEMENS_SIMATIC_IPC_WDT tristate "Siemens Simatic IPC Watchdog" depends on SIEMENS_SIMATIC_IPC select WATCHDOG_CORE + select P2SB help This driver adds support for several watchdogs found in Industrial PCs from Siemens. diff --git a/drivers/watchdog/simatic-ipc-wdt.c b/drivers/watchdog/simatic-ipc-wdt.c index 8bac793c63fb..6599695dc672 100644 --- a/drivers/watchdog/simatic-ipc-wdt.c +++ b/drivers/watchdog/simatic-ipc-wdt.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -54,9 +55,9 @@ static struct resource io_resource_trigger = DEFINE_RES_IO_NAMED(WD_TRIGGER_IOADR, SZ_1, KBUILD_MODNAME " WD_TRIGGER_IOADR"); -/* the actual start will be discovered with pci, 0 is a placeholder */ +/* the actual start will be discovered with p2sb, 0 is a placeholder */ static struct resource mem_resource = - DEFINE_RES_MEM_NAMED(0, SZ_4, "WD_RESET_BASE_ADR"); + DEFINE_RES_MEM_NAMED(0, 0, "WD_RESET_BASE_ADR"); static u32 wd_timeout_table[] = {2, 4, 6, 8, 16, 32, 48, 64 }; static void __iomem *wd_reset_base_addr; @@ -150,6 +151,7 @@ static int simatic_ipc_wdt_probe(struct platform_device *pdev) struct simatic_ipc_platform *plat = pdev->dev.platform_data; struct device *dev = &pdev->dev; struct resource *res; + int ret; switch (plat->devmode) { case SIMATIC_IPC_DEVICE_227E: @@ -190,15 +192,14 @@ static int simatic_ipc_wdt_probe(struct platform_device *pdev) if (plat->devmode == SIMATIC_IPC_DEVICE_427E) { res = &mem_resource; - /* get GPIO base from PCI */ - res->start = simatic_ipc_get_membase0(PCI_DEVFN(0x1f, 1)); - if (res->start == 0) - return -ENODEV; + ret = p2sb_bar(NULL, 0, res); + if (ret) + return ret; /* do the final address calculation */ res->start = res->start + (GPIO_COMMUNITY0_PORT_ID << 16) + PAD_CFG_DW0_GPP_A_23; - res->end += res->start; + res->end = res->start + SZ_4 - 1; wd_reset_base_addr = devm_ioremap_resource(dev, res); if (IS_ERR(wd_reset_base_addr)) From 759273c3c429ffbd8f24655fd0480cd408a1804c Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Mon, 6 Jun 2022 19:41:36 +0300 Subject: [PATCH 1025/1436] leds: simatic-ipc-leds: Convert to use P2SB accessor Since we have a common P2SB accessor in tree we may use it instead of open coded variants. Replace custom code by p2sb_bar() call. Signed-off-by: Henning Schild Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/leds/simple/Kconfig | 1 + drivers/leds/simple/simatic-ipc-leds.c | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/leds/simple/Kconfig b/drivers/leds/simple/Kconfig index 9f6a68336659..bbf8cff3c3f6 100644 --- a/drivers/leds/simple/Kconfig +++ b/drivers/leds/simple/Kconfig @@ -3,6 +3,7 @@ config LEDS_SIEMENS_SIMATIC_IPC tristate "LED driver for Siemens Simatic IPCs" depends on LEDS_CLASS depends on SIEMENS_SIMATIC_IPC + select P2SB help This option enables support for the LEDs of several Industrial PCs from Siemens. diff --git a/drivers/leds/simple/simatic-ipc-leds.c b/drivers/leds/simple/simatic-ipc-leds.c index 078d43f5ba38..2e7597c143d8 100644 --- a/drivers/leds/simple/simatic-ipc-leds.c +++ b/drivers/leds/simple/simatic-ipc-leds.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -38,8 +39,8 @@ static struct simatic_ipc_led simatic_ipc_leds_io[] = { { } }; -/* the actual start will be discovered with PCI, 0 is a placeholder */ -static struct resource simatic_ipc_led_mem_res = DEFINE_RES_MEM_NAMED(0, SZ_4K, KBUILD_MODNAME); +/* the actual start will be discovered with p2sb, 0 is a placeholder */ +static struct resource simatic_ipc_led_mem_res = DEFINE_RES_MEM_NAMED(0, 0, KBUILD_MODNAME); static void __iomem *simatic_ipc_led_memory; @@ -145,14 +146,13 @@ static int simatic_ipc_leds_probe(struct platform_device *pdev) ipcled = simatic_ipc_leds_mem; type = IORESOURCE_MEM; - /* get GPIO base from PCI */ - res->start = simatic_ipc_get_membase0(PCI_DEVFN(13, 0)); - if (res->start == 0) - return -ENODEV; + err = p2sb_bar(NULL, 0, res); + if (err) + return err; /* do the final address calculation */ res->start = res->start + (0xC5 << 16); - res->end += res->start; + res->end = res->start + SZ_4K - 1; simatic_ipc_led_memory = devm_ioremap_resource(dev, res); if (IS_ERR(simatic_ipc_led_memory)) From 446f0cf9e08b483d7dc6f61eee0ee846b22f6386 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Mon, 6 Jun 2022 19:41:37 +0300 Subject: [PATCH 1026/1436] platform/x86: simatic-ipc: drop custom P2SB bar code The two drivers that used to use this have been switched over to the common P2SB accessor, so this code is not needed any longer. Signed-off-by: Henning Schild Signed-off-by: Andy Shevchenko Reviewed-by: Hans de Goede Signed-off-by: Lee Jones --- drivers/platform/x86/simatic-ipc.c | 38 ------------------- .../platform_data/x86/simatic-ipc-base.h | 2 - 2 files changed, 40 deletions(-) diff --git a/drivers/platform/x86/simatic-ipc.c b/drivers/platform/x86/simatic-ipc.c index b599cda5ba3c..26c35e1660cb 100644 --- a/drivers/platform/x86/simatic-ipc.c +++ b/drivers/platform/x86/simatic-ipc.c @@ -101,44 +101,6 @@ static int register_platform_devices(u32 station_id) return 0; } -/* FIXME: this should eventually be done with generic P2SB discovery code - * the individual drivers for watchdogs and LEDs access memory that implements - * GPIO, but pinctrl will not come up because of missing ACPI entries - * - * While there is no conflict a cleaner solution would be to somehow bring up - * pinctrl even with these ACPI entries missing, and base the drivers on pinctrl. - * After which the following function could be dropped, together with the code - * poking the memory. - */ -/* - * Get membase address from PCI, used in leds and wdt module. Here we read - * the bar0. The final address calculation is done in the appropriate modules - */ -u32 simatic_ipc_get_membase0(unsigned int p2sb) -{ - struct pci_bus *bus; - u32 bar0 = 0; - /* - * The GPIO memory is in bar0 of the hidden P2SB device. - * Unhide the device to have a quick look at it, before we hide it - * again. - * Also grab the pci rescan lock so that device does not get discovered - * and remapped while it is visible. - * This code is inspired by drivers/mfd/lpc_ich.c - */ - bus = pci_find_bus(0, 0); - pci_lock_rescan_remove(); - pci_bus_write_config_byte(bus, p2sb, 0xE1, 0x0); - pci_bus_read_config_dword(bus, p2sb, PCI_BASE_ADDRESS_0, &bar0); - - bar0 &= ~0xf; - pci_bus_write_config_byte(bus, p2sb, 0xE1, 0x1); - pci_unlock_rescan_remove(); - - return bar0; -} -EXPORT_SYMBOL(simatic_ipc_get_membase0); - static int __init simatic_ipc_init_module(void) { const struct dmi_system_id *match; diff --git a/include/linux/platform_data/x86/simatic-ipc-base.h b/include/linux/platform_data/x86/simatic-ipc-base.h index 62d2bc774067..39fefd48cf4d 100644 --- a/include/linux/platform_data/x86/simatic-ipc-base.h +++ b/include/linux/platform_data/x86/simatic-ipc-base.h @@ -24,6 +24,4 @@ struct simatic_ipc_platform { u8 devmode; }; -u32 simatic_ipc_get_membase0(unsigned int p2sb); - #endif /* __PLATFORM_DATA_X86_SIMATIC_IPC_BASE_H */ From a6c80bec3c9357506e2bfdae82623ef34f8cab40 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Mon, 6 Jun 2022 19:41:38 +0300 Subject: [PATCH 1027/1436] leds: simatic-ipc-leds-gpio: Add GPIO version of Siemens driver On Apollo Lake the pinctrl drivers will now come up without ACPI. Use that instead of open coding it. Create a new driver for that which can later be filled with more GPIO based models, and which has different dependencies. Signed-off-by: Henning Schild Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/leds/simple/Kconfig | 7 +- drivers/leds/simple/Makefile | 1 + drivers/leds/simple/simatic-ipc-leds-gpio.c | 105 ++++++++++++++++++++ drivers/leds/simple/simatic-ipc-leds.c | 80 +-------------- drivers/platform/x86/simatic-ipc.c | 5 +- 5 files changed, 117 insertions(+), 81 deletions(-) create mode 100644 drivers/leds/simple/simatic-ipc-leds-gpio.c diff --git a/drivers/leds/simple/Kconfig b/drivers/leds/simple/Kconfig index bbf8cff3c3f6..fd2b8225d926 100644 --- a/drivers/leds/simple/Kconfig +++ b/drivers/leds/simple/Kconfig @@ -1,12 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only config LEDS_SIEMENS_SIMATIC_IPC tristate "LED driver for Siemens Simatic IPCs" - depends on LEDS_CLASS + depends on LEDS_GPIO depends on SIEMENS_SIMATIC_IPC - select P2SB help This option enables support for the LEDs of several Industrial PCs from Siemens. - To compile this driver as a module, choose M here: the module - will be called simatic-ipc-leds. + To compile this driver as a module, choose M here: the modules + will be called simatic-ipc-leds and simatic-ipc-leds-gpio. diff --git a/drivers/leds/simple/Makefile b/drivers/leds/simple/Makefile index 8481f1e9e360..1c7ef5e1324b 100644 --- a/drivers/leds/simple/Makefile +++ b/drivers/leds/simple/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds.o +obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds-gpio.o diff --git a/drivers/leds/simple/simatic-ipc-leds-gpio.c b/drivers/leds/simple/simatic-ipc-leds-gpio.c new file mode 100644 index 000000000000..4c9e663a90ba --- /dev/null +++ b/drivers/leds/simple/simatic-ipc-leds-gpio.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Siemens SIMATIC IPC driver for GPIO based LEDs + * + * Copyright (c) Siemens AG, 2022 + * + * Authors: + * Henning Schild + */ + +#include +#include +#include +#include +#include + +static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { + .dev_id = "leds-gpio", + .table = { + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 51, NULL, 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 52, NULL, 1, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 53, NULL, 2, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 57, NULL, 3, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 58, NULL, 4, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 60, NULL, 5, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 56, NULL, 6, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 59, NULL, 7, GPIO_ACTIVE_HIGH), + }, +}; + +static const struct gpio_led simatic_ipc_gpio_leds[] = { + { .name = "green:" LED_FUNCTION_STATUS "-3" }, + { .name = "red:" LED_FUNCTION_STATUS "-1" }, + { .name = "green:" LED_FUNCTION_STATUS "-1" }, + { .name = "red:" LED_FUNCTION_STATUS "-2" }, + { .name = "green:" LED_FUNCTION_STATUS "-2" }, + { .name = "red:" LED_FUNCTION_STATUS "-3" }, +}; + +static const struct gpio_led_platform_data simatic_ipc_gpio_leds_pdata = { + .num_leds = ARRAY_SIZE(simatic_ipc_gpio_leds), + .leds = simatic_ipc_gpio_leds, +}; + +static struct platform_device *simatic_leds_pdev; + +static int simatic_ipc_leds_gpio_remove(struct platform_device *pdev) +{ + gpiod_remove_lookup_table(&simatic_ipc_led_gpio_table); + platform_device_unregister(simatic_leds_pdev); + + return 0; +} + +static int simatic_ipc_leds_gpio_probe(struct platform_device *pdev) +{ + struct gpio_desc *gpiod; + int err; + + gpiod_add_lookup_table(&simatic_ipc_led_gpio_table); + simatic_leds_pdev = platform_device_register_resndata(NULL, + "leds-gpio", PLATFORM_DEVID_NONE, NULL, 0, + &simatic_ipc_gpio_leds_pdata, + sizeof(simatic_ipc_gpio_leds_pdata)); + if (IS_ERR(simatic_leds_pdev)) { + err = PTR_ERR(simatic_leds_pdev); + goto out; + } + + /* PM_BIOS_BOOT_N */ + gpiod = gpiod_get_index(&simatic_leds_pdev->dev, NULL, 6, GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + err = PTR_ERR(gpiod); + goto out; + } + gpiod_put(gpiod); + + /* PM_WDT_OUT */ + gpiod = gpiod_get_index(&simatic_leds_pdev->dev, NULL, 7, GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + err = PTR_ERR(gpiod); + goto out; + } + gpiod_put(gpiod); + + return 0; +out: + simatic_ipc_leds_gpio_remove(pdev); + + return err; +} + +static struct platform_driver simatic_ipc_led_gpio_driver = { + .probe = simatic_ipc_leds_gpio_probe, + .remove = simatic_ipc_leds_gpio_remove, + .driver = { + .name = KBUILD_MODNAME, + } +}; +module_platform_driver(simatic_ipc_led_gpio_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" KBUILD_MODNAME); +MODULE_SOFTDEP("pre: platform:leds-gpio"); +MODULE_AUTHOR("Henning Schild "); diff --git a/drivers/leds/simple/simatic-ipc-leds.c b/drivers/leds/simple/simatic-ipc-leds.c index 2e7597c143d8..4894c228c165 100644 --- a/drivers/leds/simple/simatic-ipc-leds.c +++ b/drivers/leds/simple/simatic-ipc-leds.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -24,7 +23,7 @@ #define SIMATIC_IPC_LED_PORT_BASE 0x404E struct simatic_ipc_led { - unsigned int value; /* mask for io and offset for mem */ + unsigned int value; /* mask for io */ char *name; struct led_classdev cdev; }; @@ -39,21 +38,6 @@ static struct simatic_ipc_led simatic_ipc_leds_io[] = { { } }; -/* the actual start will be discovered with p2sb, 0 is a placeholder */ -static struct resource simatic_ipc_led_mem_res = DEFINE_RES_MEM_NAMED(0, 0, KBUILD_MODNAME); - -static void __iomem *simatic_ipc_led_memory; - -static struct simatic_ipc_led simatic_ipc_leds_mem[] = { - {0x500 + 0x1A0, "red:" LED_FUNCTION_STATUS "-1"}, - {0x500 + 0x1A8, "green:" LED_FUNCTION_STATUS "-1"}, - {0x500 + 0x1C8, "red:" LED_FUNCTION_STATUS "-2"}, - {0x500 + 0x1D0, "green:" LED_FUNCTION_STATUS "-2"}, - {0x500 + 0x1E0, "red:" LED_FUNCTION_STATUS "-3"}, - {0x500 + 0x198, "green:" LED_FUNCTION_STATUS "-3"}, - { } -}; - static struct resource simatic_ipc_led_io_res = DEFINE_RES_IO_NAMED(SIMATIC_IPC_LED_PORT_BASE, SZ_2, KBUILD_MODNAME); @@ -89,28 +73,6 @@ static enum led_brightness simatic_ipc_led_get_io(struct led_classdev *led_cd) return inw(SIMATIC_IPC_LED_PORT_BASE) & led->value ? LED_OFF : led_cd->max_brightness; } -static void simatic_ipc_led_set_mem(struct led_classdev *led_cd, - enum led_brightness brightness) -{ - struct simatic_ipc_led *led = cdev_to_led(led_cd); - void __iomem *reg = simatic_ipc_led_memory + led->value; - u32 val; - - val = readl(reg); - val = (val & ~1) | (brightness == LED_OFF); - writel(val, reg); -} - -static enum led_brightness simatic_ipc_led_get_mem(struct led_classdev *led_cd) -{ - struct simatic_ipc_led *led = cdev_to_led(led_cd); - void __iomem *reg = simatic_ipc_led_memory + led->value; - u32 val; - - val = readl(reg); - return (val & 1) ? LED_OFF : led_cd->max_brightness; -} - static int simatic_ipc_leds_probe(struct platform_device *pdev) { const struct simatic_ipc_platform *plat = pdev->dev.platform_data; @@ -118,9 +80,7 @@ static int simatic_ipc_leds_probe(struct platform_device *pdev) struct simatic_ipc_led *ipcled; struct led_classdev *cdev; struct resource *res; - void __iomem *reg; - int err, type; - u32 val; + int err; switch (plat->devmode) { case SIMATIC_IPC_DEVICE_227D: @@ -135,51 +95,19 @@ static int simatic_ipc_leds_probe(struct platform_device *pdev) } ipcled = simatic_ipc_leds_io; } - type = IORESOURCE_IO; if (!devm_request_region(dev, res->start, resource_size(res), KBUILD_MODNAME)) { dev_err(dev, "Unable to register IO resource at %pR\n", res); return -EBUSY; } break; - case SIMATIC_IPC_DEVICE_127E: - res = &simatic_ipc_led_mem_res; - ipcled = simatic_ipc_leds_mem; - type = IORESOURCE_MEM; - - err = p2sb_bar(NULL, 0, res); - if (err) - return err; - - /* do the final address calculation */ - res->start = res->start + (0xC5 << 16); - res->end = res->start + SZ_4K - 1; - - simatic_ipc_led_memory = devm_ioremap_resource(dev, res); - if (IS_ERR(simatic_ipc_led_memory)) - return PTR_ERR(simatic_ipc_led_memory); - - /* initialize power/watchdog LED */ - reg = simatic_ipc_led_memory + 0x500 + 0x1D8; /* PM_WDT_OUT */ - val = readl(reg); - writel(val & ~1, reg); - - reg = simatic_ipc_led_memory + 0x500 + 0x1C0; /* PM_BIOS_BOOT_N */ - val = readl(reg); - writel(val | 1, reg); - break; default: return -ENODEV; } while (ipcled->value) { cdev = &ipcled->cdev; - if (type == IORESOURCE_MEM) { - cdev->brightness_set = simatic_ipc_led_set_mem; - cdev->brightness_get = simatic_ipc_led_get_mem; - } else { - cdev->brightness_set = simatic_ipc_led_set_io; - cdev->brightness_get = simatic_ipc_led_get_io; - } + cdev->brightness_set = simatic_ipc_led_set_io; + cdev->brightness_get = simatic_ipc_led_get_io; cdev->max_brightness = LED_ON; cdev->name = ipcled->name; diff --git a/drivers/platform/x86/simatic-ipc.c b/drivers/platform/x86/simatic-ipc.c index 26c35e1660cb..ca3647b751d5 100644 --- a/drivers/platform/x86/simatic-ipc.c +++ b/drivers/platform/x86/simatic-ipc.c @@ -51,6 +51,7 @@ static int register_platform_devices(u32 station_id) { u8 ledmode = SIMATIC_IPC_DEVICE_NONE; u8 wdtmode = SIMATIC_IPC_DEVICE_NONE; + char *pdevname = KBUILD_MODNAME "_leds"; int i; platform_data.devmode = SIMATIC_IPC_DEVICE_NONE; @@ -64,10 +65,12 @@ static int register_platform_devices(u32 station_id) } if (ledmode != SIMATIC_IPC_DEVICE_NONE) { + if (ledmode == SIMATIC_IPC_DEVICE_127E) + pdevname = KBUILD_MODNAME "_leds_gpio"; platform_data.devmode = ledmode; ipc_led_platform_device = platform_device_register_data(NULL, - KBUILD_MODNAME "_leds", PLATFORM_DEVID_NONE, + pdevname, PLATFORM_DEVID_NONE, &platform_data, sizeof(struct simatic_ipc_platform)); if (IS_ERR(ipc_led_platform_device)) From f39b6c58d8550ddcbd9907fd0818990d0be384c4 Mon Sep 17 00:00:00 2001 From: Binyi Han Date: Wed, 13 Jul 2022 00:59:25 -0700 Subject: [PATCH 1028/1436] staging: qlge: Fix indentation issue under long for loop Fix indentation issue to adhere to Linux kernel coding style, issue found by checkpatch. And change the long for loop into 3 lines. Signed-off-by: Binyi Han Link: https://lore.kernel.org/r/4e18dabcce7f589386a33ceed59096aa049779f0.1657697683.git.dantengknight@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/qlge/qlge_main.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c index 1a378330d775..5209456edc39 100644 --- a/drivers/staging/qlge/qlge_main.c +++ b/drivers/staging/qlge/qlge_main.c @@ -3007,10 +3007,11 @@ static int qlge_start_rx_ring(struct qlge_adapter *qdev, struct rx_ring *rx_ring tmp = (u64)rx_ring->lbq.base_dma; base_indirect_ptr = rx_ring->lbq.base_indirect; - for (page_entries = 0; page_entries < - MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN); page_entries++) - base_indirect_ptr[page_entries] = - cpu_to_le64(tmp + (page_entries * DB_PAGE_SIZE)); + for (page_entries = 0; + page_entries < MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN); + page_entries++) + base_indirect_ptr[page_entries] = + cpu_to_le64(tmp + (page_entries * DB_PAGE_SIZE)); cqicb->lbq_addr = cpu_to_le64(rx_ring->lbq.base_indirect_dma); cqicb->lbq_buf_size = cpu_to_le16(QLGE_FIT16(qdev->lbq_buf_size)); @@ -3022,10 +3023,11 @@ static int qlge_start_rx_ring(struct qlge_adapter *qdev, struct rx_ring *rx_ring tmp = (u64)rx_ring->sbq.base_dma; base_indirect_ptr = rx_ring->sbq.base_indirect; - for (page_entries = 0; page_entries < - MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN); page_entries++) - base_indirect_ptr[page_entries] = - cpu_to_le64(tmp + (page_entries * DB_PAGE_SIZE)); + for (page_entries = 0; + page_entries < MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN); + page_entries++) + base_indirect_ptr[page_entries] = + cpu_to_le64(tmp + (page_entries * DB_PAGE_SIZE)); cqicb->sbq_addr = cpu_to_le64(rx_ring->sbq.base_indirect_dma); cqicb->sbq_buf_size = cpu_to_le16(SMALL_BUFFER_SIZE); From 4cdb845db3217091737159908fcba1f643d818a1 Mon Sep 17 00:00:00 2001 From: Binyi Han Date: Wed, 13 Jul 2022 01:00:23 -0700 Subject: [PATCH 1029/1436] staging: qlge: Avoid multiplication while keep the same logic Avoid the more expensive multiplication while keep the same logic. Signed-off-by: Binyi Han Link: https://lore.kernel.org/r/31fe21bf4a9e8f13cf27bd50073e9d5d197654ea.1657697683.git.dantengknight@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/qlge/qlge_main.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c index 5209456edc39..4b166c66cfc5 100644 --- a/drivers/staging/qlge/qlge_main.c +++ b/drivers/staging/qlge/qlge_main.c @@ -3009,9 +3009,10 @@ static int qlge_start_rx_ring(struct qlge_adapter *qdev, struct rx_ring *rx_ring for (page_entries = 0; page_entries < MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN); - page_entries++) - base_indirect_ptr[page_entries] = - cpu_to_le64(tmp + (page_entries * DB_PAGE_SIZE)); + page_entries++) { + base_indirect_ptr[page_entries] = cpu_to_le64(tmp); + tmp += DB_PAGE_SIZE; + } cqicb->lbq_addr = cpu_to_le64(rx_ring->lbq.base_indirect_dma); cqicb->lbq_buf_size = cpu_to_le16(QLGE_FIT16(qdev->lbq_buf_size)); @@ -3025,9 +3026,10 @@ static int qlge_start_rx_ring(struct qlge_adapter *qdev, struct rx_ring *rx_ring for (page_entries = 0; page_entries < MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN); - page_entries++) - base_indirect_ptr[page_entries] = - cpu_to_le64(tmp + (page_entries * DB_PAGE_SIZE)); + page_entries++) { + base_indirect_ptr[page_entries] = cpu_to_le64(tmp); + tmp += DB_PAGE_SIZE; + } cqicb->sbq_addr = cpu_to_le64(rx_ring->sbq.base_indirect_dma); cqicb->sbq_buf_size = cpu_to_le16(SMALL_BUFFER_SIZE); From c1da5a7befa82c01e06c8ec2059bdc9ed422033b Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Wed, 13 Jul 2022 09:58:04 +0200 Subject: [PATCH 1030/1436] staging: r888eu: use dynamic allocation for efuse buffer Use kmalloc to allocate the efuse buffer in ReadAdapterInfo8188EU and free it on exit. This is better than using a 512 byte array on the stack. It's ok to drop the __aligned(4) qualifier. kmalloc aligns to ARCH_KMALLOC_MINALIGN, this is at least 8 bytes. Suggested-by: Dan Carpenter Suggested-by: Larry Finger Acked-by: Larry Finger Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220713075804.140986-1-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/usb_halinit.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 68d012a442a8..695424bbecfc 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -927,7 +927,7 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) { struct eeprom_priv *eeprom = &Adapter->eeprompriv; struct led_priv *ledpriv = &Adapter->ledpriv; - u8 efuse_buf[EFUSE_MAP_LEN_88E] __aligned(4); + u8 *efuse_buf; u8 eeValue; int res; @@ -938,7 +938,10 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) eeprom->bautoload_fail_flag = !(eeValue & EEPROM_EN); - memset(efuse_buf, 0xFF, sizeof(efuse_buf)); + efuse_buf = kmalloc(EFUSE_MAP_LEN_88E, GFP_KERNEL); + if (!efuse_buf) + return; + memset(efuse_buf, 0xFF, EFUSE_MAP_LEN_88E); if (!(eeValue & BOOT_FROM_EEPROM) && !eeprom->bautoload_fail_flag) { rtl8188e_EfusePowerSwitch(Adapter, true); @@ -958,6 +961,7 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) Hal_ReadThermalMeter_88E(Adapter, efuse_buf, eeprom->bautoload_fail_flag); ledpriv->bRegUseLed = true; + kfree(efuse_buf); } static void ResumeTxBeacon(struct adapter *adapt) From 724933e37a90cfbaafc8d9e52d15fafc311cc6f2 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Wed, 13 Jul 2022 09:55:52 +0200 Subject: [PATCH 1031/1436] staging: r8188eu: fall back to random mac address Call eth_random_addr to generate a random mac address if we cannot load the mac address from the efuses. Do not use a constant mac address as fallback. This may create conflicts if we have several r8188eu devices on the network. Suggested-by: Joe Perches Tested-by: Philipp Hortmann # Edimax N150 Reviewed-by: Pavel Skripkin Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220713075552.140927-1-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/usb_halinit.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 695424bbecfc..421fe7c40390 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -912,11 +912,10 @@ exit: static void Hal_EfuseParseMACAddr_8188EU(struct adapter *adapt, u8 *hwinfo, bool AutoLoadFail) { - u8 sMacAddr[6] = {0x00, 0xE0, 0x4C, 0x81, 0x88, 0x02}; struct eeprom_priv *eeprom = &adapt->eeprompriv; if (AutoLoadFail) { - memcpy(eeprom->mac_addr, sMacAddr, ETH_ALEN); + eth_random_addr(eeprom->mac_addr); } else { /* Read Permanent MAC address */ memcpy(eeprom->mac_addr, &hwinfo[EEPROM_MAC_ADDR_88EU], ETH_ALEN); From 186c46008c9d563facd247e2d97d00a044a5870e Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 06:58:56 +0200 Subject: [PATCH 1032/1436] staging: vt6655: Rename byRegOfs to reg_offset in four macros Fix name of a variable in four macros that use CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/82f65d22ac8cd75b2c7790c13be3d0068968925b.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 5c14a76ed799..b3803143673c 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -537,32 +537,32 @@ /*--------------------- Export Macros ------------------------------*/ -#define MACvRegBitsOn(iobase, byRegOfs, byBits) \ +#define MACvRegBitsOn(iobase, reg_offset, byBits) \ do { \ unsigned char byData; \ - byData = ioread8(iobase + byRegOfs); \ - iowrite8(byData | (byBits), iobase + byRegOfs); \ + byData = ioread8(iobase + reg_offset); \ + iowrite8(byData | (byBits), iobase + reg_offset); \ } while (0) -#define MACvWordRegBitsOn(iobase, byRegOfs, wBits) \ +#define MACvWordRegBitsOn(iobase, reg_offset, wBits) \ do { \ unsigned short wData; \ - wData = ioread16(iobase + byRegOfs); \ - iowrite16(wData | (wBits), iobase + byRegOfs); \ + wData = ioread16(iobase + reg_offset); \ + iowrite16(wData | (wBits), iobase + reg_offset); \ } while (0) -#define MACvRegBitsOff(iobase, byRegOfs, byBits) \ +#define MACvRegBitsOff(iobase, reg_offset, byBits) \ do { \ unsigned char byData; \ - byData = ioread8(iobase + byRegOfs); \ - iowrite8(byData & ~(byBits), iobase + byRegOfs); \ + byData = ioread8(iobase + reg_offset); \ + iowrite8(byData & ~(byBits), iobase + reg_offset); \ } while (0) -#define MACvWordRegBitsOff(iobase, byRegOfs, wBits) \ +#define MACvWordRegBitsOff(iobase, reg_offset, wBits) \ do { \ unsigned short wData; \ - wData = ioread16(iobase + byRegOfs); \ - iowrite16(wData & ~(wBits), iobase + byRegOfs); \ + wData = ioread16(iobase + reg_offset); \ + iowrite16(wData & ~(wBits), iobase + reg_offset); \ } while (0) #define MACvReceive0(iobase) \ From 10ff399bf600d371929f0dc20148986aac03b872 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 06:59:18 +0200 Subject: [PATCH 1033/1436] staging: vt6655: Rename byBits to bit_mask in two macros Fix name of a variable in two macros that use CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/5ac7e8860ecb23232cf5befea024872e7db76d59.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index b3803143673c..3037502c1883 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -537,11 +537,11 @@ /*--------------------- Export Macros ------------------------------*/ -#define MACvRegBitsOn(iobase, reg_offset, byBits) \ +#define MACvRegBitsOn(iobase, reg_offset, bit_mask) \ do { \ unsigned char byData; \ byData = ioread8(iobase + reg_offset); \ - iowrite8(byData | (byBits), iobase + reg_offset); \ + iowrite8(byData | (bit_mask), iobase + reg_offset); \ } while (0) #define MACvWordRegBitsOn(iobase, reg_offset, wBits) \ @@ -551,11 +551,11 @@ do { \ iowrite16(wData | (wBits), iobase + reg_offset); \ } while (0) -#define MACvRegBitsOff(iobase, reg_offset, byBits) \ +#define MACvRegBitsOff(iobase, reg_offset, bit_mask) \ do { \ unsigned char byData; \ byData = ioread8(iobase + reg_offset); \ - iowrite8(byData & ~(byBits), iobase + reg_offset); \ + iowrite8(byData & ~(bit_mask), iobase + reg_offset); \ } while (0) #define MACvWordRegBitsOff(iobase, reg_offset, wBits) \ From 5bd643b197ffbd039951a9475d8f887ec3f2beb6 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 06:59:38 +0200 Subject: [PATCH 1034/1436] staging: vt6655: Rename wBits to bit_mask in two macros Fix name of a variable in two macros that use CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/8929407dc7355df515b7f9fdd195b45ff44f6b98.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 3037502c1883..b8f543aef716 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -544,11 +544,11 @@ do { \ iowrite8(byData | (bit_mask), iobase + reg_offset); \ } while (0) -#define MACvWordRegBitsOn(iobase, reg_offset, wBits) \ +#define MACvWordRegBitsOn(iobase, reg_offset, bit_mask) \ do { \ unsigned short wData; \ wData = ioread16(iobase + reg_offset); \ - iowrite16(wData | (wBits), iobase + reg_offset); \ + iowrite16(wData | (bit_mask), iobase + reg_offset); \ } while (0) #define MACvRegBitsOff(iobase, reg_offset, bit_mask) \ @@ -558,11 +558,11 @@ do { \ iowrite8(byData & ~(bit_mask), iobase + reg_offset); \ } while (0) -#define MACvWordRegBitsOff(iobase, reg_offset, wBits) \ +#define MACvWordRegBitsOff(iobase, reg_offset, bit_mask) \ do { \ unsigned short wData; \ wData = ioread16(iobase + reg_offset); \ - iowrite16(wData & ~(wBits), iobase + reg_offset); \ + iowrite16(wData & ~(bit_mask), iobase + reg_offset); \ } while (0) #define MACvReceive0(iobase) \ From d57561d9609e0946ee2bcf9cafcce665095d0f91 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 06:59:58 +0200 Subject: [PATCH 1035/1436] staging: vt6655: Rename byData to reg_value in two macros Fix name of a variable in two macros that use CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/159014866cce40913d360a0692fb3c426d4cb840.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index b8f543aef716..16c18a1ed22e 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -539,9 +539,9 @@ #define MACvRegBitsOn(iobase, reg_offset, bit_mask) \ do { \ - unsigned char byData; \ - byData = ioread8(iobase + reg_offset); \ - iowrite8(byData | (bit_mask), iobase + reg_offset); \ + unsigned char reg_value; \ + reg_value = ioread8(iobase + reg_offset); \ + iowrite8(reg_value | (bit_mask), iobase + reg_offset); \ } while (0) #define MACvWordRegBitsOn(iobase, reg_offset, bit_mask) \ @@ -553,9 +553,9 @@ do { \ #define MACvRegBitsOff(iobase, reg_offset, bit_mask) \ do { \ - unsigned char byData; \ - byData = ioread8(iobase + reg_offset); \ - iowrite8(byData & ~(bit_mask), iobase + reg_offset); \ + unsigned char reg_value; \ + reg_value = ioread8(iobase + reg_offset); \ + iowrite8(reg_value & ~(bit_mask), iobase + reg_offset); \ } while (0) #define MACvWordRegBitsOff(iobase, reg_offset, bit_mask) \ From ee9aded6d39a3d78eb832a5eef0bf31286332e03 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 07:00:12 +0200 Subject: [PATCH 1036/1436] staging: vt6655: Rename wData to reg_value in two macros Fix name of a variable in two macros that use CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/8f2e9451a24e380c997fcf7c87249f7ed9b66787.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 16c18a1ed22e..2a31c94156b2 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -546,9 +546,9 @@ do { \ #define MACvWordRegBitsOn(iobase, reg_offset, bit_mask) \ do { \ - unsigned short wData; \ - wData = ioread16(iobase + reg_offset); \ - iowrite16(wData | (bit_mask), iobase + reg_offset); \ + unsigned short reg_value; \ + reg_value = ioread16(iobase + reg_offset); \ + iowrite16(reg_value | (bit_mask), iobase + reg_offset); \ } while (0) #define MACvRegBitsOff(iobase, reg_offset, bit_mask) \ @@ -560,9 +560,9 @@ do { \ #define MACvWordRegBitsOff(iobase, reg_offset, bit_mask) \ do { \ - unsigned short wData; \ - wData = ioread16(iobase + reg_offset); \ - iowrite16(wData & ~(bit_mask), iobase + reg_offset); \ + unsigned short reg_value; \ + reg_value = ioread16(iobase + reg_offset); \ + iowrite16(reg_value & ~(bit_mask), iobase + reg_offset); \ } while (0) #define MACvReceive0(iobase) \ From 67ec557644db7643a4dd14c3068f01f5c729d62b Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 07:00:40 +0200 Subject: [PATCH 1037/1436] staging: vt6655: Rename MACvRegBitsOn Fix name of a macro that uses CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/7fb9627441ff97897d132c62d59676355b6d14ea.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/baseband.c | 8 ++++---- drivers/staging/vt6655/card.c | 14 ++++++-------- drivers/staging/vt6655/channel.c | 2 +- drivers/staging/vt6655/device_main.c | 9 ++++----- drivers/staging/vt6655/mac.h | 2 +- drivers/staging/vt6655/power.c | 15 +++++++-------- drivers/staging/vt6655/rxtx.c | 2 +- 7 files changed, 24 insertions(+), 28 deletions(-) diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c index a5412ca0ea68..5de841cb776c 100644 --- a/drivers/staging/vt6655/baseband.c +++ b/drivers/staging/vt6655/baseband.c @@ -1912,7 +1912,7 @@ bool bb_read_embedded(struct vnt_private *priv, unsigned char by_bb_addr, iowrite8(by_bb_addr, iobase + MAC_REG_BBREGADR); /* turn on REGR */ - MACvRegBitsOn(iobase, MAC_REG_BBREGCTL, BBREGCTL_REGR); + vt6655_mac_reg_bits_on(iobase, MAC_REG_BBREGCTL, BBREGCTL_REGR); /* W_MAX_TIMEOUT is the timeout period */ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { by_value = ioread8(iobase + MAC_REG_BBREGCTL); @@ -1957,7 +1957,7 @@ bool bb_write_embedded(struct vnt_private *priv, unsigned char by_bb_addr, iowrite8(by_data, iobase + MAC_REG_BBREGDATA); /* turn on BBREGCTL_REGW */ - MACvRegBitsOn(iobase, MAC_REG_BBREGCTL, BBREGCTL_REGW); + vt6655_mac_reg_bits_on(iobase, MAC_REG_BBREGCTL, BBREGCTL_REGW); /* W_MAX_TIMEOUT is the timeout period */ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { by_value = ioread8(iobase + MAC_REG_BBREGCTL); @@ -2014,7 +2014,7 @@ bool bb_vt3253_init(struct vnt_private *priv) byVT3253B0_AGC4_RFMD2959[ii][1]); iowrite32(0x23, iobase + MAC_REG_ITRTMSET); - MACvRegBitsOn(iobase, MAC_REG_PAPEDELAY, BIT(0)); + vt6655_mac_reg_bits_on(iobase, MAC_REG_PAPEDELAY, BIT(0)); } priv->abyBBVGA[0] = 0x18; priv->abyBBVGA[1] = 0x0A; @@ -2054,7 +2054,7 @@ bool bb_vt3253_init(struct vnt_private *priv) byVT3253B0_AGC[ii][1]); iowrite8(0x23, iobase + MAC_REG_ITRTMSET); - MACvRegBitsOn(iobase, MAC_REG_PAPEDELAY, BIT(0)); + vt6655_mac_reg_bits_on(iobase, MAC_REG_PAPEDELAY, BIT(0)); priv->abyBBVGA[0] = 0x14; priv->abyBBVGA[1] = 0x0A; diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 3380c7604e84..220b47106855 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -296,8 +296,7 @@ bool CARDbUpdateTSF(struct vnt_private *priv, unsigned char byRxRate, qwTSFOffset = le64_to_cpu(qwTSFOffset); iowrite32((u32)qwTSFOffset, priv->port_offset + MAC_REG_TSFOFST); iowrite32((u32)(qwTSFOffset >> 32), priv->port_offset + MAC_REG_TSFOFST + 4); - MACvRegBitsOn(priv->port_offset, MAC_REG_TFTCTL, - TFTCTL_TSFSYNCEN); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_TSFSYNCEN); } return true; } @@ -331,7 +330,7 @@ bool CARDbSetBeaconPeriod(struct vnt_private *priv, qwNextTBTT = le64_to_cpu(qwNextTBTT); iowrite32((u32)qwNextTBTT, priv->port_offset + MAC_REG_NEXTTBTT); iowrite32((u32)(qwNextTBTT >> 32), priv->port_offset + MAC_REG_NEXTTBTT + 4); - MACvRegBitsOn(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); return true; } @@ -374,8 +373,7 @@ void CARDbRadioPowerOff(struct vnt_private *priv) priv->radio_off = true; pr_debug("chester power off\n"); - MACvRegBitsOn(priv->port_offset, MAC_REG_GPIOCTL0, - LED_ACTSET); /* LED issue */ + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_GPIOCTL0, LED_ACTSET); /* LED issue */ } void CARDvSafeResetTx(struct vnt_private *priv) @@ -734,7 +732,7 @@ u64 vt6655_get_current_tsf(struct vnt_private *priv) unsigned char data; u32 low, high; - MACvRegBitsOn(iobase, MAC_REG_TFTCTL, TFTCTL_TSFCNTRRD); + vt6655_mac_reg_bits_on(iobase, MAC_REG_TFTCTL, TFTCTL_TSFCNTRRD); for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { data = ioread8(iobase + MAC_REG_TFTCTL); if (!(data & TFTCTL_TSFCNTRRD)) @@ -800,7 +798,7 @@ void CARDvSetFirstNextTBTT(struct vnt_private *priv, qwNextTBTT = le64_to_cpu(qwNextTBTT); iowrite32((u32)qwNextTBTT, iobase + MAC_REG_NEXTTBTT); iowrite32((u32)(qwNextTBTT >> 32), iobase + MAC_REG_NEXTTBTT + 4); - MACvRegBitsOn(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); + vt6655_mac_reg_bits_on(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); } /* @@ -827,6 +825,6 @@ void CARDvUpdateNextTBTT(struct vnt_private *priv, u64 qwTSF, qwTSF = le64_to_cpu(qwTSF); iowrite32((u32)qwTSF, iobase + MAC_REG_NEXTTBTT); iowrite32((u32)(qwTSF >> 32), iobase + MAC_REG_NEXTTBTT + 4); - MACvRegBitsOn(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); + vt6655_mac_reg_bits_on(iobase, MAC_REG_TFTCTL, TFTCTL_TBTTSYNCEN); pr_debug("Card:Update Next TBTT[%8llx]\n", qwTSF); } diff --git a/drivers/staging/vt6655/channel.c b/drivers/staging/vt6655/channel.c index 652dcaf61169..e926f9829a15 100644 --- a/drivers/staging/vt6655/channel.c +++ b/drivers/staging/vt6655/channel.c @@ -94,7 +94,7 @@ bool set_channel(struct vnt_private *priv, struct ieee80211_channel *ch) } /* clear NAV */ - MACvRegBitsOn(priv->port_offset, MAC_REG_MACCR, MACCR_CLRNAV); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_MACCR, MACCR_CLRNAV); /* TX_PE will reserve 3 us for MAX2829 A mode only, * it is for better TX throughput diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 19840dddb4bf..1a202e5fa39f 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -417,7 +417,7 @@ static void device_init_registers(struct vnt_private *priv) CARDvSafeResetTx(priv); if (priv->local_id <= REV_ID_VT3253_A1) - MACvRegBitsOn(priv->port_offset, MAC_REG_RCR, RCR_WPAERR); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_RCR, RCR_WPAERR); /* Turn On Rx DMA */ MACvReceive0(priv->port_offset); @@ -1324,13 +1324,13 @@ static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) case NL80211_IFTYPE_ADHOC: MACvRegBitsOff(priv->port_offset, MAC_REG_RCR, RCR_UNICAST); - MACvRegBitsOn(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_ADHOC); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_ADHOC); break; case NL80211_IFTYPE_AP: MACvRegBitsOff(priv->port_offset, MAC_REG_RCR, RCR_UNICAST); - MACvRegBitsOn(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_AP); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_AP); break; default: @@ -1476,8 +1476,7 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, if (conf->enable_beacon) { vnt_beacon_enable(priv, vif, conf); - MACvRegBitsOn(priv->port_offset, MAC_REG_TCR, - TCR_AUTOBCNTX); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); } else { MACvRegBitsOff(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 2a31c94156b2..4e15174ca2ee 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -537,7 +537,7 @@ /*--------------------- Export Macros ------------------------------*/ -#define MACvRegBitsOn(iobase, reg_offset, bit_mask) \ +#define vt6655_mac_reg_bits_on(iobase, reg_offset, bit_mask) \ do { \ unsigned char reg_value; \ reg_value = ioread8(iobase + reg_offset); \ diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c index 0bd2ddc61648..c8a456305e1d 100644 --- a/drivers/staging/vt6655/power.c +++ b/drivers/staging/vt6655/power.c @@ -59,23 +59,23 @@ void PSvEnablePowerSaving(struct vnt_private *priv, } /* Set AutoSleep */ - MACvRegBitsOn(priv->port_offset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); /* Set HWUTSF */ - MACvRegBitsOn(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_HWUTSF); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_HWUTSF); if (wListenInterval >= 2) { /* clear always listen beacon */ MACvRegBitsOff(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); /* first time set listen next beacon */ - MACvRegBitsOn(priv->port_offset, MAC_REG_PSCTL, PSCTL_LNBCN); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_LNBCN); } else { /* always listen beacon */ - MACvRegBitsOn(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); } /* enable power saving hw function */ - MACvRegBitsOn(priv->port_offset, MAC_REG_PSCTL, PSCTL_PSEN); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_PSEN); priv->bEnablePSMode = true; priv->bPWBitOn = true; @@ -104,7 +104,7 @@ void PSvDisablePowerSaving(struct vnt_private *priv) MACvRegBitsOff(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_HWUTSF); /* set always listen beacon */ - MACvRegBitsOn(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); priv->bEnablePSMode = false; @@ -135,8 +135,7 @@ bool PSbIsNextTBTTWakeUp(struct vnt_private *priv) if (priv->wake_up_count == 1) { /* Turn on wake up to listen next beacon */ - MACvRegBitsOn(priv->port_offset, - MAC_REG_PSCTL, PSCTL_LNBCN); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_LNBCN); wake_up = true; } } diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 736681274296..537f54cf23c2 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1424,7 +1424,7 @@ static int vnt_beacon_xmit(struct vnt_private *priv, iowrite16(priv->wBCNBufLen, priv->port_offset + MAC_REG_BCNDMACTL + 2); /* Set auto Transmit on */ - MACvRegBitsOn(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); + vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); /* Poll Transmit the adapter */ iowrite8(BEACON_READY, priv->port_offset + MAC_REG_BCNDMACTL); From ee67fe63b415caf0a367652399eae2e51bfe2e1a Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 07:00:25 +0200 Subject: [PATCH 1038/1436] staging: vt6655: Rename MACvWordRegBitsOn Fix name of a macro that uses CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/b3873e1103d642a804d42c945dc0c73d94b0c1cf.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/card.c | 4 ++-- drivers/staging/vt6655/device_main.c | 4 ++-- drivers/staging/vt6655/mac.h | 4 ++-- drivers/staging/vt6655/rf.c | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 220b47106855..54a12c97aa16 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -354,8 +354,8 @@ void CARDbRadioPowerOff(struct vnt_private *priv) case RF_RFMD2959: MACvWordRegBitsOff(priv->port_offset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_TXPEINV); - MACvWordRegBitsOn(priv->port_offset, MAC_REG_SOFTPWRCTL, - SOFTPWRCTL_SWPE1); + vt6655_mac_word_reg_bits_on(priv->port_offset, MAC_REG_SOFTPWRCTL, + SOFTPWRCTL_SWPE1); break; case RF_AIROHA: diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 1a202e5fa39f..bcf35a89730e 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -359,8 +359,8 @@ static void device_init_registers(struct vnt_private *priv) } /* use relative tx timeout and 802.11i D4 */ - MACvWordRegBitsOn(priv->port_offset, - MAC_REG_CFG, (CFG_TKIPOPT | CFG_NOTXTIMEOUT)); + vt6655_mac_word_reg_bits_on(priv->port_offset, MAC_REG_CFG, + (CFG_TKIPOPT | CFG_NOTXTIMEOUT)); /* set performance parameter by registry */ MACvSetShortRetryLimit(priv, priv->byShortRetryLimit); diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 4e15174ca2ee..3303b9ba3bee 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -544,7 +544,7 @@ do { \ iowrite8(reg_value | (bit_mask), iobase + reg_offset); \ } while (0) -#define MACvWordRegBitsOn(iobase, reg_offset, bit_mask) \ +#define vt6655_mac_word_reg_bits_on(iobase, reg_offset, bit_mask) \ do { \ unsigned short reg_value; \ reg_value = ioread16(iobase + reg_offset); \ @@ -661,7 +661,7 @@ do { \ } while (0) #define MACvSetRFLE_LatchBase(iobase) \ - MACvWordRegBitsOn(iobase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_RFLEOPT) + vt6655_mac_word_reg_bits_on(iobase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_RFLEOPT) #define MAKEWORD(lb, hb) \ ((unsigned short)(((unsigned char)(lb)) | (((unsigned short)((unsigned char)(hb))) << 8))) diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c index 99850367293a..6953afc0be34 100644 --- a/drivers/staging/vt6655/rf.c +++ b/drivers/staging/vt6655/rf.c @@ -209,8 +209,8 @@ static bool RFbAL2230Init(struct vnt_private *priv) /* 3-wire control for normal mode */ iowrite8(0, iobase + MAC_REG_SOFTPWRCTL); - MACvWordRegBitsOn(iobase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPECTI | - SOFTPWRCTL_TXPEINV)); + vt6655_mac_word_reg_bits_on(iobase, MAC_REG_SOFTPWRCTL, + (SOFTPWRCTL_SWPECTI | SOFTPWRCTL_TXPEINV)); /* PLL Off */ MACvWordRegBitsOff(iobase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); @@ -222,7 +222,7 @@ static bool RFbAL2230Init(struct vnt_private *priv) MACvTimer0MicroSDelay(priv, 30); /* delay 30 us */ /* PLL On */ - MACvWordRegBitsOn(iobase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); + vt6655_mac_word_reg_bits_on(iobase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); MACvTimer0MicroSDelay(priv, 150);/* 150us */ ret &= IFRFbWriteEmbedded(priv, (0x00d80f00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW)); @@ -232,10 +232,10 @@ static bool RFbAL2230Init(struct vnt_private *priv) ret &= IFRFbWriteEmbedded(priv, al2230_init_table[CB_AL2230_INIT_SEQ - 1]); - MACvWordRegBitsOn(iobase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 | - SOFTPWRCTL_SWPE2 | - SOFTPWRCTL_SWPECTI | - SOFTPWRCTL_TXPEINV)); + vt6655_mac_word_reg_bits_on(iobase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 | + SOFTPWRCTL_SWPE2 | + SOFTPWRCTL_SWPECTI | + SOFTPWRCTL_TXPEINV)); /* 3-wire control for power saving mode */ iowrite8(PSSIG_WPE3 | PSSIG_WPE2, iobase + MAC_REG_PSPWRSIG); From 5327d71d19556dda35343fc9dcb93d860ca92ebe Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 07:01:10 +0200 Subject: [PATCH 1039/1436] staging: vt6655: Rename MACvRegBitsOff Fix name of a macro that uses CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/e6bea6707f20a53d0631dd1f477ce72d36cd6f3e.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/card.c | 2 +- drivers/staging/vt6655/device_main.c | 24 ++++++++++++------------ drivers/staging/vt6655/mac.c | 10 +++++----- drivers/staging/vt6655/mac.h | 2 +- drivers/staging/vt6655/power.c | 6 +++--- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 54a12c97aa16..ec70a1f611d4 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -367,7 +367,7 @@ void CARDbRadioPowerOff(struct vnt_private *priv) break; } - MACvRegBitsOff(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_RXON); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_RXON); bb_set_deep_sleep(priv, priv->local_id); diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index bcf35a89730e..92583ee8bffd 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1322,13 +1322,13 @@ static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) case NL80211_IFTYPE_STATION: break; case NL80211_IFTYPE_ADHOC: - MACvRegBitsOff(priv->port_offset, MAC_REG_RCR, RCR_UNICAST); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_RCR, RCR_UNICAST); vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_ADHOC); break; case NL80211_IFTYPE_AP: - MACvRegBitsOff(priv->port_offset, MAC_REG_RCR, RCR_UNICAST); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_RCR, RCR_UNICAST); vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_AP); @@ -1351,16 +1351,16 @@ static void vnt_remove_interface(struct ieee80211_hw *hw, case NL80211_IFTYPE_STATION: break; case NL80211_IFTYPE_ADHOC: - MACvRegBitsOff(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); - MACvRegBitsOff(priv->port_offset, - MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); - MACvRegBitsOff(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_ADHOC); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); + vt6655_mac_reg_bits_off(priv->port_offset, + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_ADHOC); break; case NL80211_IFTYPE_AP: - MACvRegBitsOff(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); - MACvRegBitsOff(priv->port_offset, - MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); - MACvRegBitsOff(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_AP); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); + vt6655_mac_reg_bits_off(priv->port_offset, + MAC_REG_TFTCTL, TFTCTL_TSFCNTREN); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_HOSTCR, HOSTCR_AP); break; default: break; @@ -1478,8 +1478,8 @@ static void vnt_bss_info_changed(struct ieee80211_hw *hw, vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_TCR, TCR_AUTOBCNTX); } else { - MACvRegBitsOff(priv->port_offset, MAC_REG_TCR, - TCR_AUTOBCNTX); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_TCR, + TCR_AUTOBCNTX); } } diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index 8e789ce055cd..688f7c685c97 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -337,7 +337,7 @@ bool MACbSafeRxOff(struct vnt_private *priv) } /* try to safe shutdown RX */ - MACvRegBitsOff(io_base, MAC_REG_HOSTCR, HOSTCR_RXON); + vt6655_mac_reg_bits_off(io_base, MAC_REG_HOSTCR, HOSTCR_RXON); /* W_MAX_TIMEOUT is the timeout period */ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { if (!(ioread8(io_base + MAC_REG_HOSTCR) & HOSTCR_RXONST)) @@ -392,7 +392,7 @@ bool MACbSafeTxOff(struct vnt_private *priv) } /* try to safe shutdown TX */ - MACvRegBitsOff(io_base, MAC_REG_HOSTCR, HOSTCR_TXON); + vt6655_mac_reg_bits_off(io_base, MAC_REG_HOSTCR, HOSTCR_TXON); /* W_MAX_TIMEOUT is the timeout period */ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { @@ -423,7 +423,7 @@ bool MACbSafeStop(struct vnt_private *priv) { void __iomem *io_base = priv->port_offset; - MACvRegBitsOff(io_base, MAC_REG_TCR, TCR_AUTOBCNTX); + vt6655_mac_reg_bits_off(io_base, MAC_REG_TCR, TCR_AUTOBCNTX); if (!MACbSafeRxOff(priv)) { pr_debug(" MACbSafeRxOff == false)\n"); @@ -436,7 +436,7 @@ bool MACbSafeStop(struct vnt_private *priv) return false; } - MACvRegBitsOff(io_base, MAC_REG_HOSTCR, HOSTCR_MACEN); + vt6655_mac_reg_bits_off(io_base, MAC_REG_HOSTCR, HOSTCR_MACEN); return true; } @@ -730,7 +730,7 @@ bool MACbPSWakeup(struct vnt_private *priv) return true; /* Disable PS */ - MACvRegBitsOff(io_base, MAC_REG_PSCTL, PSCTL_PSEN); + vt6655_mac_reg_bits_off(io_base, MAC_REG_PSCTL, PSCTL_PSEN); /* Check if SyncFlushOK */ for (ww = 0; ww < W_MAX_TIMEOUT; ww++) { diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 3303b9ba3bee..16f2b77e1371 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -551,7 +551,7 @@ do { \ iowrite16(reg_value | (bit_mask), iobase + reg_offset); \ } while (0) -#define MACvRegBitsOff(iobase, reg_offset, bit_mask) \ +#define vt6655_mac_reg_bits_off(iobase, reg_offset, bit_mask) \ do { \ unsigned char reg_value; \ reg_value = ioread8(iobase + reg_offset); \ diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c index c8a456305e1d..8527ad3eff48 100644 --- a/drivers/staging/vt6655/power.c +++ b/drivers/staging/vt6655/power.c @@ -66,7 +66,7 @@ void PSvEnablePowerSaving(struct vnt_private *priv, if (wListenInterval >= 2) { /* clear always listen beacon */ - MACvRegBitsOff(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); /* first time set listen next beacon */ vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_LNBCN); } else { @@ -98,10 +98,10 @@ void PSvDisablePowerSaving(struct vnt_private *priv) MACbPSWakeup(priv); /* clear AutoSleep */ - MACvRegBitsOff(priv->port_offset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP); /* clear HWUTSF */ - MACvRegBitsOff(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_HWUTSF); + vt6655_mac_reg_bits_off(priv->port_offset, MAC_REG_TFTCTL, TFTCTL_HWUTSF); /* set always listen beacon */ vt6655_mac_reg_bits_on(priv->port_offset, MAC_REG_PSCTL, PSCTL_ALBCN); From 28d4e692874cf3f730c5c28fc8a130b2faa6fbcb Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 07:00:57 +0200 Subject: [PATCH 1040/1436] staging: vt6655: Rename MACvWordRegBitsOff Fix name of a macro that uses CamelCase which is not accepted by checkpatch.pl Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/b8d4b72ddfdefb6b8a73fb95f6851e0f365118ba.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/card.c | 12 ++++++------ drivers/staging/vt6655/mac.h | 2 +- drivers/staging/vt6655/rf.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index ec70a1f611d4..846469cc06bb 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -352,18 +352,18 @@ void CARDbRadioPowerOff(struct vnt_private *priv) switch (priv->byRFType) { case RF_RFMD2959: - MACvWordRegBitsOff(priv->port_offset, MAC_REG_SOFTPWRCTL, - SOFTPWRCTL_TXPEINV); + vt6655_mac_word_reg_bits_off(priv->port_offset, MAC_REG_SOFTPWRCTL, + SOFTPWRCTL_TXPEINV); vt6655_mac_word_reg_bits_on(priv->port_offset, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE1); break; case RF_AIROHA: case RF_AL2230S: - MACvWordRegBitsOff(priv->port_offset, MAC_REG_SOFTPWRCTL, - SOFTPWRCTL_SWPE2); - MACvWordRegBitsOff(priv->port_offset, MAC_REG_SOFTPWRCTL, - SOFTPWRCTL_SWPE3); + vt6655_mac_word_reg_bits_off(priv->port_offset, MAC_REG_SOFTPWRCTL, + SOFTPWRCTL_SWPE2); + vt6655_mac_word_reg_bits_off(priv->port_offset, MAC_REG_SOFTPWRCTL, + SOFTPWRCTL_SWPE3); break; } diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 16f2b77e1371..4d328b724559 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -558,7 +558,7 @@ do { \ iowrite8(reg_value & ~(bit_mask), iobase + reg_offset); \ } while (0) -#define MACvWordRegBitsOff(iobase, reg_offset, bit_mask) \ +#define vt6655_mac_word_reg_bits_off(iobase, reg_offset, bit_mask) \ do { \ unsigned short reg_value; \ reg_value = ioread16(iobase + reg_offset); \ diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c index 6953afc0be34..1fadc2fc4412 100644 --- a/drivers/staging/vt6655/rf.c +++ b/drivers/staging/vt6655/rf.c @@ -212,7 +212,7 @@ static bool RFbAL2230Init(struct vnt_private *priv) vt6655_mac_word_reg_bits_on(iobase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPECTI | SOFTPWRCTL_TXPEINV)); /* PLL Off */ - MACvWordRegBitsOff(iobase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); + vt6655_mac_word_reg_bits_off(iobase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); /* patch abnormal AL2230 frequency output */ IFRFbWriteEmbedded(priv, (0x07168700 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW)); From 1b225449151fd01fa83ca144996509e2f936a8a2 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 07:01:26 +0200 Subject: [PATCH 1041/1436] staging: vt6655: Convert macro vt6655_mac_reg_bits_on to function Convert macro vt6655_mac_reg_bits_on to function. checkpatch.pl does not accept multiline macros. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/6b23869ec13b35359b135f005a81f3ed50e5801e.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.c | 8 ++++++++ drivers/staging/vt6655/mac.h | 8 +------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index 688f7c685c97..902034a28c6c 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -38,6 +38,14 @@ #include "mac.h" +void vt6655_mac_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask) +{ + unsigned char reg_value; + + reg_value = ioread8(iobase + reg_offset); + iowrite8(reg_value | bit_mask, iobase + reg_offset); +} + /* * Description: * Test if all test bits off diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 4d328b724559..031316d42dba 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -537,13 +537,6 @@ /*--------------------- Export Macros ------------------------------*/ -#define vt6655_mac_reg_bits_on(iobase, reg_offset, bit_mask) \ -do { \ - unsigned char reg_value; \ - reg_value = ioread8(iobase + reg_offset); \ - iowrite8(reg_value | (bit_mask), iobase + reg_offset); \ -} while (0) - #define vt6655_mac_word_reg_bits_on(iobase, reg_offset, bit_mask) \ do { \ unsigned short reg_value; \ @@ -666,6 +659,7 @@ do { \ #define MAKEWORD(lb, hb) \ ((unsigned short)(((unsigned char)(lb)) | (((unsigned short)((unsigned char)(hb))) << 8))) +void vt6655_mac_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask); bool MACbIsRegBitsOff(struct vnt_private *priv, unsigned char byRegOfs, unsigned char byTestBits); From 77072b0f4b5559a7e649b49aebdc71b1b083bf98 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 07:01:37 +0200 Subject: [PATCH 1042/1436] staging: vt6655: Convert macro vt6655_mac_word_reg_bits_on to function Convert macro vt6655_mac_word_reg_bits_on to function. checkpatch.pl does not accept multiline macros. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/255c7f5a5e98a399aa4e299e7cf567016bd86d60.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.c | 8 ++++++++ drivers/staging/vt6655/mac.h | 8 +------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index 902034a28c6c..076e1bfff3e0 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -46,6 +46,14 @@ void vt6655_mac_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u8 iowrite8(reg_value | bit_mask, iobase + reg_offset); } +void vt6655_mac_word_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u16 bit_mask) +{ + unsigned short reg_value; + + reg_value = ioread16(iobase + reg_offset); + iowrite16(reg_value | (bit_mask), iobase + reg_offset); +} + /* * Description: * Test if all test bits off diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 031316d42dba..3b23334db538 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -537,13 +537,6 @@ /*--------------------- Export Macros ------------------------------*/ -#define vt6655_mac_word_reg_bits_on(iobase, reg_offset, bit_mask) \ -do { \ - unsigned short reg_value; \ - reg_value = ioread16(iobase + reg_offset); \ - iowrite16(reg_value | (bit_mask), iobase + reg_offset); \ -} while (0) - #define vt6655_mac_reg_bits_off(iobase, reg_offset, bit_mask) \ do { \ unsigned char reg_value; \ @@ -660,6 +653,7 @@ do { \ ((unsigned short)(((unsigned char)(lb)) | (((unsigned short)((unsigned char)(hb))) << 8))) void vt6655_mac_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask); +void vt6655_mac_word_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u16 bit_mask); bool MACbIsRegBitsOff(struct vnt_private *priv, unsigned char byRegOfs, unsigned char byTestBits); From 64a5c7bf563b3825b2c46d8a8c69a1c6c4029d2d Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 07:02:03 +0200 Subject: [PATCH 1043/1436] staging: vt6655: Convert macro vt6655_mac_reg_bits_off to function Convert macro vt6655_mac_reg_bits_off to function. checkpatch.pl does not accept multiline macros. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/422950c8e1349fba2f97b0b95ba13f361cde05d9.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.c | 8 ++++++++ drivers/staging/vt6655/mac.h | 8 +------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index 076e1bfff3e0..aa9684229dfe 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -54,6 +54,14 @@ void vt6655_mac_word_reg_bits_on(void __iomem *iobase, const u8 reg_offset, cons iowrite16(reg_value | (bit_mask), iobase + reg_offset); } +void vt6655_mac_reg_bits_off(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask) +{ + unsigned char reg_value; + + reg_value = ioread8(iobase + reg_offset); + iowrite8(reg_value & ~(bit_mask), iobase + reg_offset); +} + /* * Description: * Test if all test bits off diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index 3b23334db538..e7b648cf2024 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -537,13 +537,6 @@ /*--------------------- Export Macros ------------------------------*/ -#define vt6655_mac_reg_bits_off(iobase, reg_offset, bit_mask) \ -do { \ - unsigned char reg_value; \ - reg_value = ioread8(iobase + reg_offset); \ - iowrite8(reg_value & ~(bit_mask), iobase + reg_offset); \ -} while (0) - #define vt6655_mac_word_reg_bits_off(iobase, reg_offset, bit_mask) \ do { \ unsigned short reg_value; \ @@ -654,6 +647,7 @@ do { \ void vt6655_mac_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask); void vt6655_mac_word_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u16 bit_mask); +void vt6655_mac_reg_bits_off(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask); bool MACbIsRegBitsOff(struct vnt_private *priv, unsigned char byRegOfs, unsigned char byTestBits); From 8af028c2b22bc04f5ab59cd39fa97ccf14aa8f25 Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Wed, 13 Jul 2022 07:02:14 +0200 Subject: [PATCH 1044/1436] staging: vt6655: Convert macro vt6655_mac_word_reg_bits_off to function Convert macro vt6655_mac_word_reg_bits_off to function. checkpatch.pl does not accept multiline macros. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/04fb37871c4d383c27287934a0dddb3aa7974b08.1657657918.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.c | 8 ++++++++ drivers/staging/vt6655/mac.h | 9 ++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index aa9684229dfe..a7f645f9ccf8 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -62,6 +62,14 @@ void vt6655_mac_reg_bits_off(void __iomem *iobase, const u8 reg_offset, const u8 iowrite8(reg_value & ~(bit_mask), iobase + reg_offset); } +void vt6655_mac_word_reg_bits_off(void __iomem *iobase, const u8 reg_offset, const u16 bit_mask) +{ + unsigned short reg_value; + + reg_value = ioread16(iobase + reg_offset); + iowrite16(reg_value & ~(bit_mask), iobase + reg_offset); +} + /* * Description: * Test if all test bits off diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index e7b648cf2024..b307161818a0 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -537,13 +537,6 @@ /*--------------------- Export Macros ------------------------------*/ -#define vt6655_mac_word_reg_bits_off(iobase, reg_offset, bit_mask) \ -do { \ - unsigned short reg_value; \ - reg_value = ioread16(iobase + reg_offset); \ - iowrite16(reg_value & ~(bit_mask), iobase + reg_offset); \ -} while (0) - #define MACvReceive0(iobase) \ do { \ unsigned long dwData; \ @@ -648,6 +641,8 @@ do { \ void vt6655_mac_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask); void vt6655_mac_word_reg_bits_on(void __iomem *iobase, const u8 reg_offset, const u16 bit_mask); void vt6655_mac_reg_bits_off(void __iomem *iobase, const u8 reg_offset, const u8 bit_mask); +void vt6655_mac_word_reg_bits_off(void __iomem *iobase, const u8 reg_offset, const u16 bit_mask); + bool MACbIsRegBitsOff(struct vnt_private *priv, unsigned char byRegOfs, unsigned char byTestBits); From 8097cf2fb3b2205257f1c76f4808e3398d66b6d9 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 8 Jul 2022 18:36:01 -0700 Subject: [PATCH 1045/1436] usb: gadget: udc: amd5536 depends on HAS_DMA USB_AMD5536UDC should depend on HAS_DMA since it selects USB_SNP_CORE, which depends on HAS_DMA and since 'select' does not follow any dependency chains. Fixes this kconfig warning: WARNING: unmet direct dependencies detected for USB_SNP_CORE Depends on [n]: USB_SUPPORT [=y] && USB_GADGET [=y] && (USB_AMD5536UDC [=y] || USB_SNP_UDC_PLAT [=n]) && HAS_DMA [=n] Selected by [y]: - USB_AMD5536UDC [=y] && USB_SUPPORT [=y] && USB_GADGET [=y] && USB_PCI [=y] Fixes: 97b3ffa233b9 ("usb: gadget: udc: amd5536: split core and PCI layer") Cc: Raviteja Garimella Cc: Felipe Balbi Cc: linux-usb@vger.kernel.org Cc: Greg Kroah-Hartman Signed-off-by: Randy Dunlap Link: https://lore.kernel.org/r/20220709013601.7536-1-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 03535f33511b..43130110a0b4 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -311,7 +311,7 @@ source "drivers/usb/gadget/udc/bdc/Kconfig" config USB_AMD5536UDC tristate "AMD5536 UDC" - depends on USB_PCI + depends on USB_PCI && HAS_DMA select USB_SNP_CORE help The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge. From 421c8d9a20da92deed2dac227e7ebdee7eb3e88f Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Mon, 11 Jul 2022 13:29:57 +0300 Subject: [PATCH 1046/1436] usb: gadget: f_mass_storage: forced_eject attribute It allows to reset prevent_medium_removal flag and "eject" the image. This can be useful to free the drive from a hunging host or if the host continues to use the drive even after unmounting (Linux does this). It's also a bit like using an unfolded paperclip on an optical drive. Previously, the undocumented method of sending SIGUSR1 to a special "file-storage" kernel thread could be used for these purposes, but when using multiple storages there was no way to distinguish one from the other, so we had to send a signal to everyone. Reviewed-by: Alan Stern Signed-off-by: Maxim Devaev Link: https://lore.kernel.org/r/20220711102956.19642-1-mdevaev@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../testing/configfs-usb-gadget-mass-storage | 6 +++++ Documentation/usb/gadget-testing.rst | 6 +++++ Documentation/usb/mass-storage.rst | 9 +++++++ drivers/usb/gadget/function/f_mass_storage.c | 25 +++++++++++++++++++ drivers/usb/gadget/function/storage_common.c | 15 +++++++++++ drivers/usb/gadget/function/storage_common.h | 2 ++ 6 files changed, 63 insertions(+) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-mass-storage b/Documentation/ABI/testing/configfs-usb-gadget-mass-storage index c86b63a7bb43..d899adb57e81 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-mass-storage +++ b/Documentation/ABI/testing/configfs-usb-gadget-mass-storage @@ -32,4 +32,10 @@ Description: being a CD-ROM. nofua Flag specifying that FUA flag in SCSI WRITE(10,12) + forced_eject This write-only file is useful only when + the function is active. It causes the backing + file to be forcibly detached from the LUN, + regardless of whether the host has allowed it. + Any non-zero number of bytes written will + result in ejection. =========== ============================================== diff --git a/Documentation/usb/gadget-testing.rst b/Documentation/usb/gadget-testing.rst index 1c37159fa171..2278c9ffb74a 100644 --- a/Documentation/usb/gadget-testing.rst +++ b/Documentation/usb/gadget-testing.rst @@ -333,6 +333,12 @@ In each lun directory there are the following attribute files: being a CD-ROM. nofua Flag specifying that FUA flag in SCSI WRITE(10,12) + forced_eject This write-only file is useful only when + the function is active. It causes the backing + file to be forcibly detached from the LUN, + regardless of whether the host has allowed it. + Any non-zero number of bytes written will + result in ejection. =============== ============================================== Testing the MASS STORAGE function diff --git a/Documentation/usb/mass-storage.rst b/Documentation/usb/mass-storage.rst index d181b47c3cb6..f399ec631599 100644 --- a/Documentation/usb/mass-storage.rst +++ b/Documentation/usb/mass-storage.rst @@ -181,6 +181,15 @@ sysfs entries Reflects the state of nofua flag for given logical unit. It can be read and written. + - forced_eject + + When written into, it causes the backing file to be forcibly + detached from the LUN, regardless of whether the host has allowed + it. The content doesn't matter, any non-zero number of bytes + written will result in ejection. + + Can not be read. + Other then those, as usual, the values of module parameters can be read from /sys/module/g_mass_storage/parameters/* files. diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index e884f295504f..925e99f9775c 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2651,10 +2651,21 @@ static ssize_t file_store(struct device *dev, struct device_attribute *attr, return fsg_store_file(curlun, filesem, buf, count); } +static ssize_t forced_eject_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fsg_lun *curlun = fsg_lun_from_dev(dev); + struct rw_semaphore *filesem = dev_get_drvdata(dev); + + return fsg_store_forced_eject(curlun, filesem, buf, count); +} + static DEVICE_ATTR_RW(nofua); /* mode wil be set in fsg_lun_attr_is_visible() */ static DEVICE_ATTR(ro, 0, ro_show, ro_store); static DEVICE_ATTR(file, 0, file_show, file_store); +static DEVICE_ATTR_WO(forced_eject); /****************************** FSG COMMON ******************************/ @@ -2808,6 +2819,7 @@ static struct attribute *fsg_lun_dev_attrs[] = { &dev_attr_ro.attr, &dev_attr_file.attr, &dev_attr_nofua.attr, + &dev_attr_forced_eject.attr, NULL }; @@ -3221,6 +3233,18 @@ static ssize_t fsg_lun_opts_inquiry_string_store(struct config_item *item, CONFIGFS_ATTR(fsg_lun_opts_, inquiry_string); +static ssize_t fsg_lun_opts_forced_eject_store(struct config_item *item, + const char *page, size_t len) +{ + struct fsg_lun_opts *opts = to_fsg_lun_opts(item); + struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + + return fsg_store_forced_eject(opts->lun, &fsg_opts->common->filesem, + page, len); +} + +CONFIGFS_ATTR_WO(fsg_lun_opts_, forced_eject); + static struct configfs_attribute *fsg_lun_attrs[] = { &fsg_lun_opts_attr_file, &fsg_lun_opts_attr_ro, @@ -3228,6 +3252,7 @@ static struct configfs_attribute *fsg_lun_attrs[] = { &fsg_lun_opts_attr_cdrom, &fsg_lun_opts_attr_nofua, &fsg_lun_opts_attr_inquiry_string, + &fsg_lun_opts_attr_forced_eject, NULL, }; diff --git a/drivers/usb/gadget/function/storage_common.c b/drivers/usb/gadget/function/storage_common.c index b859a158a414..03035dbbe97b 100644 --- a/drivers/usb/gadget/function/storage_common.c +++ b/drivers/usb/gadget/function/storage_common.c @@ -519,4 +519,19 @@ ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf, } EXPORT_SYMBOL_GPL(fsg_store_inquiry_string); +ssize_t fsg_store_forced_eject(struct fsg_lun *curlun, struct rw_semaphore *filesem, + const char *buf, size_t count) +{ + int ret; + + /* + * Forcibly detach the backing file from the LUN + * regardless of whether the host has allowed it. + */ + curlun->prevent_medium_removal = 0; + ret = fsg_store_file(curlun, filesem, "", 0); + return ret < 0 ? ret : count; +} +EXPORT_SYMBOL_GPL(fsg_store_forced_eject); + MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/function/storage_common.h b/drivers/usb/gadget/function/storage_common.h index bdeb1e233fc9..0a544a82cbf8 100644 --- a/drivers/usb/gadget/function/storage_common.h +++ b/drivers/usb/gadget/function/storage_common.h @@ -219,5 +219,7 @@ ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, size_t count); ssize_t fsg_store_inquiry_string(struct fsg_lun *curlun, const char *buf, size_t count); +ssize_t fsg_store_forced_eject(struct fsg_lun *curlun, struct rw_semaphore *filesem, + const char *buf, size_t count); #endif /* USB_STORAGE_COMMON_H */ From aae7948d564c614c26eb896eb8be57879146240c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Fri, 8 Jul 2022 15:26:05 -0400 Subject: [PATCH 1047/1436] Revert "dt-bindings: usb: mtk-xhci: Make all clocks required" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit ebc4969ae125e65fdb563f66f4bfa7aec95f7eb4. That commit was supposed to make the binding better reflect the MediaTek XHCI hardware block by requiring all clocks to be present. But doing that also causes too much noise in the devicetrees, since it requires updating old MediaTek DTs to add clock handles for the fixed clocks, and going forward every new clock added to the binding would require even more updates. The commit also didn't update the example to match the changes, causing additional warnings. Instead let's keep the clocks optional so that old devicetrees can keep omitting the fixed clocks, and we'll just add the clocks as required on new DTs. Fixes: ebc4969ae125 ("dt-bindings: usb: mtk-xhci: Make all clocks required") Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Chunfeng Yun Acked-by: Rob Herring Signed-off-by: Nícolas F. R. A. Prado Link: https://lore.kernel.org/r/20220708192605.43351-1-nfraprado@collabora.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml index 04cbbca0e94e..b0e58b15b9ae 100644 --- a/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.yaml @@ -68,6 +68,7 @@ properties: maxItems: 1 clocks: + minItems: 1 items: - description: Controller clock used by normal mode - description: Reference clock used by low power mode etc @@ -76,8 +77,9 @@ properties: - description: controller clock clock-names: + minItems: 1 items: - - const: sys_ck + - const: sys_ck # required, the following ones are optional - const: ref_ck - const: mcu_ck - const: dma_ck From 2d937c64e8bf3d9b11b1d62d37fbe97b3cd5dc8d Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 11 Jul 2022 09:25:05 -0700 Subject: [PATCH 1048/1436] usb: misc: onboard_hub: Fix 'missing prototype' warning When building with 'W=1' the compiler complains about missing prototypes for onboard_hub_create/destroy_pdevs(). Include the header with the prototypes to fix this. Reported-by: kernel test robot Reviewed-by: Douglas Anderson Signed-off-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/20220711092431.1.I4016c759fd7fe2b32dd482994a20661f36e2cae3@changeid Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/onboard_usb_hub_pdevs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/misc/onboard_usb_hub_pdevs.c b/drivers/usb/misc/onboard_usb_hub_pdevs.c index a0a5f719129f..ed22a18f4ab7 100644 --- a/drivers/usb/misc/onboard_usb_hub_pdevs.c +++ b/drivers/usb/misc/onboard_usb_hub_pdevs.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "onboard_usb_hub.h" From 5e76ee96be8f7bbf9416a5edddc8c064e7e7c6ac Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Mon, 11 Jul 2022 18:44:03 -0700 Subject: [PATCH 1049/1436] usb: dwc3: ep0: Properly handle setup_packet_pending scenario in data stage During a 3 stage SETUP transfer, if the host sends another SETUP token before completing the status phase, it signifies that the host has aborted the current control transfer. Currently, if a setup_packet_pending is received, there are no subsequent calls to dwc3_ep0_out_start() to fetch the new SETUP packet. This leads to a stall on EP0, as host does not expect another STATUS phase as it has aborted the current transfer. Fix this issue by explicitly stalling and restarting EP0, as well as resetting the trb_enqueue indexes. (without this, there is a chance the SETUP TRB is set up on trb_endqueue == 1) Signed-off-by: Wesley Cheng Link: https://lore.kernel.org/r/20220712014403.2977-1-quic_wcheng@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/ep0.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 2a510e84eef4..197af63f8d05 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -239,6 +239,8 @@ void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) dwc3_gadget_giveback(dep, req, -ECONNRESET); } + dwc->eps[0]->trb_enqueue = 0; + dwc->eps[1]->trb_enqueue = 0; dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); } @@ -1140,6 +1142,11 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) return; + if (dwc->setup_packet_pending) { + dwc3_ep0_stall_and_restart(dwc); + return; + } + dwc->ep0state = EP0_STATUS_PHASE; if (dwc->delayed_status) { From efa2bebf2a9fde638644d6fb0fb776345ac6fcc1 Mon Sep 17 00:00:00 2001 From: Jiangshan Yi Date: Wed, 13 Jul 2022 15:02:05 +0800 Subject: [PATCH 1050/1436] usb: ldusb: replace ternary operator with max_t() Fix the following coccicheck warning: drivers/usb/misc/ldusb.c:719: WARNING opportunity for max(). drivers/usb/misc/ldusb.c:721: WARNING opportunity for max(). max_t() macro is defined in include/linux/minmax.h. It avoids multiple evaluations of the arguments when non-constant and performs strict type-checking. Signed-off-by: Jiangshan Yi Link: https://lore.kernel.org/r/20220713070205.3047256-1-13667453960@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/ldusb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index dcc88df72df4..7cbef74dfc9a 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -716,9 +716,11 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_out_urb) goto error; - dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; + dev->interrupt_in_interval = max_t(int, min_interrupt_in_interval, + dev->interrupt_in_endpoint->bInterval); if (dev->interrupt_out_endpoint) - dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; + dev->interrupt_out_interval = max_t(int, min_interrupt_out_interval, + dev->interrupt_out_endpoint->bInterval); /* we can register the device now, as it is ready */ usb_set_intfdata(intf, dev); From 220fafb4ed04187e9c17be4152da5a7f2ffbdd8c Mon Sep 17 00:00:00 2001 From: Liang He Date: Wed, 13 Jul 2022 20:05:28 +0800 Subject: [PATCH 1051/1436] usb: aspeed-vhub: Fix refcount leak bug in ast_vhub_init_desc() We should call of_node_put() for the reference returned by of_get_child_by_name() which has increased the refcount. Fixes: 30d2617fd7ed ("usb: gadget: aspeed: allow to set usb strings in device tree") Signed-off-by: Liang He Link: https://lore.kernel.org/r/20220713120528.368168-1-windhl@126.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/aspeed-vhub/hub.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index 65cd4e46f031..e2207d014620 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -1059,8 +1059,10 @@ static int ast_vhub_init_desc(struct ast_vhub *vhub) /* Initialize vhub String Descriptors. */ INIT_LIST_HEAD(&vhub->vhub_str_desc); desc_np = of_get_child_by_name(vhub_np, "vhub-strings"); - if (desc_np) + if (desc_np) { ret = ast_vhub_of_parse_str_desc(vhub, desc_np); + of_node_put(desc_np); + } else ret = ast_vhub_str_alloc_add(vhub, &ast_vhub_strings); From 07903626d98853e605fe63e5ce149f1b7314bbea Mon Sep 17 00:00:00 2001 From: Rohith Kollalsi Date: Thu, 14 Jul 2022 10:26:25 +0530 Subject: [PATCH 1052/1436] usb: dwc3: core: Do not perform GCTL_CORE_SOFTRESET during bootup According to the programming guide, it is recommended to perform a GCTL_CORE_SOFTRESET only when switching the mode from device to host or host to device. However, it is found that during bootup when __dwc3_set_mode() is called for the first time, GCTL_CORESOFTRESET is done with suspendable bit(BIT 17) of DWC3_GUSB3PIPECTL set. This some times leads to issues like controller going into bad state and controller registers reading value zero. Until GCTL_CORESOFTRESET is done and run/stop bit is set core initialization is not complete. Setting suspendable bit of DWC3_GUSB3PIPECTL and then performing GCTL_CORESOFTRESET is therefore not recommended. Avoid this by only performing the reset if current_dr_role is set, that is, when doing subsequent role switching. Fixes: f88359e1588b ("usb: dwc3: core: Do core softreset when switch mode") Signed-off-by: Rohith Kollalsi Link: https://lore.kernel.org/r/20220714045625.20377-1-quic_rkollals@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 050b2ba5986d..c5c238ab3083 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -158,9 +158,13 @@ static void __dwc3_set_mode(struct work_struct *work) break; } - /* For DRD host or device mode only */ - if ((DWC3_IP_IS(DWC3) || DWC3_VER_IS_PRIOR(DWC31, 190A)) && - dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG) { + /* + * When current_dr_role is not set, there's no role switching. + * Only perform GCTL.CoreSoftReset when there's DRD role switching. + */ + if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) || + DWC3_VER_IS_PRIOR(DWC31, 190A)) && + dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) { reg = dwc3_readl(dwc->regs, DWC3_GCTL); reg |= DWC3_GCTL_CORESOFTRESET; dwc3_writel(dwc->regs, DWC3_GCTL, reg); From 4af37191134dfce0f3525ad863e70586a48e6ab2 Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Thu, 14 Jul 2022 16:13:49 +0800 Subject: [PATCH 1053/1436] dt-bindings: usb: Add analogix anx7411 PD binding Add analogix PD chip anx7411 device binding Reviewed-by: Rob Herring Acked-by: Krzysztof Kozlowski Signed-off-by: Xin Ji Link: https://lore.kernel.org/r/20220714081350.36447-1-xji@analogixsemi.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/analogix,anx7411.yaml | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/analogix,anx7411.yaml diff --git a/Documentation/devicetree/bindings/usb/analogix,anx7411.yaml b/Documentation/devicetree/bindings/usb/analogix,anx7411.yaml new file mode 100644 index 000000000000..ee436308e5dc --- /dev/null +++ b/Documentation/devicetree/bindings/usb/analogix,anx7411.yaml @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/analogix,anx7411.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Analogix ANX7411 Type-C controller bindings + +maintainers: + - Xin Ji + +properties: + compatible: + enum: + - analogix,anx7411 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + connector: + type: object + $ref: ../connector/usb-connector.yaml + description: + Properties for usb c connector. + + properties: + compatible: + const: usb-c-connector + + power-role: true + + data-role: true + + try-power-role: true + + required: + - compatible + +required: + - compatible + - reg + - connector + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + typec@2c { + compatible = "analogix,anx7411"; + reg = <0x2c>; + interrupts = <8 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpio0>; + + typec_con: connector { + compatible = "usb-c-connector"; + power-role = "dual"; + data-role = "dual"; + try-power-role = "source"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + typec_con_ep: endpoint { + remote-endpoint = <&usbotg_hs_ep>; + }; + }; + }; + }; + }; + }; +... From fe6d8a9c8e6456f8e7ba6b4ee528460beaf65a71 Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Thu, 14 Jul 2022 16:13:50 +0800 Subject: [PATCH 1054/1436] usb: typec: anx7411: Add Analogix PD ANX7411 support Add driver for analogix ANX7411 USB Type-C DRP port controller. Acked-by: Heikki Krogerus Signed-off-by: Xin Ji Link: https://lore.kernel.org/r/20220714081350.36447-2-xji@analogixsemi.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/Kconfig | 11 + drivers/usb/typec/Makefile | 1 + drivers/usb/typec/anx7411.c | 1596 +++++++++++++++++++++++++++++++++++ 3 files changed, 1608 insertions(+) create mode 100644 drivers/usb/typec/anx7411.c diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig index ba24847fb245..5defdfead653 100644 --- a/drivers/usb/typec/Kconfig +++ b/drivers/usb/typec/Kconfig @@ -52,6 +52,17 @@ source "drivers/usb/typec/ucsi/Kconfig" source "drivers/usb/typec/tipd/Kconfig" +config TYPEC_ANX7411 + tristate "Analogix ANX7411 Type-C DRP Port controller driver" + depends on I2C + depends on USB_ROLE_SWITCH + help + Say Y or M here if your system has Analogix ANX7411 Type-C DRP Port + controller driver. + + If you choose to build this driver as a dynamically linked module, the + module will be called anx7411.ko. + config TYPEC_RT1719 tristate "Richtek RT1719 Sink Only Type-C controller driver" depends on USB_ROLE_SWITCH || !USB_ROLE_SWITCH diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile index 2f174cd3e5df..dac5c11a3234 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_TYPEC) += altmodes/ obj-$(CONFIG_TYPEC_TCPM) += tcpm/ obj-$(CONFIG_TYPEC_UCSI) += ucsi/ obj-$(CONFIG_TYPEC_TPS6598X) += tipd/ +obj-$(CONFIG_TYPEC_ANX7411) += anx7411.o obj-$(CONFIG_TYPEC_HD3SS3220) += hd3ss3220.o obj-$(CONFIG_TYPEC_QCOM_PMIC) += qcom-pmic-typec.o obj-$(CONFIG_TYPEC_STUSB160X) += stusb160x.o diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c new file mode 100644 index 000000000000..b990376991f8 --- /dev/null +++ b/drivers/usb/typec/anx7411.c @@ -0,0 +1,1596 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Driver for Analogix ANX7411 USB Type-C and PD controller + * + * Copyright(c) 2022, Analogix Semiconductor. All rights reserved. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TCPC_ADDRESS1 0x58 +#define TCPC_ADDRESS2 0x56 +#define TCPC_ADDRESS3 0x54 +#define TCPC_ADDRESS4 0x52 +#define SPI_ADDRESS1 0x7e +#define SPI_ADDRESS2 0x6e +#define SPI_ADDRESS3 0x64 +#define SPI_ADDRESS4 0x62 + +struct anx7411_i2c_select { + u8 tcpc_address; + u8 spi_address; +}; + +#define VID_ANALOGIX 0x1F29 +#define PID_ANALOGIX 0x7411 + +/* TCPC register define */ + +#define ANALOG_CTRL_10 0xAA + +#define STATUS_LEN 2 +#define ALERT_0 0xCB +#define RECEIVED_MSG BIT(7) +#define SOFTWARE_INT BIT(6) +#define MSG_LEN 32 +#define HEADER_LEN 2 +#define MSG_HEADER 0x00 +#define MSG_TYPE 0x01 +#define MSG_RAWDATA 0x02 +#define MSG_LEN_MASK 0x1F + +#define ALERT_1 0xCC +#define INTP_POW_ON BIT(7) +#define INTP_POW_OFF BIT(6) + +#define VBUS_THRESHOLD_H 0xDD +#define VBUS_THRESHOLD_L 0xDE + +#define FW_CTRL_0 0xF0 +#define UNSTRUCT_VDM_EN BIT(0) +#define DELAY_200MS BIT(1) +#define VSAFE0 0 +#define VSAFE1 BIT(2) +#define VSAFE2 BIT(3) +#define VSAFE3 (BIT(2) | BIT(3)) +#define FRS_EN BIT(7) + +#define FW_PARAM 0xF1 +#define DONGLE_IOP BIT(0) + +#define FW_CTRL_2 0xF7 +#define SINK_CTRL_DIS_FLAG BIT(5) + +/* SPI register define */ +#define OCM_CTRL_0 0x6E +#define OCM_RESET BIT(6) + +#define MAX_VOLTAGE 0xAC +#define MAX_POWER 0xAD +#define MIN_POWER 0xAE + +#define REQUEST_VOLTAGE 0xAF +#define VOLTAGE_UNIT 100 /* mV per unit */ + +#define REQUEST_CURRENT 0xB1 +#define CURRENT_UNIT 50 /* mA per unit */ + +#define CMD_SEND_BUF 0xC0 +#define CMD_RECV_BUF 0xE0 + +#define REQ_VOL_20V_IN_100MV 0xC8 +#define REQ_CUR_2_25A_IN_50MA 0x2D +#define REQ_CUR_3_25A_IN_50MA 0x41 + +#define DEF_5V 5000 +#define DEF_1_5A 1500 + +#define LOBYTE(w) ((u8)((w) & 0xFF)) +#define HIBYTE(w) ((u8)(((u16)(w) >> 8) & 0xFF)) + +enum anx7411_typec_message_type { + TYPE_SRC_CAP = 0x00, + TYPE_SNK_CAP = 0x01, + TYPE_SNK_IDENTITY = 0x02, + TYPE_SVID = 0x03, + TYPE_SET_SNK_DP_CAP = 0x08, + TYPE_PSWAP_REQ = 0x10, + TYPE_DSWAP_REQ = 0x11, + TYPE_VDM = 0x14, + TYPE_OBJ_REQ = 0x16, + TYPE_DP_ALT_ENTER = 0x19, + TYPE_DP_DISCOVER_MODES_INFO = 0x27, + TYPE_GET_DP_CONFIG = 0x29, + TYPE_DP_CONFIGURE = 0x2A, + TYPE_GET_DP_DISCOVER_MODES_INFO = 0x2E, + TYPE_GET_DP_ALT_ENTER = 0x2F, +}; + +#define FW_CTRL_1 0xB2 +#define AUTO_PD_EN BIT(1) +#define TRYSRC_EN BIT(2) +#define TRYSNK_EN BIT(3) +#define FORCE_SEND_RDO BIT(6) + +#define FW_VER 0xB4 +#define FW_SUBVER 0xB5 + +#define INT_MASK 0xB6 +#define INT_STS 0xB7 +#define OCM_BOOT_UP BIT(0) +#define OC_OV_EVENT BIT(1) +#define VCONN_CHANGE BIT(2) +#define VBUS_CHANGE BIT(3) +#define CC_STATUS_CHANGE BIT(4) +#define DATA_ROLE_CHANGE BIT(5) +#define PR_CONSUMER_GOT_POWER BIT(6) +#define HPD_STATUS_CHANGE BIT(7) + +#define SYSTEM_STSTUS 0xB8 +/* 0: SINK off; 1: SINK on */ +#define SINK_STATUS BIT(1) +/* 0: VCONN off; 1: VCONN on*/ +#define VCONN_STATUS BIT(2) +/* 0: vbus off; 1: vbus on*/ +#define VBUS_STATUS BIT(3) +/* 1: host; 0:device*/ +#define DATA_ROLE BIT(5) +/* 0: Chunking; 1: Unchunked*/ +#define SUPPORT_UNCHUNKING BIT(6) +/* 0: HPD low; 1: HPD high*/ +#define HPD_STATUS BIT(7) + +#define DATA_DFP 1 +#define DATA_UFP 2 +#define POWER_SOURCE 1 +#define POWER_SINK 2 + +#define CC_STATUS 0xB9 +#define CC1_RD BIT(0) +#define CC2_RD BIT(4) +#define CC1_RA BIT(1) +#define CC2_RA BIT(5) +#define CC1_RD BIT(0) +#define CC1_RP(cc) (((cc) >> 2) & 0x03) +#define CC2_RP(cc) (((cc) >> 6) & 0x03) + +#define PD_REV_INIT 0xBA + +#define PD_EXT_MSG_CTRL 0xBB +#define SRC_CAP_EXT_REPLY BIT(0) +#define MANUFACTURER_INFO_REPLY BIT(1) +#define BATTERY_STS_REPLY BIT(2) +#define BATTERY_CAP_REPLY BIT(3) +#define ALERT_REPLY BIT(4) +#define STATUS_REPLY BIT(5) +#define PPS_STATUS_REPLY BIT(6) +#define SNK_CAP_EXT_REPLY BIT(7) + +#define NO_CONNECT 0x00 +#define USB3_1_CONNECTED 0x01 +#define DP_ALT_4LANES 0x02 +#define USB3_1_DP_2LANES 0x03 +#define CC1_CONNECTED 0x01 +#define CC2_CONNECTED 0x02 +#define SELECT_PIN_ASSIGMENT_C 0x04 +#define SELECT_PIN_ASSIGMENT_D 0x08 +#define SELECT_PIN_ASSIGMENT_E 0x10 +#define SELECT_PIN_ASSIGMENT_U 0x00 +#define REDRIVER_ADDRESS 0x20 +#define REDRIVER_OFFSET 0x00 + +#define DP_SVID 0xFF01 +#define VDM_ACK 0x40 +#define VDM_CMD_RES 0x00 +#define VDM_CMD_DIS_ID 0x01 +#define VDM_CMD_DIS_SVID 0x02 +#define VDM_CMD_DIS_MOD 0x03 +#define VDM_CMD_ENTER_MODE 0x04 +#define VDM_CMD_EXIT_MODE 0x05 +#define VDM_CMD_ATTENTION 0x06 +#define VDM_CMD_GET_STS 0x10 +#define VDM_CMD_AND_ACK_MASK 0x5F + +#define MAX_ALTMODE 2 + +#define HAS_SOURCE_CAP BIT(0) +#define HAS_SINK_CAP BIT(1) +#define HAS_SINK_WATT BIT(2) + +enum anx7411_psy_state { + /* copy from drivers/usb/typec/tcpm */ + ANX7411_PSY_OFFLINE = 0, + ANX7411_PSY_FIXED_ONLINE, + + /* private */ + /* PD keep in, but disconnct power to bq25700, + * this state can be active when higher capacity adapter plug in, + * and change to ONLINE state when higher capacity adapter plug out + */ + ANX7411_PSY_HANG = 0xff, +}; + +struct typec_params { + int request_current; /* ma */ + int request_voltage; /* mv */ + int cc_connect; + int cc_orientation_valid; + int cc_status; + int data_role; + int power_role; + int vconn_role; + int dp_altmode_enter; + int cust_altmode_enter; + struct usb_role_switch *role_sw; + struct typec_port *port; + struct typec_partner *partner; + struct typec_mux_dev *typec_mux; + struct typec_switch_dev *typec_switch; + struct typec_altmode *amode[MAX_ALTMODE]; + struct typec_altmode *port_amode[MAX_ALTMODE]; + struct typec_displayport_data data; + int pin_assignment; + struct typec_capability caps; + u32 src_pdo[PDO_MAX_OBJECTS]; + u32 sink_pdo[PDO_MAX_OBJECTS]; + u8 caps_flags; + u8 src_pdo_nr; + u8 sink_pdo_nr; + u8 sink_watt; + u8 sink_voltage; +}; + +#define MAX_BUF_LEN 30 +struct fw_msg { + u8 msg_len; + u8 msg_type; + u8 buf[MAX_BUF_LEN]; +} __packed; + +struct anx7411_data { + int fw_version; + int fw_subversion; + struct i2c_client *tcpc_client; + struct i2c_client *spi_client; + struct fw_msg send_msg; + struct fw_msg recv_msg; + struct gpio_desc *intp_gpiod; + struct fwnode_handle *connector_fwnode; + struct typec_params typec; + int intp_irq; + struct work_struct work; + struct workqueue_struct *workqueue; + /* Lock for interrupt work queue */ + struct mutex lock; + + enum anx7411_psy_state psy_online; + enum power_supply_usb_type usb_type; + struct power_supply *psy; + struct power_supply_desc psy_desc; + struct device *dev; +}; + +static u8 snk_identity[] = { + LOBYTE(VID_ANALOGIX), HIBYTE(VID_ANALOGIX), 0x00, 0x82, /* snk_id_hdr */ + 0x00, 0x00, 0x00, 0x00, /* snk_cert */ + 0x00, 0x00, LOBYTE(PID_ANALOGIX), HIBYTE(PID_ANALOGIX), /* 5snk_ama */ +}; + +static u8 dp_caps[4] = {0xC6, 0x00, 0x00, 0x00}; + +static int anx7411_reg_read(struct i2c_client *client, + u8 reg_addr) +{ + return i2c_smbus_read_byte_data(client, reg_addr); +} + +static int anx7411_reg_block_read(struct i2c_client *client, + u8 reg_addr, u8 len, u8 *buf) +{ + return i2c_smbus_read_i2c_block_data(client, reg_addr, len, buf); +} + +static int anx7411_reg_write(struct i2c_client *client, + u8 reg_addr, u8 reg_val) +{ + return i2c_smbus_write_byte_data(client, reg_addr, reg_val); +} + +static int anx7411_reg_block_write(struct i2c_client *client, + u8 reg_addr, u8 len, u8 *buf) +{ + return i2c_smbus_write_i2c_block_data(client, reg_addr, len, buf); +} + +static struct anx7411_i2c_select anx7411_i2c_addr[] = { + {TCPC_ADDRESS1, SPI_ADDRESS1}, + {TCPC_ADDRESS2, SPI_ADDRESS2}, + {TCPC_ADDRESS3, SPI_ADDRESS3}, + {TCPC_ADDRESS4, SPI_ADDRESS4}, +}; + +static int anx7411_detect_power_mode(struct anx7411_data *ctx) +{ + int ret; + int mode; + + ret = anx7411_reg_read(ctx->spi_client, REQUEST_CURRENT); + if (ret < 0) + return ret; + + ctx->typec.request_current = ret * CURRENT_UNIT; /* 50ma per unit */ + + ret = anx7411_reg_read(ctx->spi_client, REQUEST_VOLTAGE); + if (ret < 0) + return ret; + + ctx->typec.request_voltage = ret * VOLTAGE_UNIT; /* 100mv per unit */ + + if (ctx->psy_online == ANX7411_PSY_OFFLINE) { + ctx->psy_online = ANX7411_PSY_FIXED_ONLINE; + ctx->usb_type = POWER_SUPPLY_USB_TYPE_PD; + power_supply_changed(ctx->psy); + } + + if (!ctx->typec.cc_orientation_valid) + return 0; + + if (ctx->typec.cc_connect == CC1_CONNECTED) + mode = CC1_RP(ctx->typec.cc_status); + else + mode = CC2_RP(ctx->typec.cc_status); + if (mode) { + typec_set_pwr_opmode(ctx->typec.port, mode - 1); + return 0; + } + + typec_set_pwr_opmode(ctx->typec.port, TYPEC_PWR_MODE_PD); + + return 0; +} + +static int anx7411_register_partner(struct anx7411_data *ctx, + int pd, int accessory) +{ + struct typec_partner_desc desc; + + if (ctx->typec.partner) + return 0; + + desc.usb_pd = pd; + desc.accessory = accessory; + desc.identity = NULL; + ctx->typec.partner = typec_register_partner(ctx->typec.port, &desc); + if (IS_ERR(ctx->typec.partner)) { + ctx->typec.partner = NULL; + return PTR_ERR(ctx->typec.partner); + } + + return 0; +} + +static int anx7411_detect_cc_orientation(struct anx7411_data *ctx) +{ + struct device *dev = &ctx->spi_client->dev; + int ret; + int cc1_rd, cc2_rd; + int cc1_ra, cc2_ra; + int cc1_rp, cc2_rp; + + ret = anx7411_reg_read(ctx->spi_client, CC_STATUS); + if (ret < 0) + return ret; + + ctx->typec.cc_status = ret; + + cc1_rd = ret & CC1_RD ? 1 : 0; + cc2_rd = ret & CC2_RD ? 1 : 0; + cc1_ra = ret & CC1_RA ? 1 : 0; + cc2_ra = ret & CC2_RA ? 1 : 0; + cc1_rp = CC1_RP(ret); + cc2_rp = CC2_RP(ret); + + /* Debug cable, nothing to do */ + if (cc1_rd && cc2_rd) { + ctx->typec.cc_orientation_valid = 0; + return anx7411_register_partner(ctx, 0, TYPEC_ACCESSORY_DEBUG); + } + + if (cc1_ra && cc2_ra) { + ctx->typec.cc_orientation_valid = 0; + return anx7411_register_partner(ctx, 0, TYPEC_ACCESSORY_AUDIO); + } + + ctx->typec.cc_orientation_valid = 1; + + ret = anx7411_register_partner(ctx, 1, TYPEC_ACCESSORY_NONE); + if (ret) { + dev_err(dev, "register partner\n"); + return ret; + } + + if (cc1_rd || cc1_rp) { + typec_set_orientation(ctx->typec.port, TYPEC_ORIENTATION_NORMAL); + ctx->typec.cc_connect = CC1_CONNECTED; + } + + if (cc2_rd || cc2_rp) { + typec_set_orientation(ctx->typec.port, TYPEC_ORIENTATION_REVERSE); + ctx->typec.cc_connect = CC2_CONNECTED; + } + + return 0; +} + +static int anx7411_set_mux(struct anx7411_data *ctx, int pin_assignment) +{ + int mode = TYPEC_STATE_SAFE; + + switch (pin_assignment) { + case SELECT_PIN_ASSIGMENT_U: + /* default 4 line USB 3.1 */ + mode = TYPEC_STATE_MODAL; + break; + case SELECT_PIN_ASSIGMENT_C: + case SELECT_PIN_ASSIGMENT_E: + /* 4 line DP */ + mode = TYPEC_STATE_SAFE; + break; + case SELECT_PIN_ASSIGMENT_D: + /* 2 line DP, 2 line USB */ + mode = TYPEC_MODE_USB3; + break; + default: + mode = TYPEC_STATE_SAFE; + break; + } + + ctx->typec.pin_assignment = pin_assignment; + + return typec_set_mode(ctx->typec.port, mode); +} + +static int anx7411_set_usb_role(struct anx7411_data *ctx, enum usb_role role) +{ + if (!ctx->typec.role_sw) + return 0; + + return usb_role_switch_set_role(ctx->typec.role_sw, role); +} + +static int anx7411_data_role_detect(struct anx7411_data *ctx) +{ + int ret; + + ret = anx7411_reg_read(ctx->spi_client, SYSTEM_STSTUS); + if (ret < 0) + return ret; + + ctx->typec.data_role = (ret & DATA_ROLE) ? TYPEC_HOST : TYPEC_DEVICE; + ctx->typec.vconn_role = (ret & VCONN_STATUS) ? TYPEC_SOURCE : TYPEC_SINK; + + typec_set_data_role(ctx->typec.port, ctx->typec.data_role); + + typec_set_vconn_role(ctx->typec.port, ctx->typec.vconn_role); + + if (ctx->typec.data_role == TYPEC_HOST) + return anx7411_set_usb_role(ctx, USB_ROLE_HOST); + + return anx7411_set_usb_role(ctx, USB_ROLE_DEVICE); +} + +static int anx7411_power_role_detect(struct anx7411_data *ctx) +{ + int ret; + + ret = anx7411_reg_read(ctx->spi_client, SYSTEM_STSTUS); + if (ret < 0) + return ret; + + ctx->typec.power_role = (ret & SINK_STATUS) ? TYPEC_SINK : TYPEC_SOURCE; + + if (ctx->typec.power_role == TYPEC_SOURCE) { + ctx->typec.request_current = DEF_1_5A; + ctx->typec.request_voltage = DEF_5V; + } + + typec_set_pwr_role(ctx->typec.port, ctx->typec.power_role); + + return 0; +} + +static int anx7411_cc_status_detect(struct anx7411_data *ctx) +{ + anx7411_detect_cc_orientation(ctx); + anx7411_detect_power_mode(ctx); + + return 0; +} + +static void anx7411_partner_unregister_altmode(struct anx7411_data *ctx) +{ + int i; + + ctx->typec.dp_altmode_enter = 0; + ctx->typec.cust_altmode_enter = 0; + + for (i = 0; i < MAX_ALTMODE; i++) + if (ctx->typec.amode[i]) { + typec_unregister_altmode(ctx->typec.amode[i]); + ctx->typec.amode[i] = NULL; + } + + ctx->typec.pin_assignment = 0; +} + +static int anx7411_typec_register_altmode(struct anx7411_data *ctx, + int svid, int vdo) +{ + struct device *dev = &ctx->spi_client->dev; + struct typec_altmode_desc desc; + int i; + + desc.svid = svid; + desc.vdo = vdo; + + for (i = 0; i < MAX_ALTMODE; i++) + if (!ctx->typec.amode[i]) + break; + + desc.mode = i + 1; /* start with 1 */ + + if (i >= MAX_ALTMODE) { + dev_err(dev, "no altmode space for registering\n"); + return -ENOMEM; + } + + ctx->typec.amode[i] = typec_partner_register_altmode(ctx->typec.partner, + &desc); + if (IS_ERR(ctx->typec.amode[i])) { + dev_err(dev, "failed to register altmode\n"); + ctx->typec.amode[i] = NULL; + return PTR_ERR(ctx->typec.amode); + } + + return 0; +} + +static void anx7411_unregister_partner(struct anx7411_data *ctx) +{ + if (ctx->typec.partner) { + typec_unregister_partner(ctx->typec.partner); + ctx->typec.partner = NULL; + } +} + +static int anx7411_update_altmode(struct anx7411_data *ctx, int svid) +{ + int i; + + if (svid == DP_SVID) + ctx->typec.dp_altmode_enter = 1; + else + ctx->typec.cust_altmode_enter = 1; + + for (i = 0; i < MAX_ALTMODE; i++) { + if (!ctx->typec.amode[i]) + continue; + + if (ctx->typec.amode[i]->svid == svid) { + typec_altmode_update_active(ctx->typec.amode[i], true); + typec_altmode_notify(ctx->typec.amode[i], + ctx->typec.pin_assignment, + &ctx->typec.data); + break; + } + } + + return 0; +} + +static int anx7411_register_altmode(struct anx7411_data *ctx, + bool dp_altmode, u8 *buf) +{ + int ret; + int svid; + int mid; + + if (!ctx->typec.partner) + return 0; + + svid = DP_SVID; + if (dp_altmode) { + mid = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); + + return anx7411_typec_register_altmode(ctx, svid, mid); + } + + svid = (buf[3] << 8) | buf[2]; + if ((buf[0] & VDM_CMD_AND_ACK_MASK) != (VDM_ACK | VDM_CMD_ENTER_MODE)) + return anx7411_update_altmode(ctx, svid); + + if ((buf[0] & VDM_CMD_AND_ACK_MASK) != (VDM_ACK | VDM_CMD_DIS_MOD)) + return 0; + + mid = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24); + + ret = anx7411_typec_register_altmode(ctx, svid, mid); + if (ctx->typec.cust_altmode_enter) + ret |= anx7411_update_altmode(ctx, svid); + + return ret; +} + +static int anx7411_parse_cmd(struct anx7411_data *ctx, u8 type, u8 *buf, u8 len) +{ + struct device *dev = &ctx->spi_client->dev; + u8 cur_50ma, vol_100mv; + + switch (type) { + case TYPE_SRC_CAP: + cur_50ma = anx7411_reg_read(ctx->spi_client, REQUEST_CURRENT); + vol_100mv = anx7411_reg_read(ctx->spi_client, REQUEST_VOLTAGE); + + ctx->typec.request_voltage = vol_100mv * VOLTAGE_UNIT; + ctx->typec.request_current = cur_50ma * CURRENT_UNIT; + + ctx->psy_online = ANX7411_PSY_FIXED_ONLINE; + ctx->usb_type = POWER_SUPPLY_USB_TYPE_PD; + power_supply_changed(ctx->psy); + break; + case TYPE_SNK_CAP: + break; + case TYPE_SVID: + break; + case TYPE_SNK_IDENTITY: + break; + case TYPE_GET_DP_ALT_ENTER: + /* DP alt mode enter success */ + if (buf[0]) + anx7411_update_altmode(ctx, DP_SVID); + break; + case TYPE_DP_ALT_ENTER: + /* Update DP altmode */ + anx7411_update_altmode(ctx, DP_SVID); + break; + case TYPE_OBJ_REQ: + anx7411_detect_power_mode(ctx); + break; + case TYPE_DP_CONFIGURE: + anx7411_set_mux(ctx, buf[1]); + break; + case TYPE_DP_DISCOVER_MODES_INFO: + /* Make sure discover modes valid */ + if (buf[0] | buf[1]) + /* Register DP Altmode */ + anx7411_register_altmode(ctx, 1, buf); + break; + case TYPE_VDM: + /* Register other altmode */ + anx7411_register_altmode(ctx, 0, buf); + break; + default: + dev_err(dev, "ignore message(0x%.02x).\n", type); + break; + } + + return 0; +} + +static u8 checksum(struct device *dev, u8 *buf, u8 len) +{ + u8 ret = 0; + u8 i; + + for (i = 0; i < len; i++) + ret += buf[i]; + + return ret; +} + +static int anx7411_read_msg_ctrl_status(struct i2c_client *client) +{ + return anx7411_reg_read(client, CMD_SEND_BUF); +} + +static int anx7411_wait_msg_empty(struct i2c_client *client) +{ + int val; + + return readx_poll_timeout(anx7411_read_msg_ctrl_status, + client, val, (val < 0) || (val == 0), + 2000, 2000 * 150); +} + +static int anx7411_send_msg(struct anx7411_data *ctx, u8 type, u8 *buf, u8 size) +{ + struct device *dev = &ctx->spi_client->dev; + struct fw_msg *msg = &ctx->send_msg; + u8 crc; + int ret; + + size = min_t(u8, size, (u8)MAX_BUF_LEN); + memcpy(msg->buf, buf, size); + msg->msg_type = type; + /* msg len equals buffer length + msg_type */ + msg->msg_len = size + 1; + + /* Do CRC check for all buffer data and msg_len and msg_type */ + crc = checksum(dev, (u8 *)msg, size + HEADER_LEN); + msg->buf[size] = 0 - crc; + + ret = anx7411_wait_msg_empty(ctx->spi_client); + if (ret) + return ret; + + ret = anx7411_reg_block_write(ctx->spi_client, + CMD_SEND_BUF + 1, size + HEADER_LEN, + &msg->msg_type); + ret |= anx7411_reg_write(ctx->spi_client, CMD_SEND_BUF, + msg->msg_len); + return ret; +} + +static int anx7411_process_cmd(struct anx7411_data *ctx) +{ + struct device *dev = &ctx->spi_client->dev; + struct fw_msg *msg = &ctx->recv_msg; + u8 len; + u8 crc; + int ret; + + /* Read message from firmware */ + ret = anx7411_reg_block_read(ctx->spi_client, CMD_RECV_BUF, + MSG_LEN, (u8 *)msg); + if (ret < 0) + return 0; + + if (!msg->msg_len) + return 0; + + ret = anx7411_reg_write(ctx->spi_client, CMD_RECV_BUF, 0); + if (ret) + return ret; + + len = msg->msg_len & MSG_LEN_MASK; + crc = checksum(dev, (u8 *)msg, len + HEADER_LEN); + if (crc) { + dev_err(dev, "message error crc(0x%.02x)\n", crc); + return -ERANGE; + } + + return anx7411_parse_cmd(ctx, msg->msg_type, msg->buf, len - 1); +} + +static void anx7411_translate_payload(struct device *dev, __le32 *payload, + u32 *pdo, int nr, const char *type) +{ + int i; + + if (nr > PDO_MAX_OBJECTS) { + dev_err(dev, "nr(%d) exceed PDO_MAX_OBJECTS(%d)\n", + nr, PDO_MAX_OBJECTS); + + return; + } + + for (i = 0; i < nr; i++) + payload[i] = cpu_to_le32(pdo[i]); +} + +static int anx7411_config(struct anx7411_data *ctx) +{ + struct device *dev = &ctx->spi_client->dev; + struct typec_params *typecp = &ctx->typec; + __le32 payload[PDO_MAX_OBJECTS]; + int ret; + + /* Config PD FW work under PD 2.0 */ + ret = anx7411_reg_write(ctx->spi_client, PD_REV_INIT, PD_REV20); + ret |= anx7411_reg_write(ctx->tcpc_client, FW_CTRL_0, + UNSTRUCT_VDM_EN | DELAY_200MS | + VSAFE1 | FRS_EN); + ret |= anx7411_reg_write(ctx->spi_client, FW_CTRL_1, + AUTO_PD_EN | FORCE_SEND_RDO); + + /* Set VBUS current threshold */ + ret |= anx7411_reg_write(ctx->tcpc_client, VBUS_THRESHOLD_H, 0xff); + ret |= anx7411_reg_write(ctx->tcpc_client, VBUS_THRESHOLD_L, 0x03); + + /* Fix dongle compatible issue */ + ret |= anx7411_reg_write(ctx->tcpc_client, FW_PARAM, + anx7411_reg_read(ctx->tcpc_client, FW_PARAM) | + DONGLE_IOP); + ret |= anx7411_reg_write(ctx->spi_client, INT_MASK, 0); + + ret |= anx7411_reg_write(ctx->spi_client, PD_EXT_MSG_CTRL, 0xFF); + if (ret) + return ret; + + if (typecp->caps_flags & HAS_SOURCE_CAP) { + anx7411_translate_payload(dev, payload, typecp->src_pdo, + typecp->src_pdo_nr, "source"); + anx7411_send_msg(ctx, TYPE_SRC_CAP, (u8 *)&payload, + typecp->src_pdo_nr * 4); + anx7411_send_msg(ctx, TYPE_SNK_IDENTITY, snk_identity, + sizeof(snk_identity)); + anx7411_send_msg(ctx, TYPE_SET_SNK_DP_CAP, dp_caps, + sizeof(dp_caps)); + } + + if (typecp->caps_flags & HAS_SINK_CAP) { + anx7411_translate_payload(dev, payload, typecp->sink_pdo, + typecp->sink_pdo_nr, "sink"); + anx7411_send_msg(ctx, TYPE_SNK_CAP, (u8 *)&payload, + typecp->sink_pdo_nr * 4); + } + + if (typecp->caps_flags & HAS_SINK_WATT) { + if (typecp->sink_watt) { + ret |= anx7411_reg_write(ctx->spi_client, MAX_POWER, + typecp->sink_watt); + /* Set min power to 1W */ + ret |= anx7411_reg_write(ctx->spi_client, MIN_POWER, 2); + } + + if (typecp->sink_voltage) + ret |= anx7411_reg_write(ctx->spi_client, MAX_VOLTAGE, + typecp->sink_voltage); + if (ret) + return ret; + } + + if (!typecp->caps_flags) + usleep_range(5000, 6000); + + ctx->fw_version = anx7411_reg_read(ctx->spi_client, FW_VER); + ctx->fw_subversion = anx7411_reg_read(ctx->spi_client, FW_SUBVER); + + return 0; +} + +static void anx7411_chip_standby(struct anx7411_data *ctx) +{ + int ret; + u8 cc1, cc2; + struct device *dev = &ctx->spi_client->dev; + + ret = anx7411_reg_write(ctx->spi_client, OCM_CTRL_0, + anx7411_reg_read(ctx->spi_client, OCM_CTRL_0) | + OCM_RESET); + ret |= anx7411_reg_write(ctx->tcpc_client, ANALOG_CTRL_10, 0x80); + /* Set TCPC to RD and DRP enable */ + cc1 = TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT; + cc2 = TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT; + ret |= anx7411_reg_write(ctx->tcpc_client, TCPC_ROLE_CTRL, + TCPC_ROLE_CTRL_DRP | cc1 | cc2); + + /* Send DRP toggle command */ + ret |= anx7411_reg_write(ctx->tcpc_client, TCPC_COMMAND, + TCPC_CMD_LOOK4CONNECTION); + + /* Send TCPC enter standby command */ + ret |= anx7411_reg_write(ctx->tcpc_client, + TCPC_COMMAND, TCPC_CMD_I2C_IDLE); + if (ret) + dev_err(dev, "Chip standby failed\n"); +} + +static void anx7411_work_func(struct work_struct *work) +{ + int ret; + u8 buf[STATUS_LEN]; + u8 int_change; /* Interrupt change */ + u8 int_status; /* Firmware status update */ + u8 alert0, alert1; /* Interrupt alert source */ + struct anx7411_data *ctx = container_of(work, struct anx7411_data, work); + struct device *dev = &ctx->spi_client->dev; + + mutex_lock(&ctx->lock); + + /* Read interrupt change status */ + ret = anx7411_reg_block_read(ctx->spi_client, INT_STS, STATUS_LEN, buf); + if (ret < 0) { + /* Power standby mode, just return */ + goto unlock; + } + int_change = buf[0]; + int_status = buf[1]; + + /* Read alert register */ + ret = anx7411_reg_block_read(ctx->tcpc_client, ALERT_0, STATUS_LEN, buf); + if (ret < 0) + goto unlock; + + alert0 = buf[0]; + alert1 = buf[1]; + + /* Clear interrupt and alert status */ + ret = anx7411_reg_write(ctx->spi_client, INT_STS, 0); + ret |= anx7411_reg_write(ctx->tcpc_client, ALERT_0, alert0); + ret |= anx7411_reg_write(ctx->tcpc_client, ALERT_1, alert1); + if (ret) + goto unlock; + + if (alert1 & INTP_POW_OFF) { + anx7411_partner_unregister_altmode(ctx); + if (anx7411_set_usb_role(ctx, USB_ROLE_NONE)) + dev_err(dev, "Set usb role\n"); + anx7411_unregister_partner(ctx); + ctx->psy_online = ANX7411_PSY_OFFLINE; + ctx->usb_type = POWER_SUPPLY_USB_TYPE_C; + ctx->typec.request_voltage = 0; + ctx->typec.request_current = 0; + power_supply_changed(ctx->psy); + anx7411_chip_standby(ctx); + goto unlock; + } + + if ((alert0 & SOFTWARE_INT) && (int_change & OCM_BOOT_UP)) { + if (anx7411_config(ctx)) + dev_err(dev, "Config failed\n"); + if (anx7411_data_role_detect(ctx)) + dev_err(dev, "set PD data role\n"); + if (anx7411_power_role_detect(ctx)) + dev_err(dev, "set PD power role\n"); + anx7411_set_mux(ctx, SELECT_PIN_ASSIGMENT_C); + } + + if (alert0 & RECEIVED_MSG) + anx7411_process_cmd(ctx); + + ret = (int_status & DATA_ROLE) ? TYPEC_HOST : TYPEC_DEVICE; + if (ctx->typec.data_role != ret) + if (anx7411_data_role_detect(ctx)) + dev_err(dev, "set PD data role\n"); + + ret = (int_status & SINK_STATUS) ? TYPEC_SINK : TYPEC_SOURCE; + if (ctx->typec.power_role != ret) + if (anx7411_power_role_detect(ctx)) + dev_err(dev, "set PD power role\n"); + + if ((alert0 & SOFTWARE_INT) && (int_change & CC_STATUS_CHANGE)) + anx7411_cc_status_detect(ctx); + +unlock: + mutex_unlock(&ctx->lock); +} + +static irqreturn_t anx7411_intr_isr(int irq, void *data) +{ + struct anx7411_data *ctx = (struct anx7411_data *)data; + + queue_work(ctx->workqueue, &ctx->work); + + return IRQ_HANDLED; +} + +static int anx7411_register_i2c_dummy_clients(struct anx7411_data *ctx, + struct i2c_client *client) +{ + int i; + u8 spi_addr; + + for (i = 0; i < sizeof(anx7411_i2c_addr); i++) { + if (client->addr == (anx7411_i2c_addr[i].tcpc_address >> 1)) { + spi_addr = anx7411_i2c_addr[i].spi_address >> 1; + ctx->spi_client = i2c_new_dummy_device(client->adapter, + spi_addr); + if (ctx->spi_client) + return 0; + } + } + + dev_err(&client->dev, "unable to get SPI slave\n"); + return -ENOMEM; +} + +static void anx7411_port_unregister_altmodes(struct typec_altmode **adev) +{ + int i; + + for (i = 0; i < MAX_ALTMODE; i++) + if (adev[i]) { + typec_unregister_altmode(adev[i]); + adev[i] = NULL; + } +} + +static int anx7411_usb_mux_set(struct typec_mux_dev *mux, + struct typec_mux_state *state) +{ + struct anx7411_data *ctx = typec_mux_get_drvdata(mux); + struct device *dev = &ctx->spi_client->dev; + int has_dp; + + has_dp = (state->alt && state->alt->svid == USB_TYPEC_DP_SID && + state->alt->mode == USB_TYPEC_DP_MODE); + if (!has_dp) + dev_err(dev, "dp altmode not register\n"); + + return 0; +} + +static int anx7411_usb_set_orientation(struct typec_switch_dev *sw, + enum typec_orientation orientation) +{ + /* No need set */ + + return 0; +} + +static int anx7411_register_switch(struct anx7411_data *ctx, + struct device *dev, + struct fwnode_handle *fwnode) +{ + struct typec_switch_desc sw_desc = { }; + + sw_desc.fwnode = fwnode; + sw_desc.drvdata = ctx; + sw_desc.name = fwnode_get_name(fwnode); + sw_desc.set = anx7411_usb_set_orientation; + + ctx->typec.typec_switch = typec_switch_register(dev, &sw_desc); + if (IS_ERR(ctx->typec.typec_switch)) { + dev_err(dev, "switch register failed\n"); + return PTR_ERR(ctx->typec.typec_switch); + } + + return 0; +} + +static int anx7411_register_mux(struct anx7411_data *ctx, + struct device *dev, + struct fwnode_handle *fwnode) +{ + struct typec_mux_desc mux_desc = { }; + + mux_desc.fwnode = fwnode; + mux_desc.drvdata = ctx; + mux_desc.name = fwnode_get_name(fwnode); + mux_desc.set = anx7411_usb_mux_set; + + ctx->typec.typec_mux = typec_mux_register(dev, &mux_desc); + if (IS_ERR(ctx->typec.typec_mux)) { + dev_err(dev, "mux register failed\n"); + return PTR_ERR(ctx->typec.typec_mux); + } + + return 0; +} + +static void anx7411_unregister_mux(struct anx7411_data *ctx) +{ + if (ctx->typec.typec_mux) { + typec_mux_unregister(ctx->typec.typec_mux); + ctx->typec.typec_mux = NULL; + } +} + +static void anx7411_unregister_switch(struct anx7411_data *ctx) +{ + if (ctx->typec.typec_switch) { + typec_switch_unregister(ctx->typec.typec_switch); + ctx->typec.typec_switch = NULL; + } +} + +static int anx7411_typec_switch_probe(struct anx7411_data *ctx, + struct device *dev) +{ + int ret; + struct device_node *node; + + node = of_find_node_by_name(dev->of_node, "orientation_switch"); + if (!node) + return 0; + + ret = anx7411_register_switch(ctx, dev, &node->fwnode); + if (ret) { + dev_err(dev, "failed register switch"); + return ret; + } + + node = of_find_node_by_name(dev->of_node, "mode_switch"); + if (!node) { + dev_err(dev, "no typec mux exist"); + ret = -ENODEV; + goto unregister_switch; + } + + ret = anx7411_register_mux(ctx, dev, &node->fwnode); + if (ret) { + dev_err(dev, "failed register mode switch"); + ret = -ENODEV; + goto unregister_switch; + } + + return 0; + +unregister_switch: + anx7411_unregister_switch(ctx); + + return ret; +} + +static int anx7411_typec_port_probe(struct anx7411_data *ctx, + struct device *dev) +{ + struct typec_capability *cap = &ctx->typec.caps; + struct typec_params *typecp = &ctx->typec; + struct fwnode_handle *fwnode; + const char *buf; + int ret, i; + + fwnode = device_get_named_child_node(dev, "connector"); + if (!fwnode) + return -EINVAL; + + ret = fwnode_property_read_string(fwnode, "power-role", &buf); + if (ret) { + dev_err(dev, "power-role not found: %d\n", ret); + return ret; + } + + ret = typec_find_port_power_role(buf); + if (ret < 0) + return ret; + cap->type = ret; + + ret = fwnode_property_read_string(fwnode, "data-role", &buf); + if (ret) { + dev_err(dev, "data-role not found: %d\n", ret); + return ret; + } + + ret = typec_find_port_data_role(buf); + if (ret < 0) + return ret; + cap->data = ret; + + ret = fwnode_property_read_string(fwnode, "try-power-role", &buf); + if (ret) { + dev_err(dev, "try-power-role not found: %d\n", ret); + return ret; + } + + ret = typec_find_power_role(buf); + if (ret < 0) + return ret; + cap->prefer_role = ret; + + /* Get source pdos */ + ret = fwnode_property_count_u32(fwnode, "source-pdos"); + if (ret > 0) { + typecp->src_pdo_nr = min_t(u8, ret, PDO_MAX_OBJECTS); + ret = fwnode_property_read_u32_array(fwnode, "source-pdos", + typecp->src_pdo, + typecp->src_pdo_nr); + if (ret < 0) { + dev_err(dev, "source cap validate failed: %d\n", ret); + return -EINVAL; + } + + typecp->caps_flags |= HAS_SOURCE_CAP; + } + + ret = fwnode_property_count_u32(fwnode, "sink-pdos"); + if (ret > 0) { + typecp->sink_pdo_nr = min_t(u8, ret, PDO_MAX_OBJECTS); + ret = fwnode_property_read_u32_array(fwnode, "sink-pdos", + typecp->sink_pdo, + typecp->sink_pdo_nr); + if (ret < 0) { + dev_err(dev, "sink cap validate failed: %d\n", ret); + return -EINVAL; + } + + for (i = 0; i < typecp->sink_pdo_nr; i++) { + ret = 0; + switch (pdo_type(typecp->sink_pdo[i])) { + case PDO_TYPE_FIXED: + ret = pdo_fixed_voltage(typecp->sink_pdo[i]); + break; + case PDO_TYPE_BATT: + case PDO_TYPE_VAR: + ret = pdo_max_voltage(typecp->sink_pdo[i]); + break; + case PDO_TYPE_APDO: + default: + ret = 0; + break; + } + + /* 100mv per unit */ + typecp->sink_voltage = max(5000, ret) / 100; + } + + typecp->caps_flags |= HAS_SINK_CAP; + } + + if (!fwnode_property_read_u32(fwnode, "op-sink-microwatt", &ret)) { + typecp->sink_watt = ret / 500000; /* 500mw per unit */ + typecp->caps_flags |= HAS_SINK_WATT; + } + + cap->fwnode = fwnode; + + ctx->typec.role_sw = usb_role_switch_get(dev); + if (IS_ERR(ctx->typec.role_sw)) { + dev_err(dev, "USB role switch not found.\n"); + ctx->typec.role_sw = NULL; + } + + ctx->typec.port = typec_register_port(dev, cap); + if (IS_ERR(ctx->typec.port)) { + ret = PTR_ERR(ctx->typec.port); + ctx->typec.port = NULL; + dev_err(dev, "Failed to register type c port %d\n", ret); + return ret; + } + + typec_port_register_altmodes(ctx->typec.port, NULL, ctx, + ctx->typec.port_amode, + MAX_ALTMODE); + return 0; +} + +static int anx7411_typec_check_connection(struct anx7411_data *ctx) +{ + int ret; + + ret = anx7411_reg_read(ctx->spi_client, FW_VER); + if (ret < 0) + return 0; /* No device attached in typec port */ + + /* Clear interrupt and alert status */ + ret = anx7411_reg_write(ctx->spi_client, INT_STS, 0); + ret |= anx7411_reg_write(ctx->tcpc_client, ALERT_0, 0xFF); + ret |= anx7411_reg_write(ctx->tcpc_client, ALERT_1, 0xFF); + if (ret) + return ret; + + ret = anx7411_cc_status_detect(ctx); + ret |= anx7411_power_role_detect(ctx); + ret |= anx7411_data_role_detect(ctx); + ret |= anx7411_set_mux(ctx, SELECT_PIN_ASSIGMENT_C); + if (ret) + return ret; + + ret = anx7411_send_msg(ctx, TYPE_GET_DP_ALT_ENTER, NULL, 0); + ret |= anx7411_send_msg(ctx, TYPE_GET_DP_DISCOVER_MODES_INFO, NULL, 0); + + return ret; +} + +static int __maybe_unused anx7411_runtime_pm_suspend(struct device *dev) +{ + struct anx7411_data *ctx = dev_get_drvdata(dev); + + mutex_lock(&ctx->lock); + + anx7411_partner_unregister_altmode(ctx); + + if (ctx->typec.partner) + anx7411_unregister_partner(ctx); + + mutex_unlock(&ctx->lock); + + return 0; +} + +static int __maybe_unused anx7411_runtime_pm_resume(struct device *dev) +{ + struct anx7411_data *ctx = dev_get_drvdata(dev); + + mutex_lock(&ctx->lock); + /* Detect PD connection */ + if (anx7411_typec_check_connection(ctx)) + dev_err(dev, "check connection"); + + mutex_unlock(&ctx->lock); + + return 0; +} + +static const struct dev_pm_ops anx7411_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(anx7411_runtime_pm_suspend, + anx7411_runtime_pm_resume, NULL) +}; + +static void anx7411_get_gpio_irq(struct anx7411_data *ctx) +{ + struct device *dev = &ctx->tcpc_client->dev; + + ctx->intp_gpiod = devm_gpiod_get_optional(dev, "interrupt", GPIOD_IN); + if (!ctx->intp_gpiod) { + dev_err(dev, "no interrupt gpio property\n"); + return; + } + + ctx->intp_irq = gpiod_to_irq(ctx->intp_gpiod); + if (!ctx->intp_irq) + dev_err(dev, "failed to get GPIO IRQ\n"); +} + +static enum power_supply_usb_type anx7411_psy_usb_types[] = { + POWER_SUPPLY_USB_TYPE_C, + POWER_SUPPLY_USB_TYPE_PD, + POWER_SUPPLY_USB_TYPE_PD_PPS, +}; + +static enum power_supply_property anx7411_psy_props[] = { + POWER_SUPPLY_PROP_USB_TYPE, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_MIN, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_CURRENT_NOW, +}; + +static int anx7411_psy_set_prop(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct anx7411_data *ctx = power_supply_get_drvdata(psy); + int ret = 0; + + if (psp == POWER_SUPPLY_PROP_ONLINE) + ctx->psy_online = val->intval; + else + ret = -EINVAL; + + power_supply_changed(ctx->psy); + return ret; +} + +static int anx7411_psy_prop_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + return psp == POWER_SUPPLY_PROP_ONLINE; +} + +static int anx7411_psy_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct anx7411_data *ctx = power_supply_get_drvdata(psy); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_USB_TYPE: + val->intval = ctx->usb_type; + break; + case POWER_SUPPLY_PROP_ONLINE: + val->intval = ctx->psy_online; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + val->intval = (ctx->psy_online) ? + ctx->typec.request_voltage * 1000 : 0; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = (ctx->psy_online) ? + ctx->typec.request_current * 1000 : 0; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int anx7411_psy_register(struct anx7411_data *ctx) +{ + struct power_supply_desc *psy_desc = &ctx->psy_desc; + struct power_supply_config psy_cfg = {}; + char *psy_name; + + psy_name = devm_kasprintf(ctx->dev, GFP_KERNEL, "anx7411-source-psy-%s", + dev_name(ctx->dev)); + if (!psy_name) + return -ENOMEM; + + psy_desc->name = psy_name; + psy_desc->type = POWER_SUPPLY_TYPE_USB; + psy_desc->usb_types = anx7411_psy_usb_types; + psy_desc->num_usb_types = ARRAY_SIZE(anx7411_psy_usb_types); + psy_desc->properties = anx7411_psy_props, + psy_desc->num_properties = ARRAY_SIZE(anx7411_psy_props), + + psy_desc->get_property = anx7411_psy_get_prop, + psy_desc->set_property = anx7411_psy_set_prop, + psy_desc->property_is_writeable = anx7411_psy_prop_writeable, + + ctx->usb_type = POWER_SUPPLY_USB_TYPE_C; + ctx->psy = devm_power_supply_register(ctx->dev, psy_desc, &psy_cfg); + + if (IS_ERR(ctx->psy)) + dev_warn(ctx->dev, "unable to register psy\n"); + + return PTR_ERR_OR_ZERO(ctx->psy); +} + +static int anx7411_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct anx7411_data *plat; + struct device *dev = &client->dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENODEV; + + plat = devm_kzalloc(dev, sizeof(*plat), GFP_KERNEL); + if (!plat) + return -ENOMEM; + + plat->tcpc_client = client; + i2c_set_clientdata(client, plat); + + mutex_init(&plat->lock); + + ret = anx7411_register_i2c_dummy_clients(plat, client); + if (ret) { + dev_err(dev, "fail to reserve I2C bus\n"); + return ret; + } + + ret = anx7411_typec_switch_probe(plat, dev); + if (ret) { + dev_err(dev, "fail to probe typec switch\n"); + goto free_i2c_dummy; + } + + ret = anx7411_typec_port_probe(plat, dev); + if (ret) { + dev_err(dev, "fail to probe typec property.\n"); + ret = -ENODEV; + goto free_typec_switch; + } + + plat->intp_irq = client->irq; + if (!client->irq) + anx7411_get_gpio_irq(plat); + + if (!plat->intp_irq) { + dev_err(dev, "fail to get interrupt IRQ\n"); + goto free_typec_port; + } + + plat->dev = dev; + plat->psy_online = ANX7411_PSY_OFFLINE; + if (anx7411_psy_register(plat)) { + dev_err(dev, "register psy\n"); + goto free_typec_port; + } + + INIT_WORK(&plat->work, anx7411_work_func); + plat->workqueue = alloc_workqueue("anx7411_work", + WQ_FREEZABLE | + WQ_MEM_RECLAIM, + 1); + if (!plat->workqueue) { + dev_err(dev, "fail to create work queue\n"); + ret = -ENOMEM; + goto free_typec_port; + } + + ret = devm_request_threaded_irq(dev, plat->intp_irq, + NULL, anx7411_intr_isr, + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "anx7411-intp", plat); + if (ret) { + dev_err(dev, "fail to request irq\n"); + goto free_wq; + } + + if (anx7411_typec_check_connection(plat)) + dev_err(dev, "check status\n"); + + pm_runtime_enable(dev); + + return 0; + +free_wq: + destroy_workqueue(plat->workqueue); + +free_typec_port: + typec_unregister_port(plat->typec.port); + anx7411_port_unregister_altmodes(plat->typec.port_amode); + +free_typec_switch: + anx7411_unregister_switch(plat); + anx7411_unregister_mux(plat); + +free_i2c_dummy: + i2c_unregister_device(plat->spi_client); + + return ret; +} + +static int anx7411_i2c_remove(struct i2c_client *client) +{ + struct anx7411_data *plat = i2c_get_clientdata(client); + + anx7411_partner_unregister_altmode(plat); + anx7411_unregister_partner(plat); + + if (plat->workqueue) + destroy_workqueue(plat->workqueue); + + if (plat->spi_client) + i2c_unregister_device(plat->spi_client); + + if (plat->typec.role_sw) + usb_role_switch_put(plat->typec.role_sw); + + anx7411_unregister_mux(plat); + + anx7411_unregister_switch(plat); + + if (plat->typec.port) + typec_unregister_port(plat->typec.port); + + anx7411_port_unregister_altmodes(plat->typec.port_amode); + + return 0; +} + +static const struct i2c_device_id anx7411_id[] = { + {"anx7411", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, anx7411_id); + +static const struct of_device_id anx_match_table[] = { + {.compatible = "analogix,anx7411",}, + {}, +}; + +static struct i2c_driver anx7411_driver = { + .driver = { + .name = "anx7411", + .of_match_table = anx_match_table, + .pm = &anx7411_pm_ops, + }, + .probe = anx7411_i2c_probe, + .remove = anx7411_i2c_remove, + + .id_table = anx7411_id, +}; + +module_i2c_driver(anx7411_driver); + +MODULE_DESCRIPTION("Anx7411 USB Type-C PD driver"); +MODULE_AUTHOR("Xin Ji "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1.5"); From a5c7592366af3db61171007d103876c457cd5796 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 13 Jul 2022 15:13:34 +0200 Subject: [PATCH 1055/1436] dt-bindings: usb: qcom,dwc3: add SC8280XP binding Add SC8280XP to the DT schema. Note that the SC8280XP controllers use the common set of five clocks and an additional set of four interconnect clocks whose purpose is not entirely clear at this point. The set of wakeup interrupts is also different for SC8280XP. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220713131340.29401-2-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/qcom,dwc3.yaml | 102 +++++++++++++++--- 1 file changed, 88 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index 749e1963ddbb..c991d9103f87 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -24,6 +24,7 @@ properties: - qcom,qcs404-dwc3 - qcom,sc7180-dwc3 - qcom,sc7280-dwc3 + - qcom,sc8280xp-dwc3 - qcom,sdm660-dwc3 - qcom,sdm845-dwc3 - qcom,sdx55-dwc3 @@ -66,11 +67,11 @@ properties: - mock_utmi:: Mock utmi clock needed for ITP/SOF generation in host mode. Its frequency should be 19.2MHz. minItems: 1 - maxItems: 6 + maxItems: 9 clock-names: minItems: 1 - maxItems: 6 + maxItems: 9 assigned-clocks: items: @@ -93,20 +94,10 @@ properties: - const: apps-usb interrupts: - items: - - description: The interrupt that is asserted - when a wakeup event is received on USB2 bus. - - description: The interrupt that is asserted - when a wakeup event is received on USB3 bus. - - description: Wakeup event on DM line. - - description: Wakeup event on DP line. + maxItems: 4 interrupt-names: - items: - - const: hs_phy_irq - - const: ss_phy_irq - - const: dm_hs_phy_irq - - const: dp_hs_phy_irq + maxItems: 4 qcom,select-utmi-as-pipe-clk: description: @@ -249,6 +240,28 @@ allOf: - const: sleep - const: mock_utmi + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8280xp-dwc3 + then: + properties: + clocks: + maxItems: 9 + clock-names: + items: + - const: cfg_noc + - const: core + - const: iface + - const: sleep + - const: mock_utmi + - const: noc_aggr + - const: noc_aggr_north + - const: noc_aggr_south + - const: noc_sys + - if: properties: compatible: @@ -311,6 +324,67 @@ allOf: - const: mock_utmi - const: xo + - if: + properties: + compatible: + contains: + enum: + - qcom,ipq4019-dwc3 + - qcom,ipq6018-dwc3 + - qcom,ipq8064-dwc3 + - qcom,ipq8074-dwc3 + - qcom,msm8953-dwc3 + - qcom,msm8994-dwc3 + - qcom,msm8996-dwc3 + - qcom,msm8998-dwc3 + - qcom,qcs404-dwc3 + - qcom,sc7180-dwc3 + - qcom,sc7280-dwc3 + - qcom,sdm660-dwc3 + - qcom,sdm845-dwc3 + - qcom,sdx55-dwc3 + - qcom,sdx65-dwc3 + - qcom,sm4250-dwc3 + - qcom,sm6115-dwc3 + - qcom,sm6125-dwc3 + - qcom,sm6350-dwc3 + - qcom,sm8150-dwc3 + - qcom,sm8250-dwc3 + - qcom,sm8350-dwc3 + - qcom,sm8450-dwc3 + then: + properties: + interrupts: + items: + - description: The interrupt that is asserted + when a wakeup event is received on USB2 bus. + - description: The interrupt that is asserted + when a wakeup event is received on USB3 bus. + - description: Wakeup event on DM line. + - description: Wakeup event on DP line. + interrupt-names: + items: + - const: hs_phy_irq + - const: ss_phy_irq + - const: dm_hs_phy_irq + - const: dp_hs_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc8280xp-dwc3 + then: + properties: + interrupts: + maxItems: 4 + interrupt-names: + items: + - const: pwr_event + - const: dp_hs_phy_irq + - const: dm_hs_phy_irq + - const: ss_phy_irq additionalProperties: false From dd566faebe9f27659f2ec0135219f399bc6a2ec9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 13 Jul 2022 15:13:35 +0200 Subject: [PATCH 1056/1436] dt-bindings: usb: qcom,dwc3: refine interrupt requirements Not all platforms have all of the four wakeup interrupts currently described by the bindings. Specifically, MSM8953/6/8 and SDM660 do not use the DP/DM interrupts, while the SS PHY interrupt is optional on SDM660 and SC7280. Note that no devicetree in mainline specify any wakeup interrupts for - qcom,ipq4019-dwc3 - qcom,ipq6018-dwc3 - qcom,ipq8064-dwc3 - qcom,ipq8074-dwc3 - qcom,msm8994-dwc3 - qcom,qcs404-dwc3 but let's keep the schema warnings about that for now. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220713131340.29401-3-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/qcom,dwc3.yaml | 60 +++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml index c991d9103f87..fea3e7092ace 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.yaml @@ -94,9 +94,11 @@ properties: - const: apps-usb interrupts: + minItems: 1 maxItems: 4 interrupt-names: + minItems: 1 maxItems: 4 qcom,select-utmi-as-pipe-clk: @@ -333,14 +335,9 @@ allOf: - qcom,ipq6018-dwc3 - qcom,ipq8064-dwc3 - qcom,ipq8074-dwc3 - - qcom,msm8953-dwc3 - qcom,msm8994-dwc3 - - qcom,msm8996-dwc3 - - qcom,msm8998-dwc3 - qcom,qcs404-dwc3 - qcom,sc7180-dwc3 - - qcom,sc7280-dwc3 - - qcom,sdm660-dwc3 - qcom,sdm845-dwc3 - qcom,sdx55-dwc3 - qcom,sdx65-dwc3 @@ -369,6 +366,59 @@ allOf: - const: dm_hs_phy_irq - const: dp_hs_phy_irq + - if: + properties: + compatible: + contains: + enum: + - qcom,msm8953-dwc3 + - qcom,msm8996-dwc3 + - qcom,msm8998-dwc3 + then: + properties: + interrupts: + maxItems: 2 + interrupt-names: + items: + - const: hs_phy_irq + - const: ss_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,sdm660-dwc3 + then: + properties: + interrupts: + minItems: 1 + maxItems: 2 + interrupt-names: + minItems: 1 + items: + - const: hs_phy_irq + - const: ss_phy_irq + + - if: + properties: + compatible: + contains: + enum: + - qcom,sc7280-dwc3 + then: + properties: + interrupts: + minItems: 3 + maxItems: 4 + interrupt-names: + minItems: 3 + items: + - const: hs_phy_irq + - const: dp_hs_phy_irq + - const: dm_hs_phy_irq + - const: ss_phy_irq + - if: properties: compatible: From 69bb3520db7cecbccc9e497fc568fa5465c9d43f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 13 Jul 2022 15:13:36 +0200 Subject: [PATCH 1057/1436] usb: dwc3: qcom: fix missing optional irq warnings Not all platforms have all of the four currently supported wakeup interrupts so use the optional irq helpers when looking up interrupts to avoid printing error messages when an optional interrupt is not found: dwc3-qcom a6f8800.usb: error -ENXIO: IRQ hs_phy_irq not found Fixes: a4333c3a6ba9 ("usb: dwc3: Add Qualcomm DWC3 glue driver") Reviewed-by: Andrew Halaney Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220713131340.29401-4-johan+linaro@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-qcom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-qcom.c b/drivers/usb/dwc3/dwc3-qcom.c index 77036551987a..c5e482f53e9d 100644 --- a/drivers/usb/dwc3/dwc3-qcom.c +++ b/drivers/usb/dwc3/dwc3-qcom.c @@ -490,9 +490,9 @@ static int dwc3_qcom_get_irq(struct platform_device *pdev, int ret; if (np) - ret = platform_get_irq_byname(pdev_irq, name); + ret = platform_get_irq_byname_optional(pdev_irq, name); else - ret = platform_get_irq(pdev_irq, num); + ret = platform_get_irq_optional(pdev_irq, num); return ret; } From ddaf8d96f93bccb3f2b1f4f156c098b272440004 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 11 Jul 2022 07:22:55 +0000 Subject: [PATCH 1058/1436] usb: typec: Add support for retimers Introduce a retimer device class and associated functions that register and use retimer "switch" devices. These operate in a manner similar to the "mode-switch" and help configure retimers that exist between the Type-C connector and host controller(s). Type C ports can be linked to retimers using firmware node device references (again, in a manner similar to "mode-switch"). There are no new sysfs files being created; there is the new retimer class directory, but there are no class-specific files being created there. Signed-off-by: Prashant Malani Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220711072333.2064341-2-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/Makefile | 2 +- drivers/usb/typec/class.c | 9 +- drivers/usb/typec/class.h | 1 + drivers/usb/typec/retimer.c | 168 ++++++++++++++++++++++++++++++ drivers/usb/typec/retimer.h | 15 +++ include/linux/usb/typec_retimer.h | 45 ++++++++ 6 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 drivers/usb/typec/retimer.c create mode 100644 drivers/usb/typec/retimer.h create mode 100644 include/linux/usb/typec_retimer.h diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile index dac5c11a3234..4a83dad51a6c 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_TYPEC) += typec.o -typec-y := class.o mux.o bus.o pd.o +typec-y := class.o mux.o bus.o pd.o retimer.o typec-$(CONFIG_ACPI) += port-mapper.o obj-$(CONFIG_TYPEC) += altmodes/ obj-$(CONFIG_TYPEC_TCPM) += tcpm/ diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index bbc46b14f99a..9062836bb638 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -2299,10 +2299,14 @@ static int __init typec_init(void) if (ret) goto err_unregister_bus; - ret = class_register(&typec_class); + ret = class_register(&retimer_class); if (ret) goto err_unregister_mux_class; + ret = class_register(&typec_class); + if (ret) + goto err_unregister_retimer_class; + ret = usb_power_delivery_init(); if (ret) goto err_unregister_class; @@ -2312,6 +2316,9 @@ static int __init typec_init(void) err_unregister_class: class_unregister(&typec_class); +err_unregister_retimer_class: + class_unregister(&retimer_class); + err_unregister_mux_class: class_unregister(&typec_mux_class); diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h index b531f9853bc0..43fcf9e37a8c 100644 --- a/drivers/usb/typec/class.h +++ b/drivers/usb/typec/class.h @@ -76,6 +76,7 @@ extern const struct device_type typec_port_dev_type; #define is_typec_port(dev) ((dev)->type == &typec_port_dev_type) extern struct class typec_mux_class; +extern struct class retimer_class; extern struct class typec_class; #if defined(CONFIG_ACPI) diff --git a/drivers/usb/typec/retimer.c b/drivers/usb/typec/retimer.c new file mode 100644 index 000000000000..051eaa7d2899 --- /dev/null +++ b/drivers/usb/typec/retimer.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2022 Google LLC + * + * USB Type-C Retimer support. + * Author: Prashant Malani + * + */ + +#include +#include +#include +#include +#include +#include + +#include "class.h" +#include "retimer.h" + +static bool dev_name_ends_with(struct device *dev, const char *suffix) +{ + const char *name = dev_name(dev); + const int name_len = strlen(name); + const int suffix_len = strlen(suffix); + + if (suffix_len > name_len) + return false; + + return strcmp(name + (name_len - suffix_len), suffix) == 0; +} + +static int retimer_fwnode_match(struct device *dev, const void *fwnode) +{ + return dev_fwnode(dev) == fwnode && dev_name_ends_with(dev, "-retimer"); +} + +static void *typec_retimer_match(struct fwnode_handle *fwnode, const char *id, void *data) +{ + struct device *dev = class_find_device(&retimer_class, NULL, fwnode, + retimer_fwnode_match); + + return dev ? to_typec_retimer(dev) : ERR_PTR(-EPROBE_DEFER); +} + +/** + * fwnode_typec_retimer_get - Find USB Type-C retimer. + * @fwnode: The caller device node. + * + * Finds a retimer linked to the caller. This function is primarily meant for the + * Type-C drivers. Returns a reference to the retimer on success, NULL if no + * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection + * was found but the retimer has not been enumerated yet. + */ +struct typec_retimer *fwnode_typec_retimer_get(struct fwnode_handle *fwnode) +{ + struct typec_retimer *retimer; + + retimer = fwnode_connection_find_match(fwnode, "retimer-switch", NULL, typec_retimer_match); + if (!IS_ERR_OR_NULL(retimer)) + WARN_ON(!try_module_get(retimer->dev.parent->driver->owner)); + + return retimer; +} +EXPORT_SYMBOL_GPL(fwnode_typec_retimer_get); + +/** + * typec_retimer_put - Release handle to a retimer. + * @retimer: USB Type-C Connector Retimer. + * + * Decrements reference count for @retimer. + */ +void typec_retimer_put(struct typec_retimer *retimer) +{ + if (!IS_ERR_OR_NULL(retimer)) { + module_put(retimer->dev.parent->driver->owner); + put_device(&retimer->dev); + } +} +EXPORT_SYMBOL_GPL(typec_retimer_put); + +int typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) +{ + if (IS_ERR_OR_NULL(retimer)) + return 0; + + return retimer->set(retimer, state); +} +EXPORT_SYMBOL_GPL(typec_retimer_set); + +static void typec_retimer_release(struct device *dev) +{ + kfree(to_typec_retimer(dev)); +} + +static const struct device_type typec_retimer_dev_type = { + .name = "typec_retimer", + .release = typec_retimer_release, +}; + +/** + * typec_retimer_register - Register a retimer device. + * @parent: Parent device. + * @desc: Retimer description. + * + * Some USB Type-C connectors have their physical lines routed through retimers before they + * reach muxes or host controllers. In some cases (for example: using alternate modes) + * these retimers need to be reconfigured appropriately. This function registers retimer + * switches which route and potentially modify the signals on the Type C physical lines + * enroute to the host controllers. + */ +struct typec_retimer * +typec_retimer_register(struct device *parent, const struct typec_retimer_desc *desc) +{ + struct typec_retimer *retimer; + int ret; + + if (!desc || !desc->set) + return ERR_PTR(-EINVAL); + + retimer = kzalloc(sizeof(*retimer), GFP_KERNEL); + if (!retimer) + return ERR_PTR(-ENOMEM); + + retimer->set = desc->set; + + device_initialize(&retimer->dev); + retimer->dev.parent = parent; + retimer->dev.fwnode = desc->fwnode; + retimer->dev.class = &retimer_class; + retimer->dev.type = &typec_retimer_dev_type; + retimer->dev.driver_data = desc->drvdata; + dev_set_name(&retimer->dev, "%s-retimer", + desc->name ? desc->name : dev_name(parent)); + + ret = device_add(&retimer->dev); + if (ret) { + dev_err(parent, "failed to register retimer (%d)\n", ret); + put_device(&retimer->dev); + return ERR_PTR(ret); + } + + return retimer; +} +EXPORT_SYMBOL_GPL(typec_retimer_register); + +/** + * typec_retimer_unregister - Unregister retimer device. + * @retimer: USB Type-C Connector retimer. + * + * Unregister retimer that was registered with typec_retimer_register(). + */ +void typec_retimer_unregister(struct typec_retimer *retimer) +{ + if (!IS_ERR_OR_NULL(retimer)) + device_unregister(&retimer->dev); +} +EXPORT_SYMBOL_GPL(typec_retimer_unregister); + +void *typec_retimer_get_drvdata(struct typec_retimer *retimer) +{ + return dev_get_drvdata(&retimer->dev); +} +EXPORT_SYMBOL_GPL(typec_retimer_get_drvdata); + +struct class retimer_class = { + .name = "retimer", + .owner = THIS_MODULE, +}; diff --git a/drivers/usb/typec/retimer.h b/drivers/usb/typec/retimer.h new file mode 100644 index 000000000000..fa15951d4846 --- /dev/null +++ b/drivers/usb/typec/retimer.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __USB_TYPEC_RETIMER__ +#define __USB_TYPEC_RETIMER__ + +#include + +struct typec_retimer { + struct device dev; + typec_retimer_set_fn_t set; +}; + +#define to_typec_retimer(_dev_) container_of(_dev_, struct typec_retimer, dev) + +#endif /* __USB_TYPEC_RETIMER__ */ diff --git a/include/linux/usb/typec_retimer.h b/include/linux/usb/typec_retimer.h new file mode 100644 index 000000000000..5e036b3360e2 --- /dev/null +++ b/include/linux/usb/typec_retimer.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __USB_TYPEC_RETIMER +#define __USB_TYPEC_RETIMER + +#include +#include + +struct device; +struct typec_retimer; +struct typec_altmode; +struct fwnode_handle; + +struct typec_retimer_state { + struct typec_altmode *alt; + unsigned long mode; + void *data; +}; + +typedef int (*typec_retimer_set_fn_t)(struct typec_retimer *retimer, + struct typec_retimer_state *state); + +struct typec_retimer_desc { + struct fwnode_handle *fwnode; + typec_retimer_set_fn_t set; + const char *name; + void *drvdata; +}; + +struct typec_retimer *fwnode_typec_retimer_get(struct fwnode_handle *fwnode); +void typec_retimer_put(struct typec_retimer *retimer); +int typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state); + +static inline struct typec_retimer *typec_retimer_get(struct device *dev) +{ + return fwnode_typec_retimer_get(dev_fwnode(dev)); +} + +struct typec_retimer * +typec_retimer_register(struct device *parent, const struct typec_retimer_desc *desc); +void typec_retimer_unregister(struct typec_retimer *retimer); + +void *typec_retimer_get_drvdata(struct typec_retimer *retimer); + +#endif /* __USB_TYPEC_RETIMER */ From f31a8702cd36f7908bdc3fa1ed7f95b56c10ed35 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 11 Jul 2022 07:22:56 +0000 Subject: [PATCH 1059/1436] usb: typec: Add retimer handle to port Similar to mux and orientation switch, add a handle for registered retimer to the port, so that it has handles to the various switches connected to it. Signed-off-by: Prashant Malani Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220711072333.2064341-3-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/class.c | 9 +++++++++ drivers/usb/typec/class.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 9062836bb638..f08e32d552b4 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "bus.h" #include "class.h" @@ -1736,6 +1737,7 @@ static void typec_release(struct device *dev) ida_destroy(&port->mode_ids); typec_switch_put(port->sw); typec_mux_put(port->mux); + typec_retimer_put(port->retimer); kfree(port->cap); kfree(port); } @@ -2249,6 +2251,13 @@ struct typec_port *typec_register_port(struct device *parent, return ERR_PTR(ret); } + port->retimer = typec_retimer_get(&port->dev); + if (IS_ERR(port->retimer)) { + ret = PTR_ERR(port->retimer); + put_device(&port->dev); + return ERR_PTR(ret); + } + ret = device_add(&port->dev); if (ret) { dev_err(parent, "failed to register port (%d)\n", ret); diff --git a/drivers/usb/typec/class.h b/drivers/usb/typec/class.h index 43fcf9e37a8c..673b2952b074 100644 --- a/drivers/usb/typec/class.h +++ b/drivers/usb/typec/class.h @@ -55,6 +55,7 @@ struct typec_port { enum typec_orientation orientation; struct typec_switch *sw; struct typec_mux *mux; + struct typec_retimer *retimer; const struct typec_capability *cap; const struct typec_operations *ops; From 80dd7ae16bea69a055d14b81e43317207de70f83 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 14 Jul 2022 12:25:29 +0100 Subject: [PATCH 1060/1436] docs: ABI: sysfs-class-pwm: Update Lee Jones' email address Going forward, I'll be using my kernel.org for upstream work. Cc: Greg Kroah-Hartman Cc: Mauro Carvalho Chehab Signed-off-by: Lee Jones Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220714112533.539910-5-lee@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-class-pwm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-class-pwm b/Documentation/ABI/testing/sysfs-class-pwm index 3d65285bcd5f..0638c94d01ef 100644 --- a/Documentation/ABI/testing/sysfs-class-pwm +++ b/Documentation/ABI/testing/sysfs-class-pwm @@ -81,7 +81,7 @@ Description: What: /sys/class/pwm/pwmchip/pwmX/capture Date: June 2016 KernelVersion: 4.8 -Contact: Lee Jones +Contact: Lee Jones Description: Capture information about a PWM signal. The output format is a pair unsigned integers (period and duty cycle), separated by a From 9f9c909095610b1fc11f0784cfa591c756f1cdc0 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 14 Jul 2022 12:25:30 +0100 Subject: [PATCH 1061/1436] docs: ABI: sysfs-devices-soc: Update Lee Jones' email address Going forward, I'll be using my kernel.org for upstream work. Cc: Greg Kroah-Hartman Cc: Mauro Carvalho Chehab Signed-off-by: Lee Jones Signed-off-by: Lee Jones Link: https://lore.kernel.org/r/20220714112533.539910-6-lee@kernel.org Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-devices-soc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-devices-soc b/Documentation/ABI/testing/sysfs-devices-soc index ea999e292f11..5269808ec35f 100644 --- a/Documentation/ABI/testing/sysfs-devices-soc +++ b/Documentation/ABI/testing/sysfs-devices-soc @@ -1,6 +1,6 @@ What: /sys/devices/socX Date: January 2012 -contact: Lee Jones +contact: Lee Jones Description: The /sys/devices/ directory contains a sub-directory for each System-on-Chip (SoC) device on a running platform. Information @@ -14,14 +14,14 @@ Description: What: /sys/devices/socX/machine Date: January 2012 -contact: Lee Jones +contact: Lee Jones Description: Read-only attribute common to all SoCs. Contains the SoC machine name (e.g. Ux500). What: /sys/devices/socX/family Date: January 2012 -contact: Lee Jones +contact: Lee Jones Description: Read-only attribute common to all SoCs. Contains SoC family name (e.g. DB8500). @@ -59,7 +59,7 @@ Description: What: /sys/devices/socX/soc_id Date: January 2012 -contact: Lee Jones +contact: Lee Jones Description: Read-only attribute supported by most SoCs. In the case of ST-Ericsson's chips this contains the SoC serial number. @@ -72,21 +72,21 @@ Description: What: /sys/devices/socX/revision Date: January 2012 -contact: Lee Jones +contact: Lee Jones Description: Read-only attribute supported by most SoCs. Contains the SoC's manufacturing revision number. What: /sys/devices/socX/process Date: January 2012 -contact: Lee Jones +contact: Lee Jones Description: Read-only attribute supported ST-Ericsson's silicon. Contains the the process by which the silicon chip was manufactured. What: /sys/bus/soc Date: January 2012 -contact: Lee Jones +contact: Lee Jones Description: The /sys/bus/soc/ directory contains the usual sub-folders expected under most buses. /sys/bus/soc/devices is of particular From 4a4e8f7f625b48c79ec9f3b5c219a09a6c71fd83 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 12 Jul 2022 11:54:19 -0700 Subject: [PATCH 1062/1436] MAINTAINERS: Change mentions of mpm to olivia Following this mercurial changeset: https://www.mercurial-scm.org/repo/hg-stable/rev/d4ba4d51f85f update the MAINTAINERS entry to replace the now obsolete identity. Signed-off-by: Florian Fainelli Link: https://lore.kernel.org/r/20220712185419.45487-1-f.fainelli@gmail.com Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index a6d3bd9d2a8d..93cf6e8e6700 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7305,7 +7305,7 @@ F: Documentation/admin-guide/media/em28xx* F: drivers/media/usb/em28xx/ EMBEDDED LINUX -M: Matt Mackall +M: Olivia Mackall M: David Woodhouse L: linux-embedded@vger.kernel.org S: Maintained @@ -8686,7 +8686,7 @@ F: include/trace/events/hwmon*.h K: (devm_)?hwmon_device_(un)?register(|_with_groups|_with_info) HARDWARE RANDOM NUMBER GENERATOR CORE -M: Matt Mackall +M: Olivia Mackall M: Herbert Xu L: linux-crypto@vger.kernel.org S: Odd fixes From 79e48cec6cba4eee0bd3a13f31320e33a1729931 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 12 Jul 2022 02:07:22 +0000 Subject: [PATCH 1063/1436] KVM: x86/mmu: Add optimized helper to retrieve an SPTE's index Add spte_index() to dedup all the code that calculates a SPTE's index into its parent's page table and/or spt array. Opportunistically tweak the calculation to avoid pointer arithmetic, which is subtle (subtract in 8-byte chunks) and less performant (requires the compiler to generate the subtraction). Suggested-by: David Matlack Reviewed-by: David Matlack Signed-off-by: Sean Christopherson Message-Id: <20220712020724.1262121-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 22 ++++++++++------------ arch/x86/kvm/mmu/paging_tmpl.h | 4 ++-- arch/x86/kvm/mmu/spte.h | 6 ++++++ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index f7fa4c31b7c5..864a32f96082 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1038,7 +1038,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) struct kvm_rmap_head *rmap_head; sp = sptep_to_sp(spte); - gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt); + gfn = kvm_mmu_page_get_gfn(sp, spte_index(spte)); /* * Unlike rmap_add, rmap_remove does not run in the context of a vCPU @@ -1589,7 +1589,7 @@ static void __rmap_add(struct kvm *kvm, int rmap_count; sp = sptep_to_sp(spte); - kvm_mmu_page_set_translation(sp, spte - sp->spt, gfn, access); + kvm_mmu_page_set_translation(sp, spte_index(spte), gfn, access); kvm_update_page_stats(kvm, sp->role.level, 1); rmap_head = gfn_to_rmap(gfn, sp->role.level, slot); @@ -1716,11 +1716,9 @@ static void kvm_mmu_mark_parents_unsync(struct kvm_mmu_page *sp) static void mark_unsync(u64 *spte) { struct kvm_mmu_page *sp; - unsigned int index; sp = sptep_to_sp(spte); - index = spte - sp->spt; - if (__test_and_set_bit(index, sp->unsync_child_bitmap)) + if (__test_and_set_bit(spte_index(spte), sp->unsync_child_bitmap)) return; if (sp->unsync_children++) return; @@ -2203,7 +2201,7 @@ static union kvm_mmu_page_role kvm_mmu_child_role(u64 *sptep, bool direct, unsig */ if (role.has_4_byte_gpte) { WARN_ON_ONCE(role.level != PG_LEVEL_4K); - role.quadrant = (sptep - parent_sp->spt) % 2; + role.quadrant = spte_index(sptep) & 1; } return role; @@ -2828,7 +2826,7 @@ static int mmu_set_spte(struct kvm_vcpu *vcpu, struct kvm_memory_slot *slot, rmap_add(vcpu, slot, sptep, gfn, pte_access); } else { /* Already rmapped but the pte_access bits may have changed. */ - kvm_mmu_page_set_access(sp, sptep - sp->spt, pte_access); + kvm_mmu_page_set_access(sp, spte_index(sptep), pte_access); } return ret; @@ -2844,7 +2842,7 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu, int i, ret; gfn_t gfn; - gfn = kvm_mmu_page_get_gfn(sp, start - sp->spt); + gfn = kvm_mmu_page_get_gfn(sp, spte_index(start)); slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, access & ACC_WRITE_MASK); if (!slot) return -1; @@ -2870,7 +2868,7 @@ static void __direct_pte_prefetch(struct kvm_vcpu *vcpu, WARN_ON(!sp->role.direct); - i = (sptep - sp->spt) & ~(PTE_PREFETCH_NUM - 1); + i = spte_index(sptep) & ~(PTE_PREFETCH_NUM - 1); spte = sp->spt + i; for (i = 0; i < PTE_PREFETCH_NUM; i++, spte++) { @@ -6156,8 +6154,8 @@ static struct kvm_mmu_page *shadow_mmu_get_sp_for_split(struct kvm *kvm, u64 *hu unsigned int access; gfn_t gfn; - gfn = kvm_mmu_page_get_gfn(huge_sp, huge_sptep - huge_sp->spt); - access = kvm_mmu_page_get_access(huge_sp, huge_sptep - huge_sp->spt); + gfn = kvm_mmu_page_get_gfn(huge_sp, spte_index(huge_sptep)); + access = kvm_mmu_page_get_access(huge_sp, spte_index(huge_sptep)); /* * Note, huge page splitting always uses direct shadow pages, regardless @@ -6231,7 +6229,7 @@ static int shadow_mmu_try_split_huge_page(struct kvm *kvm, u64 spte; /* Grab information for the tracepoint before dropping the MMU lock. */ - gfn = kvm_mmu_page_get_gfn(huge_sp, huge_sptep - huge_sp->spt); + gfn = kvm_mmu_page_get_gfn(huge_sp, spte_index(huge_sptep)); level = huge_sp->role.level; spte = *huge_sptep; diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h index 94bfd5f723ba..f5958071220c 100644 --- a/arch/x86/kvm/mmu/paging_tmpl.h +++ b/arch/x86/kvm/mmu/paging_tmpl.h @@ -595,7 +595,7 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw, if (sp->role.direct) return __direct_pte_prefetch(vcpu, sp, sptep); - i = (sptep - sp->spt) & ~(PTE_PREFETCH_NUM - 1); + i = spte_index(sptep) & ~(PTE_PREFETCH_NUM - 1); spte = sp->spt + i; for (i = 0; i < PTE_PREFETCH_NUM; i++, spte++) { @@ -933,7 +933,7 @@ static void FNAME(invlpg)(struct kvm_vcpu *vcpu, gva_t gva, hpa_t root_hpa) break; pte_gpa = FNAME(get_level1_sp_gpa)(sp); - pte_gpa += (sptep - sp->spt) * sizeof(pt_element_t); + pte_gpa += spte_index(sptep) * sizeof(pt_element_t); mmu_page_zap_pte(vcpu->kvm, sp, sptep, NULL); if (is_shadow_present_pte(old_spte)) diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h index b5c855f5514f..ba3dccb202bc 100644 --- a/arch/x86/kvm/mmu/spte.h +++ b/arch/x86/kvm/mmu/spte.h @@ -190,6 +190,12 @@ static inline bool is_removed_spte(u64 spte) return spte == REMOVED_SPTE; } +/* Get an SPTE's index into its parent's page table (and the spt array). */ +static inline int spte_index(u64 *sptep) +{ + return ((unsigned long)sptep / sizeof(*sptep)) & (SPTE_ENT_PER_PAGE - 1); +} + /* * In some cases, we need to preserve the GFN of a non-present or reserved * SPTE when we usurp the upper five bits of the physical address space to From 39944ab99c2f9cc54272b9b871e3e759ebaa960b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 12 Jul 2022 02:07:23 +0000 Subject: [PATCH 1064/1436] KVM: x86/mmu: Expand quadrant comment for PG_LEVEL_4K shadow pages Tweak the comment above the computation of the quadrant for PG_LEVEL_4K shadow pages to explicitly call out how and why KVM uses role.quadrant to consume gPTE bits. Opportunistically wrap an unnecessarily long line. No functional change intended. Link: https://lore.kernel.org/all/YqvWvBv27fYzOFdE@google.com Reviewed-by: David Matlack Signed-off-by: Sean Christopherson Message-Id: <20220712020724.1262121-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 864a32f96082..7a65e57b9b41 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2168,7 +2168,8 @@ static struct kvm_mmu_page *kvm_mmu_get_shadow_page(struct kvm_vcpu *vcpu, return __kvm_mmu_get_shadow_page(vcpu->kvm, vcpu, &caches, gfn, role); } -static union kvm_mmu_page_role kvm_mmu_child_role(u64 *sptep, bool direct, unsigned int access) +static union kvm_mmu_page_role kvm_mmu_child_role(u64 *sptep, bool direct, + unsigned int access) { struct kvm_mmu_page *parent_sp = sptep_to_sp(sptep); union kvm_mmu_page_role role; @@ -2195,9 +2196,15 @@ static union kvm_mmu_page_role kvm_mmu_child_role(u64 *sptep, bool direct, unsig * uses 2 PAE page tables, each mapping a 2MiB region. For these, * @role.quadrant encodes which half of the region they map. * - * Note, the 4 PAE page directories are pre-allocated and the quadrant - * assigned in mmu_alloc_root(). So only page tables need to be handled - * here. + * Concretely, a 4-byte PDE consumes bits 31:22, while an 8-byte PDE + * consumes bits 29:21. To consume bits 31:30, KVM's uses 4 shadow + * PDPTEs; those 4 PAE page directories are pre-allocated and their + * quadrant is assigned in mmu_alloc_root(). A 4-byte PTE consumes + * bits 21:12, while an 8-byte PTE consumes bits 20:12. To consume + * bit 21 in the PTE (the child here), KVM propagates that bit to the + * quadrant, i.e. sets quadrant to '0' or '1'. The parent 8-byte PDE + * covers bit 21 (see above), thus the quadrant is calculated from the + * _least_ significant bit of the PDE index. */ if (role.has_4_byte_gpte) { WARN_ON_ONCE(role.level != PG_LEVEL_4K); From dfd4eb444e5cef4387605d1eef1866ceea0544ce Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 12 Jul 2022 02:07:24 +0000 Subject: [PATCH 1065/1436] KVM: x86/mmu: Fix typo and tweak comment for split_desc_cache capacity Remove a spurious closing paranthesis and tweak the comment about the cache capacity for PTE descriptors (rmaps) eager page splitting to tone down the assertion slightly, and to call out that topup requires dropping mmu_lock, which is the real motivation for avoiding topup (as opposed to memory usage). Cc: David Matlack Signed-off-by: Sean Christopherson Message-Id: <20220712020724.1262121-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 7a65e57b9b41..52664c3caaab 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -6125,14 +6125,15 @@ static int topup_split_caches(struct kvm *kvm) { /* * Allocating rmap list entries when splitting huge pages for nested - * MMUs is uncommon as KVM needs to allocate if and only if there is + * MMUs is uncommon as KVM needs to use a list if and only if there is * more than one rmap entry for a gfn, i.e. requires an L1 gfn to be - * aliased by multiple L2 gfns. Aliasing gfns when using TDP is very - * atypical for VMMs; a few gfns are often aliased during boot, e.g. - * when remapping firmware, but aliasing rarely occurs post-boot). If - * there is only one rmap entry, rmap->val points directly at that one - * entry and doesn't need to allocate a list. Buffer the cache by the - * default capacity so that KVM doesn't have to topup the cache if it + * aliased by multiple L2 gfns and/or from multiple nested roots with + * different roles. Aliasing gfns when using TDP is atypical for VMMs; + * a few gfns are often aliased during boot, e.g. when remapping BIOS, + * but aliasing rarely occurs post-boot or for many gfns. If there is + * only one rmap entry, rmap->val points directly at that one entry and + * doesn't need to allocate a list. Buffer the cache by the default + * capacity so that KVM doesn't have to drop mmu_lock to topup if KVM * encounters an aliased gfn or two. */ const int capacity = SPLIT_DESC_CACHE_MIN_NR_OBJECTS + From bdc2d7ad10724de31463a0cdbd88b0ad7353a6de Mon Sep 17 00:00:00 2001 From: Maxim Levitsky Date: Thu, 14 Jul 2022 15:44:53 +0300 Subject: [PATCH 1066/1436] KVM: SVM: fix task switch emulation on INTn instruction. Recently KVM's SVM code switched to re-injecting software interrupt events, if something prevented their delivery. Task switch due to task gate in the IDT, however is an exception to this rule, because in this case, INTn instruction causes a task switch intercept and its emulation completes the INTn emulation as well. Add a missing case to task_switch_interception for that. This fixes 32 bit kvm unit test taskswitch2. Fixes: 7e5b5ef8dca322 ("KVM: SVM: Re-inject INTn instead of retrying the insn on "failure"") Signed-off-by: Maxim Levitsky Reviewed-by: Maciej S. Szmigiero Message-Id: <20220714124453.188655-1-mlevitsk@redhat.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/svm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 37ce061dfc76..1d8eb3333f46 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -2446,6 +2446,7 @@ static int task_switch_interception(struct kvm_vcpu *vcpu) kvm_clear_exception_queue(vcpu); break; case SVM_EXITINTINFO_TYPE_INTR: + case SVM_EXITINTINFO_TYPE_SOFT: kvm_clear_interrupt_queue(vcpu); break; default: From 277ad7d58611b455662f2e3f7bd24ce5bfeb2fdc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 12 Jul 2022 02:06:45 +0200 Subject: [PATCH 1067/1436] KVM: x86: Add dedicated helper to get CPUID entry with significant index Add a second CPUID helper, kvm_find_cpuid_entry_index(), to handle KVM queries for CPUID leaves whose index _may_ be significant, and drop the index param from the existing kvm_find_cpuid_entry(). Add a WARN in the inner helper, cpuid_entry2_find(), to detect attempts to retrieve a CPUID entry whose index is significant without explicitly providing an index. Using an explicit magic number and letting callers omit the index avoids confusion by eliminating the myriad cases where KVM specifies '0' as a dummy value. Suggested-by: Paolo Bonzini Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/cpuid.c | 80 +++++++++++++++++++++++++++--------- arch/x86/kvm/cpuid.h | 16 ++++---- arch/x86/kvm/hyperv.c | 8 ++-- arch/x86/kvm/svm/svm.c | 2 +- arch/x86/kvm/vmx/pmu_intel.c | 4 +- arch/x86/kvm/vmx/sgx.c | 8 ++-- arch/x86/kvm/vmx/vmx.c | 6 +-- arch/x86/kvm/x86.c | 2 +- 8 files changed, 84 insertions(+), 42 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index d47222ab8e6e..75dcf7a72605 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -67,9 +67,17 @@ u32 xstate_required_size(u64 xstate_bv, bool compacted) #define F feature_bit #define SF(name) (boot_cpu_has(X86_FEATURE_##name) ? F(name) : 0) +/* + * Magic value used by KVM when querying userspace-provided CPUID entries and + * doesn't care about the CPIUD index because the index of the function in + * question is not significant. Note, this magic value must have at least one + * bit set in bits[63:32] and must be consumed as a u64 by cpuid_entry2_find() + * to avoid false positives when processing guest CPUID input. + */ +#define KVM_CPUID_INDEX_NOT_SIGNIFICANT -1ull static inline struct kvm_cpuid_entry2 *cpuid_entry2_find( - struct kvm_cpuid_entry2 *entries, int nent, u32 function, u32 index) + struct kvm_cpuid_entry2 *entries, int nent, u32 function, u64 index) { struct kvm_cpuid_entry2 *e; int i; @@ -77,9 +85,31 @@ static inline struct kvm_cpuid_entry2 *cpuid_entry2_find( for (i = 0; i < nent; i++) { e = &entries[i]; - if (e->function == function && - (!(e->flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX) || e->index == index)) + if (e->function != function) + continue; + + /* + * If the index isn't significant, use the first entry with a + * matching function. It's userspace's responsibilty to not + * provide "duplicate" entries in all cases. + */ + if (!(e->flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX) || e->index == index) return e; + + + /* + * Similarly, use the first matching entry if KVM is doing a + * lookup (as opposed to emulating CPUID) for a function that's + * architecturally defined as not having a significant index. + */ + if (index == KVM_CPUID_INDEX_NOT_SIGNIFICANT) { + /* + * Direct lookups from KVM should not diverge from what + * KVM defines internally (the architectural behavior). + */ + WARN_ON_ONCE(cpuid_function_is_indexed(function)); + return e; + } } return NULL; @@ -96,7 +126,8 @@ static int kvm_check_cpuid(struct kvm_vcpu *vcpu, * The existing code assumes virtual address is 48-bit or 57-bit in the * canonical address checks; exit if it is ever changed. */ - best = cpuid_entry2_find(entries, nent, 0x80000008, 0); + best = cpuid_entry2_find(entries, nent, 0x80000008, + KVM_CPUID_INDEX_NOT_SIGNIFICANT); if (best) { int vaddr_bits = (best->eax & 0xff00) >> 8; @@ -151,7 +182,7 @@ static void kvm_update_kvm_cpuid_base(struct kvm_vcpu *vcpu) vcpu->arch.kvm_cpuid_base = 0; for_each_possible_hypervisor_cpuid_base(function) { - entry = kvm_find_cpuid_entry(vcpu, function, 0); + entry = kvm_find_cpuid_entry(vcpu, function); if (entry) { u32 signature[3]; @@ -177,7 +208,8 @@ static struct kvm_cpuid_entry2 *__kvm_find_kvm_cpuid_features(struct kvm_vcpu *v if (!base) return NULL; - return cpuid_entry2_find(entries, nent, base | KVM_CPUID_FEATURES, 0); + return cpuid_entry2_find(entries, nent, base | KVM_CPUID_FEATURES, + KVM_CPUID_INDEX_NOT_SIGNIFICANT); } static struct kvm_cpuid_entry2 *kvm_find_kvm_cpuid_features(struct kvm_vcpu *vcpu) @@ -219,7 +251,7 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e struct kvm_cpuid_entry2 *best; u64 guest_supported_xcr0 = cpuid_get_supported_xcr0(entries, nent); - best = cpuid_entry2_find(entries, nent, 1, 0); + best = cpuid_entry2_find(entries, nent, 1, KVM_CPUID_INDEX_NOT_SIGNIFICANT); if (best) { /* Update OSXSAVE bit */ if (boot_cpu_has(X86_FEATURE_XSAVE)) @@ -250,7 +282,7 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e best->eax &= ~(1 << KVM_FEATURE_PV_UNHALT); if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT)) { - best = cpuid_entry2_find(entries, nent, 0x1, 0); + best = cpuid_entry2_find(entries, nent, 0x1, KVM_CPUID_INDEX_NOT_SIGNIFICANT); if (best) cpuid_entry_change(best, X86_FEATURE_MWAIT, vcpu->arch.ia32_misc_enable_msr & @@ -285,7 +317,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) struct kvm_cpuid_entry2 *best; u64 guest_supported_xcr0; - best = kvm_find_cpuid_entry(vcpu, 1, 0); + best = kvm_find_cpuid_entry(vcpu, 1); if (best && apic) { if (cpuid_entry_has(best, X86_FEATURE_TSC_DEADLINE_TIMER)) apic->lapic_timer.timer_mode_mask = 3 << 17; @@ -325,10 +357,10 @@ int cpuid_query_maxphyaddr(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; - best = kvm_find_cpuid_entry(vcpu, 0x80000000, 0); + best = kvm_find_cpuid_entry(vcpu, 0x80000000); if (!best || best->eax < 0x80000008) goto not_found; - best = kvm_find_cpuid_entry(vcpu, 0x80000008, 0); + best = kvm_find_cpuid_entry(vcpu, 0x80000008); if (best) return best->eax & 0xff; not_found: @@ -1302,12 +1334,20 @@ out_free: return r; } -struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, - u32 function, u32 index) +struct kvm_cpuid_entry2 *kvm_find_cpuid_entry_index(struct kvm_vcpu *vcpu, + u32 function, u32 index) { return cpuid_entry2_find(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent, function, index); } +EXPORT_SYMBOL_GPL(kvm_find_cpuid_entry_index); + +struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, + u32 function) +{ + return cpuid_entry2_find(vcpu->arch.cpuid_entries, vcpu->arch.cpuid_nent, + function, KVM_CPUID_INDEX_NOT_SIGNIFICANT); +} EXPORT_SYMBOL_GPL(kvm_find_cpuid_entry); /* @@ -1344,7 +1384,7 @@ get_out_of_range_cpuid_entry(struct kvm_vcpu *vcpu, u32 *fn_ptr, u32 index) struct kvm_cpuid_entry2 *basic, *class; u32 function = *fn_ptr; - basic = kvm_find_cpuid_entry(vcpu, 0, 0); + basic = kvm_find_cpuid_entry(vcpu, 0); if (!basic) return NULL; @@ -1353,11 +1393,11 @@ get_out_of_range_cpuid_entry(struct kvm_vcpu *vcpu, u32 *fn_ptr, u32 index) return NULL; if (function >= 0x40000000 && function <= 0x4fffffff) - class = kvm_find_cpuid_entry(vcpu, function & 0xffffff00, 0); + class = kvm_find_cpuid_entry(vcpu, function & 0xffffff00); else if (function >= 0xc0000000) - class = kvm_find_cpuid_entry(vcpu, 0xc0000000, 0); + class = kvm_find_cpuid_entry(vcpu, 0xc0000000); else - class = kvm_find_cpuid_entry(vcpu, function & 0x80000000, 0); + class = kvm_find_cpuid_entry(vcpu, function & 0x80000000); if (class && function <= class->eax) return NULL; @@ -1375,7 +1415,7 @@ get_out_of_range_cpuid_entry(struct kvm_vcpu *vcpu, u32 *fn_ptr, u32 index) * the effective CPUID entry is the max basic leaf. Note, the index of * the original requested leaf is observed! */ - return kvm_find_cpuid_entry(vcpu, basic->eax, index); + return kvm_find_cpuid_entry_index(vcpu, basic->eax, index); } bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, @@ -1385,7 +1425,7 @@ bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, struct kvm_cpuid_entry2 *entry; bool exact, used_max_basic = false; - entry = kvm_find_cpuid_entry(vcpu, function, index); + entry = kvm_find_cpuid_entry_index(vcpu, function, index); exact = !!entry; if (!entry && !exact_only) { @@ -1414,7 +1454,7 @@ bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, * exists. EDX can be copied from any existing index. */ if (function == 0xb || function == 0x1f) { - entry = kvm_find_cpuid_entry(vcpu, function, 1); + entry = kvm_find_cpuid_entry_index(vcpu, function, 1); if (entry) { *ecx = index & 0xff; *edx = entry->edx; diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index ac72aabba981..b1658c0de847 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -13,8 +13,10 @@ void kvm_set_cpu_caps(void); void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu); void kvm_update_pv_runtime(struct kvm_vcpu *vcpu); +struct kvm_cpuid_entry2 *kvm_find_cpuid_entry_index(struct kvm_vcpu *vcpu, + u32 function, u32 index); struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, - u32 function, u32 index); + u32 function); int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 __user *entries, unsigned int type); @@ -76,7 +78,7 @@ static __always_inline u32 *guest_cpuid_get_register(struct kvm_vcpu *vcpu, const struct cpuid_reg cpuid = x86_feature_cpuid(x86_feature); struct kvm_cpuid_entry2 *entry; - entry = kvm_find_cpuid_entry(vcpu, cpuid.function, cpuid.index); + entry = kvm_find_cpuid_entry_index(vcpu, cpuid.function, cpuid.index); if (!entry) return NULL; @@ -109,7 +111,7 @@ static inline bool guest_cpuid_is_amd_or_hygon(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; - best = kvm_find_cpuid_entry(vcpu, 0, 0); + best = kvm_find_cpuid_entry(vcpu, 0); return best && (is_guest_vendor_amd(best->ebx, best->ecx, best->edx) || is_guest_vendor_hygon(best->ebx, best->ecx, best->edx)); @@ -119,7 +121,7 @@ static inline bool guest_cpuid_is_intel(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; - best = kvm_find_cpuid_entry(vcpu, 0, 0); + best = kvm_find_cpuid_entry(vcpu, 0); return best && is_guest_vendor_intel(best->ebx, best->ecx, best->edx); } @@ -127,7 +129,7 @@ static inline int guest_cpuid_family(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; - best = kvm_find_cpuid_entry(vcpu, 0x1, 0); + best = kvm_find_cpuid_entry(vcpu, 0x1); if (!best) return -1; @@ -138,7 +140,7 @@ static inline int guest_cpuid_model(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; - best = kvm_find_cpuid_entry(vcpu, 0x1, 0); + best = kvm_find_cpuid_entry(vcpu, 0x1); if (!best) return -1; @@ -154,7 +156,7 @@ static inline int guest_cpuid_stepping(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; - best = kvm_find_cpuid_entry(vcpu, 0x1, 0); + best = kvm_find_cpuid_entry(vcpu, 0x1); if (!best) return -1; diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index e2e95a6fccfd..ed804447589c 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -1992,7 +1992,7 @@ void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu) struct kvm_cpuid_entry2 *entry; struct kvm_vcpu_hv *hv_vcpu; - entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_INTERFACE, 0); + entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_INTERFACE); if (entry && entry->eax == HYPERV_CPUID_SIGNATURE_EAX) { vcpu->arch.hyperv_enabled = true; } else { @@ -2005,7 +2005,7 @@ void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu) hv_vcpu = to_hv_vcpu(vcpu); - entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_FEATURES, 0); + entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_FEATURES); if (entry) { hv_vcpu->cpuid_cache.features_eax = entry->eax; hv_vcpu->cpuid_cache.features_ebx = entry->ebx; @@ -2016,7 +2016,7 @@ void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu) hv_vcpu->cpuid_cache.features_edx = 0; } - entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_ENLIGHTMENT_INFO, 0); + entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_ENLIGHTMENT_INFO); if (entry) { hv_vcpu->cpuid_cache.enlightenments_eax = entry->eax; hv_vcpu->cpuid_cache.enlightenments_ebx = entry->ebx; @@ -2025,7 +2025,7 @@ void kvm_hv_set_cpuid(struct kvm_vcpu *vcpu) hv_vcpu->cpuid_cache.enlightenments_ebx = 0; } - entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES, 0); + entry = kvm_find_cpuid_entry(vcpu, HYPERV_CPUID_SYNDBG_PLATFORM_CAPABILITIES); if (entry) hv_vcpu->cpuid_cache.syndbg_cap_eax = entry->eax; else diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 1d8eb3333f46..84414eafcd0d 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4194,7 +4194,7 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) /* For sev guests, the memory encryption bit is not reserved in CR3. */ if (sev_guest(vcpu->kvm)) { - best = kvm_find_cpuid_entry(vcpu, 0x8000001F, 0); + best = kvm_find_cpuid_entry(vcpu, 0x8000001F); if (best) vcpu->arch.reserved_gpa_bits &= ~(1UL << (best->ebx & 0x3f)); } diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 53ccba896e77..4bc098fbec31 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -531,7 +531,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->pebs_enable_mask = ~0ull; pmu->pebs_data_cfg_mask = ~0ull; - entry = kvm_find_cpuid_entry(vcpu, 0xa, 0); + entry = kvm_find_cpuid_entry(vcpu, 0xa); if (!entry || !vcpu->kvm->arch.enable_pmu) return; eax.full = entry->eax; @@ -577,7 +577,7 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->global_ovf_ctrl_mask &= ~MSR_CORE_PERF_GLOBAL_OVF_CTRL_TRACE_TOPA_PMI; - entry = kvm_find_cpuid_entry(vcpu, 7, 0); + entry = kvm_find_cpuid_entry_index(vcpu, 7, 0); if (entry && (boot_cpu_has(X86_FEATURE_HLE) || boot_cpu_has(X86_FEATURE_RTM)) && (entry->ebx & (X86_FEATURE_HLE|X86_FEATURE_RTM))) { diff --git a/arch/x86/kvm/vmx/sgx.c b/arch/x86/kvm/vmx/sgx.c index 7ae8aa73724c..aba8cebdc587 100644 --- a/arch/x86/kvm/vmx/sgx.c +++ b/arch/x86/kvm/vmx/sgx.c @@ -148,8 +148,8 @@ static int __handle_encls_ecreate(struct kvm_vcpu *vcpu, u8 max_size_log2; int trapnr, ret; - sgx_12_0 = kvm_find_cpuid_entry(vcpu, 0x12, 0); - sgx_12_1 = kvm_find_cpuid_entry(vcpu, 0x12, 1); + sgx_12_0 = kvm_find_cpuid_entry_index(vcpu, 0x12, 0); + sgx_12_1 = kvm_find_cpuid_entry_index(vcpu, 0x12, 1); if (!sgx_12_0 || !sgx_12_1) { kvm_prepare_emulation_failure_exit(vcpu); return 0; @@ -431,7 +431,7 @@ static bool sgx_intercept_encls_ecreate(struct kvm_vcpu *vcpu) if (!vcpu->kvm->arch.sgx_provisioning_allowed) return true; - guest_cpuid = kvm_find_cpuid_entry(vcpu, 0x12, 0); + guest_cpuid = kvm_find_cpuid_entry_index(vcpu, 0x12, 0); if (!guest_cpuid) return true; @@ -439,7 +439,7 @@ static bool sgx_intercept_encls_ecreate(struct kvm_vcpu *vcpu) if (guest_cpuid->ebx != ebx || guest_cpuid->edx != edx) return true; - guest_cpuid = kvm_find_cpuid_entry(vcpu, 0x12, 1); + guest_cpuid = kvm_find_cpuid_entry_index(vcpu, 0x12, 1); if (!guest_cpuid) return true; diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 3842e121070a..e6ab2c2c4d3b 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7430,7 +7430,7 @@ static void nested_vmx_cr_fixed1_bits_update(struct kvm_vcpu *vcpu) vmx->nested.msrs.cr4_fixed1 |= (_cr4_mask); \ } while (0) - entry = kvm_find_cpuid_entry(vcpu, 0x1, 0); + entry = kvm_find_cpuid_entry(vcpu, 0x1); cr4_fixed1_update(X86_CR4_VME, edx, feature_bit(VME)); cr4_fixed1_update(X86_CR4_PVI, edx, feature_bit(VME)); cr4_fixed1_update(X86_CR4_TSD, edx, feature_bit(TSC)); @@ -7446,7 +7446,7 @@ static void nested_vmx_cr_fixed1_bits_update(struct kvm_vcpu *vcpu) cr4_fixed1_update(X86_CR4_PCIDE, ecx, feature_bit(PCID)); cr4_fixed1_update(X86_CR4_OSXSAVE, ecx, feature_bit(XSAVE)); - entry = kvm_find_cpuid_entry(vcpu, 0x7, 0); + entry = kvm_find_cpuid_entry_index(vcpu, 0x7, 0); cr4_fixed1_update(X86_CR4_FSGSBASE, ebx, feature_bit(FSGSBASE)); cr4_fixed1_update(X86_CR4_SMEP, ebx, feature_bit(SMEP)); cr4_fixed1_update(X86_CR4_SMAP, ebx, feature_bit(SMAP)); @@ -7481,7 +7481,7 @@ static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) int i; for (i = 0; i < PT_CPUID_LEAVES; i++) { - best = kvm_find_cpuid_entry(vcpu, 0x14, i); + best = kvm_find_cpuid_entry_index(vcpu, 0x14, i); if (!best) return; vmx->pt_desc.caps[CPUID_EAX + i*PT_CPUID_REGS_NUM] = best->eax; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0729e434c51b..f389691d8c04 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -11735,7 +11735,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) * i.e. it's impossible for kvm_find_cpuid_entry() to find a valid entry * on RESET. But, go through the motions in case that's ever remedied. */ - cpuid_0x1 = kvm_find_cpuid_entry(vcpu, 1, 0); + cpuid_0x1 = kvm_find_cpuid_entry(vcpu, 1); kvm_rdx_write(vcpu, cpuid_0x1 ? cpuid_0x1->eax : 0x600); static_call(kvm_x86_vcpu_reset)(vcpu, init_event); From ba28401bb93e5c779d5762c4eb0eb665493e5dd4 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Thu, 14 Jul 2022 15:37:07 +0000 Subject: [PATCH 1068/1436] KVM: x86: Restrict get_mt_mask() to a u8, use KVM_X86_OP_OPTIONAL_RET0 Restrict get_mt_mask() to a u8 and reintroduce using a RET0 static_call for the SVM implementation. EPT stores the memtype information in the lower 8 bits (bits 6:3 to be precise), and even returns a shifted u8 without an explicit cast to a larger type; there's no need to return a full u64. Note, RET0 doesn't play nice with a u64 return on 32-bit kernels, see commit bf07be36cd88 ("KVM: x86: do not use KVM_X86_OP_OPTIONAL_RET0 for get_mt_mask"). Signed-off-by: Sean Christopherson Message-Id: <20220714153707.3239119-1-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/include/asm/kvm-x86-ops.h | 2 +- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/svm/svm.c | 6 ------ arch/x86/kvm/vmx/vmx.c | 2 +- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h index 6f2f1affbb78..51f777071584 100644 --- a/arch/x86/include/asm/kvm-x86-ops.h +++ b/arch/x86/include/asm/kvm-x86-ops.h @@ -88,7 +88,7 @@ KVM_X86_OP(deliver_interrupt) KVM_X86_OP_OPTIONAL(sync_pir_to_irr) KVM_X86_OP_OPTIONAL_RET0(set_tss_addr) KVM_X86_OP_OPTIONAL_RET0(set_identity_map_addr) -KVM_X86_OP(get_mt_mask) +KVM_X86_OP_OPTIONAL_RET0(get_mt_mask) KVM_X86_OP(load_mmu_pgd) KVM_X86_OP(has_wbinvd_exit) KVM_X86_OP(get_l2_tsc_offset) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index d4ece7bf2124..e8281d64a431 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1545,7 +1545,7 @@ struct kvm_x86_ops { int (*sync_pir_to_irr)(struct kvm_vcpu *vcpu); int (*set_tss_addr)(struct kvm *kvm, unsigned int addr); int (*set_identity_map_addr)(struct kvm *kvm, u64 ident_addr); - u64 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio); + u8 (*get_mt_mask)(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio); void (*load_mmu_pgd)(struct kvm_vcpu *vcpu, hpa_t root_hpa, int root_level); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 84414eafcd0d..ba81a7e58f75 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4159,11 +4159,6 @@ static bool svm_has_emulated_msr(struct kvm *kvm, u32 index) return true; } -static u64 svm_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio) -{ - return 0; -} - static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -4815,7 +4810,6 @@ static struct kvm_x86_ops svm_x86_ops __initdata = { .check_apicv_inhibit_reasons = avic_check_apicv_inhibit_reasons, .apicv_post_state_restore = avic_apicv_post_state_restore, - .get_mt_mask = svm_get_mt_mask, .get_exit_info = svm_get_exit_info, .vcpu_after_set_cpuid = svm_vcpu_after_set_cpuid, diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index e6ab2c2c4d3b..b0cc911a8f6f 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7354,7 +7354,7 @@ static int __init vmx_check_processor_compat(void) return 0; } -static u64 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio) +static u8 vmx_get_mt_mask(struct kvm_vcpu *vcpu, gfn_t gfn, bool is_mmio) { u8 cache; From 8031d87aa9953ddeb047a5356ebd0b240c30f233 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 12 Jul 2022 11:46:53 -0700 Subject: [PATCH 1069/1436] KVM: x86: Check target, not vCPU's x2APIC ID, when applying hotplug hack When applying the hotplug hack to match x2APIC IDs for vCPUs in xAPIC mode, check the target APID ID for being unaddressable in xAPIC mode instead of checking the vCPU's x2APIC ID, and in that case proceed as if apic_x2apic_mode(vcpu) were true. Functionally, it does not matter whether you compare kvm_x2apic_id(apic) or mda with 0xff, since the two values are then checked for equality. But in isolation, checking the x2APIC ID takes an unnecessary dependency on the x2APIC ID being read-only (which isn't strictly true on AMD CPUs, and is difficult to document as well); it also requires KVM to fallthrough and check the xAPIC ID as well to deal with a writable xAPIC ID, whereas the xAPIC ID _can't_ match a target ID greater than 0xff. Opportunistically reword the comment to call out the various subtleties, and to fix a typo reported by Zhang Jiaming. No functional change intended. Cc: Zhang Jiaming Signed-off-by: Sean Christopherson Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 50354c7a2dc1..9d4f73c4dc02 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -826,17 +826,17 @@ static bool kvm_apic_match_physical_addr(struct kvm_lapic *apic, u32 mda) if (kvm_apic_broadcast(apic, mda)) return true; - if (apic_x2apic_mode(apic)) - return mda == kvm_x2apic_id(apic); - /* - * Hotplug hack: Make LAPIC in xAPIC mode also accept interrupts as if - * it were in x2APIC mode. Hotplugged VCPUs start in xAPIC mode and - * this allows unique addressing of VCPUs with APIC ID over 0xff. - * The 0xff condition is needed because writeable xAPIC ID. + * Hotplug hack: Accept interrupts for vCPUs in xAPIC mode as if they + * were in x2APIC mode if the target APIC ID can't be encoded as an + * xAPIC ID. This allows unique addressing of hotplugged vCPUs (which + * start in xAPIC mode) with an APIC ID that is unaddressable in xAPIC + * mode. Match the x2APIC ID if and only if the target APIC ID can't + * be encoded in xAPIC to avoid spurious matches against a vCPU that + * changed its (addressable) xAPIC ID (which is writable). */ - if (kvm_x2apic_id(apic) > 0xff && mda == kvm_x2apic_id(apic)) - return true; + if (apic_x2apic_mode(apic) || mda > 0xff) + return mda == kvm_x2apic_id(apic); return mda == kvm_xapic_id(apic); } From e0e52a5cc6a589a918745e4667aaaaa564f73934 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 13 Jul 2022 23:11:01 +0200 Subject: [PATCH 1070/1436] ACPI: video: Fix acpi_video_handles_brightness_key_presses() Commit 3a0cf7ab8df3 ("ACPI: video: Change how we determine if brightness key-presses are handled") made acpi_video_handles_brightness_key_presses() report false when none of the ACPI Video Devices support backlight control. But it turns out that at least on a Dell Inspiron N4010 there is no ACPI backlight control, yet brightness hotkeys are still reported through the ACPI Video Bus; and since acpi_video_handles_brightness_key_presses() now returns false, brightness keypresses are now reported twice. To fix this rename the has_backlight flag to may_report_brightness_keys and also set it the first time a brightness key press event is received. Depending on the delivery of the other ACPI (WMI) event vs the ACPI Video Bus event this means that the first brightness key press might still get reported twice, but all further keypresses will be filtered as before. Note that this relies on other drivers reporting brightness key events calling acpi_video_handles_brightness_key_presses() when delivering the events (rather then once during driver probe). This is already required and documented in include/acpi/video.h: /* * Note: The value returned by acpi_video_handles_brightness_key_presses() * may change over time and should not be cached. */ Fixes: 3a0cf7ab8df3 ("ACPI: video: Change how we determine if brightness key-presses are handled") Link: https://lore.kernel.org/regressions/CALF=6jEe5G8+r1Wo0vvz4GjNQQhdkLT5p8uCHn6ZXhg4nsOWow@mail.gmail.com/ Reported-and-tested-by: Ben Greening Signed-off-by: Hans de Goede Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20220713211101.85547-2-hdegoede@redhat.com --- drivers/acpi/acpi_video.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 43177c20ce4f..eaea733b368a 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -73,7 +73,7 @@ module_param(device_id_scheme, bool, 0444); static int only_lcd = -1; module_param(only_lcd, int, 0444); -static bool has_backlight; +static bool may_report_brightness_keys; static int register_count; static DEFINE_MUTEX(register_count_mutex); static DEFINE_MUTEX(video_list_lock); @@ -1224,7 +1224,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device, acpi_video_device_find_cap(data); if (data->cap._BCM && data->cap._BCL) - has_backlight = true; + may_report_brightness_keys = true; mutex_lock(&video->device_list_lock); list_add_tail(&data->entry, &video->video_device_list); @@ -1693,6 +1693,9 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data) break; } + if (keycode) + may_report_brightness_keys = true; + acpi_notifier_call_chain(device, event, 0); if (keycode && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS)) { @@ -2253,7 +2256,7 @@ void acpi_video_unregister(void) if (register_count) { acpi_bus_unregister_driver(&acpi_video_bus); register_count = 0; - has_backlight = false; + may_report_brightness_keys = false; } mutex_unlock(®ister_count_mutex); } @@ -2275,7 +2278,7 @@ void acpi_video_unregister_backlight(void) bool acpi_video_handles_brightness_key_presses(void) { - return has_backlight && + return may_report_brightness_keys && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS); } EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses); From aeb47cb10aa4c2f794aa85e9fd3c9ff028455369 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Wed, 13 Jul 2022 06:09:16 +0200 Subject: [PATCH 1071/1436] MAINTAINERS: repair file entry in MICROSOFT SURFACE AGGREGATOR TABLET-MODE SWITCH Commit 9f794056db5b ("platform/surface: Add KIP/POS tablet-mode switch driver") adds the section MICROSOFT SURFACE AGGREGATOR TABLET-MODE SWITCH with a file entry, but the file that is added with this commit is actually named slightly differently. file entry name: drivers/platform/surface/surface_aggregator_tablet_switch.c added file name: drivers/platform/surface/surface_aggregator_tabletsw.c Hence, ./scripts/get_maintainer.pl --self-test=patterns complains about a broken reference. Repair this file entry to the actual file name added with the commit above. Fixes: 9f794056db5b ("platform/surface: Add KIP/POS tablet-mode switch driver") Signed-off-by: Lukas Bulwahn Reviewed-by: Andy Shevchenko Reviewed-by: Maximilian Luz Link: https://lore.kernel.org/r/20220713040916.1767-1-lukas.bulwahn@gmail.com Signed-off-by: Hans de Goede --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index e01478062c56..7a1b1b08de6d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13180,7 +13180,7 @@ MICROSOFT SURFACE AGGREGATOR TABLET-MODE SWITCH M: Maximilian Luz L: platform-driver-x86@vger.kernel.org S: Maintained -F: drivers/platform/surface/surface_aggregator_tablet_switch.c +F: drivers/platform/surface/surface_aggregator_tabletsw.c MICROSOFT SURFACE BATTERY AND AC DRIVERS M: Maximilian Luz From b644c95598adfe2b968e97daee3a890dd2fda84d Mon Sep 17 00:00:00 2001 From: PaddyKP_Yao Date: Mon, 11 Jul 2022 19:51:25 +0800 Subject: [PATCH 1072/1436] platform/x86: asus-wmi: Add mic-mute LED classdev support In some new ASUS devices, hotkey Fn+F13 is used for mic mute. If mic-mute LED is present by checking WMI ASUS_WMI_DEVID_MICMUTE_LED, we will add a mic-mute LED classdev, asus::micmute, in the asus-wmi driver to control it. The binding of mic-mute LED controls will be swithched with LED trigger. Signed-off-by: PaddyKP_Yao Link: https://lore.kernel.org/r/20220711115125.2072508-1-PaddyKP_Yao@asus.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/Kconfig | 2 ++ drivers/platform/x86/asus-wmi.c | 25 ++++++++++++++++++++++ include/linux/platform_data/x86/asus-wmi.h | 1 + 3 files changed, 28 insertions(+) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 7fa88efeef4d..6a33c862452b 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -273,6 +273,8 @@ config ASUS_WMI select INPUT_SPARSEKMAP select LEDS_CLASS select NEW_LEDS + select LEDS_TRIGGERS + select LEDS_TRIGGER_AUDIO select ACPI_PLATFORM_PROFILE help Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 62ce198a3463..89b604e04d7f 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -208,6 +208,7 @@ struct asus_wmi { int kbd_led_wk; struct led_classdev lightbar_led; int lightbar_led_wk; + struct led_classdev micmute_led; struct workqueue_struct *led_workqueue; struct work_struct tpd_led_work; struct work_struct wlan_led_work; @@ -1028,12 +1029,23 @@ static enum led_brightness lightbar_led_get(struct led_classdev *led_cdev) return result & ASUS_WMI_DSTS_LIGHTBAR_MASK; } +static int micmute_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int state = brightness != LED_OFF; + int err; + + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MICMUTE_LED, state, NULL); + return err < 0 ? err : 0; +} + static void asus_wmi_led_exit(struct asus_wmi *asus) { led_classdev_unregister(&asus->kbd_led); led_classdev_unregister(&asus->tpd_led); led_classdev_unregister(&asus->wlan_led); led_classdev_unregister(&asus->lightbar_led); + led_classdev_unregister(&asus->micmute_led); if (asus->led_workqueue) destroy_workqueue(asus->led_workqueue); @@ -1105,6 +1117,19 @@ static int asus_wmi_led_init(struct asus_wmi *asus) &asus->lightbar_led); } + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MICMUTE_LED)) { + asus->micmute_led.name = "asus::micmute"; + asus->micmute_led.max_brightness = 1; + asus->micmute_led.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE); + asus->micmute_led.brightness_set_blocking = micmute_led_set; + asus->micmute_led.default_trigger = "audio-micmute"; + + rv = led_classdev_register(&asus->platform_device->dev, + &asus->micmute_led); + if (rv) + goto error; + } + error: if (rv) asus_wmi_led_exit(asus); diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index a571b47ff362..98f2b2f20f3e 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -49,6 +49,7 @@ #define ASUS_WMI_DEVID_LED4 0x00020014 #define ASUS_WMI_DEVID_LED5 0x00020015 #define ASUS_WMI_DEVID_LED6 0x00020016 +#define ASUS_WMI_DEVID_MICMUTE_LED 0x00040017 /* Backlight and Brightness */ #define ASUS_WMI_DEVID_ALS_ENABLE 0x00050001 /* Ambient Light Sensor */ From e05d6b658fcd98bd3a09220cb5701e40269a0e57 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 11 Jul 2022 11:45:51 +0300 Subject: [PATCH 1073/1436] platform/x86: mlx-platform: Make activation of some drivers conditional Current assumption in driver that any system is capable of LED, hotplug or watchdog support. It could be not true for some new coming systems. Add validation for LED, hotplug, watchdog configuration and skip activation of relevant drivers if not configured. Signed-off-by: Vadim Pasternak Reviewed-by: Oleksandr Shamray Link: https://lore.kernel.org/r/20220711084559.62447-2-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 62 ++++++++++++++++------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 447044fdcb77..54c99f3fde51 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -4853,16 +4853,18 @@ static int __init mlxplat_init(void) } /* Add hotplug driver */ - mlxplat_hotplug->regmap = priv->regmap; - priv->pdev_hotplug = platform_device_register_resndata( - &mlxplat_dev->dev, "mlxreg-hotplug", - PLATFORM_DEVID_NONE, - mlxplat_mlxcpld_resources, - ARRAY_SIZE(mlxplat_mlxcpld_resources), - mlxplat_hotplug, sizeof(*mlxplat_hotplug)); - if (IS_ERR(priv->pdev_hotplug)) { - err = PTR_ERR(priv->pdev_hotplug); - goto fail_platform_mux_register; + if (mlxplat_hotplug) { + mlxplat_hotplug->regmap = priv->regmap; + priv->pdev_hotplug = + platform_device_register_resndata(&mlxplat_dev->dev, + "mlxreg-hotplug", PLATFORM_DEVID_NONE, + mlxplat_mlxcpld_resources, + ARRAY_SIZE(mlxplat_mlxcpld_resources), + mlxplat_hotplug, sizeof(*mlxplat_hotplug)); + if (IS_ERR(priv->pdev_hotplug)) { + err = PTR_ERR(priv->pdev_hotplug); + goto fail_platform_mux_register; + } } /* Set default registers. */ @@ -4875,24 +4877,26 @@ static int __init mlxplat_init(void) } /* Add LED driver. */ - mlxplat_led->regmap = priv->regmap; - priv->pdev_led = platform_device_register_resndata( - &mlxplat_dev->dev, "leds-mlxreg", - PLATFORM_DEVID_NONE, NULL, 0, - mlxplat_led, sizeof(*mlxplat_led)); - if (IS_ERR(priv->pdev_led)) { - err = PTR_ERR(priv->pdev_led); - goto fail_platform_hotplug_register; + if (mlxplat_led) { + mlxplat_led->regmap = priv->regmap; + priv->pdev_led = + platform_device_register_resndata(&mlxplat_dev->dev, "leds-mlxreg", + PLATFORM_DEVID_NONE, NULL, 0, mlxplat_led, + sizeof(*mlxplat_led)); + if (IS_ERR(priv->pdev_led)) { + err = PTR_ERR(priv->pdev_led); + goto fail_platform_hotplug_register; + } } /* Add registers io access driver. */ if (mlxplat_regs_io) { mlxplat_regs_io->regmap = priv->regmap; - priv->pdev_io_regs = platform_device_register_resndata( - &mlxplat_dev->dev, "mlxreg-io", - PLATFORM_DEVID_NONE, NULL, 0, - mlxplat_regs_io, - sizeof(*mlxplat_regs_io)); + priv->pdev_io_regs = platform_device_register_resndata(&mlxplat_dev->dev, + "mlxreg-io", + PLATFORM_DEVID_NONE, NULL, + 0, mlxplat_regs_io, + sizeof(*mlxplat_regs_io)); if (IS_ERR(priv->pdev_io_regs)) { err = PTR_ERR(priv->pdev_io_regs); goto fail_platform_led_register; @@ -4949,9 +4953,11 @@ fail_platform_io_regs_register: if (mlxplat_regs_io) platform_device_unregister(priv->pdev_io_regs); fail_platform_led_register: - platform_device_unregister(priv->pdev_led); + if (mlxplat_led) + platform_device_unregister(priv->pdev_led); fail_platform_hotplug_register: - platform_device_unregister(priv->pdev_hotplug); + if (mlxplat_hotplug) + platform_device_unregister(priv->pdev_hotplug); fail_platform_mux_register: while (--i >= 0) platform_device_unregister(priv->pdev_mux[i]); @@ -4974,8 +4980,10 @@ static void __exit mlxplat_exit(void) platform_device_unregister(priv->pdev_fan); if (priv->pdev_io_regs) platform_device_unregister(priv->pdev_io_regs); - platform_device_unregister(priv->pdev_led); - platform_device_unregister(priv->pdev_hotplug); + if (priv->pdev_led) + platform_device_unregister(priv->pdev_led); + if (priv->pdev_hotplug) + platform_device_unregister(priv->pdev_hotplug); for (i = mlxplat_mux_num - 1; i >= 0 ; i--) platform_device_unregister(priv->pdev_mux[i]); From 7bf8a14dedaf9ae4fd670ecd403db0dbe15bb3ac Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 11 Jul 2022 11:45:52 +0300 Subject: [PATCH 1074/1436] platform/x86: mlx-platform: Add cosmetic changes for alignment Align the first argument with open parenthesis for platform_device_register_resndata() calls. Signed-off-by: Vadim Pasternak Reviewed-by: Oleksandr Shamray Link: https://lore.kernel.org/r/20220711084559.62447-3-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 36 +++++++++++++---------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 54c99f3fde51..12d56d7090f1 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -4830,22 +4830,20 @@ static int __init mlxplat_init(void) nr = (nr == mlxplat_max_adap_num) ? -1 : nr; if (mlxplat_i2c) mlxplat_i2c->regmap = priv->regmap; - priv->pdev_i2c = platform_device_register_resndata( - &mlxplat_dev->dev, "i2c_mlxcpld", - nr, mlxplat_mlxcpld_resources, - ARRAY_SIZE(mlxplat_mlxcpld_resources), - mlxplat_i2c, sizeof(*mlxplat_i2c)); + priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld", + nr, mlxplat_mlxcpld_resources, + ARRAY_SIZE(mlxplat_mlxcpld_resources), + mlxplat_i2c, sizeof(*mlxplat_i2c)); if (IS_ERR(priv->pdev_i2c)) { err = PTR_ERR(priv->pdev_i2c); goto fail_alloc; } for (i = 0; i < mlxplat_mux_num; i++) { - priv->pdev_mux[i] = platform_device_register_resndata( - &priv->pdev_i2c->dev, - "i2c-mux-reg", i, NULL, - 0, &mlxplat_mux_data[i], - sizeof(mlxplat_mux_data[i])); + priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev, + "i2c-mux-reg", i, NULL, 0, + &mlxplat_mux_data[i], + sizeof(mlxplat_mux_data[i])); if (IS_ERR(priv->pdev_mux[i])) { err = PTR_ERR(priv->pdev_mux[i]); goto fail_platform_mux_register; @@ -4906,11 +4904,10 @@ static int __init mlxplat_init(void) /* Add FAN driver. */ if (mlxplat_fan) { mlxplat_fan->regmap = priv->regmap; - priv->pdev_fan = platform_device_register_resndata( - &mlxplat_dev->dev, "mlxreg-fan", - PLATFORM_DEVID_NONE, NULL, 0, - mlxplat_fan, - sizeof(*mlxplat_fan)); + priv->pdev_fan = platform_device_register_resndata(&mlxplat_dev->dev, "mlxreg-fan", + PLATFORM_DEVID_NONE, NULL, 0, + mlxplat_fan, + sizeof(*mlxplat_fan)); if (IS_ERR(priv->pdev_fan)) { err = PTR_ERR(priv->pdev_fan); goto fail_platform_io_regs_register; @@ -4924,11 +4921,10 @@ static int __init mlxplat_init(void) for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) { if (mlxplat_wd_data[j]) { mlxplat_wd_data[j]->regmap = priv->regmap; - priv->pdev_wd[j] = platform_device_register_resndata( - &mlxplat_dev->dev, "mlx-wdt", - j, NULL, 0, - mlxplat_wd_data[j], - sizeof(*mlxplat_wd_data[j])); + priv->pdev_wd[j] = + platform_device_register_resndata(&mlxplat_dev->dev, "mlx-wdt", j, + NULL, 0, mlxplat_wd_data[j], + sizeof(*mlxplat_wd_data[j])); if (IS_ERR(priv->pdev_wd[j])) { err = PTR_ERR(priv->pdev_wd[j]); goto fail_platform_wd_register; From 08fdb6f3acaef252e79f2d2630752f9182a82c8c Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 11 Jul 2022 11:45:53 +0300 Subject: [PATCH 1075/1436] platform/x86: mlx-platform: Add support for systems equipped with two ASICs Motivation is to support new systems equipped with two ASICs. Extend driver with: - The second ASIC health event. - Per ASIC reset control, triggering reset of ASIC internal resources and restarting ASIC initialization flow. Signed-off-by: Vadim Pasternak Reviewed-by: Oleksandr Shamray Link: https://lore.kernel.org/r/20220711084559.62447-4-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 52 ++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 12d56d7090f1..190d488d4cd1 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -34,6 +34,7 @@ #define MLXPLAT_CPLD_LPC_REG_CPLD3_PN1_OFFSET 0x09 #define MLXPLAT_CPLD_LPC_REG_CPLD4_PN_OFFSET 0x0a #define MLXPLAT_CPLD_LPC_REG_CPLD4_PN1_OFFSET 0x0b +#define MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET 0x19 #define MLXPLAT_CPLD_LPC_REG_RESET_GP4_OFFSET 0x1c #define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d #define MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET 0x1e @@ -69,6 +70,9 @@ #define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50 #define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 #define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 +#define MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET 0x53 +#define MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET 0x54 +#define MLXPLAT_CPLD_LPC_REG_ASIC2_MASK_OFFSET 0x55 #define MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET 0x56 #define MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET 0x57 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 @@ -193,6 +197,7 @@ MLXPLAT_CPLD_AGGR_MASK_LC_ACT | \ MLXPLAT_CPLD_AGGR_MASK_LC_SDWN) #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 +#define MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2 BIT(2) #define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6) #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) @@ -588,6 +593,15 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_asic_items_data[] = { }, }; +static struct mlxreg_core_data mlxplat_mlxcpld_default_asic2_items_data[] = { + { + .label = "asic2", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, +}; + static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { { .data = mlxplat_mlxcpld_default_psu_items_data, @@ -1151,6 +1165,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_ext_items[] = { .inversed = 0, .health = true, }, + { + .data = mlxplat_mlxcpld_default_asic2_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic2_items_data), + .inversed = 0, + .health = true, + } }; static @@ -1160,7 +1183,7 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = { .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, - .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2, }; static struct mlxreg_core_data mlxplat_mlxcpld_modular_pwr_items_data[] = { @@ -2856,6 +2879,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .bit = GENMASK(7, 0), .mode = 0444, }, + { + .label = "asic_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0200, + }, + { + .label = "asic2_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0200, + }, { .label = "reset_long_pb", .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, @@ -2995,6 +3030,13 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .bit = 1, .mode = 0444, }, + { + .label = "asic2_health", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .bit = 1, + .mode = 0444, + }, { .label = "fan_dir", .reg = MLXPLAT_CPLD_LPC_REG_FAN_DIRECTION, @@ -3934,6 +3976,8 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC2_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: @@ -4026,6 +4070,9 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC2_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: @@ -4153,6 +4200,9 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC2_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC2_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: From 6995e711b69ce8741191bd8649d8f13748b24141 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 11 Jul 2022 11:45:54 +0300 Subject: [PATCH 1076/1436] platform/x86: mlx-platform: Introduce support for COMe NVSwitch management module for Vulcan chassis The Vulcan is chassis containing Nvidia's Hopper dGPU (GH100), NVswitch (LS10) based HGX baseboard and COMe NVSwitch management module. The system is built for artificial intelligence and accelerated analytics applications. Vulcan is offered as an HGX product to cloud service providers and OEMs, who intend to build fully interconnected GPU systems for large scale deployments. Driver is extended to support new COMe NVSwitch management module. Signed-off-by: Vadim Pasternak Reviewed-by: Oleksandr Shamray Link: https://lore.kernel.org/r/20220711084559.62447-5-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 269 ++++++++++++++++++++++++++++ 1 file changed, 269 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 190d488d4cd1..9e6054e2f0ac 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -67,6 +67,9 @@ #define MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET 0x43 #define MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET 0x44 #define MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET 0x45 +#define MLXPLAT_CPLD_LPC_REG_GWP_OFFSET 0x4a +#define MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET 0x4b +#define MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET 0x4c #define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50 #define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 #define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 @@ -209,6 +212,7 @@ #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) +#define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0) #define MLXPLAT_CPLD_I2C_CAP_BIT 0x04 #define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT) @@ -2027,6 +2031,38 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_modular_data = { .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, }; +/* Platform hotplug for NVLink blade systems family data */ +static struct mlxreg_core_data mlxplat_mlxcpld_global_wp_items_data[] = { + { + .label = "global_wp_grant", + .reg = MLXPLAT_CPLD_LPC_REG_GWP_OFFSET, + .mask = MLXPLAT_CPLD_GWP_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, +}; + +static struct mlxreg_core_item mlxplat_mlxcpld_nvlink_blade_items[] = { + { + .data = mlxplat_mlxcpld_global_wp_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_GWP_OFFSET, + .mask = MLXPLAT_CPLD_GWP_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_global_wp_items_data), + .inversed = 0, + .health = false, + }, +}; + +static +struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_nvlink_blade_data = { + .items = mlxplat_mlxcpld_nvlink_blade_items, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_nvlink_blade_items), + .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, + .mask = MLXPLAT_CPLD_AGGR_MASK_COMEX, + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, +}; + /* Platform led default data */ static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { { @@ -3589,6 +3625,203 @@ static struct mlxreg_core_platform_data mlxplat_modular_regs_io_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_regs_io_data), }; +/* Platform register access for NVLink blade systems family data */ +static struct mlxreg_core_data mlxplat_mlxcpld_nvlink_blade_regs_io_data[] = { + { + .label = "cpld1_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld1_pn", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_PN_OFFSET, + .bit = GENMASK(15, 0), + .mode = 0444, + .regnum = 2, + }, + { + .label = "cpld1_version_min", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "reset_aux_pwr_or_ref", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, + { + .label = "reset_from_comex", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "reset_comex_pwr_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0444, + }, + { + .label = "reset_platform", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "reset_soc", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "reset_comex_wd", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "reset_voltmon_upgrade_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, + }, + { + .label = "reset_system", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, + { + .label = "reset_sw_pwr_off", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, + { + .label = "reset_comex_thermal", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0444, + }, + { + .label = "reset_reload_bios", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "reset_ac_pwr_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "pwr_cycle", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0200, + }, + { + .label = "pwr_down", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0200, + }, + { + .label = "global_wp_request", + .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0644, + }, + { + .label = "jtag_enable", + .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0644, + }, + { + .label = "comm_chnl_ready", + .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0200, + }, + { + .label = "bios_safe_mode", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "bios_active_image", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "bios_auth_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "bios_upgrade_fail", + .reg = MLXPLAT_CPLD_LPC_REG_GPCOM0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, + { + .label = "voltreg_update_status", + .reg = MLXPLAT_CPLD_LPC_REG_GP0_RO_OFFSET, + .mask = MLXPLAT_CPLD_VOLTREG_UPD_MASK, + .bit = 5, + .mode = 0444, + }, + { + .label = "vpd_wp", + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0644, + }, + { + .label = "pcie_asic_reset_dis", + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0644, + }, + { + .label = "global_wp_response", + .reg = MLXPLAT_CPLD_LPC_REG_GWP_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, + }, + { + .label = "config1", + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "config2", + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "ufm_version", + .reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_nvlink_blade_regs_io_data = { + .data = mlxplat_mlxcpld_nvlink_blade_regs_io_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_nvlink_blade_regs_io_data), +}; + /* Platform FAN default */ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { { @@ -3974,6 +4207,8 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET: @@ -4067,6 +4302,9 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: @@ -4197,6 +4435,9 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: @@ -4629,6 +4870,28 @@ static int __init mlxplat_dmi_modular_matched(const struct dmi_system_id *dmi) return 1; } +static int __init mlxplat_dmi_nvlink_blade_matched(const struct dmi_system_id *dmi) +{ + int i; + + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; + mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data); + mlxplat_mux_data = mlxplat_default_mux_data; + mlxplat_hotplug = &mlxplat_mlxcpld_nvlink_blade_data; + mlxplat_hotplug->deferred_nr = + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + for (i = 0; i < mlxplat_mux_num; i++) { + mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; + mlxplat_mux_data[i].n_values = + ARRAY_SIZE(mlxplat_msn21xx_channels); + } + mlxplat_regs_io = &mlxplat_nvlink_blade_regs_io_data; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng400; + + return 1; +} + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { { .callback = mlxplat_dmi_default_wc_matched, @@ -4691,6 +4954,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { DMI_MATCH(DMI_BOARD_NAME, "VMOD0011"), }, }, + { + .callback = mlxplat_dmi_nvlink_blade_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0015"), + }, + }, { .callback = mlxplat_dmi_msn274x_matched, .matches = { From 2deb92864348fe7f313ed4efba12c89ebd03ef41 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 11 Jul 2022 11:45:55 +0300 Subject: [PATCH 1077/1436] platform/x86: mlx-platform: Add support for new system XH3000 Add support for new system type XH3000, which is a water cooling Ethernet switch blade equipped with 32x200G Ethernet ports. The system is recognized by "DMI_BOARD_NAME" and "DMI_PRODUCT_SKU" matches, when these fields are set to "VMOD0005" and "HI139" respectively. Signed-off-by: Vadim Pasternak Reviewed-by: Felix Radensky Link: https://lore.kernel.org/r/20220711084559.62447-6-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 51 +++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 9e6054e2f0ac..31609c1df027 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -2161,6 +2161,25 @@ static struct mlxreg_core_platform_data mlxplat_default_led_wc_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_wc_data), }; +/* Platform led default data for water cooling Ethernet switch blade */ +static struct mlxreg_core_data mlxplat_mlxcpld_default_led_eth_wc_blade_data[] = { + { + .label = "status:green", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK, + }, + { + .label = "status:red", + .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET, + .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK + }, +}; + +static struct mlxreg_core_platform_data mlxplat_default_led_eth_wc_blade_data = { + .data = mlxplat_mlxcpld_default_led_eth_wc_blade_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_eth_wc_blade_data), +}; + /* Platform led MSN21xx system family data */ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = { { @@ -4708,6 +4727,31 @@ static int __init mlxplat_dmi_default_wc_matched(const struct dmi_system_id *dmi return 1; } +static int __init mlxplat_dmi_default_eth_wc_blade_matched(const struct dmi_system_id *dmi) +{ + int i; + + mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; + mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data); + mlxplat_mux_data = mlxplat_default_mux_data; + for (i = 0; i < mlxplat_mux_num; i++) { + mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; + mlxplat_mux_data[i].n_values = + ARRAY_SIZE(mlxplat_msn21xx_channels); + } + mlxplat_hotplug = &mlxplat_mlxcpld_default_wc_data; + mlxplat_hotplug->deferred_nr = + mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; + mlxplat_led = &mlxplat_default_led_eth_wc_blade_data; + mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; + for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) + mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; + mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; + mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng; + + return 1; +} + static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) { int i; @@ -4924,6 +4968,13 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"), }, }, + { + .callback = mlxplat_dmi_default_eth_wc_blade_matched, + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "HI139"), + }, + }, { .callback = mlxplat_dmi_qmb7xx_matched, .matches = { From 095a2c1891512630d8674579b3b023f427d5330e Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 11 Jul 2022 11:45:56 +0300 Subject: [PATCH 1078/1436] platform/x86: mlx-platform: Add COME board revision register Extend COME CPLD with board configuration register for getting board revision. The value of this register is pushed by hardware through GPIO pins. The purpose of it is to expose some minor BOM changes. Signed-off-by: Vadim Pasternak Reviewed-by: Oleksandr Shamray Link: https://lore.kernel.org/r/20220711084559.62447-7-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/mlx-platform.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 31609c1df027..5e072a0666f4 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -150,6 +150,7 @@ #define MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET 0xfa #define MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET 0xfb #define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc +#define MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET 0xfd #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda @@ -3153,6 +3154,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { .bit = GENMASK(7, 0), .mode = 0444, }, + { + .label = "config3", + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, { .label = "ufm_version", .reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET, @@ -3631,6 +3638,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_regs_io_data[] = { .bit = GENMASK(7, 0), .mode = 0444, }, + { + .label = "config3", + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, { .label = "ufm_version", .reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET, @@ -3828,6 +3841,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_nvlink_blade_regs_io_data[] = { .bit = GENMASK(7, 0), .mode = 0444, }, + { + .label = "config3", + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, { .label = "ufm_version", .reg = MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET, @@ -4404,6 +4423,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET: case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET: case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET: case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET: return true; } @@ -4531,6 +4551,7 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_SLOT_QTY_OFFSET: case MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET: case MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET: case MLXPLAT_CPLD_LPC_REG_UFM_VERSION_OFFSET: return true; } From 7964f8fc52b1b1c646615423fb4e1b6d8d685822 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 11 Jul 2022 11:45:57 +0300 Subject: [PATCH 1079/1436] platform/mellanox: mlxreg-io: Add locking for io operations Add lock to protect user read/write access to the registers. Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220711084559.62447-8-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-io.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c index 2c2686d5c2fc..ddc08abf398c 100644 --- a/drivers/platform/mellanox/mlxreg-io.c +++ b/drivers/platform/mellanox/mlxreg-io.c @@ -31,6 +31,7 @@ * @group: sysfs attribute group; * @groups: list of sysfs attribute group for hwmon registration; * @regsize: size of a register value; + * @io_lock: user access locking; */ struct mlxreg_io_priv_data { struct platform_device *pdev; @@ -41,6 +42,7 @@ struct mlxreg_io_priv_data { struct attribute_group group; const struct attribute_group *groups[2]; int regsize; + struct mutex io_lock; /* Protects user access. */ }; static int @@ -116,14 +118,19 @@ mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr, u32 regval = 0; int ret; + mutex_lock(&priv->io_lock); + ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true, priv->regsize, ®val); if (ret) goto access_error; + mutex_unlock(&priv->io_lock); + return sprintf(buf, "%u\n", regval); access_error: + mutex_unlock(&priv->io_lock); return ret; } @@ -145,6 +152,8 @@ mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr, if (ret) return ret; + mutex_lock(&priv->io_lock); + ret = mlxreg_io_get_reg(priv->pdata->regmap, data, input_val, false, priv->regsize, ®val); if (ret) @@ -154,9 +163,12 @@ mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr, if (ret) goto access_error; + mutex_unlock(&priv->io_lock); + return len; access_error: + mutex_unlock(&priv->io_lock); dev_err(&priv->pdev->dev, "Bus access error\n"); return ret; } @@ -246,16 +258,27 @@ static int mlxreg_io_probe(struct platform_device *pdev) return PTR_ERR(priv->hwmon); } + mutex_init(&priv->io_lock); dev_set_drvdata(&pdev->dev, priv); return 0; } +static int mlxreg_io_remove(struct platform_device *pdev) +{ + struct mlxreg_io_priv_data *priv = dev_get_drvdata(&pdev->dev); + + mutex_destroy(&priv->io_lock); + + return 0; +} + static struct platform_driver mlxreg_io_driver = { .driver = { .name = "mlxreg-io", }, .probe = mlxreg_io_probe, + .remove = mlxreg_io_remove, }; module_platform_driver(mlxreg_io_driver); From 91dd6ef8971085c8ea67af68dc45153917a004c4 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 11 Jul 2022 11:45:58 +0300 Subject: [PATCH 1080/1436] Documentation/ABI: mlxreg-io: Fix contact info Fix e-mail in contact fields. Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220711084559.62447-9-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../ABI/stable/sysfs-driver-mlxreg-io | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io index b312242d4f40..3539b1839829 100644 --- a/Documentation/ABI/stable/sysfs-driver-mlxreg-io +++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io @@ -1,7 +1,7 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic_health Date: June 2018 KernelVersion: 4.19 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: This file shows ASIC health status. The possible values are: 0 - health failed, 2 - health OK, 3 - ASIC in booting state. @@ -11,7 +11,7 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld1_version What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld2_version Date: June 2018 KernelVersion: 4.19 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files show with which CPLD versions have been burned on carrier and switch boards. @@ -20,7 +20,7 @@ Description: These files show with which CPLD versions have been burned What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/fan_dir Date: December 2018 KernelVersion: 5.0 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: This file shows the system fans direction: forward direction - relevant bit is set 0; reversed direction - relevant bit is set 1. @@ -30,7 +30,7 @@ Description: This file shows the system fans direction: What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld3_version Date: November 2018 KernelVersion: 5.0 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files show with which CPLD versions have been burned on LED or Gearbox board. @@ -39,7 +39,7 @@ Description: These files show with which CPLD versions have been burned What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/jtag_enable Date: November 2018 KernelVersion: 5.0 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files enable and disable the access to the JTAG domain. By default access to the JTAG domain is disabled. @@ -48,7 +48,7 @@ Description: These files enable and disable the access to the JTAG domain. What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/select_iio Date: June 2018 KernelVersion: 4.19 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: This file allows iio devices selection. Attribute select_iio can be written with 0 or with 1. It @@ -62,7 +62,7 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/psu1_on /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pwr_down Date: June 2018 KernelVersion: 4.19 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files allow asserting system power cycling, switching power supply units on and off and system's main power domain shutdown. @@ -89,7 +89,7 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_short_pb What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_sw_reset Date: June 2018 KernelVersion: 4.19 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files show the system reset cause, as following: power auxiliary outage or power refresh, ASIC thermal shutdown, halt, hotswap, watchdog, firmware reset, long press power button, @@ -106,7 +106,7 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_system What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_voltmon_upgrade_fail Date: November 2018 KernelVersion: 5.0 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files show the system reset cause, as following: ComEx power fail, reset from ComEx, system platform reset, reset due to voltage monitor devices upgrade failure, @@ -119,7 +119,7 @@ Description: These files show the system reset cause, as following: ComEx What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld4_version Date: November 2018 KernelVersion: 5.0 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files show with which CPLD versions have been burned on LED board. @@ -133,7 +133,7 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_sff_wd What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_swb_wd Date: June 2019 KernelVersion: 5.3 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files show the system reset cause, as following: COMEX thermal shutdown; wathchdog power off or reset was derived by one of the next components: COMEX, switch board or by Small Form @@ -148,7 +148,7 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/config1 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/config2 Date: January 2020 KernelVersion: 5.6 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files show system static topology identification like system's static I2C topology, number and type of FPGA devices within the system and so on. @@ -161,7 +161,7 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_soc What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_sw_pwr_off Date: January 2020 KernelVersion: 5.6 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files show the system reset causes, as following: reset due to AC power failure, reset invoked from software by assertion reset signal through CPLD. reset caused by signal @@ -173,7 +173,7 @@ Description: These files show the system reset causes, as following: reset What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/pcie_asic_reset_dis Date: January 2020 KernelVersion: 5.6 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: This file allows to retain ASIC up during PCIe root complex reset, when attribute is set 1. @@ -182,7 +182,7 @@ Description: This file allows to retain ASIC up during PCIe root complex What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/vpd_wp Date: January 2020 KernelVersion: 5.6 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: This file allows to overwrite system VPD hardware write protection when attribute is set 1. @@ -191,7 +191,7 @@ Description: This file allows to overwrite system VPD hardware write What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/voltreg_update_status Date: January 2020 KernelVersion: 5.6 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: This file exposes the configuration update status of burnable voltage regulator devices. The status values are as following: 0 - OK; 1 - CRC failure; 2 = I2C failure; 3 - in progress. @@ -201,7 +201,7 @@ Description: This file exposes the configuration update status of burnable What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/ufm_version Date: January 2020 KernelVersion: 5.6 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: This file exposes the firmware version of burnable voltage regulator devices. @@ -217,7 +217,7 @@ What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld3_version_min What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld4_version_min Date: July 2020 KernelVersion: 5.9 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: These files show with which CPLD part numbers and minor versions have been burned CPLD devices equipped on a system. @@ -471,7 +471,7 @@ Description: These files provide the maximum powered required for line card What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/phy_reset Date: May 2022 KernelVersion: 5.19 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: This file allows to reset PHY 88E1548 when attribute is set 0 due to some abnormal PHY behavior. Expected behavior: @@ -483,7 +483,7 @@ Description: This file allows to reset PHY 88E1548 when attribute is set 0 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/mac_reset Date: May 2022 KernelVersion: 5.19 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: This file allows to reset ASIC MT52132 when attribute is set 0 due to some abnormal ASIC behavior. Expected behavior: @@ -495,7 +495,7 @@ Description: This file allows to reset ASIC MT52132 when attribute is set 0 What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/qsfp_pwr_good Date: May 2022 KernelVersion: 5.19 -Contact: Vadim Pasternak +Contact: Vadim Pasternak Description: This file shows QSFP ports power status. The value is set to 0 when one of any QSFP ports is plugged. The value is set to 1 when there are no any QSFP ports are plugged. From 5c8b3f11565e64366d53295e8004edaa1fcf1ec9 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 11 Jul 2022 11:45:59 +0300 Subject: [PATCH 1081/1436] Documentation/ABI: Add new attributes for mlxreg-io sysfs interfaces Add documentation for the new attributes: - "asic2_health" - health of 2-nd ASIC for system equipped with two ASICs. - "asic_reset" and "asic2_reset" - ASICs reset control. - "comm_chnl_ready" - communication channel indication to remote end (BMC). - "config3" - indication of system minor BOM changes. Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220711084559.62447-10-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- .../ABI/stable/sysfs-driver-mlxreg-io | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io index 3539b1839829..af0cbf143c48 100644 --- a/Documentation/ABI/stable/sysfs-driver-mlxreg-io +++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io @@ -503,3 +503,42 @@ Description: This file shows QSFP ports power status. The value is set to 0 0 - Power good, 1 - Not power good. The files are read only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic2_health +Date: July 2022 +KernelVersion: 5.20 +Contact: Vadim Pasternak +Description: This file shows 2-nd ASIC health status. The possible values are: + 0 - health failed, 2 - health OK, 3 - ASIC in booting state. + + The file is read only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic_reset +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic2_reset +Date: July 2022 +KernelVersion: 5.20 +Contact: Vadim Pasternak +Description: These files allow to each of ASICs by writing 1. + + The files are write only. + + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/comm_chnl_ready +Date: July 2022 +KernelVersion: 5.20 +Contact: Vadim Pasternak +Description: This file is used to indicate remote end (for example BMC) that system + host CPU is ready for sending telemetry data to remote end. + For indication the file should be written 1. + + The file is write only. + +What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/config3 +Date: January 2020 +KernelVersion: 5.6 +Contact: Vadim Pasternak +Description: The file indicates COME module hardware configuration. + The value is pushed by hardware through GPIO pins. + The purpose is to expose some minor BOM changes for the same system SKU. + + The file is read only. From 6a4f7fcd750497cb2fa870f799e8b23270bec6e3 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 14 Jul 2022 16:41:08 +0100 Subject: [PATCH 1082/1436] KVM: arm64: selftests: Add support for GICv2 on v3 The current vgic_init test wrongly assumes that the host cannot multiple versions of the GIC architecture, while v2 emulation on v3 has almost always been supported (it was supported before the standalone v3 emulation). Tweak the test to support multiple GIC incarnations. Signed-off-by: Marc Zyngier Fixes: 3f4db37e203b ("KVM: arm64: selftests: Make vgic_init gic version agnostic") Reviewed-by: Ricardo Koller Link: https://lore.kernel.org/r/20220714154108.3531213-1-maz@kernel.org --- tools/testing/selftests/kvm/aarch64/vgic_init.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/vgic_init.c b/tools/testing/selftests/kvm/aarch64/vgic_init.c index 34379c98d2f4..21ba4002fc18 100644 --- a/tools/testing/selftests/kvm/aarch64/vgic_init.c +++ b/tools/testing/selftests/kvm/aarch64/vgic_init.c @@ -670,7 +670,7 @@ int test_kvm_device(uint32_t gic_dev_type) if (!_kvm_create_device(v.vm, other, true, &fd)) { ret = _kvm_create_device(v.vm, other, false, &fd); - TEST_ASSERT(ret && errno == EINVAL, + TEST_ASSERT(ret && (errno == EINVAL || errno == EEXIST), "create GIC device while other version exists"); } @@ -698,6 +698,7 @@ int main(int ac, char **av) { int ret; int pa_bits; + int cnt_impl = 0; pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT].pa_bits; max_phys_size = 1ULL << pa_bits; @@ -706,17 +707,19 @@ int main(int ac, char **av) if (!ret) { pr_info("Running GIC_v3 tests.\n"); run_tests(KVM_DEV_TYPE_ARM_VGIC_V3); - return 0; + cnt_impl++; } ret = test_kvm_device(KVM_DEV_TYPE_ARM_VGIC_V2); if (!ret) { pr_info("Running GIC_v2 tests.\n"); run_tests(KVM_DEV_TYPE_ARM_VGIC_V2); - return 0; + cnt_impl++; } - print_skip("No GICv2 nor GICv3 support"); - exit(KSFT_SKIP); + if (!cnt_impl) { + print_skip("No GICv2 nor GICv3 support"); + exit(KSFT_SKIP); + } return 0; } From 28a6ed8e39f77f6ac613ec9b7461aa75e85fa79a Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 11 Jul 2022 07:22:57 +0000 Subject: [PATCH 1083/1436] platform/chrome: Add Type-C mux set command definitions Copy EC header definitions for the USB Type-C Mux control command from the EC code base. Also pull in "TBT_UFP_REPLY" definitions, since that is the prior entry in the enum. These headers are already present in the EC code base. [1] [1] https://chromium.googlesource.com/chromiumos/platform/ec/+/b80f85a94a423273c1638ef7b662c56931a138dd/include/ec_commands.h Signed-off-by: Prashant Malani Link: https://lore.kernel.org/r/20220711072333.2064341-4-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- include/linux/platform_data/cros_ec_commands.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index 8cfa8cfca77e..a3945c5e7f50 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -5722,8 +5722,21 @@ enum typec_control_command { TYPEC_CONTROL_COMMAND_EXIT_MODES, TYPEC_CONTROL_COMMAND_CLEAR_EVENTS, TYPEC_CONTROL_COMMAND_ENTER_MODE, + TYPEC_CONTROL_COMMAND_TBT_UFP_REPLY, + TYPEC_CONTROL_COMMAND_USB_MUX_SET, }; +/* Replies the AP may specify to the TBT EnterMode command as a UFP */ +enum typec_tbt_ufp_reply { + TYPEC_TBT_UFP_REPLY_NAK, + TYPEC_TBT_UFP_REPLY_ACK, +}; + +struct typec_usb_mux_set { + uint8_t mux_index; /* Index of the mux to set in the chain */ + uint8_t mux_flags; /* USB_PD_MUX_*-encoded USB mux state to set */ +} __ec_align1; + struct ec_params_typec_control { uint8_t port; uint8_t command; /* enum typec_control_command */ @@ -5737,6 +5750,8 @@ struct ec_params_typec_control { union { uint32_t clear_events_mask; uint8_t mode_to_enter; /* enum typec_mode */ + uint8_t tbt_ufp_reply; /* enum typec_tbt_ufp_reply */ + struct typec_usb_mux_set mux_params; uint8_t placeholder[128]; }; } __ec_align1; @@ -5815,6 +5830,9 @@ enum tcpc_cc_polarity { #define PD_STATUS_EVENT_SOP_DISC_DONE BIT(0) #define PD_STATUS_EVENT_SOP_PRIME_DISC_DONE BIT(1) #define PD_STATUS_EVENT_HARD_RESET BIT(2) +#define PD_STATUS_EVENT_DISCONNECTED BIT(3) +#define PD_STATUS_EVENT_MUX_0_SET_DONE BIT(4) +#define PD_STATUS_EVENT_MUX_1_SET_DONE BIT(5) struct ec_params_typec_status { uint8_t port; From e54369058f3da181fcc4c893f224a0c5a8a526b6 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 11 Jul 2022 07:22:58 +0000 Subject: [PATCH 1084/1436] platform/chrome: cros_typec_switch: Add switch driver Introduce a driver to configure USB Type-C mode switches and retimers which are controlled by the Chrome OS EC (Embedded Controller). This allows Type-C port drivers, as well as alternate mode drivers to configure their relevant mode switches and retimers according to the Type-C state they want to achieve. ACPI devices with ID GOOG001A will bind to this driver. Currently, we only register a retimer switch with a stub set function. Subsequent patches will implement the host command set functionality, and introduce mode switches. Reported-by: kernel test robot Signed-off-by: Prashant Malani Link: https://lore.kernel.org/r/20220711072333.2064341-5-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 + drivers/platform/chrome/Kconfig | 11 ++ drivers/platform/chrome/Makefile | 1 + drivers/platform/chrome/cros_typec_switch.c | 170 ++++++++++++++++++++ 4 files changed, 183 insertions(+) create mode 100644 drivers/platform/chrome/cros_typec_switch.c diff --git a/MAINTAINERS b/MAINTAINERS index f43b126eaf59..d5cdf81ea2c0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4752,6 +4752,7 @@ M: Prashant Malani L: chrome-platform@lists.linux.dev S: Maintained F: drivers/platform/chrome/cros_ec_typec.c +F: drivers/platform/chrome/cros_typec_switch.c CHROMEOS EC USB PD NOTIFY DRIVER M: Prashant Malani diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 717299cbccac..c62a514a087f 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -265,6 +265,17 @@ config CHROMEOS_PRIVACY_SCREEN this should probably always be built into the kernel to avoid or minimize drm probe deferral. +config CROS_TYPEC_SWITCH + tristate "ChromeOS EC Type-C Switch Control" + depends on MFD_CROS_EC_DEV && TYPEC + default MFD_CROS_EC_DEV + help + If you say Y here, you get support for configuring the Chrome OS EC Type C + muxes and retimers. + + To compile this driver as a module, choose M here: the module will be + called cros_typec_switch. + source "drivers/platform/chrome/wilco_ec/Kconfig" endif # CHROMEOS_PLATFORMS diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 52f5a2dde8b8..0dcaf6a7ed27 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o obj-$(CONFIG_CROS_EC) += cros_ec.o obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_CROS_EC_ISHTP) += cros_ec_ishtp.o +obj-$(CONFIG_CROS_TYPEC_SWITCH) += cros_typec_switch.o obj-$(CONFIG_CROS_EC_RPMSG) += cros_ec_rpmsg.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_mec.o diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c new file mode 100644 index 000000000000..0d319e315d57 --- /dev/null +++ b/drivers/platform/chrome/cros_typec_switch.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2022 Google LLC + * + * This driver provides the ability to configure Type C muxes and retimers which are controlled by + * the Chrome OS EC. + */ + +#include +#include +#include +#include +#include + +#define DRV_NAME "cros-typec-switch" + +/* Handles and other relevant data required for each port's switches. */ +struct cros_typec_port { + int port_num; + struct typec_retimer *retimer; + struct cros_typec_switch_data *sdata; +}; + +/* Driver-specific data. */ +struct cros_typec_switch_data { + struct device *dev; + struct cros_ec_device *ec; + struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS]; +}; + +static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) +{ + return 0; +} + +static void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata) +{ + int i; + + for (i = 0; i < EC_USB_PD_MAX_PORTS; i++) { + if (!sdata->ports[i]) + continue; + typec_retimer_unregister(sdata->ports[i]->retimer); + } +} + +static int cros_typec_register_retimer(struct cros_typec_port *port, struct fwnode_handle *fwnode) +{ + struct typec_retimer_desc retimer_desc = { + .fwnode = fwnode, + .drvdata = port, + .name = fwnode_get_name(fwnode), + .set = cros_typec_retimer_set, + }; + + port->retimer = typec_retimer_register(port->sdata->dev, &retimer_desc); + if (IS_ERR(port->retimer)) + return PTR_ERR(port->retimer); + + return 0; +} + +static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) +{ + struct cros_typec_port *port = NULL; + struct device *dev = sdata->dev; + struct fwnode_handle *fwnode; + struct acpi_device *adev; + unsigned long long index; + int ret = 0; + int nports; + + nports = device_get_child_node_count(dev); + if (nports == 0) { + dev_err(dev, "No switch devices found.\n"); + return -ENODEV; + } + + device_for_each_child_node(dev, fwnode) { + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) { + ret = -ENOMEM; + goto err_switch; + } + + adev = to_acpi_device_node(fwnode); + if (!adev) { + dev_err(fwnode->dev, "Couldn't get ACPI device handle\n"); + ret = -ENODEV; + goto err_switch; + } + + ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); + if (ACPI_FAILURE(ret)) { + dev_err(fwnode->dev, "_ADR wasn't evaluated\n"); + ret = -ENODATA; + goto err_switch; + } + + if (index < 0 || index >= EC_USB_PD_MAX_PORTS) { + dev_err(fwnode->dev, "Invalid port index number: %llu", index); + ret = -EINVAL; + goto err_switch; + } + port->sdata = sdata; + port->port_num = index; + sdata->ports[index] = port; + + ret = cros_typec_register_retimer(port, fwnode); + if (ret) { + dev_err(dev, "Retimer switch register failed\n"); + goto err_switch; + } + + dev_dbg(dev, "Retimer switch registered for index %llu\n", index); + } + + return 0; +err_switch: + cros_typec_unregister_switches(sdata); + return ret; +} + +static int cros_typec_switch_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cros_typec_switch_data *sdata; + + sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL); + if (!sdata) + return -ENOMEM; + + sdata->dev = dev; + sdata->ec = dev_get_drvdata(pdev->dev.parent); + + platform_set_drvdata(pdev, sdata); + + return cros_typec_register_switches(sdata); +} + +static int cros_typec_switch_remove(struct platform_device *pdev) +{ + struct cros_typec_switch_data *sdata = platform_get_drvdata(pdev); + + cros_typec_unregister_switches(sdata); + return 0; +} + +#ifdef CONFIG_ACPI +static const struct acpi_device_id cros_typec_switch_acpi_id[] = { + { "GOOG001A", 0 }, + {} +}; +MODULE_DEVICE_TABLE(acpi, cros_typec_switch_acpi_id); +#endif + +static struct platform_driver cros_typec_switch_driver = { + .driver = { + .name = DRV_NAME, + .acpi_match_table = ACPI_PTR(cros_typec_switch_acpi_id), + }, + .probe = cros_typec_switch_probe, + .remove = cros_typec_switch_remove, +}; + +module_platform_driver(cros_typec_switch_driver); + +MODULE_AUTHOR("Prashant Malani "); +MODULE_DESCRIPTION("Chrome OS EC Type C Switch control"); +MODULE_LICENSE("GPL"); From 34f375f0fdf67f8804142fa37a28e73426d4c1df Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 11 Jul 2022 07:22:59 +0000 Subject: [PATCH 1085/1436] platform/chrome: cros_typec_switch: Set EC retimer Invoke Chrome EC host commands to set EC-controlled retimer switches to the state the Type-C framework instructs. Signed-off-by: Prashant Malani Link: https://lore.kernel.org/r/20220711072333.2064341-6-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_typec_switch.c | 56 ++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c index 0d319e315d57..b50ecedce662 100644 --- a/drivers/platform/chrome/cros_typec_switch.c +++ b/drivers/platform/chrome/cros_typec_switch.c @@ -9,7 +9,10 @@ #include #include #include +#include #include +#include +#include #include #define DRV_NAME "cros-typec-switch" @@ -28,9 +31,60 @@ struct cros_typec_switch_data { struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS]; }; +static int cros_typec_cmd_mux_set(struct cros_typec_switch_data *sdata, int port_num, u8 index, + u8 state) +{ + struct typec_usb_mux_set params = { + .mux_index = index, + .mux_flags = state, + }; + + struct ec_params_typec_control req = { + .port = port_num, + .command = TYPEC_CONTROL_COMMAND_USB_MUX_SET, + .mux_params = params, + }; + + return cros_ec_command(sdata->ec, 0, EC_CMD_TYPEC_CONTROL, &req, + sizeof(req), NULL, 0); +} + +static int cros_typec_get_mux_state(unsigned long mode, struct typec_altmode *alt) +{ + int ret = -EOPNOTSUPP; + + if (mode == TYPEC_STATE_SAFE) + ret = USB_PD_MUX_SAFE_MODE; + else if (mode == TYPEC_STATE_USB) + ret = USB_PD_MUX_USB_ENABLED; + else if (alt && alt->svid == USB_TYPEC_DP_SID) + ret = USB_PD_MUX_DP_ENABLED; + + return ret; +} + +/* + * The Chrome EC treats both mode-switches and retimers as "muxes" for the purposes of the + * host command API. This common function configures and verifies the retimer/mode-switch + * according to the provided setting. + */ +static int cros_typec_configure_mux(struct cros_typec_switch_data *sdata, int port_num, int index, + unsigned long mode, struct typec_altmode *alt) +{ + int ret = cros_typec_get_mux_state(mode, alt); + + if (ret < 0) + return ret; + + return cros_typec_cmd_mux_set(sdata, port_num, index, (u8)ret); +} + static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) { - return 0; + struct cros_typec_port *port = typec_retimer_get_drvdata(retimer); + + /* Retimers have index 1. */ + return cros_typec_configure_mux(port->sdata, port->port_num, 1, state->mode, state->alt); } static void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata) From bb53ad958012f5a8d88b3b7159c22b3b877601bb Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 11 Jul 2022 07:23:00 +0000 Subject: [PATCH 1086/1436] platform/chrome: cros_typec_switch: Add event check The Chrome EC updates Type-C status events when mux set requests from the Application Processor (AP) are completed. Add a check to the flow of configuring muxes to look for this status done bit, so that the driver is aware that the mux set completed successfully or not. Reported-by: kernel test robot Signed-off-by: Prashant Malani Link: https://lore.kernel.org/r/20220711072333.2064341-7-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_typec_switch.c | 72 ++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c index b50ecedce662..7c01957a032d 100644 --- a/drivers/platform/chrome/cros_typec_switch.c +++ b/drivers/platform/chrome/cros_typec_switch.c @@ -7,6 +7,8 @@ */ #include +#include +#include #include #include #include @@ -63,6 +65,40 @@ static int cros_typec_get_mux_state(unsigned long mode, struct typec_altmode *al return ret; } +static int cros_typec_send_clear_event(struct cros_typec_switch_data *sdata, int port_num, + u32 events_mask) +{ + struct ec_params_typec_control req = { + .port = port_num, + .command = TYPEC_CONTROL_COMMAND_CLEAR_EVENTS, + .clear_events_mask = events_mask, + }; + + return cros_ec_command(sdata->ec, 0, EC_CMD_TYPEC_CONTROL, &req, + sizeof(req), NULL, 0); +} + +static bool cros_typec_check_event(struct cros_typec_switch_data *sdata, int port_num, u32 mask) +{ + struct ec_response_typec_status resp; + struct ec_params_typec_status req = { + .port = port_num, + }; + int ret; + + ret = cros_ec_command(sdata->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req), + &resp, sizeof(resp)); + if (ret < 0) { + dev_warn(sdata->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num); + return false; + } + + if (resp.events & mask) + return true; + + return false; +} + /* * The Chrome EC treats both mode-switches and retimers as "muxes" for the purposes of the * host command API. This common function configures and verifies the retimer/mode-switch @@ -71,12 +107,44 @@ static int cros_typec_get_mux_state(unsigned long mode, struct typec_altmode *al static int cros_typec_configure_mux(struct cros_typec_switch_data *sdata, int port_num, int index, unsigned long mode, struct typec_altmode *alt) { - int ret = cros_typec_get_mux_state(mode, alt); + unsigned long end; + u32 event_mask; + u8 mux_state; + int ret; + ret = cros_typec_get_mux_state(mode, alt); + if (ret < 0) + return ret; + mux_state = (u8)ret; + + /* Clear any old mux set done event. */ + if (index == 0) + event_mask = PD_STATUS_EVENT_MUX_0_SET_DONE; + else + event_mask = PD_STATUS_EVENT_MUX_1_SET_DONE; + + ret = cros_typec_send_clear_event(sdata, port_num, event_mask); if (ret < 0) return ret; - return cros_typec_cmd_mux_set(sdata, port_num, index, (u8)ret); + /* Send the set command. */ + ret = cros_typec_cmd_mux_set(sdata, port_num, index, mux_state); + if (ret < 0) + return ret; + + /* Check for the mux set done event. */ + end = jiffies + msecs_to_jiffies(1000); + do { + if (cros_typec_check_event(sdata, port_num, event_mask)) + return 0; + + usleep_range(500, 1000); + } while (time_before(jiffies, end)); + + dev_err(sdata->dev, "Timed out waiting for mux set done on index: %d, state: %d\n", + index, mux_state); + + return -ETIMEDOUT; } static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) From f5434e30011e011b24852959365b7cbc61dd8c85 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 11 Jul 2022 07:23:01 +0000 Subject: [PATCH 1087/1436] platform/chrome: cros_typec_switch: Register mode switches Register mode switch devices for Type C connectors, when they are specified by firmware. These control Type C configuration for any USB Type-C mode switches (sometimes known as "muxes") which are controlled by the Chrome EC. Signed-off-by: Prashant Malani Link: https://lore.kernel.org/r/20220711072333.2064341-8-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_typec_switch.c | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c index 7c01957a032d..024a2bb146b2 100644 --- a/drivers/platform/chrome/cros_typec_switch.c +++ b/drivers/platform/chrome/cros_typec_switch.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #define DRV_NAME "cros-typec-switch" @@ -22,6 +23,7 @@ /* Handles and other relevant data required for each port's switches. */ struct cros_typec_port { int port_num; + struct typec_mux_dev *mode_switch; struct typec_retimer *retimer; struct cros_typec_switch_data *sdata; }; @@ -147,6 +149,15 @@ static int cros_typec_configure_mux(struct cros_typec_switch_data *sdata, int po return -ETIMEDOUT; } +static int cros_typec_mode_switch_set(struct typec_mux_dev *mode_switch, + struct typec_mux_state *state) +{ + struct cros_typec_port *port = typec_mux_get_drvdata(mode_switch); + + /* Mode switches have index 0. */ + return cros_typec_configure_mux(port->sdata, port->port_num, 0, state->mode, state->alt); +} + static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) { struct cros_typec_port *port = typec_retimer_get_drvdata(retimer); @@ -163,9 +174,27 @@ static void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata) if (!sdata->ports[i]) continue; typec_retimer_unregister(sdata->ports[i]->retimer); + typec_mux_unregister(sdata->ports[i]->mode_switch); } } +static int cros_typec_register_mode_switch(struct cros_typec_port *port, + struct fwnode_handle *fwnode) +{ + struct typec_mux_desc mode_switch_desc = { + .fwnode = fwnode, + .drvdata = port, + .name = fwnode_get_name(fwnode), + .set = cros_typec_mode_switch_set, + }; + + port->mode_switch = typec_mux_register(port->sdata->dev, &mode_switch_desc); + if (IS_ERR(port->mode_switch)) + return PTR_ERR(port->mode_switch); + + return 0; +} + static int cros_typec_register_retimer(struct cros_typec_port *port, struct fwnode_handle *fwnode) { struct typec_retimer_desc retimer_desc = { @@ -235,6 +264,17 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) } dev_dbg(dev, "Retimer switch registered for index %llu\n", index); + + if (!fwnode_property_read_bool(fwnode, "mode-switch")) + continue; + + ret = cros_typec_register_mode_switch(port, fwnode); + if (ret) { + dev_err(dev, "Mode switch register failed\n"); + goto err_switch; + } + + dev_dbg(dev, "Mode switch registered for index %llu\n", index); } return 0; From 66fe238a9bcc158f75ddecf976d1ce7efe20f713 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 11 Jul 2022 07:23:02 +0000 Subject: [PATCH 1088/1436] platform/chrome: cros_ec_typec: Cleanup switch handle return paths Some of the return paths for the cros_typec_get_switch_handles() aren't necessary. Clean up the return paths to only undo the handle get's which succeeded. Signed-off-by: Prashant Malani Link: https://lore.kernel.org/r/20220711072333.2064341-9-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_ec_typec.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 7cb2e35c4ded..39e6fd4491a9 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -157,12 +157,10 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port, return 0; role_sw_err: - usb_role_switch_put(port->role_sw); -ori_sw_err: typec_switch_put(port->ori_sw); -mux_err: +ori_sw_err: typec_mux_put(port->mux); - +mux_err: return -ENODEV; } From c76d09da77d69d7f737540985912ad2bca654713 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 11 Jul 2022 07:23:03 +0000 Subject: [PATCH 1089/1436] platform/chrome: cros_ec_typec: Get retimer handle Where available, obtain the handle to retimer switch specified via firmware, and update the mux configuration callsites to add retimer support for supported modes. Signed-off-by: Prashant Malani Link: https://lore.kernel.org/r/20220711072333.2064341-10-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_ec_typec.c | 44 +++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 39e6fd4491a9..38c4ac754ea9 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,7 @@ struct cros_typec_port { struct usb_pd_identity c_identity; struct typec_switch *ori_sw; struct typec_mux *mux; + struct typec_retimer *retimer; struct usb_role_switch *role_sw; /* Variables keeping track of switch state. */ @@ -142,6 +144,12 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port, goto mux_err; } + port->retimer = fwnode_typec_retimer_get(fwnode); + if (IS_ERR(port->retimer)) { + dev_dbg(dev, "Retimer handle not found.\n"); + goto retimer_sw_err; + } + port->ori_sw = fwnode_typec_switch_get(fwnode); if (IS_ERR(port->ori_sw)) { dev_dbg(dev, "Orientation switch handle not found.\n"); @@ -159,6 +167,8 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port, role_sw_err: typec_switch_put(port->ori_sw); ori_sw_err: + typec_retimer_put(port->retimer); +retimer_sw_err: typec_mux_put(port->mux); mux_err: return -ENODEV; @@ -203,6 +213,21 @@ static void cros_typec_unregister_altmodes(struct cros_typec_data *typec, int po } } +/* + * Map the Type-C Mux state to retimer state and call the retimer set function. We need this + * because we re-use the Type-C mux state for retimers. + */ +static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_mux_state state) +{ + struct typec_retimer_state rstate = { + .alt = state.alt, + .mode = state.mode, + .data = state.data, + }; + + return typec_retimer_set(retimer, &rstate); +} + static int cros_typec_usb_disconnect_state(struct cros_typec_port *port) { port->state.alt = NULL; @@ -211,6 +236,7 @@ static int cros_typec_usb_disconnect_state(struct cros_typec_port *port) usb_role_switch_set_role(port->role_sw, USB_ROLE_NONE); typec_switch_set(port->ori_sw, TYPEC_ORIENTATION_NONE); + cros_typec_retimer_set(port->retimer, port->state); return typec_mux_set(port->mux, &port->state); } @@ -381,9 +407,14 @@ unregister_ports: static int cros_typec_usb_safe_state(struct cros_typec_port *port) { + int ret; port->state.mode = TYPEC_STATE_SAFE; - return typec_mux_set(port->mux, &port->state); + ret = cros_typec_retimer_set(port->retimer, port->state); + if (!ret) + ret = typec_mux_set(port->mux, &port->state); + + return ret; } /* @@ -480,7 +511,11 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec, port->state.data = &dp_data; port->state.mode = TYPEC_MODAL_STATE(ffs(pd_ctrl->dp_mode)); - return typec_mux_set(port->mux, &port->state); + ret = cros_typec_retimer_set(port->retimer, port->state); + if (!ret) + ret = typec_mux_set(port->mux, &port->state); + + return ret; } static int cros_typec_enable_usb4(struct cros_typec_data *typec, @@ -569,7 +604,10 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, } else if (port->mux_flags & USB_PD_MUX_USB_ENABLED) { port->state.alt = NULL; port->state.mode = TYPEC_STATE_USB; - ret = typec_mux_set(port->mux, &port->state); + + ret = cros_typec_retimer_set(port->retimer, port->state); + if (!ret) + ret = typec_mux_set(port->mux, &port->state); } else { dev_dbg(typec->dev, "Unrecognized mode requested, mux flags: %x\n", From 7ee951acd31a88f941fd6535fbdee3a1567f1d63 Mon Sep 17 00:00:00 2001 From: Phil Auld Date: Fri, 15 Jul 2022 09:49:24 -0400 Subject: [PATCH 1090/1436] drivers/base: fix userspace break from using bin_attributes for cpumap and cpulist Using bin_attributes with a 0 size causes fstat and friends to return that 0 size. This breaks userspace code that retrieves the size before reading the file. Rather than reverting 75bd50fa841 ("drivers/base/node.c: use bin_attribute to break the size limitation of cpumap ABI") let's put in a size value at compile time. For cpulist the maximum size is on the order of NR_CPUS * (ceil(log10(NR_CPUS)) + 1)/2 which for 8192 is 20480 (8192 * 5)/2. In order to get near that you'd need a system with every other CPU on one node. For example: (0,2,4,8, ... ). To simplify the math and support larger NR_CPUS in the future we are using (NR_CPUS * 7)/2. We also set it to a min of PAGE_SIZE to retain the older behavior for smaller NR_CPUS. The cpumap file the size works out to be NR_CPUS/4 + NR_CPUS/32 - 1 (or NR_CPUS * 9/32 - 1) including the ","s. Add a set of macros for these values to cpumask.h so they can be used in multiple places. Apply these to the handful of such files in drivers/base/topology.c as well as node.c. As an example, on an 80 cpu 4-node system (NR_CPUS == 8192): before: -r--r--r--. 1 root root 0 Jul 12 14:08 system/node/node0/cpulist -r--r--r--. 1 root root 0 Jul 11 17:25 system/node/node0/cpumap after: -r--r--r--. 1 root root 28672 Jul 13 11:32 system/node/node0/cpulist -r--r--r--. 1 root root 4096 Jul 13 11:31 system/node/node0/cpumap CONFIG_NR_CPUS = 16384 -r--r--r--. 1 root root 57344 Jul 13 14:03 system/node/node0/cpulist -r--r--r--. 1 root root 4607 Jul 13 14:02 system/node/node0/cpumap The actual number of cpus doesn't matter for the reported size since they are based on NR_CPUS. Fixes: 75bd50fa841d ("drivers/base/node.c: use bin_attribute to break the size limitation of cpumap ABI") Fixes: bb9ec13d156e ("topology: use bin_attribute to break the size limitation of cpumap ABI") Cc: Greg Kroah-Hartman Cc: "Rafael J. Wysocki" Cc: Yury Norov Cc: stable@vger.kernel.org Acked-by: Yury Norov (for include/linux/cpumask.h) Signed-off-by: Phil Auld Link: https://lore.kernel.org/r/20220715134924.3466194-1-pauld@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/node.c | 4 ++-- drivers/base/topology.c | 32 ++++++++++++++++---------------- include/linux/cpumask.h | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/drivers/base/node.c b/drivers/base/node.c index 0ac6376ef7a1..eb0f43784c2b 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -45,7 +45,7 @@ static inline ssize_t cpumap_read(struct file *file, struct kobject *kobj, return n; } -static BIN_ATTR_RO(cpumap, 0); +static BIN_ATTR_RO(cpumap, CPUMAP_FILE_MAX_BYTES); static inline ssize_t cpulist_read(struct file *file, struct kobject *kobj, struct bin_attribute *attr, char *buf, @@ -66,7 +66,7 @@ static inline ssize_t cpulist_read(struct file *file, struct kobject *kobj, return n; } -static BIN_ATTR_RO(cpulist, 0); +static BIN_ATTR_RO(cpulist, CPULIST_FILE_MAX_BYTES); /** * struct node_access_nodes - Access class device to hold user visible diff --git a/drivers/base/topology.c b/drivers/base/topology.c index ac6ad9ab67f9..89f98be5c5b9 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -62,47 +62,47 @@ define_id_show_func(ppin, "0x%llx"); static DEVICE_ATTR_ADMIN_RO(ppin); define_siblings_read_func(thread_siblings, sibling_cpumask); -static BIN_ATTR_RO(thread_siblings, 0); -static BIN_ATTR_RO(thread_siblings_list, 0); +static BIN_ATTR_RO(thread_siblings, CPUMAP_FILE_MAX_BYTES); +static BIN_ATTR_RO(thread_siblings_list, CPULIST_FILE_MAX_BYTES); define_siblings_read_func(core_cpus, sibling_cpumask); -static BIN_ATTR_RO(core_cpus, 0); -static BIN_ATTR_RO(core_cpus_list, 0); +static BIN_ATTR_RO(core_cpus, CPUMAP_FILE_MAX_BYTES); +static BIN_ATTR_RO(core_cpus_list, CPULIST_FILE_MAX_BYTES); define_siblings_read_func(core_siblings, core_cpumask); -static BIN_ATTR_RO(core_siblings, 0); -static BIN_ATTR_RO(core_siblings_list, 0); +static BIN_ATTR_RO(core_siblings, CPUMAP_FILE_MAX_BYTES); +static BIN_ATTR_RO(core_siblings_list, CPULIST_FILE_MAX_BYTES); #ifdef TOPOLOGY_CLUSTER_SYSFS define_siblings_read_func(cluster_cpus, cluster_cpumask); -static BIN_ATTR_RO(cluster_cpus, 0); -static BIN_ATTR_RO(cluster_cpus_list, 0); +static BIN_ATTR_RO(cluster_cpus, CPUMAP_FILE_MAX_BYTES); +static BIN_ATTR_RO(cluster_cpus_list, CPULIST_FILE_MAX_BYTES); #endif #ifdef TOPOLOGY_DIE_SYSFS define_siblings_read_func(die_cpus, die_cpumask); -static BIN_ATTR_RO(die_cpus, 0); -static BIN_ATTR_RO(die_cpus_list, 0); +static BIN_ATTR_RO(die_cpus, CPUMAP_FILE_MAX_BYTES); +static BIN_ATTR_RO(die_cpus_list, CPULIST_FILE_MAX_BYTES); #endif define_siblings_read_func(package_cpus, core_cpumask); -static BIN_ATTR_RO(package_cpus, 0); -static BIN_ATTR_RO(package_cpus_list, 0); +static BIN_ATTR_RO(package_cpus, CPUMAP_FILE_MAX_BYTES); +static BIN_ATTR_RO(package_cpus_list, CPULIST_FILE_MAX_BYTES); #ifdef TOPOLOGY_BOOK_SYSFS define_id_show_func(book_id, "%d"); static DEVICE_ATTR_RO(book_id); define_siblings_read_func(book_siblings, book_cpumask); -static BIN_ATTR_RO(book_siblings, 0); -static BIN_ATTR_RO(book_siblings_list, 0); +static BIN_ATTR_RO(book_siblings, CPUMAP_FILE_MAX_BYTES); +static BIN_ATTR_RO(book_siblings_list, CPULIST_FILE_MAX_BYTES); #endif #ifdef TOPOLOGY_DRAWER_SYSFS define_id_show_func(drawer_id, "%d"); static DEVICE_ATTR_RO(drawer_id); define_siblings_read_func(drawer_siblings, drawer_cpumask); -static BIN_ATTR_RO(drawer_siblings, 0); -static BIN_ATTR_RO(drawer_siblings_list, 0); +static BIN_ATTR_RO(drawer_siblings, CPUMAP_FILE_MAX_BYTES); +static BIN_ATTR_RO(drawer_siblings_list, CPULIST_FILE_MAX_BYTES); #endif static struct bin_attribute *bin_attrs[] = { diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index fe29ac7cc469..4592d0845941 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -1071,4 +1071,22 @@ cpumap_print_list_to_buf(char *buf, const struct cpumask *mask, [0] = 1UL \ } } +/* + * Provide a valid theoretical max size for cpumap and cpulist sysfs files + * to avoid breaking userspace which may allocate a buffer based on the size + * reported by e.g. fstat. + * + * for cpumap NR_CPUS * 9/32 - 1 should be an exact length. + * + * For cpulist 7 is (ceil(log10(NR_CPUS)) + 1) allowing for NR_CPUS to be up + * to 2 orders of magnitude larger than 8192. And then we divide by 2 to + * cover a worst-case of every other cpu being on one of two nodes for a + * very large NR_CPUS. + * + * Use PAGE_SIZE as a minimum for smaller configurations. + */ +#define CPUMAP_FILE_MAX_BYTES ((((NR_CPUS * 9)/32 - 1) > PAGE_SIZE) \ + ? (NR_CPUS * 9)/32 - 1 : PAGE_SIZE) +#define CPULIST_FILE_MAX_BYTES (((NR_CPUS * 7)/2 > PAGE_SIZE) ? (NR_CPUS * 7)/2 : PAGE_SIZE) + #endif /* __LINUX_CPUMASK_H */ From ed6313a93fd11d2015ad17046f3c418bf6a8dab1 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Fri, 15 Jul 2022 16:58:24 -0700 Subject: [PATCH 1091/1436] KVM: arm64: Fix hypervisor address symbolization With CONFIG_RANDOMIZE_BASE=y vmlinux addresses will resolve incorrectly from kallsyms. Fix this by adding the KASLR offset before printing the symbols. Fixes: 6ccf9cb557bd ("KVM: arm64: Symbolize the nVHE HYP addresses") Reported-by: Fuad Tabba Signed-off-by: Kalesh Singh Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220715235824.2549012-1-kaleshsingh@google.com --- arch/arm64/kvm/handle_exit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index f66c0142b335..e43926ef2bc2 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -347,10 +347,10 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, kvm_err("nVHE hyp BUG at: %s:%u!\n", file, line); else kvm_err("nVHE hyp BUG at: [<%016llx>] %pB!\n", panic_addr, - (void *)panic_addr); + (void *)(panic_addr + kaslr_offset())); } else { kvm_err("nVHE hyp panic at: [<%016llx>] %pB!\n", panic_addr, - (void *)panic_addr); + (void *)(panic_addr + kaslr_offset())); } /* From da8d120fbafe1d3217d25ac45493538b37cff87c Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 3 Jul 2022 14:08:46 +0100 Subject: [PATCH 1092/1436] KVM: arm64: Add get_reg_by_id() as a sys_reg_desc retrieving helper find_reg_by_id() requires a sys_reg_param as input, which most users provide as a on-stack variable, but don't make any use of the result. Provide a helper that doesn't have this requirement and simplify the callers (all but one). Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 28 +++++++++++++++++----------- arch/arm64/kvm/sys_regs.h | 4 ++++ arch/arm64/kvm/vgic-sys-reg-v3.c | 8 ++------ 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index c06c0477fab5..1f410283c592 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2650,21 +2650,29 @@ const struct sys_reg_desc *find_reg_by_id(u64 id, return find_reg(params, table, num); } +const struct sys_reg_desc *get_reg_by_id(u64 id, + const struct sys_reg_desc table[], + unsigned int num) +{ + struct sys_reg_params params; + + if (!index_to_params(id, ¶ms)) + return NULL; + + return find_reg(¶ms, table, num); +} + /* Decode an index value, and find the sys_reg_desc entry. */ static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id) { const struct sys_reg_desc *r; - struct sys_reg_params params; /* We only do sys_reg for now. */ if ((id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM64_SYSREG) return NULL; - if (!index_to_params(id, ¶ms)) - return NULL; - - r = find_reg(¶ms, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); + r = get_reg_by_id(id, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); /* Not saved in the sys_reg array and not otherwise accessible? */ if (r && !(r->reg || r->get_user)) @@ -2723,11 +2731,10 @@ static int reg_to_user(void __user *uaddr, const u64 *val, u64 id) static int get_invariant_sys_reg(u64 id, void __user *uaddr) { - struct sys_reg_params params; const struct sys_reg_desc *r; - r = find_reg_by_id(id, ¶ms, invariant_sys_regs, - ARRAY_SIZE(invariant_sys_regs)); + r = get_reg_by_id(id, invariant_sys_regs, + ARRAY_SIZE(invariant_sys_regs)); if (!r) return -ENOENT; @@ -2736,13 +2743,12 @@ static int get_invariant_sys_reg(u64 id, void __user *uaddr) static int set_invariant_sys_reg(u64 id, void __user *uaddr) { - struct sys_reg_params params; const struct sys_reg_desc *r; int err; u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */ - r = find_reg_by_id(id, ¶ms, invariant_sys_regs, - ARRAY_SIZE(invariant_sys_regs)); + r = get_reg_by_id(id, invariant_sys_regs, + ARRAY_SIZE(invariant_sys_regs)); if (!r) return -ENOENT; diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index aee8ea054f0d..ce30ed9566ae 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -195,6 +195,10 @@ const struct sys_reg_desc *find_reg_by_id(u64 id, const struct sys_reg_desc table[], unsigned int num); +const struct sys_reg_desc *get_reg_by_id(u64 id, + const struct sys_reg_desc table[], + unsigned int num); + #define AA32(_x) .aarch32_map = AA32_##_x #define Op0(_x) .Op0 = _x #define Op1(_x) .Op1 = _x diff --git a/arch/arm64/kvm/vgic-sys-reg-v3.c b/arch/arm64/kvm/vgic-sys-reg-v3.c index 07d5271e9f05..644acda33c7c 100644 --- a/arch/arm64/kvm/vgic-sys-reg-v3.c +++ b/arch/arm64/kvm/vgic-sys-reg-v3.c @@ -263,14 +263,10 @@ static const struct sys_reg_desc gic_v3_icc_reg_descs[] = { int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id, u64 *reg) { - struct sys_reg_params params; u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64; - params.regval = *reg; - params.is_write = is_write; - - if (find_reg_by_id(sysreg, ¶ms, gic_v3_icc_reg_descs, - ARRAY_SIZE(gic_v3_icc_reg_descs))) + if (get_reg_by_id(sysreg, gic_v3_icc_reg_descs, + ARRAY_SIZE(gic_v3_icc_reg_descs))) return 0; return -ENXIO; From 1deeffb559663dc44e4b8a61fe7e271fe3b4b836 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 3 Jul 2022 15:11:50 +0100 Subject: [PATCH 1093/1436] KVM: arm64: Reorder handling of invariant sysregs from userspace In order to allow some further refactor of the sysreg helpers, move the handling of invariant sysreg to occur before we handle all the other ones. Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 1f410283c592..9291cb94c2e4 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2849,6 +2849,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg { const struct sys_reg_desc *r; void __user *uaddr = (void __user *)(unsigned long)reg->addr; + int err; if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) return demux_c15_get(reg->id, uaddr); @@ -2856,12 +2857,14 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg if (KVM_REG_SIZE(reg->id) != sizeof(__u64)) return -ENOENT; + err = get_invariant_sys_reg(reg->id, uaddr); + if (err != -ENOENT) + return err; + r = index_to_sys_reg_desc(vcpu, reg->id); - if (!r) - return get_invariant_sys_reg(reg->id, uaddr); /* Check for regs disabled by runtime config */ - if (sysreg_hidden(vcpu, r)) + if (!r || sysreg_hidden(vcpu, r)) return -ENOENT; if (r->get_user) @@ -2874,6 +2877,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg { const struct sys_reg_desc *r; void __user *uaddr = (void __user *)(unsigned long)reg->addr; + int err; if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) return demux_c15_set(reg->id, uaddr); @@ -2881,12 +2885,14 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg if (KVM_REG_SIZE(reg->id) != sizeof(__u64)) return -ENOENT; + err = set_invariant_sys_reg(reg->id, uaddr); + if (err != -ENOENT) + return err; + r = index_to_sys_reg_desc(vcpu, reg->id); - if (!r) - return set_invariant_sys_reg(reg->id, uaddr); /* Check for regs disabled by runtime config */ - if (sysreg_hidden(vcpu, r)) + if (!r || sysreg_hidden(vcpu, r)) return -ENOENT; if (r->set_user) From ba23aec9f4f27c00ac7a504aae60cae8a4087a19 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 3 Jul 2022 16:06:51 +0100 Subject: [PATCH 1094/1436] KVM: arm64: Introduce generic get_user/set_user helpers for system registers The userspace access to the system registers is done using helpers that hardcode the table that is looked up. extract some generic helpers from this, moving the handling of hidden sysregs into the core code. Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 60 +++++++++++++++++++++++++-------------- arch/arm64/kvm/sys_regs.h | 6 ++++ 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 9291cb94c2e4..0fbdb21a3600 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2663,8 +2663,10 @@ const struct sys_reg_desc *get_reg_by_id(u64 id, } /* Decode an index value, and find the sys_reg_desc entry. */ -static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu, - u64 id) +static const struct sys_reg_desc * +id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id, + const struct sys_reg_desc table[], unsigned int num) + { const struct sys_reg_desc *r; @@ -2672,10 +2674,10 @@ static const struct sys_reg_desc *index_to_sys_reg_desc(struct kvm_vcpu *vcpu, if ((id & KVM_REG_ARM_COPROC_MASK) != KVM_REG_ARM64_SYSREG) return NULL; - r = get_reg_by_id(id, sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); + r = get_reg_by_id(id, table, num); /* Not saved in the sys_reg array and not otherwise accessible? */ - if (r && !(r->reg || r->get_user)) + if (r && (!(r->reg || r->get_user) || sysreg_hidden(vcpu, r))) r = NULL; return r; @@ -2845,9 +2847,24 @@ static int demux_c15_set(u64 id, void __user *uaddr) } } +int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, + const struct sys_reg_desc table[], unsigned int num) +{ + void __user *uaddr = (void __user *)(unsigned long)reg->addr; + const struct sys_reg_desc *r; + + r = id_to_sys_reg_desc(vcpu, reg->id, table, num); + if (!r) + return -ENOENT; + + if (r->get_user) + return (r->get_user)(vcpu, r, reg, uaddr); + + return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id); +} + int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { - const struct sys_reg_desc *r; void __user *uaddr = (void __user *)(unsigned long)reg->addr; int err; @@ -2861,21 +2878,28 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg if (err != -ENOENT) return err; - r = index_to_sys_reg_desc(vcpu, reg->id); + return kvm_sys_reg_get_user(vcpu, reg, + sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); +} - /* Check for regs disabled by runtime config */ - if (!r || sysreg_hidden(vcpu, r)) +int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, + const struct sys_reg_desc table[], unsigned int num) +{ + void __user *uaddr = (void __user *)(unsigned long)reg->addr; + const struct sys_reg_desc *r; + + r = id_to_sys_reg_desc(vcpu, reg->id, table, num); + if (!r) return -ENOENT; - if (r->get_user) - return (r->get_user)(vcpu, r, reg, uaddr); + if (r->set_user) + return (r->set_user)(vcpu, r, reg, uaddr); - return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id); + return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id); } int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { - const struct sys_reg_desc *r; void __user *uaddr = (void __user *)(unsigned long)reg->addr; int err; @@ -2889,16 +2913,8 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg if (err != -ENOENT) return err; - r = index_to_sys_reg_desc(vcpu, reg->id); - - /* Check for regs disabled by runtime config */ - if (!r || sysreg_hidden(vcpu, r)) - return -ENOENT; - - if (r->set_user) - return (r->set_user)(vcpu, r, reg, uaddr); - - return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id); + return kvm_sys_reg_set_user(vcpu, reg, + sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); } static unsigned int num_demux_regs(void) diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index ce30ed9566ae..4fb6d59e7874 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -199,6 +199,12 @@ const struct sys_reg_desc *get_reg_by_id(u64 id, const struct sys_reg_desc table[], unsigned int num); +int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, + const struct sys_reg_desc table[], unsigned int num); + +int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, + const struct sys_reg_desc table[], unsigned int num); + #define AA32(_x) .aarch32_map = AA32_##_x #define Op0(_x) .Op0 = _x #define Op1(_x) .Op1 = _x From e48407ff9796529a1e5048b9e4d6ea8a0334468e Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 4 Jul 2022 17:01:50 +0100 Subject: [PATCH 1095/1436] KVM: arm64: Rely on index_to_param() for size checks on userspace access index_to_param() already checks that we use 64bit accesses for all registers accessed from userspace. However, we have extra checks in other places (such as index_to_params), which is pretty confusing. Get rid off these redundant checks. Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 0fbdb21a3600..5dbe0f4b8167 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2871,9 +2871,6 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) return demux_c15_get(reg->id, uaddr); - if (KVM_REG_SIZE(reg->id) != sizeof(__u64)) - return -ENOENT; - err = get_invariant_sys_reg(reg->id, uaddr); if (err != -ENOENT) return err; @@ -2906,9 +2903,6 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) return demux_c15_set(reg->id, uaddr); - if (KVM_REG_SIZE(reg->id) != sizeof(__u64)) - return -ENOENT; - err = set_invariant_sys_reg(reg->id, uaddr); if (err != -ENOENT) return err; From 978ceeb3e40a59973ff1d1c3d23484f71f141819 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 4 Jul 2022 17:27:00 +0100 Subject: [PATCH 1096/1436] KVM: arm64: Consolidate sysreg userspace accesses Until now, the .set_user and .get_user callbacks have to implement (directly or not) the userspace memory accesses. Although this gives us maximem flexibility, this is also a maintenance burden, making it hard to audit, and I'd feel much better if it was all located in a single place. So let's do just that, simplifying most of the function signatures in the process (the callbacks are now only concerned with the data itself, and not with userspace). Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 160 ++++++++++++++------------------------ arch/arm64/kvm/sys_regs.h | 4 +- 2 files changed, 61 insertions(+), 103 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 5dbe0f4b8167..526798524697 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -321,16 +321,8 @@ static bool trap_oslsr_el1(struct kvm_vcpu *vcpu, } static int set_oslsr_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 val) { - u64 id = sys_reg_to_index(rd); - u64 val; - int err; - - err = reg_from_user(&val, uaddr, id); - if (err) - return err; - /* * The only modifiable bit is the OSLK bit. Refuse the write if * userspace attempts to change any other bit in the register. @@ -451,22 +443,16 @@ static bool trap_bvr(struct kvm_vcpu *vcpu, } static int set_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 val) { - __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm]; - - if (copy_from_user(r, uaddr, KVM_REG_SIZE(reg->id)) != 0) - return -EFAULT; + vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm] = val; return 0; } static int get_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 *val) { - __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm]; - - if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) - return -EFAULT; + *val = vcpu->arch.vcpu_debug_state.dbg_bvr[rd->CRm]; return 0; } @@ -493,23 +479,16 @@ static bool trap_bcr(struct kvm_vcpu *vcpu, } static int set_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 val) { - __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm]; - - if (copy_from_user(r, uaddr, KVM_REG_SIZE(reg->id)) != 0) - return -EFAULT; - + vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm] = val; return 0; } static int get_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 *val) { - __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm]; - - if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) - return -EFAULT; + *val = vcpu->arch.vcpu_debug_state.dbg_bcr[rd->CRm]; return 0; } @@ -537,22 +516,16 @@ static bool trap_wvr(struct kvm_vcpu *vcpu, } static int set_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 val) { - __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm]; - - if (copy_from_user(r, uaddr, KVM_REG_SIZE(reg->id)) != 0) - return -EFAULT; + vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm] = val; return 0; } static int get_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 *val) { - __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm]; - - if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) - return -EFAULT; + *val = vcpu->arch.vcpu_debug_state.dbg_wvr[rd->CRm]; return 0; } @@ -579,22 +552,16 @@ static bool trap_wcr(struct kvm_vcpu *vcpu, } static int set_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 val) { - __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm]; - - if (copy_from_user(r, uaddr, KVM_REG_SIZE(reg->id)) != 0) - return -EFAULT; + vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm] = val; return 0; } static int get_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 *val) { - __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm]; - - if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) - return -EFAULT; + *val = vcpu->arch.vcpu_debug_state.dbg_wcr[rd->CRm]; return 0; } @@ -1227,16 +1194,9 @@ static unsigned int sve_visibility(const struct kvm_vcpu *vcpu, static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 val) { - const u64 id = sys_reg_to_index(rd); u8 csv2, csv3; - int err; - u64 val; - - err = reg_from_user(&val, uaddr, id); - if (err) - return err; /* * Allow AA64PFR0_EL1.CSV2 to be set from userspace as long as @@ -1262,7 +1222,7 @@ static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, return -EINVAL; vcpu->kvm->arch.pfr0_csv2 = csv2; - vcpu->kvm->arch.pfr0_csv3 = csv3 ; + vcpu->kvm->arch.pfr0_csv3 = csv3; return 0; } @@ -1275,27 +1235,17 @@ static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu, * to be changed. */ static int __get_id_reg(const struct kvm_vcpu *vcpu, - const struct sys_reg_desc *rd, void __user *uaddr, + const struct sys_reg_desc *rd, u64 *val, bool raz) { - const u64 id = sys_reg_to_index(rd); - const u64 val = read_id_reg(vcpu, rd, raz); - - return reg_to_user(uaddr, &val, id); + *val = read_id_reg(vcpu, rd, raz); + return 0; } static int __set_id_reg(const struct kvm_vcpu *vcpu, - const struct sys_reg_desc *rd, void __user *uaddr, + const struct sys_reg_desc *rd, u64 val, bool raz) { - const u64 id = sys_reg_to_index(rd); - int err; - u64 val; - - err = reg_from_user(&val, uaddr, id); - if (err) - return err; - /* This is what we mean by invariant: you can't change it. */ if (val != read_id_reg(vcpu, rd, raz)) return -EINVAL; @@ -1304,47 +1254,37 @@ static int __set_id_reg(const struct kvm_vcpu *vcpu, } static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 *val) { bool raz = sysreg_visible_as_raz(vcpu, rd); - return __get_id_reg(vcpu, rd, uaddr, raz); + return __get_id_reg(vcpu, rd, val, raz); } static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 val) { bool raz = sysreg_visible_as_raz(vcpu, rd); - return __set_id_reg(vcpu, rd, uaddr, raz); + return __set_id_reg(vcpu, rd, val, raz); } static int set_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 val) { - return __set_id_reg(vcpu, rd, uaddr, true); + return __set_id_reg(vcpu, rd, val, true); } static int get_raz_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 *val) { - const u64 id = sys_reg_to_index(rd); - const u64 val = 0; - - return reg_to_user(uaddr, &val, id); + *val = 0; + return 0; } static int set_wi_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr) + u64 val) { - int err; - u64 val; - - /* Perform the access even if we are going to ignore the value */ - err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); - if (err) - return err; - return 0; } @@ -2850,17 +2790,26 @@ static int demux_c15_set(u64 id, void __user *uaddr) int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, const struct sys_reg_desc table[], unsigned int num) { - void __user *uaddr = (void __user *)(unsigned long)reg->addr; + u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr; const struct sys_reg_desc *r; + u64 val; + int ret; r = id_to_sys_reg_desc(vcpu, reg->id, table, num); if (!r) return -ENOENT; - if (r->get_user) - return (r->get_user)(vcpu, r, reg, uaddr); + if (r->get_user) { + ret = (r->get_user)(vcpu, r, &val); + } else { + val = __vcpu_sys_reg(vcpu, r->reg); + ret = 0; + } - return reg_to_user(uaddr, &__vcpu_sys_reg(vcpu, r->reg), reg->id); + if (!ret) + ret = put_user(val, uaddr); + + return ret; } int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) @@ -2882,17 +2831,26 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, const struct sys_reg_desc table[], unsigned int num) { - void __user *uaddr = (void __user *)(unsigned long)reg->addr; + u64 __user *uaddr = (u64 __user *)(unsigned long)reg->addr; const struct sys_reg_desc *r; + u64 val; + int ret; + + if (get_user(val, uaddr)) + return -EFAULT; r = id_to_sys_reg_desc(vcpu, reg->id, table, num); if (!r) return -ENOENT; - if (r->set_user) - return (r->set_user)(vcpu, r, reg, uaddr); + if (r->set_user) { + ret = (r->set_user)(vcpu, r, val); + } else { + __vcpu_sys_reg(vcpu, r->reg) = val; + ret = 0; + } - return reg_from_user(&__vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id); + return ret; } int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index 4fb6d59e7874..b8b576a2af2b 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -75,9 +75,9 @@ struct sys_reg_desc { /* Custom get/set_user functions, fallback to generic if NULL */ int (*get_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr); + u64 *val); int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, - const struct kvm_one_reg *reg, void __user *uaddr); + u64 val); /* Return mask of REG_* runtime visibility overrides */ unsigned int (*visibility)(const struct kvm_vcpu *vcpu, From 5a420ed9646a934e983358aeba1bf3cd993d1cc5 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 4 Jul 2022 17:55:43 +0100 Subject: [PATCH 1097/1436] KVM: arm64: Get rid of reg_from/to_user() These helpers are only used by the invariant stuff now, and while they pretend to support non-64bit registers, this only serves as a way to scare the casual reviewer... Replace these helpers with our good friends get/put_user(), and don't look back. Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 526798524697..379478eecfaa 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -44,8 +44,6 @@ * 64bit interface. */ -static int reg_from_user(u64 *val, const void __user *uaddr, u64 id); -static int reg_to_user(void __user *uaddr, const u64 *val, u64 id); static u64 sys_reg_to_index(const struct sys_reg_desc *reg); static bool read_from_write_only(struct kvm_vcpu *vcpu, @@ -2657,21 +2655,7 @@ static struct sys_reg_desc invariant_sys_regs[] = { { SYS_DESC(SYS_CTR_EL0), NULL, get_ctr_el0 }, }; -static int reg_from_user(u64 *val, const void __user *uaddr, u64 id) -{ - if (copy_from_user(val, uaddr, KVM_REG_SIZE(id)) != 0) - return -EFAULT; - return 0; -} - -static int reg_to_user(void __user *uaddr, const u64 *val, u64 id) -{ - if (copy_to_user(uaddr, val, KVM_REG_SIZE(id)) != 0) - return -EFAULT; - return 0; -} - -static int get_invariant_sys_reg(u64 id, void __user *uaddr) +static int get_invariant_sys_reg(u64 id, u64 __user *uaddr) { const struct sys_reg_desc *r; @@ -2680,23 +2664,21 @@ static int get_invariant_sys_reg(u64 id, void __user *uaddr) if (!r) return -ENOENT; - return reg_to_user(uaddr, &r->val, id); + return put_user(r->val, uaddr); } -static int set_invariant_sys_reg(u64 id, void __user *uaddr) +static int set_invariant_sys_reg(u64 id, u64 __user *uaddr) { const struct sys_reg_desc *r; - int err; - u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */ + u64 val; r = get_reg_by_id(id, invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs)); if (!r) return -ENOENT; - err = reg_from_user(&val, uaddr, id); - if (err) - return err; + if (get_user(val, uaddr)) + return -EFAULT; /* This is what we mean by invariant: you can't change it. */ if (r->val != val) From b61fc0857a3ad4cdee44128ad13685033e237367 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Sun, 3 Jul 2022 14:57:29 +0100 Subject: [PATCH 1098/1436] KVM: arm64: vgic-v3: Simplify vgic_v3_has_cpu_sysregs_attr() Finding out whether a sysreg exists has little to do with that register being accessed, so drop the is_write parameter. Also, the reg pointer is completely unused, and we're better off just passing the attr pointer to the function. This result in a small cleanup of the calling site, with a new helper converting the vGIC view of a sysreg into the canonical one (this is purely cosmetic, as the encoding is the same). Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic-sys-reg-v3.c | 14 ++++++++++---- arch/arm64/kvm/vgic/vgic-mmio-v3.c | 8 ++------ arch/arm64/kvm/vgic/vgic.h | 3 +-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/arch/arm64/kvm/vgic-sys-reg-v3.c b/arch/arm64/kvm/vgic-sys-reg-v3.c index 644acda33c7c..85a5e1d15e9f 100644 --- a/arch/arm64/kvm/vgic-sys-reg-v3.c +++ b/arch/arm64/kvm/vgic-sys-reg-v3.c @@ -260,12 +260,18 @@ static const struct sys_reg_desc gic_v3_icc_reg_descs[] = { { SYS_DESC(SYS_ICC_IGRPEN1_EL1), access_gic_grpen1 }, }; -int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id, - u64 *reg) +static u64 attr_to_id(u64 attr) { - u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64; + return ARM64_SYS_REG(FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP0_MASK, attr), + FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP1_MASK, attr), + FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_CRN_MASK, attr), + FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_CRM_MASK, attr), + FIELD_GET(KVM_REG_ARM_VGIC_SYSREG_OP2_MASK, attr)); +} - if (get_reg_by_id(sysreg, gic_v3_icc_reg_descs, +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) +{ + if (get_reg_by_id(attr_to_id(attr->attr), gic_v3_icc_reg_descs, ARRAY_SIZE(gic_v3_icc_reg_descs))) return 0; diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index f15e29cc63ce..a2ff73899976 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -986,12 +986,8 @@ int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr) iodev.base_addr = 0; break; } - case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: { - u64 reg, id; - - id = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK); - return vgic_v3_has_cpu_sysregs_attr(vcpu, 0, id, ®); - } + case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: + return vgic_v3_has_cpu_sysregs_attr(vcpu, attr); default: return -ENXIO; } diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index 4c6bdd321faa..ffc2d3c81b28 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -247,8 +247,7 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write, int offset, u32 *val); int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id, u64 *val); -int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, bool is_write, u64 id, - u64 *reg); +int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write, u32 intid, u64 *val); int kvm_register_vgic_device(unsigned long type); From db25081e147c3cc496b8cd8c9d67f992546df6d5 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 4 Jul 2022 08:07:44 +0100 Subject: [PATCH 1099/1436] KVM: arm64: vgic-v3: Push user access into vgic_v3_cpu_sysregs_uaccess() In order to start making the vgic sysreg access from userspace similar to all the other sysregs, push the userspace memory access one level down into vgic_v3_cpu_sysregs_uaccess(). The next step will be to rely on the sysreg infrastructure to perform this task. Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic-sys-reg-v3.c | 22 ++++++++++++------ arch/arm64/kvm/vgic/vgic-kvm-device.c | 33 ++++++--------------------- arch/arm64/kvm/vgic/vgic.h | 4 ++-- 3 files changed, 24 insertions(+), 35 deletions(-) diff --git a/arch/arm64/kvm/vgic-sys-reg-v3.c b/arch/arm64/kvm/vgic-sys-reg-v3.c index 85a5e1d15e9f..88eb5b049c2c 100644 --- a/arch/arm64/kvm/vgic-sys-reg-v3.c +++ b/arch/arm64/kvm/vgic-sys-reg-v3.c @@ -278,15 +278,21 @@ int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr * return -ENXIO; } -int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id, - u64 *reg) +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr, + bool is_write) { + u64 __user *uaddr = (u64 __user *)(long)attr->addr; struct sys_reg_params params; const struct sys_reg_desc *r; - u64 sysreg = (id & KVM_DEV_ARM_VGIC_SYSREG_MASK) | KVM_REG_SIZE_U64; + u64 sysreg; - if (is_write) - params.regval = *reg; + sysreg = attr_to_id(attr->attr); + + if (is_write) { + if (get_user(params.regval, uaddr)) + return -EFAULT; + } params.is_write = is_write; r = find_reg_by_id(sysreg, ¶ms, gic_v3_icc_reg_descs, @@ -297,8 +303,10 @@ int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, u64 id, if (!r->access(vcpu, ¶ms, r)) return -EINVAL; - if (!is_write) - *reg = params.regval; + if (!is_write) { + if (put_user(params.regval, uaddr)) + return -EFAULT; + } return 0; } diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c index c6d52a1fd9c8..bf745c6ab2ea 100644 --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c @@ -512,7 +512,7 @@ int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, * * @dev: kvm device handle * @attr: kvm device attribute - * @reg: address the value is read or written + * @reg: address the value is read or written, NULL for sysregs * @is_write: true if userspace is writing a register */ static int vgic_v3_attr_regs_access(struct kvm_device *dev, @@ -561,14 +561,9 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev, if (!is_write) *reg = tmp32; break; - case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: { - u64 regid; - - regid = (attr->attr & KVM_DEV_ARM_VGIC_SYSREG_INSTR_MASK); - ret = vgic_v3_cpu_sysregs_uaccess(vcpu, is_write, - regid, reg); + case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: + ret = vgic_v3_cpu_sysregs_uaccess(vcpu, attr, is_write); break; - } case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { unsigned int info, intid; @@ -617,15 +612,8 @@ static int vgic_v3_set_attr(struct kvm_device *dev, reg = tmp32; return vgic_v3_attr_regs_access(dev, attr, ®, true); } - case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: { - u64 __user *uaddr = (u64 __user *)(long)attr->addr; - u64 reg; - - if (get_user(reg, uaddr)) - return -EFAULT; - - return vgic_v3_attr_regs_access(dev, attr, ®, true); - } + case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: + return vgic_v3_attr_regs_access(dev, attr, NULL, true); case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { u32 __user *uaddr = (u32 __user *)(long)attr->addr; u64 reg; @@ -681,15 +669,8 @@ static int vgic_v3_get_attr(struct kvm_device *dev, tmp32 = reg; return put_user(tmp32, uaddr); } - case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: { - u64 __user *uaddr = (u64 __user *)(long)attr->addr; - u64 reg; - - ret = vgic_v3_attr_regs_access(dev, attr, ®, false); - if (ret) - return ret; - return put_user(reg, uaddr); - } + case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: + return vgic_v3_attr_regs_access(dev, attr, NULL, false); case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { u32 __user *uaddr = (u32 __user *)(long)attr->addr; u64 reg; diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index ffc2d3c81b28..c23118467a35 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -245,8 +245,8 @@ int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write, int offset, u32 *val); int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write, int offset, u32 *val); -int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, bool is_write, - u64 id, u64 *val); +int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, + struct kvm_device_attr *attr, bool is_write); int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write, u32 intid, u64 *val); From cbcf14dd23bcf228eb6061991acf3721506b97ae Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 4 Jul 2022 09:57:38 +0100 Subject: [PATCH 1100/1436] KVM: arm64: vgic-v3: Make the userspace accessors use sysreg API The vgic-v3 sysreg accessors have been ignored as the rest of the sysreg internal API was evolving, and are stuck with the .access method (which is normally reserved to the guest's own access) for the userspace accesses (which should use the .set/.get_user() methods). Catch up with the program and repaint all the accessors so that they fit into the normal userspace model, and plug the result into the helpers that have been introduced earlier. Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic-sys-reg-v3.c | 456 +++++++++++++++++-------------- 1 file changed, 258 insertions(+), 198 deletions(-) diff --git a/arch/arm64/kvm/vgic-sys-reg-v3.c b/arch/arm64/kvm/vgic-sys-reg-v3.c index 88eb5b049c2c..b755b02bc8ba 100644 --- a/arch/arm64/kvm/vgic-sys-reg-v3.c +++ b/arch/arm64/kvm/vgic-sys-reg-v3.c @@ -10,254 +10,330 @@ #include "vgic/vgic.h" #include "sys_regs.h" -static bool access_gic_ctlr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, - const struct sys_reg_desc *r) +static int set_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 val) { u32 host_pri_bits, host_id_bits, host_seis, host_a3v, seis, a3v; struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu; struct vgic_vmcr vmcr; + + vgic_get_vmcr(vcpu, &vmcr); + + /* + * Disallow restoring VM state if not supported by this + * hardware. + */ + host_pri_bits = ((val & ICC_CTLR_EL1_PRI_BITS_MASK) >> + ICC_CTLR_EL1_PRI_BITS_SHIFT) + 1; + if (host_pri_bits > vgic_v3_cpu->num_pri_bits) + return -EINVAL; + + vgic_v3_cpu->num_pri_bits = host_pri_bits; + + host_id_bits = (val & ICC_CTLR_EL1_ID_BITS_MASK) >> + ICC_CTLR_EL1_ID_BITS_SHIFT; + if (host_id_bits > vgic_v3_cpu->num_id_bits) + return -EINVAL; + + vgic_v3_cpu->num_id_bits = host_id_bits; + + host_seis = ((kvm_vgic_global_state.ich_vtr_el2 & + ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT); + seis = (val & ICC_CTLR_EL1_SEIS_MASK) >> + ICC_CTLR_EL1_SEIS_SHIFT; + if (host_seis != seis) + return -EINVAL; + + host_a3v = ((kvm_vgic_global_state.ich_vtr_el2 & + ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT); + a3v = (val & ICC_CTLR_EL1_A3V_MASK) >> ICC_CTLR_EL1_A3V_SHIFT; + if (host_a3v != a3v) + return -EINVAL; + + /* + * Here set VMCR.CTLR in ICC_CTLR_EL1 layout. + * The vgic_set_vmcr() will convert to ICH_VMCR layout. + */ + vmcr.cbpr = (val & ICC_CTLR_EL1_CBPR_MASK) >> ICC_CTLR_EL1_CBPR_SHIFT; + vmcr.eoim = (val & ICC_CTLR_EL1_EOImode_MASK) >> ICC_CTLR_EL1_EOImode_SHIFT; + vgic_set_vmcr(vcpu, &vmcr); + + return 0; +} + +static int get_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 *valp) +{ + struct vgic_cpu *vgic_v3_cpu = &vcpu->arch.vgic_cpu; + struct vgic_vmcr vmcr; u64 val; vgic_get_vmcr(vcpu, &vmcr); - if (p->is_write) { - val = p->regval; + val = 0; + val |= (vgic_v3_cpu->num_pri_bits - 1) << ICC_CTLR_EL1_PRI_BITS_SHIFT; + val |= vgic_v3_cpu->num_id_bits << ICC_CTLR_EL1_ID_BITS_SHIFT; + val |= ((kvm_vgic_global_state.ich_vtr_el2 & + ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT) << + ICC_CTLR_EL1_SEIS_SHIFT; + val |= ((kvm_vgic_global_state.ich_vtr_el2 & + ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT) << + ICC_CTLR_EL1_A3V_SHIFT; + /* + * The VMCR.CTLR value is in ICC_CTLR_EL1 layout. + * Extract it directly using ICC_CTLR_EL1 reg definitions. + */ + val |= (vmcr.cbpr << ICC_CTLR_EL1_CBPR_SHIFT) & ICC_CTLR_EL1_CBPR_MASK; + val |= (vmcr.eoim << ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK; - /* - * Disallow restoring VM state if not supported by this - * hardware. - */ - host_pri_bits = ((val & ICC_CTLR_EL1_PRI_BITS_MASK) >> - ICC_CTLR_EL1_PRI_BITS_SHIFT) + 1; - if (host_pri_bits > vgic_v3_cpu->num_pri_bits) - return false; + *valp = val; - vgic_v3_cpu->num_pri_bits = host_pri_bits; - - host_id_bits = (val & ICC_CTLR_EL1_ID_BITS_MASK) >> - ICC_CTLR_EL1_ID_BITS_SHIFT; - if (host_id_bits > vgic_v3_cpu->num_id_bits) - return false; - - vgic_v3_cpu->num_id_bits = host_id_bits; - - host_seis = ((kvm_vgic_global_state.ich_vtr_el2 & - ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT); - seis = (val & ICC_CTLR_EL1_SEIS_MASK) >> - ICC_CTLR_EL1_SEIS_SHIFT; - if (host_seis != seis) - return false; - - host_a3v = ((kvm_vgic_global_state.ich_vtr_el2 & - ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT); - a3v = (val & ICC_CTLR_EL1_A3V_MASK) >> ICC_CTLR_EL1_A3V_SHIFT; - if (host_a3v != a3v) - return false; - - /* - * Here set VMCR.CTLR in ICC_CTLR_EL1 layout. - * The vgic_set_vmcr() will convert to ICH_VMCR layout. - */ - vmcr.cbpr = (val & ICC_CTLR_EL1_CBPR_MASK) >> ICC_CTLR_EL1_CBPR_SHIFT; - vmcr.eoim = (val & ICC_CTLR_EL1_EOImode_MASK) >> ICC_CTLR_EL1_EOImode_SHIFT; - vgic_set_vmcr(vcpu, &vmcr); - } else { - val = 0; - val |= (vgic_v3_cpu->num_pri_bits - 1) << - ICC_CTLR_EL1_PRI_BITS_SHIFT; - val |= vgic_v3_cpu->num_id_bits << ICC_CTLR_EL1_ID_BITS_SHIFT; - val |= ((kvm_vgic_global_state.ich_vtr_el2 & - ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT) << - ICC_CTLR_EL1_SEIS_SHIFT; - val |= ((kvm_vgic_global_state.ich_vtr_el2 & - ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT) << - ICC_CTLR_EL1_A3V_SHIFT; - /* - * The VMCR.CTLR value is in ICC_CTLR_EL1 layout. - * Extract it directly using ICC_CTLR_EL1 reg definitions. - */ - val |= (vmcr.cbpr << ICC_CTLR_EL1_CBPR_SHIFT) & ICC_CTLR_EL1_CBPR_MASK; - val |= (vmcr.eoim << ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK; - - p->regval = val; - } - - return true; + return 0; } -static bool access_gic_pmr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, - const struct sys_reg_desc *r) +static int set_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 val) { struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - if (p->is_write) { - vmcr.pmr = (p->regval & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT; - vgic_set_vmcr(vcpu, &vmcr); - } else { - p->regval = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK; - } + vmcr.pmr = (val & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT; + vgic_set_vmcr(vcpu, &vmcr); - return true; + return 0; } -static bool access_gic_bpr0(struct kvm_vcpu *vcpu, struct sys_reg_params *p, - const struct sys_reg_desc *r) +static int get_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 *val) { struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - if (p->is_write) { - vmcr.bpr = (p->regval & ICC_BPR0_EL1_MASK) >> - ICC_BPR0_EL1_SHIFT; - vgic_set_vmcr(vcpu, &vmcr); - } else { - p->regval = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) & - ICC_BPR0_EL1_MASK; - } + *val = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK; - return true; + return 0; } -static bool access_gic_bpr1(struct kvm_vcpu *vcpu, struct sys_reg_params *p, - const struct sys_reg_desc *r) +static int set_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 val) { struct vgic_vmcr vmcr; - if (!p->is_write) - p->regval = 0; + vgic_get_vmcr(vcpu, &vmcr); + vmcr.bpr = (val & ICC_BPR0_EL1_MASK) >> ICC_BPR0_EL1_SHIFT; + vgic_set_vmcr(vcpu, &vmcr); + + return 0; +} + +static int get_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 *val) +{ + struct vgic_vmcr vmcr; + + vgic_get_vmcr(vcpu, &vmcr); + *val = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) & ICC_BPR0_EL1_MASK; + + return 0; +} + +static int set_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 val) +{ + struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); if (!vmcr.cbpr) { - if (p->is_write) { - vmcr.abpr = (p->regval & ICC_BPR1_EL1_MASK) >> - ICC_BPR1_EL1_SHIFT; - vgic_set_vmcr(vcpu, &vmcr); - } else { - p->regval = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) & - ICC_BPR1_EL1_MASK; - } - } else { - if (!p->is_write) - p->regval = min((vmcr.bpr + 1), 7U); + vmcr.abpr = (val & ICC_BPR1_EL1_MASK) >> ICC_BPR1_EL1_SHIFT; + vgic_set_vmcr(vcpu, &vmcr); } - return true; + return 0; } -static bool access_gic_grpen0(struct kvm_vcpu *vcpu, struct sys_reg_params *p, - const struct sys_reg_desc *r) +static int get_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 *val) { struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - if (p->is_write) { - vmcr.grpen0 = (p->regval & ICC_IGRPEN0_EL1_MASK) >> - ICC_IGRPEN0_EL1_SHIFT; - vgic_set_vmcr(vcpu, &vmcr); - } else { - p->regval = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) & - ICC_IGRPEN0_EL1_MASK; - } + if (!vmcr.cbpr) + *val = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) & ICC_BPR1_EL1_MASK; + else + *val = min((vmcr.bpr + 1), 7U); - return true; + + return 0; } -static bool access_gic_grpen1(struct kvm_vcpu *vcpu, struct sys_reg_params *p, - const struct sys_reg_desc *r) +static int set_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 val) { struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - if (p->is_write) { - vmcr.grpen1 = (p->regval & ICC_IGRPEN1_EL1_MASK) >> - ICC_IGRPEN1_EL1_SHIFT; - vgic_set_vmcr(vcpu, &vmcr); - } else { - p->regval = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) & - ICC_IGRPEN1_EL1_MASK; - } + vmcr.grpen0 = (val & ICC_IGRPEN0_EL1_MASK) >> ICC_IGRPEN0_EL1_SHIFT; + vgic_set_vmcr(vcpu, &vmcr); - return true; + return 0; } -static void vgic_v3_access_apr_reg(struct kvm_vcpu *vcpu, - struct sys_reg_params *p, u8 apr, u8 idx) +static int get_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 *val) +{ + struct vgic_vmcr vmcr; + + vgic_get_vmcr(vcpu, &vmcr); + *val = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) & ICC_IGRPEN0_EL1_MASK; + + return 0; +} + +static int set_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 val) +{ + struct vgic_vmcr vmcr; + + vgic_get_vmcr(vcpu, &vmcr); + vmcr.grpen1 = (val & ICC_IGRPEN1_EL1_MASK) >> ICC_IGRPEN1_EL1_SHIFT; + vgic_set_vmcr(vcpu, &vmcr); + + return 0; +} + +static int get_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 *val) +{ + struct vgic_vmcr vmcr; + + vgic_get_vmcr(vcpu, &vmcr); + *val = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) & ICC_IGRPEN1_EL1_MASK; + + return 0; +} + +static void set_apr_reg(struct kvm_vcpu *vcpu, u64 val, u8 apr, u8 idx) { struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; - uint32_t *ap_reg; if (apr) - ap_reg = &vgicv3->vgic_ap1r[idx]; + vgicv3->vgic_ap1r[idx] = val; else - ap_reg = &vgicv3->vgic_ap0r[idx]; - - if (p->is_write) - *ap_reg = p->regval; - else - p->regval = *ap_reg; + vgicv3->vgic_ap0r[idx] = val; } -static bool access_gic_aprn(struct kvm_vcpu *vcpu, struct sys_reg_params *p, - const struct sys_reg_desc *r, u8 apr) +static u64 get_apr_reg(struct kvm_vcpu *vcpu, u8 apr, u8 idx) +{ + struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; + + if (apr) + return vgicv3->vgic_ap1r[idx]; + else + return vgicv3->vgic_ap0r[idx]; +} + +static int set_gic_ap0r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 val) + { u8 idx = r->Op2 & 3; if (idx > vgic_v3_max_apr_idx(vcpu)) - goto err; + return -EINVAL; - vgic_v3_access_apr_reg(vcpu, p, apr, idx); - return true; -err: - if (!p->is_write) - p->regval = 0; - - return false; + set_apr_reg(vcpu, val, 0, idx); + return 0; } -static bool access_gic_ap0r(struct kvm_vcpu *vcpu, struct sys_reg_params *p, - const struct sys_reg_desc *r) +static int get_gic_ap0r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 *val) +{ + u8 idx = r->Op2 & 3; + + if (idx > vgic_v3_max_apr_idx(vcpu)) + return -EINVAL; + + *val = get_apr_reg(vcpu, 0, idx); + + return 0; +} + +static int set_gic_ap1r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 val) { - return access_gic_aprn(vcpu, p, r, 0); + u8 idx = r->Op2 & 3; + + if (idx > vgic_v3_max_apr_idx(vcpu)) + return -EINVAL; + + set_apr_reg(vcpu, val, 1, idx); + return 0; } -static bool access_gic_ap1r(struct kvm_vcpu *vcpu, struct sys_reg_params *p, - const struct sys_reg_desc *r) +static int get_gic_ap1r(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 *val) { - return access_gic_aprn(vcpu, p, r, 1); + u8 idx = r->Op2 & 3; + + if (idx > vgic_v3_max_apr_idx(vcpu)) + return -EINVAL; + + *val = get_apr_reg(vcpu, 1, idx); + + return 0; } -static bool access_gic_sre(struct kvm_vcpu *vcpu, struct sys_reg_params *p, - const struct sys_reg_desc *r) +static int set_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 val) +{ + /* Validate SRE bit */ + if (!(val & ICC_SRE_EL1_SRE)) + return -EINVAL; + + return 0; +} + +static int get_gic_sre(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, + u64 *val) { struct vgic_v3_cpu_if *vgicv3 = &vcpu->arch.vgic_cpu.vgic_v3; - /* Validate SRE bit */ - if (p->is_write) { - if (!(p->regval & ICC_SRE_EL1_SRE)) - return false; - } else { - p->regval = vgicv3->vgic_sre; - } + *val = vgicv3->vgic_sre; - return true; + return 0; } + static const struct sys_reg_desc gic_v3_icc_reg_descs[] = { - { SYS_DESC(SYS_ICC_PMR_EL1), access_gic_pmr }, - { SYS_DESC(SYS_ICC_BPR0_EL1), access_gic_bpr0 }, - { SYS_DESC(SYS_ICC_AP0R0_EL1), access_gic_ap0r }, - { SYS_DESC(SYS_ICC_AP0R1_EL1), access_gic_ap0r }, - { SYS_DESC(SYS_ICC_AP0R2_EL1), access_gic_ap0r }, - { SYS_DESC(SYS_ICC_AP0R3_EL1), access_gic_ap0r }, - { SYS_DESC(SYS_ICC_AP1R0_EL1), access_gic_ap1r }, - { SYS_DESC(SYS_ICC_AP1R1_EL1), access_gic_ap1r }, - { SYS_DESC(SYS_ICC_AP1R2_EL1), access_gic_ap1r }, - { SYS_DESC(SYS_ICC_AP1R3_EL1), access_gic_ap1r }, - { SYS_DESC(SYS_ICC_BPR1_EL1), access_gic_bpr1 }, - { SYS_DESC(SYS_ICC_CTLR_EL1), access_gic_ctlr }, - { SYS_DESC(SYS_ICC_SRE_EL1), access_gic_sre }, - { SYS_DESC(SYS_ICC_IGRPEN0_EL1), access_gic_grpen0 }, - { SYS_DESC(SYS_ICC_IGRPEN1_EL1), access_gic_grpen1 }, + { SYS_DESC(SYS_ICC_PMR_EL1), + .set_user = set_gic_pmr, .get_user = get_gic_pmr, }, + { SYS_DESC(SYS_ICC_BPR0_EL1), + .set_user = set_gic_bpr0, .get_user = get_gic_bpr0, }, + { SYS_DESC(SYS_ICC_AP0R0_EL1), + .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, }, + { SYS_DESC(SYS_ICC_AP0R1_EL1), + .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, }, + { SYS_DESC(SYS_ICC_AP0R2_EL1), + .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, }, + { SYS_DESC(SYS_ICC_AP0R3_EL1), + .set_user = set_gic_ap0r, .get_user = get_gic_ap0r, }, + { SYS_DESC(SYS_ICC_AP1R0_EL1), + .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, }, + { SYS_DESC(SYS_ICC_AP1R1_EL1), + .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, }, + { SYS_DESC(SYS_ICC_AP1R2_EL1), + .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, }, + { SYS_DESC(SYS_ICC_AP1R3_EL1), + .set_user = set_gic_ap1r, .get_user = get_gic_ap1r, }, + { SYS_DESC(SYS_ICC_BPR1_EL1), + .set_user = set_gic_bpr1, .get_user = get_gic_bpr1, }, + { SYS_DESC(SYS_ICC_CTLR_EL1), + .set_user = set_gic_ctlr, .get_user = get_gic_ctlr, }, + { SYS_DESC(SYS_ICC_SRE_EL1), + .set_user = set_gic_sre, .get_user = get_gic_sre, }, + { SYS_DESC(SYS_ICC_IGRPEN0_EL1), + .set_user = set_gic_grpen0, .get_user = get_gic_grpen0, }, + { SYS_DESC(SYS_ICC_IGRPEN1_EL1), + .set_user = set_gic_grpen1, .get_user = get_gic_grpen1, }, }; static u64 attr_to_id(u64 attr) @@ -282,31 +358,15 @@ int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr, bool is_write) { - u64 __user *uaddr = (u64 __user *)(long)attr->addr; - struct sys_reg_params params; - const struct sys_reg_desc *r; - u64 sysreg; + struct kvm_one_reg reg = { + .id = attr_to_id(attr->attr), + .addr = attr->addr, + }; - sysreg = attr_to_id(attr->attr); - - if (is_write) { - if (get_user(params.regval, uaddr)) - return -EFAULT; - } - params.is_write = is_write; - - r = find_reg_by_id(sysreg, ¶ms, gic_v3_icc_reg_descs, - ARRAY_SIZE(gic_v3_icc_reg_descs)); - if (!r) - return -ENXIO; - - if (!r->access(vcpu, ¶ms, r)) - return -EINVAL; - - if (!is_write) { - if (put_user(params.regval, uaddr)) - return -EFAULT; - } - - return 0; + if (is_write) + return kvm_sys_reg_set_user(vcpu, ®, gic_v3_icc_reg_descs, + ARRAY_SIZE(gic_v3_icc_reg_descs)); + else + return kvm_sys_reg_get_user(vcpu, ®, gic_v3_icc_reg_descs, + ARRAY_SIZE(gic_v3_icc_reg_descs)); } From 71c3c7753c722b8b10566dcdf1ff0a2eaf33a9c1 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 5 Jul 2022 08:11:54 +0100 Subject: [PATCH 1101/1436] KVM: arm64: vgic-v3: Convert userspace accessors over to FIELD_GET/FIELD_PREP The GICv3 userspace accessors are all about dealing with conversion between fields from architectural registers and internal representations. However, and owing to the age of this code, the accessors use a combination of shift/mask that is hard to read. It is nonetheless easy to make it better by using the FIELD_{GET,PREP} macros that solely rely on a mask. This results in somewhat nicer looking code, and is probably easier to maintain. Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic-sys-reg-v3.c | 60 ++++++++++++++------------------ 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/arch/arm64/kvm/vgic-sys-reg-v3.c b/arch/arm64/kvm/vgic-sys-reg-v3.c index b755b02bc8ba..9e7c486b48c2 100644 --- a/arch/arm64/kvm/vgic-sys-reg-v3.c +++ b/arch/arm64/kvm/vgic-sys-reg-v3.c @@ -23,30 +23,25 @@ static int set_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, * Disallow restoring VM state if not supported by this * hardware. */ - host_pri_bits = ((val & ICC_CTLR_EL1_PRI_BITS_MASK) >> - ICC_CTLR_EL1_PRI_BITS_SHIFT) + 1; + host_pri_bits = FIELD_GET(ICC_CTLR_EL1_PRI_BITS_MASK, val) + 1; if (host_pri_bits > vgic_v3_cpu->num_pri_bits) return -EINVAL; vgic_v3_cpu->num_pri_bits = host_pri_bits; - host_id_bits = (val & ICC_CTLR_EL1_ID_BITS_MASK) >> - ICC_CTLR_EL1_ID_BITS_SHIFT; + host_id_bits = FIELD_GET(ICC_CTLR_EL1_ID_BITS_MASK, val); if (host_id_bits > vgic_v3_cpu->num_id_bits) return -EINVAL; vgic_v3_cpu->num_id_bits = host_id_bits; - host_seis = ((kvm_vgic_global_state.ich_vtr_el2 & - ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT); - seis = (val & ICC_CTLR_EL1_SEIS_MASK) >> - ICC_CTLR_EL1_SEIS_SHIFT; + host_seis = FIELD_GET(ICH_VTR_SEIS_MASK, kvm_vgic_global_state.ich_vtr_el2); + seis = FIELD_GET(ICC_CTLR_EL1_SEIS_MASK, val); if (host_seis != seis) return -EINVAL; - host_a3v = ((kvm_vgic_global_state.ich_vtr_el2 & - ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT); - a3v = (val & ICC_CTLR_EL1_A3V_MASK) >> ICC_CTLR_EL1_A3V_SHIFT; + host_a3v = FIELD_GET(ICH_VTR_A3V_MASK, kvm_vgic_global_state.ich_vtr_el2); + a3v = FIELD_GET(ICC_CTLR_EL1_A3V_MASK, val); if (host_a3v != a3v) return -EINVAL; @@ -54,8 +49,8 @@ static int set_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, * Here set VMCR.CTLR in ICC_CTLR_EL1 layout. * The vgic_set_vmcr() will convert to ICH_VMCR layout. */ - vmcr.cbpr = (val & ICC_CTLR_EL1_CBPR_MASK) >> ICC_CTLR_EL1_CBPR_SHIFT; - vmcr.eoim = (val & ICC_CTLR_EL1_EOImode_MASK) >> ICC_CTLR_EL1_EOImode_SHIFT; + vmcr.cbpr = FIELD_GET(ICC_CTLR_EL1_CBPR_MASK, val); + vmcr.eoim = FIELD_GET(ICC_CTLR_EL1_EOImode_MASK, val); vgic_set_vmcr(vcpu, &vmcr); return 0; @@ -70,20 +65,19 @@ static int get_gic_ctlr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, vgic_get_vmcr(vcpu, &vmcr); val = 0; - val |= (vgic_v3_cpu->num_pri_bits - 1) << ICC_CTLR_EL1_PRI_BITS_SHIFT; - val |= vgic_v3_cpu->num_id_bits << ICC_CTLR_EL1_ID_BITS_SHIFT; - val |= ((kvm_vgic_global_state.ich_vtr_el2 & - ICH_VTR_SEIS_MASK) >> ICH_VTR_SEIS_SHIFT) << - ICC_CTLR_EL1_SEIS_SHIFT; - val |= ((kvm_vgic_global_state.ich_vtr_el2 & - ICH_VTR_A3V_MASK) >> ICH_VTR_A3V_SHIFT) << - ICC_CTLR_EL1_A3V_SHIFT; + val |= FIELD_PREP(ICC_CTLR_EL1_PRI_BITS_MASK, vgic_v3_cpu->num_pri_bits - 1); + val |= FIELD_PREP(ICC_CTLR_EL1_ID_BITS_MASK, vgic_v3_cpu->num_id_bits); + val |= FIELD_PREP(ICC_CTLR_EL1_SEIS_MASK, + FIELD_GET(ICH_VTR_SEIS_MASK, + kvm_vgic_global_state.ich_vtr_el2)); + val |= FIELD_PREP(ICC_CTLR_EL1_A3V_MASK, + FIELD_GET(ICH_VTR_A3V_MASK, kvm_vgic_global_state.ich_vtr_el2)); /* * The VMCR.CTLR value is in ICC_CTLR_EL1 layout. * Extract it directly using ICC_CTLR_EL1 reg definitions. */ - val |= (vmcr.cbpr << ICC_CTLR_EL1_CBPR_SHIFT) & ICC_CTLR_EL1_CBPR_MASK; - val |= (vmcr.eoim << ICC_CTLR_EL1_EOImode_SHIFT) & ICC_CTLR_EL1_EOImode_MASK; + val |= FIELD_PREP(ICC_CTLR_EL1_CBPR_MASK, vmcr.cbpr); + val |= FIELD_PREP(ICC_CTLR_EL1_EOImode_MASK, vmcr.eoim); *valp = val; @@ -96,7 +90,7 @@ static int set_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - vmcr.pmr = (val & ICC_PMR_EL1_MASK) >> ICC_PMR_EL1_SHIFT; + vmcr.pmr = FIELD_GET(ICC_PMR_EL1_MASK, val); vgic_set_vmcr(vcpu, &vmcr); return 0; @@ -108,7 +102,7 @@ static int get_gic_pmr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - *val = (vmcr.pmr << ICC_PMR_EL1_SHIFT) & ICC_PMR_EL1_MASK; + *val = FIELD_PREP(ICC_PMR_EL1_MASK, vmcr.pmr); return 0; } @@ -119,7 +113,7 @@ static int set_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - vmcr.bpr = (val & ICC_BPR0_EL1_MASK) >> ICC_BPR0_EL1_SHIFT; + vmcr.bpr = FIELD_GET(ICC_BPR0_EL1_MASK, val); vgic_set_vmcr(vcpu, &vmcr); return 0; @@ -131,7 +125,7 @@ static int get_gic_bpr0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - *val = (vmcr.bpr << ICC_BPR0_EL1_SHIFT) & ICC_BPR0_EL1_MASK; + *val = FIELD_PREP(ICC_BPR0_EL1_MASK, vmcr.bpr); return 0; } @@ -143,7 +137,7 @@ static int set_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, vgic_get_vmcr(vcpu, &vmcr); if (!vmcr.cbpr) { - vmcr.abpr = (val & ICC_BPR1_EL1_MASK) >> ICC_BPR1_EL1_SHIFT; + vmcr.abpr = FIELD_GET(ICC_BPR1_EL1_MASK, val); vgic_set_vmcr(vcpu, &vmcr); } @@ -157,7 +151,7 @@ static int get_gic_bpr1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, vgic_get_vmcr(vcpu, &vmcr); if (!vmcr.cbpr) - *val = (vmcr.abpr << ICC_BPR1_EL1_SHIFT) & ICC_BPR1_EL1_MASK; + *val = FIELD_PREP(ICC_BPR1_EL1_MASK, vmcr.abpr); else *val = min((vmcr.bpr + 1), 7U); @@ -171,7 +165,7 @@ static int set_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - vmcr.grpen0 = (val & ICC_IGRPEN0_EL1_MASK) >> ICC_IGRPEN0_EL1_SHIFT; + vmcr.grpen0 = FIELD_GET(ICC_IGRPEN0_EL1_MASK, val); vgic_set_vmcr(vcpu, &vmcr); return 0; @@ -183,7 +177,7 @@ static int get_gic_grpen0(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - *val = (vmcr.grpen0 << ICC_IGRPEN0_EL1_SHIFT) & ICC_IGRPEN0_EL1_MASK; + *val = FIELD_PREP(ICC_IGRPEN0_EL1_MASK, vmcr.grpen0); return 0; } @@ -194,7 +188,7 @@ static int set_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - vmcr.grpen1 = (val & ICC_IGRPEN1_EL1_MASK) >> ICC_IGRPEN1_EL1_SHIFT; + vmcr.grpen1 = FIELD_GET(ICC_IGRPEN1_EL1_MASK, val); vgic_set_vmcr(vcpu, &vmcr); return 0; @@ -206,7 +200,7 @@ static int get_gic_grpen1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, struct vgic_vmcr vmcr; vgic_get_vmcr(vcpu, &vmcr); - *val = (vmcr.grpen1 << ICC_IGRPEN1_EL1_SHIFT) & ICC_IGRPEN1_EL1_MASK; + *val = FIELD_GET(ICC_IGRPEN1_EL1_MASK, vmcr.grpen1); return 0; } From 38cf0bb7625a58625efeef9ec944671464ff7430 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 5 Jul 2022 10:16:44 +0100 Subject: [PATCH 1102/1436] KVM: arm64: vgic-v3: Use u32 to manage the line level from userspace Despite the userspace ABI clearly defining the bits dealt with by KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO as a __u32, the kernel uses a u64. Use a u32 to match the userspace ABI, which will subsequently lead to some simplifications. Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic/vgic-kvm-device.c | 6 +++++- arch/arm64/kvm/vgic/vgic-mmio-v3.c | 2 +- arch/arm64/kvm/vgic/vgic-mmio.c | 6 +++--- arch/arm64/kvm/vgic/vgic-mmio.h | 4 ++-- arch/arm64/kvm/vgic/vgic.h | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c index bf745c6ab2ea..f02294b9aef1 100644 --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c @@ -570,10 +570,14 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev, info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >> KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT; if (info == VGIC_LEVEL_INFO_LINE_LEVEL) { + if (is_write) + tmp32 = *reg; intid = attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK; ret = vgic_v3_line_level_info_uaccess(vcpu, is_write, - intid, reg); + intid, &tmp32); + if (!is_write) + *reg = tmp32; } else { ret = -EINVAL; } diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c index a2ff73899976..91201f743033 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c +++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c @@ -1154,7 +1154,7 @@ int vgic_v3_redist_uaccess(struct kvm_vcpu *vcpu, bool is_write, } int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write, - u32 intid, u64 *val) + u32 intid, u32 *val) { if (intid % 32) return -EINVAL; diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c index 997d0fce2088..b32d434c1d4a 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio.c +++ b/arch/arm64/kvm/vgic/vgic-mmio.c @@ -775,10 +775,10 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu, } } -u64 vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid) +u32 vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid) { int i; - u64 val = 0; + u32 val = 0; int nr_irqs = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS; for (i = 0; i < 32; i++) { @@ -798,7 +798,7 @@ u64 vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid) } void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid, - const u64 val) + const u32 val) { int i; int nr_irqs = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS; diff --git a/arch/arm64/kvm/vgic/vgic-mmio.h b/arch/arm64/kvm/vgic/vgic-mmio.h index 6082d4b66d39..5b490a4dfa5e 100644 --- a/arch/arm64/kvm/vgic/vgic-mmio.h +++ b/arch/arm64/kvm/vgic/vgic-mmio.h @@ -207,10 +207,10 @@ void vgic_mmio_write_config(struct kvm_vcpu *vcpu, int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev, bool is_write, int offset, u32 *val); -u64 vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid); +u32 vgic_read_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid); void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid, - const u64 val); + const u32 val); unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev); diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index c23118467a35..0c8da72953f0 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -249,7 +249,7 @@ int vgic_v3_cpu_sysregs_uaccess(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr, bool is_write); int vgic_v3_has_cpu_sysregs_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); int vgic_v3_line_level_info_uaccess(struct kvm_vcpu *vcpu, bool is_write, - u32 intid, u64 *val); + u32 intid, u32 *val); int kvm_register_vgic_device(unsigned long type); void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr); void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr); From e1246f3f2df7aec025fd587ac3d7912007d1144d Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 5 Jul 2022 10:26:07 +0100 Subject: [PATCH 1103/1436] KVM: arm64: vgic-v3: Consolidate userspace access for MMIO registers For userspace accesses to GICv3 MMIO registers (and related data), vgic_v3_{get,set}_attr are littered with {get,put}_user() calls, making it hard to audit and reason about. Consolidate all userspace accesses in vgic_v3_attr_regs_access(), making the code far simpler to audit. Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic/vgic-kvm-device.c | 103 +++++++++----------------- 1 file changed, 37 insertions(+), 66 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c index f02294b9aef1..e9db6795fb90 100644 --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c @@ -512,18 +512,18 @@ int vgic_v3_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr, * * @dev: kvm device handle * @attr: kvm device attribute - * @reg: address the value is read or written, NULL for sysregs * @is_write: true if userspace is writing a register */ static int vgic_v3_attr_regs_access(struct kvm_device *dev, struct kvm_device_attr *attr, - u64 *reg, bool is_write) + bool is_write) { struct vgic_reg_attr reg_attr; gpa_t addr; struct kvm_vcpu *vcpu; + bool uaccess; + u32 val; int ret; - u32 tmp32; ret = vgic_v3_parse_attr(dev, attr, ®_attr); if (ret) @@ -532,6 +532,21 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev, vcpu = reg_attr.vcpu; addr = reg_attr.addr; + switch (attr->group) { + case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: + /* Sysregs uaccess is performed by the sysreg handling code */ + uaccess = false; + break; + default: + uaccess = true; + } + + if (uaccess && is_write) { + u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr; + if (get_user(val, uaddr)) + return -EFAULT; + } + mutex_lock(&dev->kvm->lock); if (unlikely(!vgic_initialized(dev->kvm))) { @@ -546,20 +561,10 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev, switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: - if (is_write) - tmp32 = *reg; - - ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &tmp32); - if (!is_write) - *reg = tmp32; + ret = vgic_v3_dist_uaccess(vcpu, is_write, addr, &val); break; case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: - if (is_write) - tmp32 = *reg; - - ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &tmp32); - if (!is_write) - *reg = tmp32; + ret = vgic_v3_redist_uaccess(vcpu, is_write, addr, &val); break; case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: ret = vgic_v3_cpu_sysregs_uaccess(vcpu, attr, is_write); @@ -570,14 +575,10 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev, info = (attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_MASK) >> KVM_DEV_ARM_VGIC_LINE_LEVEL_INFO_SHIFT; if (info == VGIC_LEVEL_INFO_LINE_LEVEL) { - if (is_write) - tmp32 = *reg; intid = attr->attr & KVM_DEV_ARM_VGIC_LINE_LEVEL_INTID_MASK; ret = vgic_v3_line_level_info_uaccess(vcpu, is_write, - intid, &tmp32); - if (!is_write) - *reg = tmp32; + intid, &val); } else { ret = -EINVAL; } @@ -591,6 +592,12 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev, unlock_all_vcpus(dev->kvm); out: mutex_unlock(&dev->kvm->lock); + + if (!ret && uaccess && !is_write) { + u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr; + ret = put_user(val, uaddr); + } + return ret; } @@ -605,30 +612,12 @@ static int vgic_v3_set_attr(struct kvm_device *dev, switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: - case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: { - u32 __user *uaddr = (u32 __user *)(long)attr->addr; - u32 tmp32; - u64 reg; - - if (get_user(tmp32, uaddr)) - return -EFAULT; - - reg = tmp32; - return vgic_v3_attr_regs_access(dev, attr, ®, true); - } + case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: + return vgic_v3_attr_regs_access(dev, attr, true); case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: - return vgic_v3_attr_regs_access(dev, attr, NULL, true); - case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { - u32 __user *uaddr = (u32 __user *)(long)attr->addr; - u64 reg; - u32 tmp32; - - if (get_user(tmp32, uaddr)) - return -EFAULT; - - reg = tmp32; - return vgic_v3_attr_regs_access(dev, attr, ®, true); - } + return vgic_v3_attr_regs_access(dev, attr, true); + case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: + return vgic_v3_attr_regs_access(dev, attr, true); case KVM_DEV_ARM_VGIC_GRP_CTRL: { int ret; @@ -662,30 +651,12 @@ static int vgic_v3_get_attr(struct kvm_device *dev, switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: - case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: { - u32 __user *uaddr = (u32 __user *)(long)attr->addr; - u64 reg; - u32 tmp32; - - ret = vgic_v3_attr_regs_access(dev, attr, ®, false); - if (ret) - return ret; - tmp32 = reg; - return put_user(tmp32, uaddr); - } + case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: + return vgic_v3_attr_regs_access(dev, attr, false); case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: - return vgic_v3_attr_regs_access(dev, attr, NULL, false); - case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: { - u32 __user *uaddr = (u32 __user *)(long)attr->addr; - u64 reg; - u32 tmp32; - - ret = vgic_v3_attr_regs_access(dev, attr, ®, false); - if (ret) - return ret; - tmp32 = reg; - return put_user(tmp32, uaddr); - } + return vgic_v3_attr_regs_access(dev, attr, false); + case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: + return vgic_v3_attr_regs_access(dev, attr, false); } return -ENXIO; } From 7e9f723c2a90e41407d5889700169be4797a2009 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 5 Jul 2022 10:26:07 +0100 Subject: [PATCH 1104/1436] KVM: arm64: vgic-v2: Consolidate userspace access for MMIO registers Align the GICv2 MMIO accesses from userspace with the way the GICv3 code is now structured. Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic/vgic-kvm-device.c | 39 ++++++++++++--------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c index e9db6795fb90..066b95d606fd 100644 --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c @@ -348,17 +348,18 @@ bool lock_all_vcpus(struct kvm *kvm) * * @dev: kvm device handle * @attr: kvm device attribute - * @reg: address the value is read or written * @is_write: true if userspace is writing a register */ static int vgic_v2_attr_regs_access(struct kvm_device *dev, struct kvm_device_attr *attr, - u32 *reg, bool is_write) + bool is_write) { + u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr; struct vgic_reg_attr reg_attr; gpa_t addr; struct kvm_vcpu *vcpu; int ret; + u32 val; ret = vgic_v2_parse_attr(dev, attr, ®_attr); if (ret) @@ -367,6 +368,10 @@ static int vgic_v2_attr_regs_access(struct kvm_device *dev, vcpu = reg_attr.vcpu; addr = reg_attr.addr; + if (is_write) + if (get_user(val, uaddr)) + return -EFAULT; + mutex_lock(&dev->kvm->lock); ret = vgic_init(dev->kvm); @@ -380,10 +385,10 @@ static int vgic_v2_attr_regs_access(struct kvm_device *dev, switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: - ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg); + ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, &val); break; case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: - ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, reg); + ret = vgic_v2_dist_uaccess(vcpu, is_write, addr, &val); break; default: ret = -EINVAL; @@ -393,6 +398,10 @@ static int vgic_v2_attr_regs_access(struct kvm_device *dev, unlock_all_vcpus(dev->kvm); out: mutex_unlock(&dev->kvm->lock); + + if (!ret && !is_write) + ret = put_user(val, uaddr); + return ret; } @@ -407,15 +416,8 @@ static int vgic_v2_set_attr(struct kvm_device *dev, switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: - case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { - u32 __user *uaddr = (u32 __user *)(long)attr->addr; - u32 reg; - - if (get_user(reg, uaddr)) - return -EFAULT; - - return vgic_v2_attr_regs_access(dev, attr, ®, true); - } + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: + return vgic_v2_attr_regs_access(dev, attr, true); } return -ENXIO; @@ -432,15 +434,8 @@ static int vgic_v2_get_attr(struct kvm_device *dev, switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: - case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { - u32 __user *uaddr = (u32 __user *)(long)attr->addr; - u32 reg = 0; - - ret = vgic_v2_attr_regs_access(dev, attr, ®, false); - if (ret) - return ret; - return put_user(reg, uaddr); - } + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: + return vgic_v2_attr_regs_access(dev, attr, false); } return -ENXIO; From d7df6f282db67677c06456fd29d47eda0ba060b9 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 5 Jul 2022 11:27:37 +0100 Subject: [PATCH 1105/1436] KVM: arm64: vgic: Use {get,put}_user() instead of copy_{from.to}_user Tidy-up vgic_get_common_attr() and vgic_set_common_attr() to use {get,put}_user() instead of the more complex (and less type-safe) copy_{from,to}_user(). Reviewed-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic/vgic-kvm-device.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c index 066b95d606fd..c17e5502c0b3 100644 --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c @@ -170,7 +170,7 @@ static int vgic_set_common_attr(struct kvm_device *dev, u64 addr; unsigned long type = (unsigned long)attr->attr; - if (copy_from_user(&addr, uaddr, sizeof(addr))) + if (get_user(addr, uaddr)) return -EFAULT; r = kvm_vgic_addr(dev->kvm, type, &addr, true); @@ -233,14 +233,14 @@ static int vgic_get_common_attr(struct kvm_device *dev, u64 addr; unsigned long type = (unsigned long)attr->attr; - if (copy_from_user(&addr, uaddr, sizeof(addr))) + if (get_user(addr, uaddr)) return -EFAULT; r = kvm_vgic_addr(dev->kvm, type, &addr, false); if (r) return (r == -ENODEV) ? -ENXIO : r; - if (copy_to_user(uaddr, &addr, sizeof(addr))) + if (put_user(addr, uaddr)) return -EFAULT; break; } From 9f968c9266aa30b0e81be0c6a560e45b93bed3dc Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 5 Jul 2022 14:34:33 +0100 Subject: [PATCH 1106/1436] KVM: arm64: vgic-v2: Add helper for legacy dist/cpuif base address setting We carry a legacy interface to set the base addresses for GICv2. As this is currently plumbed into the same handling code as the modern interface, it limits the evolution we can make there. Add a helper dedicated to this handling, with a view of maybe removing this in the future. Signed-off-by: Marc Zyngier --- arch/arm64/kvm/arm.c | 11 ++------- arch/arm64/kvm/vgic/vgic-kvm-device.c | 32 +++++++++++++++++++++++++++ include/kvm/arm_vgic.h | 1 + 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index a0188144a122..fd26beacbbe5 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1414,18 +1414,11 @@ void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm, static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev_addr) { - unsigned long dev_id, type; - - dev_id = (dev_addr->id & KVM_ARM_DEVICE_ID_MASK) >> - KVM_ARM_DEVICE_ID_SHIFT; - type = (dev_addr->id & KVM_ARM_DEVICE_TYPE_MASK) >> - KVM_ARM_DEVICE_TYPE_SHIFT; - - switch (dev_id) { + switch (FIELD_GET(KVM_ARM_DEVICE_ID_MASK, dev_addr->id)) { case KVM_ARM_DEVICE_VGIC_V2: if (!vgic_present) return -ENXIO; - return kvm_vgic_addr(kvm, type, &dev_addr->addr, true); + return kvm_set_legacy_vgic_v2_addr(kvm, dev_addr); default: return -ENODEV; } diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c index c17e5502c0b3..04175fd55da6 100644 --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c @@ -41,6 +41,38 @@ static int vgic_check_type(struct kvm *kvm, int type_needed) return 0; } +int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev_addr) +{ + struct vgic_dist *vgic = &kvm->arch.vgic; + int r; + + mutex_lock(&kvm->lock); + switch (FIELD_GET(KVM_ARM_DEVICE_TYPE_MASK, dev_addr->id)) { + case KVM_VGIC_V2_ADDR_TYPE_DIST: + r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); + if (!r) + r = vgic_check_iorange(kvm, vgic->vgic_dist_base, dev_addr->addr, + SZ_4K, KVM_VGIC_V2_DIST_SIZE); + if (!r) + vgic->vgic_dist_base = dev_addr->addr; + break; + case KVM_VGIC_V2_ADDR_TYPE_CPU: + r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); + if (!r) + r = vgic_check_iorange(kvm, vgic->vgic_cpu_base, dev_addr->addr, + SZ_4K, KVM_VGIC_V2_CPU_SIZE); + if (!r) + vgic->vgic_cpu_base = dev_addr->addr; + break; + default: + r = -ENODEV; + } + + mutex_unlock(&kvm->lock); + + return r; +} + /** * kvm_vgic_addr - set or get vgic VM base addresses * @kvm: pointer to the vm struct diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 2d8f2e90edc2..f79cce67563e 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -365,6 +365,7 @@ extern struct static_key_false vgic_v2_cpuif_trap; extern struct static_key_false vgic_v3_cpuif_trap; int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write); +int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev_addr); void kvm_vgic_early_init(struct kvm *kvm); int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu); int kvm_vgic_create(struct kvm *kvm, u32 type); From 4b85080f4e378f617f88964dec94fd282bcf2af4 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 5 Jul 2022 14:39:24 +0100 Subject: [PATCH 1107/1436] KVM: arm64: vgic: Consolidate userspace access for base address setting Align kvm_vgic_addr() with the rest of the code by moving the userspace accesses into it. kvm_vgic_addr() is also made static. Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic/vgic-kvm-device.c | 75 +++++++++++---------------- include/kvm/arm_vgic.h | 1 - 2 files changed, 31 insertions(+), 45 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c index 04175fd55da6..011171dc41c5 100644 --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c @@ -76,8 +76,7 @@ int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev /** * kvm_vgic_addr - set or get vgic VM base addresses * @kvm: pointer to the vm struct - * @type: the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX - * @addr: pointer to address value + * @attr: pointer to the attribute being retrieved/updated * @write: if true set the address in the VM address space, if false read the * address * @@ -89,15 +88,22 @@ int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev * overlapping regions in case of a virtual GICv3 here, since we don't know * the number of VCPUs yet, so we defer this check to map_resources(). */ -int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) +static int kvm_vgic_addr(struct kvm *kvm, struct kvm_device_attr *attr, bool write) { - int r = 0; + u64 __user *uaddr = (u64 __user *)attr->addr; struct vgic_dist *vgic = &kvm->arch.vgic; phys_addr_t *addr_ptr, alignment, size; u64 undef_value = VGIC_ADDR_UNDEF; + u64 addr; + int r; + + /* Reading a redistributor region addr implies getting the index */ + if (write || attr->attr == KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION) + if (get_user(addr, uaddr)) + return -EFAULT; mutex_lock(&kvm->lock); - switch (type) { + switch (attr->attr) { case KVM_VGIC_V2_ADDR_TYPE_DIST: r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); addr_ptr = &vgic->vgic_dist_base; @@ -123,7 +129,7 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) if (r) break; if (write) { - r = vgic_v3_set_redist_base(kvm, 0, *addr, 0); + r = vgic_v3_set_redist_base(kvm, 0, addr, 0); goto out; } rdreg = list_first_entry_or_null(&vgic->rd_regions, @@ -143,14 +149,12 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) if (r) break; - index = *addr & KVM_VGIC_V3_RDIST_INDEX_MASK; + index = addr & KVM_VGIC_V3_RDIST_INDEX_MASK; if (write) { - gpa_t base = *addr & KVM_VGIC_V3_RDIST_BASE_MASK; - u32 count = (*addr & KVM_VGIC_V3_RDIST_COUNT_MASK) - >> KVM_VGIC_V3_RDIST_COUNT_SHIFT; - u8 flags = (*addr & KVM_VGIC_V3_RDIST_FLAGS_MASK) - >> KVM_VGIC_V3_RDIST_FLAGS_SHIFT; + gpa_t base = addr & KVM_VGIC_V3_RDIST_BASE_MASK; + u32 count = FIELD_GET(KVM_VGIC_V3_RDIST_COUNT_MASK, addr); + u8 flags = FIELD_GET(KVM_VGIC_V3_RDIST_FLAGS_MASK, addr); if (!count || flags) r = -EINVAL; @@ -166,9 +170,9 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) goto out; } - *addr = index; - *addr |= rdreg->base; - *addr |= (u64)rdreg->count << KVM_VGIC_V3_RDIST_COUNT_SHIFT; + addr = index; + addr |= rdreg->base; + addr |= (u64)rdreg->count << KVM_VGIC_V3_RDIST_COUNT_SHIFT; goto out; } default: @@ -179,15 +183,19 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) goto out; if (write) { - r = vgic_check_iorange(kvm, *addr_ptr, *addr, alignment, size); + r = vgic_check_iorange(kvm, *addr_ptr, addr, alignment, size); if (!r) - *addr_ptr = *addr; + *addr_ptr = addr; } else { - *addr = *addr_ptr; + addr = *addr_ptr; } out: mutex_unlock(&kvm->lock); + + if (!r && !write) + r = put_user(addr, uaddr); + return r; } @@ -197,17 +205,9 @@ static int vgic_set_common_attr(struct kvm_device *dev, int r; switch (attr->group) { - case KVM_DEV_ARM_VGIC_GRP_ADDR: { - u64 __user *uaddr = (u64 __user *)(long)attr->addr; - u64 addr; - unsigned long type = (unsigned long)attr->attr; - - if (get_user(addr, uaddr)) - return -EFAULT; - - r = kvm_vgic_addr(dev->kvm, type, &addr, true); + case KVM_DEV_ARM_VGIC_GRP_ADDR: + r = kvm_vgic_addr(dev->kvm, attr, true); return (r == -ENODEV) ? -ENXIO : r; - } case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: { u32 __user *uaddr = (u32 __user *)(long)attr->addr; u32 val; @@ -260,22 +260,9 @@ static int vgic_get_common_attr(struct kvm_device *dev, int r = -ENXIO; switch (attr->group) { - case KVM_DEV_ARM_VGIC_GRP_ADDR: { - u64 __user *uaddr = (u64 __user *)(long)attr->addr; - u64 addr; - unsigned long type = (unsigned long)attr->attr; - - if (get_user(addr, uaddr)) - return -EFAULT; - - r = kvm_vgic_addr(dev->kvm, type, &addr, false); - if (r) - return (r == -ENODEV) ? -ENXIO : r; - - if (put_user(addr, uaddr)) - return -EFAULT; - break; - } + case KVM_DEV_ARM_VGIC_GRP_ADDR: + r = kvm_vgic_addr(dev->kvm, attr, false); + return (r == -ENODEV) ? -ENXIO : r; case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: { u32 __user *uaddr = (u32 __user *)(long)attr->addr; diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index f79cce67563e..4df9e73a8bb5 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -364,7 +364,6 @@ struct vgic_cpu { extern struct static_key_false vgic_v2_cpuif_trap; extern struct static_key_false vgic_v3_cpuif_trap; -int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write); int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev_addr); void kvm_vgic_early_init(struct kvm *kvm); int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu); From 619064afa9b6f0088b86a1fed20c049cfe94cdf7 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Thu, 14 Jul 2022 08:10:09 +0100 Subject: [PATCH 1108/1436] KVM: arm64: vgic: Tidy-up calls to vgic_{get,set}_common_attr() The userspace accessors have an early call to vgic_{get,set}_common_attr() that makes the code hard to follow. Move it to the default: clause of the decoding switch statement, which results in a nice cleanup. This requires us to move the handling of the pending table into the common handling, even if it is strictly a GICv3 feature (it has the benefit of keeping the whole control group handling in the same function). Also cleanup vgic_v3_{get,set}_attr() while we're at it, deduplicating the calls to vgic_v3_attr_regs_access(). Suggested-by: Reiji Watanabe Signed-off-by: Marc Zyngier --- arch/arm64/kvm/vgic/vgic-kvm-device.c | 78 +++++++++------------------ 1 file changed, 26 insertions(+), 52 deletions(-) diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c index 011171dc41c5..edeac2380591 100644 --- a/arch/arm64/kvm/vgic/vgic-kvm-device.c +++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c @@ -246,6 +246,24 @@ static int vgic_set_common_attr(struct kvm_device *dev, r = vgic_init(dev->kvm); mutex_unlock(&dev->kvm->lock); return r; + case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES: + /* + * OK, this one isn't common at all, but we + * want to handle all control group attributes + * in a single place. + */ + if (vgic_check_type(dev->kvm, KVM_DEV_TYPE_ARM_VGIC_V3)) + return -ENXIO; + mutex_lock(&dev->kvm->lock); + + if (!lock_all_vcpus(dev->kvm)) { + mutex_unlock(&dev->kvm->lock); + return -EBUSY; + } + r = vgic_v3_save_pending_tables(dev->kvm); + unlock_all_vcpus(dev->kvm); + mutex_unlock(&dev->kvm->lock); + return r; } break; } @@ -427,37 +445,25 @@ out: static int vgic_v2_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) { - int ret; - - ret = vgic_set_common_attr(dev, attr); - if (ret != -ENXIO) - return ret; - switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: return vgic_v2_attr_regs_access(dev, attr, true); + default: + return vgic_set_common_attr(dev, attr); } - - return -ENXIO; } static int vgic_v2_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) { - int ret; - - ret = vgic_get_common_attr(dev, attr); - if (ret != -ENXIO) - return ret; - switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: return vgic_v2_attr_regs_access(dev, attr, false); + default: + return vgic_get_common_attr(dev, attr); } - - return -ENXIO; } static int vgic_v2_has_attr(struct kvm_device *dev, @@ -618,61 +624,29 @@ out: static int vgic_v3_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) { - int ret; - - ret = vgic_set_common_attr(dev, attr); - if (ret != -ENXIO) - return ret; - switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: - return vgic_v3_attr_regs_access(dev, attr, true); case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: - return vgic_v3_attr_regs_access(dev, attr, true); case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: return vgic_v3_attr_regs_access(dev, attr, true); - case KVM_DEV_ARM_VGIC_GRP_CTRL: { - int ret; - - switch (attr->attr) { - case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES: - mutex_lock(&dev->kvm->lock); - - if (!lock_all_vcpus(dev->kvm)) { - mutex_unlock(&dev->kvm->lock); - return -EBUSY; - } - ret = vgic_v3_save_pending_tables(dev->kvm); - unlock_all_vcpus(dev->kvm); - mutex_unlock(&dev->kvm->lock); - return ret; - } - break; + default: + return vgic_set_common_attr(dev, attr); } - } - return -ENXIO; } static int vgic_v3_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) { - int ret; - - ret = vgic_get_common_attr(dev, attr); - if (ret != -ENXIO) - return ret; - switch (attr->group) { case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS: - return vgic_v3_attr_regs_access(dev, attr, false); case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS: - return vgic_v3_attr_regs_access(dev, attr, false); case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO: return vgic_v3_attr_regs_access(dev, attr, false); + default: + return vgic_get_common_attr(dev, attr); } - return -ENXIO; } static int vgic_v3_has_attr(struct kvm_device *dev, From f6dddbb25572218d2e8ab93bfdad20cddeb99b5a Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 4 Jul 2022 10:03:33 +0100 Subject: [PATCH 1109/1436] KVM: arm64: Get rid of find_reg_by_id() This helper doesn't have a user anymore, let's get rid of it. Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 11 ----------- arch/arm64/kvm/sys_regs.h | 5 ----- 2 files changed, 16 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 379478eecfaa..7ab67a7fc0d8 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2577,17 +2577,6 @@ static bool index_to_params(u64 id, struct sys_reg_params *params) } } -const struct sys_reg_desc *find_reg_by_id(u64 id, - struct sys_reg_params *params, - const struct sys_reg_desc table[], - unsigned int num) -{ - if (!index_to_params(id, params)) - return NULL; - - return find_reg(params, table, num); -} - const struct sys_reg_desc *get_reg_by_id(u64 id, const struct sys_reg_desc table[], unsigned int num) diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index b8b576a2af2b..49517f58deb5 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -190,11 +190,6 @@ find_reg(const struct sys_reg_params *params, const struct sys_reg_desc table[], return __inline_bsearch((void *)pval, table, num, sizeof(table[0]), match_sys_reg); } -const struct sys_reg_desc *find_reg_by_id(u64 id, - struct sys_reg_params *params, - const struct sys_reg_desc table[], - unsigned int num); - const struct sys_reg_desc *get_reg_by_id(u64 id, const struct sys_reg_desc table[], unsigned int num); From c5332898dc35bbed7d3aa02b491e3388315ee481 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 4 Jul 2022 18:25:41 +0100 Subject: [PATCH 1110/1436] KVM: arm64: Descope kvm_arm_sys_reg_{get,set}_reg() Having kvm_arm_sys_reg_get_reg and co in kvm_host.h gives the impression that these functions are free to be called from anywhere. Not quite. They really are tied to out internal sysreg handling, and they would be better off in the sys_regs.h header, which is private. kvm_host.h could also get a bit of a diet, so let's just do that. Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 2 -- arch/arm64/kvm/sys_regs.h | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index de32152cea04..0c9c85981a8e 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -620,8 +620,6 @@ int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg); unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu); int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices); -int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); -int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu, struct kvm_vcpu_events *events); diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index 49517f58deb5..a8c4cc32eb9a 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -194,9 +194,10 @@ const struct sys_reg_desc *get_reg_by_id(u64 id, const struct sys_reg_desc table[], unsigned int num); +int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); +int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, const struct sys_reg_desc table[], unsigned int num); - int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, const struct sys_reg_desc table[], unsigned int num); From 4274d42716d87d5301fdf67eb799e7db08fe73de Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Mon, 4 Jul 2022 18:11:04 +0100 Subject: [PATCH 1111/1436] KVM: arm64: Get rid or outdated comments Once apon a time, the 32bit KVM/arm port was the reference, while the arm64 version was the new kid on the block, without a clear future... This was a long time ago. "The times, they are a-changing." Signed-off-by: Marc Zyngier --- arch/arm64/kvm/sys_regs.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 7ab67a7fc0d8..b4fda04413f2 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -34,11 +34,6 @@ #include "trace.h" /* - * All of this file is extremely similar to the ARM coproc.c, but the - * types are different. My gut feeling is that it should be pretty - * easy to merge, but that would be an ABI breakage -- again. VFP - * would also need to be abstracted. - * * For AArch32, we only take care of what is being trapped. Anything * that has to do with init and userspace access has to go via the * 64bit interface. From 7a4a04f4e90d746928501a6d551de87d02c28323 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 17 Jul 2022 14:07:35 +0200 Subject: [PATCH 1112/1436] platform/surface: tabletsw: Fix __le32 integer access The sources.count field is a __le32 inside a packed struct. So use the proper functions to access it. Reported-by: kernel test robot Fixes: 9f794056db5b ("platform/surface: Add KIP/POS tablet-mode switch driver") Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220717120735.2052160-1-luzmaximilian@gmail.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_aggregator_tabletsw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c index 596ca6c80681..27d95a6a7851 100644 --- a/drivers/platform/surface/surface_aggregator_tabletsw.c +++ b/drivers/platform/surface/surface_aggregator_tabletsw.c @@ -410,7 +410,7 @@ static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id) if (status) return status; - if (sources.count == 0) { + if (get_unaligned_le32(&sources.count) == 0) { dev_err(&sw->sdev->dev, "no posture sources found\n"); return -ENODEV; } @@ -422,7 +422,7 @@ static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id) * is a device that provides multiple sources, at which point we can * then try to figure out how to handle them. */ - WARN_ON(sources.count > 1); + WARN_ON(get_unaligned_le32(&sources.count) > 1); *source_id = get_unaligned_le32(&sources.id[0]); return 0; From a47bc5a0c4c04958b6a0eb9136c6f553baf37284 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Tue, 12 Jul 2022 21:03:17 +0000 Subject: [PATCH 1113/1436] platform/chrome: cros_ec_typec: Rename port altmode array Rename "p_altmode" to "port_altmode" which is a less ambiguous name for the port_altmode struct array. Signed-off-by: Prashant Malani Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220712210318.2671292-1-pmalani@chromium.org --- drivers/platform/chrome/cros_ec_typec.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 8c0ca3c128ee..bba8bf863f34 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -60,8 +60,7 @@ struct cros_typec_port { uint8_t mux_flags; uint8_t role; - /* Port alt modes. */ - struct typec_altmode p_altmode[CROS_EC_ALTMODE_MAX]; + struct typec_altmode port_altmode[CROS_EC_ALTMODE_MAX]; /* Flag indicating that PD partner discovery data parsing is completed. */ bool sop_disc_done; @@ -282,16 +281,16 @@ static void cros_typec_register_port_altmodes(struct cros_typec_data *typec, struct cros_typec_port *port = typec->ports[port_num]; /* All PD capable CrOS devices are assumed to support DP altmode. */ - port->p_altmode[CROS_EC_ALTMODE_DP].svid = USB_TYPEC_DP_SID; - port->p_altmode[CROS_EC_ALTMODE_DP].mode = USB_TYPEC_DP_MODE; + port->port_altmode[CROS_EC_ALTMODE_DP].svid = USB_TYPEC_DP_SID; + port->port_altmode[CROS_EC_ALTMODE_DP].mode = USB_TYPEC_DP_MODE; /* * Register TBT compatibility alt mode. The EC will not enter the mode * if it doesn't support it, so it's safe to register it unconditionally * here for now. */ - port->p_altmode[CROS_EC_ALTMODE_TBT].svid = USB_TYPEC_TBT_SID; - port->p_altmode[CROS_EC_ALTMODE_TBT].mode = TYPEC_ANY_MODE; + port->port_altmode[CROS_EC_ALTMODE_TBT].svid = USB_TYPEC_TBT_SID; + port->port_altmode[CROS_EC_ALTMODE_TBT].mode = TYPEC_ANY_MODE; port->state.alt = NULL; port->state.mode = TYPEC_STATE_USB; @@ -431,7 +430,7 @@ static int cros_typec_enable_tbt(struct cros_typec_data *typec, data.enter_vdo |= TBT_ENTER_MODE_ACTIVE_CABLE; if (!port->state.alt) { - port->state.alt = &port->p_altmode[CROS_EC_ALTMODE_TBT]; + port->state.alt = &port->port_altmode[CROS_EC_ALTMODE_TBT]; ret = cros_typec_usb_safe_state(port); if (ret) return ret; @@ -473,7 +472,7 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec, /* Configuration VDO. */ dp_data.conf = DP_CONF_SET_PIN_ASSIGN(pd_ctrl->dp_mode); if (!port->state.alt) { - port->state.alt = &port->p_altmode[CROS_EC_ALTMODE_DP]; + port->state.alt = &port->port_altmode[CROS_EC_ALTMODE_DP]; ret = cros_typec_usb_safe_state(port); if (ret) return ret; From 1ff5d97f070c31b0bac438034c64baa3f840f4da Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Tue, 12 Jul 2022 21:03:18 +0000 Subject: [PATCH 1114/1436] platform/chrome: cros_ec_typec: Register port altmodes Instead of using manually managed altmode structs, register the port's altmodes with the Type-C framework. This facilitates matching them to partner altmodes later. Cc: Heikki Krogerus Signed-off-by: Prashant Malani Acked-by: Heikki Krogerus Link: https://lore.kernel.org/r/20220712210318.2671292-2-pmalani@chromium.org --- drivers/platform/chrome/cros_ec_typec.c | 51 +++++++++++++++++++------ 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index bba8bf863f34..de6ee0f926a6 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -25,6 +25,8 @@ #define DRV_NAME "cros-ec-typec" +#define DP_PORT_VDO (BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D) | DP_CAP_DFP_D) + /* Supported alt modes. */ enum { CROS_EC_ALTMODE_DP = 0, @@ -60,7 +62,7 @@ struct cros_typec_port { uint8_t mux_flags; uint8_t role; - struct typec_altmode port_altmode[CROS_EC_ALTMODE_MAX]; + struct typec_altmode *port_altmode[CROS_EC_ALTMODE_MAX]; /* Flag indicating that PD partner discovery data parsing is completed. */ bool sop_disc_done; @@ -253,6 +255,14 @@ static void cros_typec_remove_cable(struct cros_typec_data *typec, port->sop_prime_disc_done = false; } +static void cros_typec_unregister_port_altmodes(struct cros_typec_port *port) +{ + int i; + + for (i = 0; i < CROS_EC_ALTMODE_MAX; i++) + typec_unregister_altmode(port->port_altmode[i]); +} + static void cros_unregister_ports(struct cros_typec_data *typec) { int i; @@ -267,34 +277,49 @@ static void cros_unregister_ports(struct cros_typec_data *typec) usb_role_switch_put(typec->ports[i]->role_sw); typec_switch_put(typec->ports[i]->ori_sw); typec_mux_put(typec->ports[i]->mux); + cros_typec_unregister_port_altmodes(typec->ports[i]); typec_unregister_port(typec->ports[i]->port); } } /* - * Fake the alt mode structs until we actually start registering Type C port - * and partner alt modes. + * Register port alt modes with known values till we start retrieving + * port capabilities from the EC. */ -static void cros_typec_register_port_altmodes(struct cros_typec_data *typec, +static int cros_typec_register_port_altmodes(struct cros_typec_data *typec, int port_num) { struct cros_typec_port *port = typec->ports[port_num]; + struct typec_altmode_desc desc; + struct typec_altmode *amode; /* All PD capable CrOS devices are assumed to support DP altmode. */ - port->port_altmode[CROS_EC_ALTMODE_DP].svid = USB_TYPEC_DP_SID; - port->port_altmode[CROS_EC_ALTMODE_DP].mode = USB_TYPEC_DP_MODE; + desc.svid = USB_TYPEC_DP_SID, + desc.mode = USB_TYPEC_DP_MODE, + desc.vdo = DP_PORT_VDO, + amode = typec_port_register_altmode(port->port, &desc); + if (IS_ERR(amode)) + return PTR_ERR(amode); + port->port_altmode[CROS_EC_ALTMODE_DP] = amode; /* * Register TBT compatibility alt mode. The EC will not enter the mode * if it doesn't support it, so it's safe to register it unconditionally * here for now. */ - port->port_altmode[CROS_EC_ALTMODE_TBT].svid = USB_TYPEC_TBT_SID; - port->port_altmode[CROS_EC_ALTMODE_TBT].mode = TYPEC_ANY_MODE; + memset(&desc, 0, sizeof(desc)); + desc.svid = USB_TYPEC_TBT_SID, + desc.mode = TYPEC_ANY_MODE, + amode = typec_port_register_altmode(port->port, &desc); + if (IS_ERR(amode)) + return PTR_ERR(amode); + port->port_altmode[CROS_EC_ALTMODE_TBT] = amode; port->state.alt = NULL; port->state.mode = TYPEC_STATE_USB; port->state.data = NULL; + + return 0; } static int cros_typec_init_ports(struct cros_typec_data *typec) @@ -361,7 +386,11 @@ static int cros_typec_init_ports(struct cros_typec_data *typec) dev_dbg(dev, "No switch control for port %d\n", port_num); - cros_typec_register_port_altmodes(typec, port_num); + ret = cros_typec_register_port_altmodes(typec, port_num); + if (ret) { + dev_err(dev, "Failed to register port altmodes\n"); + goto unregister_ports; + } cros_port->disc_data = devm_kzalloc(dev, EC_PROTO2_MAX_RESPONSE_SIZE, GFP_KERNEL); if (!cros_port->disc_data) { @@ -430,7 +459,7 @@ static int cros_typec_enable_tbt(struct cros_typec_data *typec, data.enter_vdo |= TBT_ENTER_MODE_ACTIVE_CABLE; if (!port->state.alt) { - port->state.alt = &port->port_altmode[CROS_EC_ALTMODE_TBT]; + port->state.alt = port->port_altmode[CROS_EC_ALTMODE_TBT]; ret = cros_typec_usb_safe_state(port); if (ret) return ret; @@ -472,7 +501,7 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec, /* Configuration VDO. */ dp_data.conf = DP_CONF_SET_PIN_ASSIGN(pd_ctrl->dp_mode); if (!port->state.alt) { - port->state.alt = &port->port_altmode[CROS_EC_ALTMODE_DP]; + port->state.alt = port->port_altmode[CROS_EC_ALTMODE_DP]; ret = cros_typec_usb_safe_state(port); if (ret) return ret; From 2aa0d4c881986b4d0eef35c2651cdc9f3c96d365 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 12 Jul 2022 17:46:02 +0200 Subject: [PATCH 1115/1436] dt-bindings: bus: qcom,ssc-block-bus: rework arrays and drop redundant minItems There is no need to specify "minItems" if it equals to "maxItems". On the other hand number of items in an array can be specified via describing items, which might bring some additional information. This simplifies a bit the binding. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220712154602.26994-1-krzysztof.kozlowski@linaro.org --- .../bindings/bus/qcom,ssc-block-bus.yaml | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/bus/qcom,ssc-block-bus.yaml b/Documentation/devicetree/bindings/bus/qcom,ssc-block-bus.yaml index 5b9705079015..8e9e6ff35d7d 100644 --- a/Documentation/devicetree/bindings/bus/qcom,ssc-block-bus.yaml +++ b/Documentation/devicetree/bindings/bus/qcom,ssc-block-bus.yaml @@ -28,11 +28,9 @@ properties: - const: qcom,ssc-block-bus reg: - description: | - Shall contain the addresses of the SSCAON_CONFIG0 and SSCAON_CONFIG1 - registers - minItems: 2 - maxItems: 2 + items: + - description: SSCAON_CONFIG0 registers + - description: SSCAON_CONFIG1 registers reg-names: items: @@ -48,7 +46,6 @@ properties: ranges: true clocks: - minItems: 6 maxItems: 6 clock-names: @@ -61,9 +58,9 @@ properties: - const: ssc_ahbs power-domains: - description: Power domain phandles for the ssc_cx and ssc_mx power domains - minItems: 2 - maxItems: 2 + items: + - description: CX power domain + - description: MX power domain power-domain-names: items: @@ -71,11 +68,11 @@ properties: - const: ssc_mx resets: - description: | - Reset phandles for the ssc_reset and ssc_bcr resets (note: ssc_bcr is the - branch control register associated with the ssc_xo and ssc_ahbs clocks) - minItems: 2 - maxItems: 2 + items: + - description: Main reset + - description: + SSC Branch Control Register reset (associated with the ssc_xo and + ssc_ahbs clocks) reset-names: items: From 88a15fbb47db483d06b12b1ae69f114b96361a96 Mon Sep 17 00:00:00 2001 From: Prashant Malani Date: Mon, 18 Jul 2022 18:55:51 +0000 Subject: [PATCH 1116/1436] platform/chrome: cros_typec_switch: Add ACPI Kconfig dep Add the ACPI Kconfig dependency that was missed during the initial driver submission. Fixes the following compiler errors: drivers/platform/chrome/cros_typec_switch.c:93:9: error: call to undeclared function 'acpi_evaluate_integer'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); drivers/platform/chrome/cros_typec_switch.c:93:35: error: incomplete definition of type 'struct acpi_device' ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); Fixes: e54369058f3d ("platform/chrome: cros_typec_switch: Add switch driver") Reported-by: Reported-by: kernel test robot Signed-off-by: Prashant Malani Link: https://lore.kernel.org/r/20220718185551.1025288-1-pmalani@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index c62a514a087f..9d4fc505fa25 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -267,7 +267,7 @@ config CHROMEOS_PRIVACY_SCREEN config CROS_TYPEC_SWITCH tristate "ChromeOS EC Type-C Switch Control" - depends on MFD_CROS_EC_DEV && TYPEC + depends on MFD_CROS_EC_DEV && TYPEC && ACPI default MFD_CROS_EC_DEV help If you say Y here, you get support for configuring the Chrome OS EC Type C From 2b038e786f8338a3bc22d791000753e0ec113e00 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 22 Jun 2022 20:28:42 +0300 Subject: [PATCH 1117/1436] gpiolib: devres: Get rid of unused devm_gpio_free() The last user, which in fact was a dead code, has gone a year ago, previous one 3 years ago. On top of that we want to drop away the legacy GPIO APIs in the kernel, so take a chance to get rid of unused devm_gpio_free() and accompanying stuff. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- .../driver-api/driver-model/devres.rst | 1 - drivers/gpio/gpiolib-devres.c | 32 ------------------- include/linux/gpio.h | 6 ---- 3 files changed, 39 deletions(-) diff --git a/Documentation/driver-api/driver-model/devres.rst b/Documentation/driver-api/driver-model/devres.rst index 2d39967bafcc..55272942e721 100644 --- a/Documentation/driver-api/driver-model/devres.rst +++ b/Documentation/driver-api/driver-model/devres.rst @@ -277,7 +277,6 @@ GPIO devm_gpiochip_add_data() devm_gpio_request() devm_gpio_request_one() - devm_gpio_free() I2C devm_i2c_new_dummy_device() diff --git a/drivers/gpio/gpiolib-devres.c b/drivers/gpio/gpiolib-devres.c index 79da85d17b71..16a696249229 100644 --- a/drivers/gpio/gpiolib-devres.c +++ b/drivers/gpio/gpiolib-devres.c @@ -375,9 +375,6 @@ void devm_gpiod_put_array(struct device *dev, struct gpio_descs *descs) } EXPORT_SYMBOL_GPL(devm_gpiod_put_array); - - - static void devm_gpio_release(struct device *dev, void *res) { unsigned *gpio = res; @@ -385,13 +382,6 @@ static void devm_gpio_release(struct device *dev, void *res) gpio_free(*gpio); } -static int devm_gpio_match(struct device *dev, void *res, void *data) -{ - unsigned *this = res, *gpio = data; - - return *this == *gpio; -} - /** * devm_gpio_request - request a GPIO for a managed device * @dev: device to request the GPIO for @@ -402,11 +392,7 @@ static int devm_gpio_match(struct device *dev, void *res, void *data) * same arguments and performs the same function as * gpio_request(). GPIOs requested with this function will be * automatically freed on driver detach. - * - * If an GPIO allocated with this function needs to be freed - * separately, devm_gpio_free() must be used. */ - int devm_gpio_request(struct device *dev, unsigned gpio, const char *label) { unsigned *dr; @@ -459,24 +445,6 @@ int devm_gpio_request_one(struct device *dev, unsigned gpio, } EXPORT_SYMBOL_GPL(devm_gpio_request_one); -/** - * devm_gpio_free - free a GPIO - * @dev: device to free GPIO for - * @gpio: GPIO to free - * - * Except for the extra @dev argument, this function takes the - * same arguments and performs the same function as gpio_free(). - * This function instead of gpio_free() should be used to manually - * free GPIOs allocated with devm_gpio_request(). - */ -void devm_gpio_free(struct device *dev, unsigned int gpio) -{ - - WARN_ON(devres_release(dev, devm_gpio_release, devm_gpio_match, - &gpio)); -} -EXPORT_SYMBOL_GPL(devm_gpio_free); - static void devm_gpio_chip_release(void *data) { struct gpio_chip *gc = data; diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 008ad3ee56b7..a370387fa406 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -95,7 +95,6 @@ struct device; int devm_gpio_request(struct device *dev, unsigned gpio, const char *label); int devm_gpio_request_one(struct device *dev, unsigned gpio, unsigned long flags, const char *label); -void devm_gpio_free(struct device *dev, unsigned int gpio); #else /* ! CONFIG_GPIOLIB */ @@ -240,11 +239,6 @@ static inline int devm_gpio_request_one(struct device *dev, unsigned gpio, return -EINVAL; } -static inline void devm_gpio_free(struct device *dev, unsigned int gpio) -{ - WARN_ON(1); -} - #endif /* ! CONFIG_GPIOLIB */ #endif /* __LINUX_GPIO_H */ From 1282157a6cf48993d90347fdc5bcb93e00b58f2b Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 26 May 2022 13:29:44 +1200 Subject: [PATCH 1118/1436] dt-bindings: gpio: gpio-mvebu: convert txt binding to DT schema format Convert the existing device tree binding to DT schema format. The old binding listed the interrupt-controller and related properties as required but there are sufficiently many existing usages without it that the YAML binding does not make the interrupt properties required. Signed-off-by: Chris Packham Reviewed-by: Andrew Lunn Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski --- .../arm/marvell/ap80x-system-controller.txt | 2 +- .../arm/marvell/cp110-system-controller.txt | 2 +- .../devicetree/bindings/gpio/gpio-mvebu.txt | 93 ----------- .../devicetree/bindings/gpio/gpio-mvebu.yaml | 146 ++++++++++++++++++ MAINTAINERS | 2 +- 5 files changed, 149 insertions(+), 96 deletions(-) delete mode 100644 Documentation/devicetree/bindings/gpio/gpio-mvebu.txt create mode 100644 Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml diff --git a/Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt b/Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt index 052a967c1f28..c83245065d44 100644 --- a/Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt +++ b/Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt @@ -72,7 +72,7 @@ mpp19 19 gpio, uart0(rxd), sdio(pw_off) GPIO: ----- For common binding part and usage, refer to -Documentation/devicetree/bindings/gpio/gpio-mvebu.txt. +Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml. Required properties: diff --git a/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller.txt b/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller.txt index 0705e765f432..d84105c7c935 100644 --- a/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller.txt +++ b/Documentation/devicetree/bindings/arm/marvell/cp110-system-controller.txt @@ -156,7 +156,7 @@ GPIO: ----- For common binding part and usage, refer to -Documentation/devicetree/bindings/gpio/gpio-mvebu.txt. +Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml. Required properties: diff --git a/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt b/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt deleted file mode 100644 index 0fc6700ed800..000000000000 --- a/Documentation/devicetree/bindings/gpio/gpio-mvebu.txt +++ /dev/null @@ -1,93 +0,0 @@ -* Marvell EBU GPIO controller - -Required properties: - -- compatible : Should be "marvell,orion-gpio", "marvell,mv78200-gpio", - "marvell,armadaxp-gpio" or "marvell,armada-8k-gpio". - - "marvell,orion-gpio" should be used for Orion, Kirkwood, Dove, - Discovery (except MV78200) and Armada 370. "marvell,mv78200-gpio" - should be used for the Discovery MV78200. - - "marvel,armadaxp-gpio" should be used for all Armada XP SoCs - (MV78230, MV78260, MV78460). - - "marvell,armada-8k-gpio" should be used for the Armada 7K and 8K - SoCs (either from AP or CP), see - Documentation/devicetree/bindings/arm/marvell/ap80x-system-controller.txt - for specific details about the offset property. - -- reg: Address and length of the register set for the device. Only one - entry is expected, except for the "marvell,armadaxp-gpio" variant - for which two entries are expected: one for the general registers, - one for the per-cpu registers. Not used for marvell,armada-8k-gpio. - -- interrupts: The list of interrupts that are used for all the pins - managed by this GPIO bank. There can be more than one interrupt - (example: 1 interrupt per 8 pins on Armada XP, which means 4 - interrupts per bank of 32 GPIOs). - -- interrupt-controller: identifies the node as an interrupt controller - -- #interrupt-cells: specifies the number of cells needed to encode an - interrupt source. Should be two. - The first cell is the GPIO number. - The second cell is used to specify flags: - bits[3:0] trigger type and level flags: - 1 = low-to-high edge triggered. - 2 = high-to-low edge triggered. - 4 = active high level-sensitive. - 8 = active low level-sensitive. - -- gpio-controller: marks the device node as a gpio controller - -- ngpios: number of GPIOs this controller has - -- #gpio-cells: Should be two. The first cell is the pin number. The - second cell is reserved for flags, unused at the moment. - -Optional properties: - -In order to use the GPIO lines in PWM mode, some additional optional -properties are required. - -- compatible: Must contain "marvell,armada-370-gpio" - -- reg: an additional register set is needed, for the GPIO Blink - Counter on/off registers. - -- reg-names: Must contain an entry "pwm" corresponding to the - additional register range needed for PWM operation. - -- #pwm-cells: Should be two. The first cell is the GPIO line number. The - second cell is the period in nanoseconds. - -- clocks: Must be a phandle to the clock for the GPIO controller. - -Example: - - gpio0: gpio@d0018100 { - compatible = "marvell,armadaxp-gpio"; - reg = <0xd0018100 0x40>, - <0xd0018800 0x30>; - ngpios = <32>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = <16>, <17>, <18>, <19>; - }; - - gpio1: gpio@18140 { - compatible = "marvell,armada-370-gpio"; - reg = <0x18140 0x40>, <0x181c8 0x08>; - reg-names = "gpio", "pwm"; - ngpios = <17>; - gpio-controller; - #gpio-cells = <2>; - #pwm-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - interrupts = <87>, <88>, <89>; - clocks = <&coreclk 0>; - }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml b/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml new file mode 100644 index 000000000000..d1695e7bd825 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml @@ -0,0 +1,146 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/gpio-mvebu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Marvell EBU GPIO controller + +maintainers: + - Thomas Petazzoni + - Andrew Lunn + +properties: + compatible: + oneOf: + - enum: + - marvell,armada-8k-gpio + - marvell,orion-gpio + + - items: + - enum: + - marvell,mv78200-gpio + - marvell,armada-370-gpio + - marvell,armadaxp-gpio + - const: marvell,orion-gpio + + reg: + description: | + Address and length of the register set for the device. Not used for + marvell,armada-8k-gpio. + + For the "marvell,armadaxp-gpio" variant a second entry is expected for + the per-cpu registers. For other variants second entry can be provided, + for the PWM function using the GPIO Blink Counter on/off registers. + minItems: 1 + maxItems: 2 + + reg-names: + items: + - const: gpio + - const: pwm + minItems: 1 + + interrupts: + description: | + The list of interrupts that are used for all the pins managed by this + GPIO bank. There can be more than one interrupt (example: 1 interrupt + per 8 pins on Armada XP, which means 4 interrupts per bank of 32 + GPIOs). + minItems: 1 + maxItems: 4 + + interrupt-controller: true + + "#interrupt-cells": + const: 2 + + gpio-controller: true + + ngpios: + minimum: 1 + maximum: 32 + + "#gpio-cells": + const: 2 + + "#pwm-cells": + description: + The first cell is the GPIO line number. The second cell is the period + in nanoseconds. + const: 2 + + clocks: + description: + Clock(s) used for PWM function. + items: + - description: Core clock + - description: AXI bus clock + minItems: 1 + + clock-names: + items: + - const: core + - const: axi + minItems: 1 + +required: + - compatible + - gpio-controller + - ngpios + - "#gpio-cells" + +allOf: + - if: + properties: + compatible: + contains: + const: marvell,armada-8k-gpio + then: + required: + - offset + else: + required: + - reg + + - if: + properties: + compatible: + contains: + const: marvell,armadaxp-gpio + then: + properties: + reg: + minItems: 2 + reg-names: + minItems: 2 + +unevaluatedProperties: true + +examples: + - | + gpio@d0018100 { + compatible = "marvell,armadaxp-gpio", "marvell,orion-gpio"; + reg = <0xd0018100 0x40>, <0xd0018800 0x30>; + ngpios = <32>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <16>, <17>, <18>, <19>; + }; + + - | + gpio@18140 { + compatible = "marvell,armada-370-gpio", "marvell,orion-gpio"; + reg = <0x18140 0x40>, <0x181c8 0x08>; + reg-names = "gpio", "pwm"; + ngpios = <17>; + gpio-controller; + #gpio-cells = <2>; + #pwm-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupts = <87>, <88>, <89>; + clocks = <&coreclk 0>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 651616ed8ae2..3405cb36cf02 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -16330,7 +16330,7 @@ L: linux-pwm@vger.kernel.org S: Maintained Q: https://patchwork.ozlabs.org/project/linux-pwm/list/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm.git -F: Documentation/devicetree/bindings/gpio/gpio-mvebu.txt +F: Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml F: Documentation/devicetree/bindings/pwm/ F: Documentation/driver-api/pwm.rst F: drivers/gpio/gpio-mvebu.c From 988c8c0cd04de81c7cde5b0a55cabf0c67136340 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 26 May 2022 13:29:45 +1200 Subject: [PATCH 1119/1436] dt-bindings: gpio: gpio-mvebu: deprecate armadaxp-gpio Commit 5f79c651e81e ("arm: mvebu: use global interrupts for GPIOs on Armada XP") the marvell,armadaxp-gpio compatible obsolete. The driver code still exists to handle the armadaxp behaviour but all the in-tree boards use the marvell,armada-370-gpio. Document the marvell,armadaxp-gpio compatible as deprecated. Signed-off-by: Chris Packham Reviewed-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski --- .../devicetree/bindings/gpio/gpio-mvebu.yaml | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml b/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml index d1695e7bd825..459ec35864fe 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml @@ -21,17 +21,21 @@ properties: - enum: - marvell,mv78200-gpio - marvell,armada-370-gpio - - marvell,armadaxp-gpio - const: marvell,orion-gpio + - description: Deprecated binding + items: + - const: marvell,armadaxp-gpio + - const: marvell,orion-gpio + deprecated: true + reg: description: | Address and length of the register set for the device. Not used for marvell,armada-8k-gpio. - For the "marvell,armadaxp-gpio" variant a second entry is expected for - the per-cpu registers. For other variants second entry can be provided, - for the PWM function using the GPIO Blink Counter on/off registers. + A second entry can be provided, for the PWM function using the GPIO Blink + Counter on/off registers. minItems: 1 maxItems: 2 @@ -103,18 +107,6 @@ allOf: required: - reg - - if: - properties: - compatible: - contains: - const: marvell,armadaxp-gpio - then: - properties: - reg: - minItems: 2 - reg-names: - minItems: 2 - unevaluatedProperties: true examples: From df08a6fc0d5d7dd579dd0902893a433765d9f4c5 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Thu, 26 May 2022 13:29:46 +1200 Subject: [PATCH 1120/1436] dt-bindings: gpio: gpio-mvebu: document offset and marvell,pwm-offset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The offset and marvell,pwm-offset properties weren't in the old binding. Add them based on the existing usage in the driver and board DTS when the marvell,armada-8k-gpio compatible is used. Signed-off-by: Chris Packham Reviewed-by: Krzysztof Kozlowski Acked-by: Uwe Kleine-König Acked-by: Thierry Reding Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml b/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml index 459ec35864fe..f1bd1e6b2e1f 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-mvebu.yaml @@ -45,6 +45,10 @@ properties: - const: pwm minItems: 1 + offset: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Offset in the register map for the gpio registers (in bytes) + interrupts: description: | The list of interrupts that are used for all the pins managed by this @@ -68,6 +72,10 @@ properties: "#gpio-cells": const: 2 + marvell,pwm-offset: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Offset in the register map for the pwm registers (in bytes) + "#pwm-cells": description: The first cell is the GPIO line number. The second cell is the period From 0651a730924b172476f67c7c6e01e898f84cd8f3 Mon Sep 17 00:00:00 2001 From: Devarsh Thakkar Date: Mon, 13 Jun 2022 11:13:10 +0530 Subject: [PATCH 1121/1436] gpio: davinci: Add support for system suspend/resume PM Add support for system suspend/resume PM hooks, save the register context of all the required gpio registers on suspend and restore context on the resume. Signed-off-by: Devarsh Thakkar Signed-off-by: Aswath Govindraju Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-davinci.c | 83 +++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index f960587f86a3..59c4c48d8296 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -62,6 +63,8 @@ struct davinci_gpio_controller { void __iomem *regs[MAX_REGS_BANKS]; int gpio_unbanked; int irqs[MAX_INT_PER_BANK]; + struct davinci_gpio_regs context[MAX_REGS_BANKS]; + u32 binten_context; }; static inline u32 __gpio_mask(unsigned gpio) @@ -622,6 +625,85 @@ done: return 0; } +static void davinci_gpio_save_context(struct davinci_gpio_controller *chips, + u32 nbank) +{ + struct davinci_gpio_regs __iomem *g; + struct davinci_gpio_regs *context; + u32 bank; + void __iomem *base; + + base = chips->regs[0] - offset_array[0]; + chips->binten_context = readl_relaxed(base + BINTEN); + + for (bank = 0; bank < nbank; bank++) { + g = chips->regs[bank]; + context = &chips->context[bank]; + context->dir = readl_relaxed(&g->dir); + context->set_data = readl_relaxed(&g->set_data); + context->set_rising = readl_relaxed(&g->set_rising); + context->set_falling = readl_relaxed(&g->set_falling); + } + + /* Clear Bank interrupt enable bit */ + writel_relaxed(0, base + BINTEN); + + /* Clear all interrupt status registers */ + writel_relaxed(GENMASK(31, 0), &g->intstat); +} + +static void davinci_gpio_restore_context(struct davinci_gpio_controller *chips, + u32 nbank) +{ + struct davinci_gpio_regs __iomem *g; + struct davinci_gpio_regs *context; + u32 bank; + void __iomem *base; + + base = chips->regs[0] - offset_array[0]; + + if (readl_relaxed(base + BINTEN) != chips->binten_context) + writel_relaxed(chips->binten_context, base + BINTEN); + + for (bank = 0; bank < nbank; bank++) { + g = chips->regs[bank]; + context = &chips->context[bank]; + if (readl_relaxed(&g->dir) != context->dir) + writel_relaxed(context->dir, &g->dir); + if (readl_relaxed(&g->set_data) != context->set_data) + writel_relaxed(context->set_data, &g->set_data); + if (readl_relaxed(&g->set_rising) != context->set_rising) + writel_relaxed(context->set_rising, &g->set_rising); + if (readl_relaxed(&g->set_falling) != context->set_falling) + writel_relaxed(context->set_falling, &g->set_falling); + } +} + +static int davinci_gpio_suspend(struct device *dev) +{ + struct davinci_gpio_controller *chips = dev_get_drvdata(dev); + struct davinci_gpio_platform_data *pdata = dev_get_platdata(dev); + u32 nbank = DIV_ROUND_UP(pdata->ngpio, 32); + + davinci_gpio_save_context(chips, nbank); + + return 0; +} + +static int davinci_gpio_resume(struct device *dev) +{ + struct davinci_gpio_controller *chips = dev_get_drvdata(dev); + struct davinci_gpio_platform_data *pdata = dev_get_platdata(dev); + u32 nbank = DIV_ROUND_UP(pdata->ngpio, 32); + + davinci_gpio_restore_context(chips, nbank); + + return 0; +} + +DEFINE_SIMPLE_DEV_PM_OPS(davinci_gpio_dev_pm_ops, davinci_gpio_suspend, + davinci_gpio_resume); + static const struct of_device_id davinci_gpio_ids[] = { { .compatible = "ti,keystone-gpio", keystone_gpio_get_irq_chip}, { .compatible = "ti,am654-gpio", keystone_gpio_get_irq_chip}, @@ -634,6 +716,7 @@ static struct platform_driver davinci_gpio_driver = { .probe = davinci_gpio_probe, .driver = { .name = "davinci_gpio", + .pm = pm_sleep_ptr(&davinci_gpio_dev_pm_ops), .of_match_table = of_match_ptr(davinci_gpio_ids), }, }; From 31212be403585d118ec6c97c3abbf36e88439b30 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 10 Jun 2022 12:08:22 +0200 Subject: [PATCH 1122/1436] dt-bindings: gpio: renesas,rcar-gpio: R-Car V3U is R-Car Gen4 Despite the name, R-Car V3U is the first member of the R-Car Gen4 family. Hence move its compatible value to the R-Car Gen4 section. Signed-off-by: Geert Uytterhoeven Acked-by: Krzysztof Kozlowski Reviewed-by: Wolfram Sang Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml b/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml index 0681a4790cd6..75e5da6a7cc0 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/renesas,rcar-gpio.yaml @@ -48,11 +48,9 @@ properties: - renesas,gpio-r8a77995 # R-Car D3 - const: renesas,rcar-gen3-gpio # R-Car Gen3 or RZ/G2 - - items: - - const: renesas,gpio-r8a779a0 # R-Car V3U - - items: - enum: + - renesas,gpio-r8a779a0 # R-Car V3U - renesas,gpio-r8a779f0 # R-Car S4-8 - const: renesas,rcar-gen4-gpio # R-Car Gen4 From 2a1192ff0835cb4b0ccd6f6e85c93aa0dc6f66b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 14 Jun 2022 17:23:38 +0200 Subject: [PATCH 1123/1436] gpio: twl4030: Drop platform teardown callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no machine providing a teardown callback, so drop the unused code. This is a preparation for making platform remove callbacks return void. Signed-off-by: Uwe Kleine-König Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-twl4030.c | 11 ----------- include/linux/mfd/twl.h | 2 -- 2 files changed, 13 deletions(-) diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index de249726230e..e2cb7cb90c8c 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -593,18 +593,7 @@ out: /* Cannot use as gpio_twl4030_probe() calls us */ static int gpio_twl4030_remove(struct platform_device *pdev) { - struct twl4030_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct gpio_twl4030_priv *priv = platform_get_drvdata(pdev); - int status; - - if (pdata && pdata->teardown) { - status = pdata->teardown(&pdev->dev, priv->gpio_chip.base, - TWL4030_GPIO_MAX); - if (status) { - dev_dbg(&pdev->dev, "teardown --> %d\n", status); - return status; - } - } gpiochip_remove(&priv->gpio_chip); diff --git a/include/linux/mfd/twl.h b/include/linux/mfd/twl.h index 8871cc5188a0..c8cd31756037 100644 --- a/include/linux/mfd/twl.h +++ b/include/linux/mfd/twl.h @@ -594,8 +594,6 @@ struct twl4030_gpio_platform_data { int (*setup)(struct device *dev, unsigned gpio, unsigned ngpio); - int (*teardown)(struct device *dev, - unsigned gpio, unsigned ngpio); }; struct twl4030_madc_platform_data { From 421e3c16c32ad37b7124ae663d61e50546a57f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 14 Jun 2022 17:23:39 +0200 Subject: [PATCH 1124/1436] gpio: twl4030: Don't return an error after WARN in .remove MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Returning a non-zero value in a platform driver's remove callback only results in an error message ("remove callback returned a non-zero value. This will be ignored.", see platform_remove()), and then the device is removed anyhow. As there was just a WARN_ON triggered, return 0 to drop the follow up warning. The latter output is hardly relevant after the big WARN splat. This is a preparation for making platform remove callbacks return void. Signed-off-by: Uwe Kleine-König Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-twl4030.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index e2cb7cb90c8c..5046e51af8df 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -597,12 +597,9 @@ static int gpio_twl4030_remove(struct platform_device *pdev) gpiochip_remove(&priv->gpio_chip); - if (is_module()) - return 0; - /* REVISIT no support yet for deregistering all the IRQs */ - WARN_ON(1); - return -EIO; + WARN_ON(!is_module()); + return 0; } static const struct of_device_id twl_gpio_match[] = { From 7e55b33d3f18fde5c7a57b6c52d80499485c737f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 14 Jun 2022 21:48:02 +0200 Subject: [PATCH 1125/1436] gpio: ucb1400: Remove platform setup and teardown support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no user of these callbacks. The motivation for this change is to stop returning an error code from the remove callback. This is a preparation for making platform remove callbacks return void. Signed-off-by: Uwe Kleine-König Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-ucb1400.c | 20 -------------------- drivers/mfd/ucb1400_core.c | 6 ++---- include/linux/ucb1400.h | 2 -- 3 files changed, 2 insertions(+), 26 deletions(-) diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c index d2a8644864c3..386e69300332 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/gpio-ucb1400.c @@ -64,34 +64,14 @@ static int ucb1400_gpio_probe(struct platform_device *dev) ucb->gc.can_sleep = true; err = devm_gpiochip_add_data(&dev->dev, &ucb->gc, ucb); - if (err) - goto err; - - if (ucb->gpio_setup) - err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio); err: return err; } -static int ucb1400_gpio_remove(struct platform_device *dev) -{ - int err = 0; - struct ucb1400_gpio *ucb = platform_get_drvdata(dev); - - if (ucb && ucb->gpio_teardown) { - err = ucb->gpio_teardown(&dev->dev, ucb->gc.ngpio); - if (err) - return err; - } - - return err; -} - static struct platform_driver ucb1400_gpio_driver = { .probe = ucb1400_gpio_probe, - .remove = ucb1400_gpio_remove, .driver = { .name = "ucb1400_gpio" }, diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index 8c3832a58ef6..ac1d18039568 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c @@ -72,11 +72,9 @@ static int ucb1400_core_probe(struct device *dev) /* GPIO */ ucb_gpio.ac97 = ac97; - if (pdata) { - ucb_gpio.gpio_setup = pdata->gpio_setup; - ucb_gpio.gpio_teardown = pdata->gpio_teardown; + if (pdata) ucb_gpio.gpio_offset = pdata->gpio_offset; - } + ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1); if (!ucb->ucb1400_gpio) { err = -ENOMEM; diff --git a/include/linux/ucb1400.h b/include/linux/ucb1400.h index 0968ef458447..22345391350b 100644 --- a/include/linux/ucb1400.h +++ b/include/linux/ucb1400.h @@ -84,8 +84,6 @@ struct ucb1400_gpio { struct gpio_chip gc; struct snd_ac97 *ac97; int gpio_offset; - int (*gpio_setup)(struct device *dev, int ngpio); - int (*gpio_teardown)(struct device *dev, int ngpio); }; struct ucb1400_ts { From 1923433cd660fda6315b8eb1bb8372cf7e85acf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 21 Jun 2022 08:35:24 +0200 Subject: [PATCH 1126/1436] gpio: brcmstb: Make .remove() obviously always return 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit priv cannot be NULL because brcmstb_gpio_probe() calls platform_set_drvdata() with a non-NULL argument, so the check for !priv can be dropped. Also remove the variable ret that is only used to hide a bit that in the end zero is returned. This is a preparation for making platform remove callbacks return void. Signed-off-by: Uwe Kleine-König Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-brcmstb.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/gpio/gpio-brcmstb.c b/drivers/gpio/gpio-brcmstb.c index 6b7439b44690..f620f0712134 100644 --- a/drivers/gpio/gpio-brcmstb.c +++ b/drivers/gpio/gpio-brcmstb.c @@ -385,12 +385,7 @@ static int brcmstb_gpio_remove(struct platform_device *pdev) { struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev); struct brcmstb_gpio_bank *bank; - int offset, ret = 0, virq; - - if (!priv) { - dev_err(&pdev->dev, "called %s without drvdata!\n", __func__); - return -EFAULT; - } + int offset, virq; if (priv->parent_irq > 0) irq_set_chained_handler_and_data(priv->parent_irq, NULL, NULL); @@ -411,7 +406,7 @@ static int brcmstb_gpio_remove(struct platform_device *pdev) list_for_each_entry(bank, &priv->bank_list, node) gpiochip_remove(&bank->gc); - return ret; + return 0; } static int brcmstb_gpio_of_xlate(struct gpio_chip *gc, From 3d57fa2a228c973032e94aceeef92a3e9704b9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 15 Jun 2022 14:47:18 +0200 Subject: [PATCH 1127/1436] gpio: xgs-iproc: Drop if with an always false condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The remove callback is only called after probe completed successfully. In this case platform_set_drvdata() was called with a non-NULL argument and so chip is never NULL. Also note that returning an error code from a remove callback doesn't result in the device staying bound. It's still removed and devm callbacks are called. This is a preparation for making platform remove callbacks return void. Signed-off-by: Uwe Kleine-König Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-xgs-iproc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-xgs-iproc.c b/drivers/gpio/gpio-xgs-iproc.c index 43ca52fa6f9a..fd88500399c6 100644 --- a/drivers/gpio/gpio-xgs-iproc.c +++ b/drivers/gpio/gpio-xgs-iproc.c @@ -281,11 +281,7 @@ static int iproc_gpio_probe(struct platform_device *pdev) static int iproc_gpio_remove(struct platform_device *pdev) { - struct iproc_gpio_chip *chip; - - chip = platform_get_drvdata(pdev); - if (!chip) - return -ENODEV; + struct iproc_gpio_chip *chip = platform_get_drvdata(pdev); if (chip->intr) { u32 val; From 91e9111bdd088993948f8c215a8a01acc67a7a86 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 29 Jun 2022 19:04:19 +0200 Subject: [PATCH 1128/1436] gpio: pca9570: Add DT bindings for NXP PCA9571 This patch adds device tree bindings for the NXP PCA9571, a 8-bit I2C GPIO expander. Signed-off-by: Lucas Stach Acked-by: Krzysztof Kozlowski Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/gpio-pca9570.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/gpio/gpio-pca9570.yaml b/Documentation/devicetree/bindings/gpio/gpio-pca9570.yaml index 338c5312a106..1acaa0a3d35a 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-pca9570.yaml +++ b/Documentation/devicetree/bindings/gpio/gpio-pca9570.yaml @@ -13,6 +13,7 @@ properties: compatible: enum: - nxp,pca9570 + - nxp,pca9571 reg: maxItems: 1 From d274f02eb98be8ec1d13bb9d16493eb1711a3d37 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 29 Jun 2022 19:04:20 +0200 Subject: [PATCH 1129/1436] gpio: pca9570: add pca9571 support The PCA9571 very similar to the PCA9570, it only differs in the number of GPIOs. Signed-off-by: Lucas Stach Reviewed-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-pca9570.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-pca9570.c b/drivers/gpio/gpio-pca9570.c index cb2b2f735c15..ab2a652964ec 100644 --- a/drivers/gpio/gpio-pca9570.c +++ b/drivers/gpio/gpio-pca9570.c @@ -121,12 +121,14 @@ static int pca9570_probe(struct i2c_client *client) static const struct i2c_device_id pca9570_id_table[] = { { "pca9570", 4 }, + { "pca9571", 8 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, pca9570_id_table); static const struct of_device_id pca9570_of_match_table[] = { { .compatible = "nxp,pca9570", .data = (void *)4 }, + { .compatible = "nxp,pca9571", .data = (void *)8 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, pca9570_of_match_table); From a2a15e1263ab1c17f798eab1290180ffa4011223 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 28 Jun 2022 22:59:12 +0300 Subject: [PATCH 1130/1436] gpio: adnp: use simple i2c probe function The i2c probe functions here don't use the id information provided in their second argument, so the single-parameter i2c probe function ("probe_new") can be used instead. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-adnp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index cc349d4e4973..075782831044 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -485,8 +485,7 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios, return 0; } -static int adnp_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int adnp_i2c_probe(struct i2c_client *client) { struct device_node *np = client->dev.of_node; struct adnp *adnp; @@ -535,7 +534,7 @@ static struct i2c_driver adnp_i2c_driver = { .name = "gpio-adnp", .of_match_table = adnp_of_match, }, - .probe = adnp_i2c_probe, + .probe_new = adnp_i2c_probe, .id_table = adnp_i2c_id, }; module_i2c_driver(adnp_i2c_driver); From 8773bacefcd7a5c742437974771976a9e79288f7 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 28 Jun 2022 22:59:13 +0300 Subject: [PATCH 1131/1436] gpio: adnp: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-adnp.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 075782831044..a6439e3daff0 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -6,8 +6,9 @@ #include #include #include +#include #include -#include +#include #include #include @@ -487,19 +488,15 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios, static int adnp_i2c_probe(struct i2c_client *client) { - struct device_node *np = client->dev.of_node; + struct device *dev = &client->dev; struct adnp *adnp; u32 num_gpios; int err; - err = of_property_read_u32(np, "nr-gpios", &num_gpios); + err = device_property_read_u32(dev, "nr-gpios", &num_gpios); if (err < 0) return err; - client->irq = irq_of_parse_and_map(np, 0); - if (!client->irq) - return -EPROBE_DEFER; - adnp = devm_kzalloc(&client->dev, sizeof(*adnp), GFP_KERNEL); if (!adnp) return -ENOMEM; @@ -507,8 +504,7 @@ static int adnp_i2c_probe(struct i2c_client *client) mutex_init(&adnp->i2c_lock); adnp->client = client; - err = adnp_gpio_setup(adnp, num_gpios, - of_property_read_bool(np, "interrupt-controller")); + err = adnp_gpio_setup(adnp, num_gpios, device_property_read_bool(dev, "interrupt-controller")); if (err) return err; From 036e9cf35689b9f6a0d1bb8d34ec7ddf44714942 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Thu, 23 Jun 2022 18:08:00 +0200 Subject: [PATCH 1132/1436] dt-bindings: gpio: rockchip: add gpio-ranges Allow usage of gpio-ranges with the rockchip gpio controller. The driver already had support for this since it has been added to the mainline kernel in the first place. Acked-by: Rob Herring Signed-off-by: Sebastian Reichel Reviewed-by: Heiko Stuebner Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml b/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml index d4e42c2b995b..affd823c881d 100644 --- a/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml +++ b/Documentation/devicetree/bindings/gpio/rockchip,gpio-bank.yaml @@ -27,6 +27,8 @@ properties: - description: APB interface clock source - description: GPIO debounce reference clock source + gpio-ranges: true + gpio-controller: true gpio-line-names: true From cc165ba48aaf7d792e99d0c7e4b12e9625bc73e3 Mon Sep 17 00:00:00 2001 From: Jianqun Xu Date: Thu, 23 Jun 2022 18:08:01 +0200 Subject: [PATCH 1133/1436] gpio: rockchip: add support for rk3588 Add V2.1 rockchip gpio controller type, which is part of the RK3588 SoC. Signed-off-by: Jianqun Xu Reviewed-by: Linus Walleij Signed-off-by: Sebastian Reichel Reviewed-by: Heiko Stuebner --- drivers/gpio/gpio-rockchip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-rockchip.c b/drivers/gpio/gpio-rockchip.c index e342a6dc4c6c..f91e876fd969 100644 --- a/drivers/gpio/gpio-rockchip.c +++ b/drivers/gpio/gpio-rockchip.c @@ -27,6 +27,7 @@ #define GPIO_TYPE_V1 (0) /* GPIO Version ID reserved */ #define GPIO_TYPE_V2 (0x01000C2B) /* GPIO Version ID 0x01000C2B */ +#define GPIO_TYPE_V2_1 (0x0101157C) /* GPIO Version ID 0x0101157C */ static const struct rockchip_gpio_regs gpio_regs_v1 = { .port_dr = 0x00, @@ -664,7 +665,7 @@ static int rockchip_get_bank_data(struct rockchip_pin_bank *bank) id = readl(bank->reg_base + gpio_regs_v2.version_id); /* If not gpio v2, that is default to v1. */ - if (id == GPIO_TYPE_V2) { + if (id == GPIO_TYPE_V2 || id == GPIO_TYPE_V2_1) { bank->gpio_regs = &gpio_regs_v2; bank->gpio_type = GPIO_TYPE_V2; bank->db_clk = of_clk_get(bank->of_node, 1); From 4a40ccccb660d9e62fe9f4a157be8d3c3a5ca013 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 28 Jun 2022 22:39:03 +0300 Subject: [PATCH 1134/1436] gpio: adp5588: Switch from of headers to mod_devicetable.h There is nothing directly using of specific interfaces in this driver, so lets not include the headers. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-adp5588.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index e388e75103f4..51ed23ba4645 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -6,7 +6,6 @@ * Copyright 2009-2010 Analog Devices Inc. */ -#include #include #include #include @@ -14,7 +13,8 @@ #include #include #include -#include +#include +#include #include @@ -427,18 +427,16 @@ static const struct i2c_device_id adp5588_gpio_id[] = { }; MODULE_DEVICE_TABLE(i2c, adp5588_gpio_id); -#ifdef CONFIG_OF static const struct of_device_id adp5588_gpio_of_id[] = { { .compatible = "adi," DRV_NAME, }, {}, }; MODULE_DEVICE_TABLE(of, adp5588_gpio_of_id); -#endif static struct i2c_driver adp5588_gpio_driver = { .driver = { .name = DRV_NAME, - .of_match_table = of_match_ptr(adp5588_gpio_of_id), + .of_match_table = adp5588_gpio_of_id, }, .probe_new = adp5588_gpio_probe, .remove = adp5588_gpio_remove, From 669f5618feb8b4847f3a64d541cfae22e999a91a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 28 Jun 2022 22:39:04 +0300 Subject: [PATCH 1135/1436] gpio: adp5588: Do not use defined value for driver name and compatible It's wrong to use defined string literal for three semantically different cases, i.e.: 1) compatible string, which is part of ABI and has to have specific format; 2) I2C ID, which is user space visible and also ABI; 3) driver name, that can be changed. Drop the define and use appropriate string literals in place. While at it, drop comma at terminator entry of OF ID table. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-adp5588.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 51ed23ba4645..d6a229a67044 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -18,8 +18,6 @@ #include -#define DRV_NAME "adp5588-gpio" - /* * Early pre 4.0 Silicon required to delay readout by at least 25ms, * since the Event Counter Register updated 25ms after the interrupt @@ -422,20 +420,20 @@ static int adp5588_gpio_remove(struct i2c_client *client) } static const struct i2c_device_id adp5588_gpio_id[] = { - {DRV_NAME, 0}, + { "adp5588-gpio" }, {} }; MODULE_DEVICE_TABLE(i2c, adp5588_gpio_id); static const struct of_device_id adp5588_gpio_of_id[] = { - { .compatible = "adi," DRV_NAME, }, - {}, + { .compatible = "adi,adp5588-gpio" }, + {} }; MODULE_DEVICE_TABLE(of, adp5588_gpio_of_id); static struct i2c_driver adp5588_gpio_driver = { .driver = { - .name = DRV_NAME, + .name = "adp5588-gpio", .of_match_table = adp5588_gpio_of_id, }, .probe_new = adp5588_gpio_probe, From 6169d76c56b30e57fcb080206edd5324d9cea296 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 28 Jun 2022 22:39:05 +0300 Subject: [PATCH 1136/1436] gpio: adp5588: sort header inclusion alphabetically Sort header inclusion alphabetically. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-adp5588.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index d6a229a67044..d49f12560cde 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -6,15 +6,15 @@ * Copyright 2009-2010 Analog Devices Inc. */ -#include -#include -#include -#include #include +#include +#include #include #include +#include #include #include +#include #include From 597a8a888d349c3804e92ef087646bd9a89fe53d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 29 Jun 2022 14:30:58 +0300 Subject: [PATCH 1137/1436] gpiolib: of: Use device_match_of_node() helper Instead of open coding, use device_match_of_node() helper. Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 3d6c3ffd5576..23b8de98bf7c 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -720,7 +720,7 @@ static void of_gpiochip_remove_hog(struct gpio_chip *chip, static int of_gpiochip_match_node(struct gpio_chip *chip, void *data) { - return chip->gpiodev->dev.of_node == data; + return device_match_of_node(&chip->gpiodev->dev, data); } static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np) From 13e024b66ca1f72b383f141b43cfa4e1140cedd1 Mon Sep 17 00:00:00 2001 From: Shinyzenith Date: Mon, 11 Jul 2022 10:59:35 +0530 Subject: [PATCH 1138/1436] gpio: lp3943: unsigned to unsigned int cleanup Getting rid of checkpatch findings. No functional changes. Signed-off-by: Shinyzenith Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-lp3943.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpio/gpio-lp3943.c b/drivers/gpio/gpio-lp3943.c index 8a30fb185aab..79edd5db49d2 100644 --- a/drivers/gpio/gpio-lp3943.c +++ b/drivers/gpio/gpio-lp3943.c @@ -42,7 +42,7 @@ struct lp3943_gpio { u16 input_mask; /* 1 = GPIO is input direction, 0 = output */ }; -static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset) +static int lp3943_gpio_request(struct gpio_chip *chip, unsigned int offset) { struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); struct lp3943 *lp3943 = lp3943_gpio->lp3943; @@ -54,7 +54,7 @@ static int lp3943_gpio_request(struct gpio_chip *chip, unsigned offset) return 0; } -static void lp3943_gpio_free(struct gpio_chip *chip, unsigned offset) +static void lp3943_gpio_free(struct gpio_chip *chip, unsigned int offset) { struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); struct lp3943 *lp3943 = lp3943_gpio->lp3943; @@ -72,7 +72,7 @@ static int lp3943_gpio_set_mode(struct lp3943_gpio *lp3943_gpio, u8 offset, val << mux[offset].shift); } -static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); @@ -82,7 +82,7 @@ static int lp3943_gpio_direction_input(struct gpio_chip *chip, unsigned offset) } static int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio, - struct gpio_chip *chip, unsigned offset) + struct gpio_chip *chip, unsigned int offset) { u8 addr, read; int err; @@ -107,7 +107,7 @@ static int lp3943_get_gpio_in_status(struct lp3943_gpio *lp3943_gpio, } static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio, - struct gpio_chip *chip, unsigned offset) + struct gpio_chip *chip, unsigned int offset) { struct lp3943 *lp3943 = lp3943_gpio->lp3943; const struct lp3943_reg_cfg *mux = lp3943->mux_cfg; @@ -128,7 +128,7 @@ static int lp3943_get_gpio_out_status(struct lp3943_gpio *lp3943_gpio, return -EINVAL; } -static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset) +static int lp3943_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); @@ -147,7 +147,7 @@ static int lp3943_gpio_get(struct gpio_chip *chip, unsigned offset) return lp3943_get_gpio_out_status(lp3943_gpio, chip, offset); } -static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static void lp3943_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); u8 data; @@ -160,7 +160,7 @@ static void lp3943_gpio_set(struct gpio_chip *chip, unsigned offset, int value) lp3943_gpio_set_mode(lp3943_gpio, offset, data); } -static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned offset, +static int lp3943_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) { struct lp3943_gpio *lp3943_gpio = gpiochip_get_data(chip); From 6b7e8c796de0a0f1089c818097b9cd65817a2834 Mon Sep 17 00:00:00 2001 From: Aparna M Date: Fri, 8 Jul 2022 21:28:19 +0530 Subject: [PATCH 1139/1436] dt-bindings: gpio: Convert TI TPIC2810 GPIO Controller bindings to YAML Convert gpio-tpic2810 bindings to yaml format and remove outdated bindings in .txt format. Signed-off-by: Aparna M Reviewed-by: Rob Herring Reviewed-by: Linus Walleij Signed-off-by: Vignesh Raghavendra Signed-off-by: Bartosz Golaszewski --- .../bindings/gpio/gpio-tpic2810.txt | 16 ------ .../bindings/gpio/gpio-tpic2810.yaml | 51 +++++++++++++++++++ 2 files changed, 51 insertions(+), 16 deletions(-) delete mode 100644 Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt create mode 100644 Documentation/devicetree/bindings/gpio/gpio-tpic2810.yaml diff --git a/Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt b/Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt deleted file mode 100644 index 1afc2de7a537..000000000000 --- a/Documentation/devicetree/bindings/gpio/gpio-tpic2810.txt +++ /dev/null @@ -1,16 +0,0 @@ -TPIC2810 GPIO controller bindings - -Required properties: - - compatible : Should be "ti,tpic2810". - - reg : The I2C address of the device - - gpio-controller : Marks the device node as a GPIO controller. - - #gpio-cells : Should be two. For consumer use see gpio.txt. - -Example: - - gpio@60 { - compatible = "ti,tpic2810"; - reg = <0x60>; - gpio-controller; - #gpio-cells = <2>; - }; diff --git a/Documentation/devicetree/bindings/gpio/gpio-tpic2810.yaml b/Documentation/devicetree/bindings/gpio/gpio-tpic2810.yaml new file mode 100644 index 000000000000..cb8a5c376e1e --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-tpic2810.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/gpio-tpic2810.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TPIC2810 GPIO controller bindings + +maintainers: + - Aswath Govindraju + +properties: + compatible: + enum: + - ti,tpic2810 + + reg: + maxItems: 1 + + gpio-controller: true + + "#gpio-cells": + const: 2 + + gpio-line-names: + minItems: 1 + maxItems: 32 + +required: + - compatible + - reg + - gpio-controller + - "#gpio-cells" + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + gpio@60 { + compatible = "ti,tpic2810"; + reg = <0x60>; + gpio-controller; + #gpio-cells = <2>; + gpio-line-names = "LED A", "LED B", "LED C"; + }; + }; From 5d07a692f9562f9c06e62cce369e9dd108173a0f Mon Sep 17 00:00:00 2001 From: Liang He Date: Mon, 11 Jul 2022 20:52:38 +0800 Subject: [PATCH 1140/1436] gpio: gpiolib-of: Fix refcount bugs in of_mm_gpiochip_add_data() We should use of_node_get() when a new reference of device_node is created. It is noted that the old reference stored in 'mm_gc->gc.of_node' should also be decreased. This patch is based on the fact that there is a call site in function 'qe_add_gpiochips()' of src file 'drivers\soc\fsl\qe\gpio.c'. In this function, of_mm_gpiochip_add_data() is contained in an iteration of for_each_compatible_node() which will automatically increase and decrease the refcount. So we need additional of_node_get() for the reference escape in of_mm_gpiochip_add_data(). Fixes: a19e3da5bc5f ("of/gpio: Kill of_gpio_chip and add members directly to gpio_chip") Signed-off-by: Liang He Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-of.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 23b8de98bf7c..f80307be37d5 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -860,7 +860,8 @@ int of_mm_gpiochip_add_data(struct device_node *np, if (mm_gc->save_regs) mm_gc->save_regs(mm_gc); - mm_gc->gc.of_node = np; + of_node_put(mm_gc->gc.of_node); + mm_gc->gc.of_node = of_node_get(np); ret = gpiochip_add_data(gc, data); if (ret) @@ -868,6 +869,7 @@ int of_mm_gpiochip_add_data(struct device_node *np, return 0; err2: + of_node_put(np); iounmap(mm_gc->regs); err1: kfree(gc->label); From b06d7b458a6eace1cebd0c1e4a235407824125e8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 11 Jul 2022 10:36:35 +0200 Subject: [PATCH 1141/1436] gpio: GPIO_SAMA5D2_PIOBU should depend on ARCH_AT91 The SAMA5D2 PIOBU is only present on some AT91/Microchip SoCs. Hence add a dependency on ARCH_AT91, to prevent asking the user about this driver when configuring a kernel without AT91/Microchip SoC support. Signed-off-by: Geert Uytterhoeven Acked-by: Nicolas Ferre Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b01961999ced..1d9316cecacd 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -544,6 +544,7 @@ config GPIO_SAMA5D2_PIOBU tristate "SAMA5D2 PIOBU GPIO support" depends on MFD_SYSCON depends on OF_GPIO + depends on ARCH_AT91 || COMPILE_TEST select GPIO_SYSCON help Say yes here to use the PIOBU pins as GPIOs. From 3e2d53b2734bea05dba4f8fa94332ad6dd343712 Mon Sep 17 00:00:00 2001 From: Aakash Sen Sharma Date: Mon, 11 Jul 2022 19:47:53 +0530 Subject: [PATCH 1142/1436] gpio: 104-idi-48: unsigned to unsigned int cleanup Remove checkpatch warnings. No functional changes. Signed-off-by: Aakash Sen Sharma Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-104-idi-48.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index 9521ece3ebef..c1e4c3629e17 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -51,23 +51,23 @@ struct idi_48_gpio { unsigned char cos_enb; }; -static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +static int idi_48_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { return GPIO_LINE_DIRECTION_IN; } -static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { return 0; } -static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset) +static int idi_48_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - unsigned i; + unsigned int i; static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 }; void __iomem *port_addr; - unsigned mask; + unsigned int mask; for (i = 0; i < 48; i += 8) if (offset < i + 8) { @@ -112,10 +112,10 @@ static void idi_48_irq_mask(struct irq_data *data) { struct gpio_chip *chip = irq_data_get_irq_chip_data(data); struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - const unsigned offset = irqd_to_hwirq(data); - unsigned i; - unsigned mask; - unsigned boundary; + const unsigned int offset = irqd_to_hwirq(data); + unsigned int i; + unsigned int mask; + unsigned int boundary; unsigned long flags; for (i = 0; i < 48; i += 8) @@ -143,11 +143,11 @@ static void idi_48_irq_unmask(struct irq_data *data) { struct gpio_chip *chip = irq_data_get_irq_chip_data(data); struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - const unsigned offset = irqd_to_hwirq(data); - unsigned i; - unsigned mask; - unsigned boundary; - unsigned prev_irq_mask; + const unsigned int offset = irqd_to_hwirq(data); + unsigned int i; + unsigned int mask; + unsigned int boundary; + unsigned int prev_irq_mask; unsigned long flags; for (i = 0; i < 48; i += 8) @@ -172,7 +172,7 @@ static void idi_48_irq_unmask(struct irq_data *data) } } -static int idi_48_irq_set_type(struct irq_data *data, unsigned flow_type) +static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type) { /* The only valid irq types are none and both-edges */ if (flow_type != IRQ_TYPE_NONE && From 160d6e402900672d4b0689a7c939be487460a1fe Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Thu, 14 Jul 2022 10:03:14 +0800 Subject: [PATCH 1143/1436] gpiolib: cdev: simplify linereq_free The edge detector is only ever started after the line desc has been determined, so move edge_detector_stop() inside the line desc check, and merge the two checked regions into one. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Acked-by: Dipen Patel Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-cdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 0c9a63becfef..b44526e3630e 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -1460,15 +1460,15 @@ static ssize_t linereq_read(struct file *file, static void linereq_free(struct linereq *lr) { unsigned int i; - bool hte = false; + bool hte; for (i = 0; i < lr->num_lines; i++) { - if (lr->lines[i].desc) + if (lr->lines[i].desc) { hte = !!test_bit(FLAG_EVENT_CLOCK_HTE, &lr->lines[i].desc->flags); - edge_detector_stop(&lr->lines[i], hte); - if (lr->lines[i].desc) + edge_detector_stop(&lr->lines[i], hte); gpiod_free(lr->lines[i].desc); + } } kfifo_free(&lr->events); kfree(lr->label); From 2487a812236cdeecd0729cfc673fa352db44da5d Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Thu, 14 Jul 2022 10:03:15 +0800 Subject: [PATCH 1144/1436] gpiolib: cdev: simplify parameter in call to hte_edge_setup Improve readability by using the GPIO_V2_LINE_FLAG_EDGE_BOTH instead of combining the rising and falling edge flags. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Acked-by: Dipen Patel Tested-by: Dipen Patel Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-cdev.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index b44526e3630e..f635bbbb6a6d 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -885,9 +885,7 @@ static int debounce_setup(struct line *line, return ret; line->irq = irq; } else { - ret = hte_edge_setup(line, - GPIO_V2_LINE_FLAG_EDGE_RISING | - GPIO_V2_LINE_FLAG_EDGE_FALLING); + ret = hte_edge_setup(line, GPIO_V2_LINE_FLAG_EDGE_BOTH); if (ret) return ret; } From cfa53463ac62d30e4f30ec6e171b9228689d5a83 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Thu, 14 Jul 2022 10:03:16 +0800 Subject: [PATCH 1145/1436] gpiolib: cdev: replace if-else chains with switches Improve readability by replacing if-else chains with switch statements. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-cdev.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index f635bbbb6a6d..bc7c8822ede0 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -588,7 +588,8 @@ static enum hte_return process_hw_ts_thread(void *p) le.timestamp_ns = line->timestamp_ns; eflags = READ_ONCE(line->eflags); - if (eflags == GPIO_V2_LINE_FLAG_EDGE_BOTH) { + switch (eflags) { + case GPIO_V2_LINE_FLAG_EDGE_BOTH: if (line->raw_level >= 0) { if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags)) level = !line->raw_level; @@ -602,13 +603,16 @@ static enum hte_return process_hw_ts_thread(void *p) le.id = GPIO_V2_LINE_EVENT_RISING_EDGE; else le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; - } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) { + break; + case GPIO_V2_LINE_FLAG_EDGE_RISING: /* Emit low-to-high event */ le.id = GPIO_V2_LINE_EVENT_RISING_EDGE; - } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) { + break; + case GPIO_V2_LINE_FLAG_EDGE_FALLING: /* Emit high-to-low event */ le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; - } else { + break; + default: return HTE_CB_HANDLED; } le.line_seqno = line->line_seqno; @@ -660,7 +664,6 @@ static irqreturn_t edge_irq_thread(int irq, void *p) struct line *line = p; struct linereq *lr = line->req; struct gpio_v2_line_event le; - u64 eflags; /* Do not leak kernel stack to userspace */ memset(&le, 0, sizeof(le)); @@ -679,23 +682,25 @@ static irqreturn_t edge_irq_thread(int irq, void *p) } line->timestamp_ns = 0; - eflags = READ_ONCE(line->eflags); - if (eflags == GPIO_V2_LINE_FLAG_EDGE_BOTH) { - int level = gpiod_get_value_cansleep(line->desc); - - if (level) + switch (READ_ONCE(line->eflags)) { + case GPIO_V2_LINE_FLAG_EDGE_BOTH: + if (gpiod_get_value_cansleep(line->desc)) /* Emit low-to-high event */ le.id = GPIO_V2_LINE_EVENT_RISING_EDGE; else /* Emit high-to-low event */ le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; - } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_RISING) { + + break; + case GPIO_V2_LINE_FLAG_EDGE_RISING: /* Emit low-to-high event */ le.id = GPIO_V2_LINE_EVENT_RISING_EDGE; - } else if (eflags == GPIO_V2_LINE_FLAG_EDGE_FALLING) { + break; + case GPIO_V2_LINE_FLAG_EDGE_FALLING: /* Emit high-to-low event */ le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; - } else { + break; + default: return IRQ_NONE; } line->line_seqno++; From 242202329f0d851f64901111217ca4d52795a4b6 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Thu, 14 Jul 2022 10:03:17 +0800 Subject: [PATCH 1146/1436] gpiolib: cdev: simplify line event identification Reorganise line event identification code to reduce code duplication, and replace if-else initializers with a helper function to improve readability. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij --- drivers/gpio/gpiolib-cdev.c | 44 +++++++++++++------------------------ 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index bc7c8822ede0..5765379f4b54 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -569,6 +569,12 @@ static u64 line_event_timestamp(struct line *line) return ktime_get_ns(); } +static u32 line_event_id(int level) +{ + return level ? GPIO_V2_LINE_EVENT_RISING_EDGE : + GPIO_V2_LINE_EVENT_FALLING_EDGE; +} + static enum hte_return process_hw_ts_thread(void *p) { struct line *line; @@ -590,26 +596,19 @@ static enum hte_return process_hw_ts_thread(void *p) switch (eflags) { case GPIO_V2_LINE_FLAG_EDGE_BOTH: - if (line->raw_level >= 0) { - if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags)) - level = !line->raw_level; - else - level = line->raw_level; - } else { - level = gpiod_get_value_cansleep(line->desc); - } + level = (line->raw_level >= 0) ? + line->raw_level : + gpiod_get_raw_value_cansleep(line->desc); - if (level) - le.id = GPIO_V2_LINE_EVENT_RISING_EDGE; - else - le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; + if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags)) + level = !level; + + le.id = line_event_id(level); break; case GPIO_V2_LINE_FLAG_EDGE_RISING: - /* Emit low-to-high event */ le.id = GPIO_V2_LINE_EVENT_RISING_EDGE; break; case GPIO_V2_LINE_FLAG_EDGE_FALLING: - /* Emit high-to-low event */ le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; break; default: @@ -684,20 +683,12 @@ static irqreturn_t edge_irq_thread(int irq, void *p) switch (READ_ONCE(line->eflags)) { case GPIO_V2_LINE_FLAG_EDGE_BOTH: - if (gpiod_get_value_cansleep(line->desc)) - /* Emit low-to-high event */ - le.id = GPIO_V2_LINE_EVENT_RISING_EDGE; - else - /* Emit high-to-low event */ - le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; - + le.id = line_event_id(gpiod_get_value_cansleep(line->desc)); break; case GPIO_V2_LINE_FLAG_EDGE_RISING: - /* Emit low-to-high event */ le.id = GPIO_V2_LINE_EVENT_RISING_EDGE; break; case GPIO_V2_LINE_FLAG_EDGE_FALLING: - /* Emit high-to-low event */ le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; break; default: @@ -821,12 +812,7 @@ static void debounce_work_func(struct work_struct *work) le.line_seqno : atomic_inc_return(&lr->seqno); } - if (level) - /* Emit low-to-high event */ - le.id = GPIO_V2_LINE_EVENT_RISING_EDGE; - else - /* Emit high-to-low event */ - le.id = GPIO_V2_LINE_EVENT_FALLING_EDGE; + le.id = line_event_id(level); linereq_put_event(lr, &le); } From b1a92e94560def63b71057d770e9db2f798ab58c Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Thu, 14 Jul 2022 10:03:18 +0800 Subject: [PATCH 1147/1436] gpiolib: cdev: consolidate edge detector configuration flags Combine the polarity_change flag, struct line eflags, and hte enable flag into a single flag variable. The combination of these flags describes the configuration state of the edge detector, so formalize and clarify that by combining them into a single variable, edflags, in struct line. The edflags is a subset of the GPIO_V2_LINE_FLAGsb relevant to the edge detector, and is also a superset of the eflags it replaces. The eflags name is still used to describe the subset of edflags corresponding to the rising/falling edge flags where edflags is masked down to that subset. This consolidation reduces the number of variables being passed, simplifies state comparisons, and provides a more extensible foundation should additional edge sources be integrated in the future. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-cdev.c | 126 +++++++++++++++++------------------- 1 file changed, 60 insertions(+), 66 deletions(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 5765379f4b54..01c76aa00701 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -430,12 +430,15 @@ struct line { struct linereq *req; unsigned int irq; /* - * eflags is set by edge_detector_setup(), edge_detector_stop() and - * edge_detector_update(), which are themselves mutually exclusive, - * and is accessed by edge_irq_thread() and debounce_work_func(), - * which can both live with a slightly stale value. + * The flags for the active edge detector configuration. + * + * edflags is set by linereq_create(), linereq_free(), and + * linereq_set_config_unlocked(), which are themselves mutually + * exclusive, and is accessed by edge_irq_thread(), + * process_hw_ts_thread() and debounce_work_func(), + * which can all live with a slightly stale value. */ - u64 eflags; + u64 edflags; /* * timestamp_ns and req_seqno are accessed only by * edge_irq_handler() and edge_irq_thread(), which are themselves @@ -541,6 +544,12 @@ struct linereq { GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \ GPIO_V2_LINE_BIAS_FLAGS) +/* subset of flags relevant for edge detector configuration */ +#define GPIO_V2_LINE_EDGE_DETECTOR_FLAGS \ + (GPIO_V2_LINE_FLAG_ACTIVE_LOW | \ + GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE | \ + GPIO_V2_LINE_EDGE_FLAGS) + static void linereq_put_event(struct linereq *lr, struct gpio_v2_line_event *le) { @@ -580,8 +589,8 @@ static enum hte_return process_hw_ts_thread(void *p) struct line *line; struct linereq *lr; struct gpio_v2_line_event le; + u64 edflags; int level; - u64 eflags; if (!p) return HTE_CB_HANDLED; @@ -592,15 +601,15 @@ static enum hte_return process_hw_ts_thread(void *p) memset(&le, 0, sizeof(le)); le.timestamp_ns = line->timestamp_ns; - eflags = READ_ONCE(line->eflags); + edflags = READ_ONCE(line->edflags); - switch (eflags) { + switch (edflags & GPIO_V2_LINE_EDGE_FLAGS) { case GPIO_V2_LINE_FLAG_EDGE_BOTH: level = (line->raw_level >= 0) ? line->raw_level : gpiod_get_raw_value_cansleep(line->desc); - if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags)) + if (edflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) level = !level; le.id = line_event_id(level); @@ -681,7 +690,7 @@ static irqreturn_t edge_irq_thread(int irq, void *p) } line->timestamp_ns = 0; - switch (READ_ONCE(line->eflags)) { + switch (READ_ONCE(line->edflags) & GPIO_V2_LINE_EDGE_FLAGS) { case GPIO_V2_LINE_FLAG_EDGE_BOTH: le.id = line_event_id(gpiod_get_value_cansleep(line->desc)); break; @@ -756,16 +765,13 @@ static void debounce_work_func(struct work_struct *work) struct gpio_v2_line_event le; struct line *line = container_of(work, struct line, work.work); struct linereq *lr; - int level, diff_seqno; - u64 eflags; + u64 eflags, edflags = READ_ONCE(line->edflags); + int level = -1, diff_seqno; - if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) { + if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) level = line->raw_level; - if (level < 0) - level = gpiod_get_raw_value_cansleep(line->desc); - } else { + if (level < 0) level = gpiod_get_raw_value_cansleep(line->desc); - } if (level < 0) { pr_debug_ratelimited("debouncer failed to read line value\n"); return; @@ -777,12 +783,12 @@ static void debounce_work_func(struct work_struct *work) WRITE_ONCE(line->level, level); /* -- edge detection -- */ - eflags = READ_ONCE(line->eflags); + eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS; if (!eflags) return; /* switch from physical level to logical - if they differ */ - if (test_bit(FLAG_ACTIVE_LOW, &line->desc->flags)) + if (edflags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) level = !level; /* ignore edges that are not being monitored */ @@ -796,7 +802,7 @@ static void debounce_work_func(struct work_struct *work) lr = line->req; le.timestamp_ns = line_event_timestamp(line); le.offset = gpio_chip_hwgpio(line->desc); - if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) { + if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) { /* discard events except the last one */ line->total_discard_seq -= 1; diff_seqno = line->last_seqno - line->total_discard_seq - @@ -843,8 +849,7 @@ static int hte_edge_setup(struct line *line, u64 eflags) process_hw_ts_thread, line); } -static int debounce_setup(struct line *line, - unsigned int debounce_period_us, bool hte_req) +static int debounce_setup(struct line *line, unsigned int debounce_period_us) { unsigned long irqflags; int ret, level, irq; @@ -864,7 +869,7 @@ static int debounce_setup(struct line *line, if (level < 0) return level; - if (!hte_req) { + if (!test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) { irq = gpiod_to_irq(line->desc); if (irq < 0) return -ENXIO; @@ -915,19 +920,19 @@ static u32 gpio_v2_line_config_debounce_period(struct gpio_v2_line_config *lc, return 0; } -static void edge_detector_stop(struct line *line, bool hte_en) +static void edge_detector_stop(struct line *line) { - if (line->irq && !hte_en) { + if (line->irq) { free_irq(line->irq, line); line->irq = 0; } - if (hte_en) + if (READ_ONCE(line->edflags) & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) hte_ts_put(&line->hdesc); cancel_delayed_work_sync(&line->work); WRITE_ONCE(line->sw_debounced, 0); - WRITE_ONCE(line->eflags, 0); + WRITE_ONCE(line->edflags, 0); if (line->desc) WRITE_ONCE(line->desc->debounce_period_us, 0); /* do not change line->level - see comment in debounced_value() */ @@ -935,23 +940,23 @@ static void edge_detector_stop(struct line *line, bool hte_en) static int edge_detector_setup(struct line *line, struct gpio_v2_line_config *lc, - unsigned int line_idx, - u64 eflags, bool hte_req) + unsigned int line_idx, u64 edflags) { u32 debounce_period_us; unsigned long irqflags = 0; + u64 eflags; int irq, ret; + eflags = edflags & GPIO_V2_LINE_EDGE_FLAGS; if (eflags && !kfifo_initialized(&line->req->events)) { ret = kfifo_alloc(&line->req->events, line->req->event_buffer_size, GFP_KERNEL); if (ret) return ret; } - WRITE_ONCE(line->eflags, eflags); if (gpio_v2_line_config_debounced(lc, line_idx)) { debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx); - ret = debounce_setup(line, debounce_period_us, hte_req); + ret = debounce_setup(line, debounce_period_us); if (ret) return ret; WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); @@ -961,8 +966,8 @@ static int edge_detector_setup(struct line *line, if (!eflags || READ_ONCE(line->sw_debounced)) return 0; - if (hte_req) - return hte_edge_setup(line, eflags); + if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) + return hte_edge_setup(line, edflags); irq = gpiod_to_irq(line->desc); if (irq < 0) @@ -988,35 +993,29 @@ static int edge_detector_setup(struct line *line, static int edge_detector_update(struct line *line, struct gpio_v2_line_config *lc, - unsigned int line_idx, - u64 flags, bool polarity_change, - bool prev_hte_flag) + unsigned int line_idx, u64 edflags) { - u64 eflags = flags & GPIO_V2_LINE_EDGE_FLAGS; + u64 active_edflags = READ_ONCE(line->edflags); unsigned int debounce_period_us = gpio_v2_line_config_debounce_period(lc, line_idx); - bool hte_change = (prev_hte_flag != - ((flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) != 0)); - if ((READ_ONCE(line->eflags) == eflags) && !polarity_change && - (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us) - && !hte_change) + if ((active_edflags == edflags) && + (READ_ONCE(line->desc->debounce_period_us) == debounce_period_us)) return 0; /* sw debounced and still will be...*/ if (debounce_period_us && READ_ONCE(line->sw_debounced)) { - WRITE_ONCE(line->eflags, eflags); WRITE_ONCE(line->desc->debounce_period_us, debounce_period_us); return 0; } /* reconfiguring edge detection or sw debounce being disabled */ - if ((line->irq && !READ_ONCE(line->sw_debounced)) || prev_hte_flag || + if ((line->irq && !READ_ONCE(line->sw_debounced)) || + (active_edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) || (!debounce_period_us && READ_ONCE(line->sw_debounced))) - edge_detector_stop(line, prev_hte_flag); + edge_detector_stop(line); - return edge_detector_setup(line, lc, line_idx, eflags, - flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE); + return edge_detector_setup(line, lc, line_idx, edflags); } static u64 gpio_v2_line_config_flags(struct gpio_v2_line_config *lc, @@ -1285,22 +1284,17 @@ static long linereq_set_config_unlocked(struct linereq *lr, struct gpio_v2_line_config *lc) { struct gpio_desc *desc; + struct line *line; unsigned int i; - u64 flags; - bool polarity_change; - bool prev_hte_flag; + u64 flags, edflags; int ret; for (i = 0; i < lr->num_lines; i++) { + line = &lr->lines[i]; desc = lr->lines[i].desc; flags = gpio_v2_line_config_flags(lc, i); - polarity_change = - (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) != - ((flags & GPIO_V2_LINE_FLAG_ACTIVE_LOW) != 0)); - - prev_hte_flag = !!test_bit(FLAG_EVENT_CLOCK_HTE, &desc->flags); - gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags); + edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS; /* * Lines have to be requested explicitly for input * or output, else the line will be treated "as is". @@ -1308,7 +1302,7 @@ static long linereq_set_config_unlocked(struct linereq *lr, if (flags & GPIO_V2_LINE_FLAG_OUTPUT) { int val = gpio_v2_line_config_output_value(lc, i); - edge_detector_stop(&lr->lines[i], prev_hte_flag); + edge_detector_stop(line); ret = gpiod_direction_output(desc, val); if (ret) return ret; @@ -1317,12 +1311,13 @@ static long linereq_set_config_unlocked(struct linereq *lr, if (ret) return ret; - ret = edge_detector_update(&lr->lines[i], lc, i, - flags, polarity_change, prev_hte_flag); + ret = edge_detector_update(line, lc, i, edflags); if (ret) return ret; } + WRITE_ONCE(line->edflags, edflags); + blocking_notifier_call_chain(&desc->gdev->notifier, GPIO_V2_LINE_CHANGED_CONFIG, desc); @@ -1449,13 +1444,10 @@ static ssize_t linereq_read(struct file *file, static void linereq_free(struct linereq *lr) { unsigned int i; - bool hte; for (i = 0; i < lr->num_lines; i++) { if (lr->lines[i].desc) { - hte = !!test_bit(FLAG_EVENT_CLOCK_HTE, - &lr->lines[i].desc->flags); - edge_detector_stop(&lr->lines[i], hte); + edge_detector_stop(&lr->lines[i]); gpiod_free(lr->lines[i].desc); } } @@ -1491,7 +1483,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) struct gpio_v2_line_config *lc; struct linereq *lr; struct file *file; - u64 flags; + u64 flags, edflags; unsigned int i; int fd, ret; @@ -1565,6 +1557,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) if (ret < 0) goto out_free_linereq; + edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS; /* * Lines have to be requested explicitly for input * or output, else the line will be treated "as is". @@ -1581,12 +1574,13 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip) goto out_free_linereq; ret = edge_detector_setup(&lr->lines[i], lc, i, - flags & GPIO_V2_LINE_EDGE_FLAGS, - flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE); + edflags); if (ret) goto out_free_linereq; } + lr->lines[i].edflags = edflags; + blocking_notifier_call_chain(&desc->gdev->notifier, GPIO_V2_LINE_CHANGED_REQUESTED, desc); From 272ddba004731503cb6c30f2336dd501eaf25955 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Thu, 14 Jul 2022 10:03:19 +0800 Subject: [PATCH 1148/1436] gpiolib: cdev: compile out HTE unless CONFIG_HTE selected The majority of builds do not include HTE, so compile out hte functionality unless CONFIG_HTE is selected. Signed-off-by: Kent Gibson Reviewed-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-cdev.c | 98 ++++++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 35 deletions(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index 01c76aa00701..7e4670a286b2 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -468,9 +468,7 @@ struct line { * stale value. */ unsigned int level; - /* - * -- hte specific fields -- - */ +#ifdef CONFIG_HTE struct hte_ts_desc hdesc; /* * HTE provider sets line level at the time of event. The valid @@ -487,6 +485,7 @@ struct line { * last sequence number before debounce period expires. */ u32 last_seqno; +#endif /* CONFIG_HTE */ }; /** @@ -572,7 +571,8 @@ static u64 line_event_timestamp(struct line *line) { if (test_bit(FLAG_EVENT_CLOCK_REALTIME, &line->desc->flags)) return ktime_get_real_ns(); - else if (test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) + else if (IS_ENABLED(CONFIG_HTE) && + test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) return line->timestamp_ns; return ktime_get_ns(); @@ -584,6 +584,8 @@ static u32 line_event_id(int level) GPIO_V2_LINE_EVENT_FALLING_EDGE; } +#ifdef CONFIG_HTE + static enum hte_return process_hw_ts_thread(void *p) { struct line *line; @@ -667,6 +669,42 @@ static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p) return HTE_CB_HANDLED; } +static int hte_edge_setup(struct line *line, u64 eflags) +{ + int ret; + unsigned long flags = 0; + struct hte_ts_desc *hdesc = &line->hdesc; + + if (eflags & GPIO_V2_LINE_FLAG_EDGE_RISING) + flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ? + HTE_FALLING_EDGE_TS : + HTE_RISING_EDGE_TS; + if (eflags & GPIO_V2_LINE_FLAG_EDGE_FALLING) + flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ? + HTE_RISING_EDGE_TS : + HTE_FALLING_EDGE_TS; + + line->total_discard_seq = 0; + + hte_init_line_attr(hdesc, desc_to_gpio(line->desc), flags, NULL, + line->desc); + + ret = hte_ts_get(NULL, hdesc, 0); + if (ret) + return ret; + + return hte_request_ts_ns(hdesc, process_hw_ts, process_hw_ts_thread, + line); +} + +#else + +static int hte_edge_setup(struct line *line, u64 eflags) +{ + return 0; +} +#endif /* CONFIG_HTE */ + static irqreturn_t edge_irq_thread(int irq, void *p) { struct line *line = p; @@ -766,10 +804,13 @@ static void debounce_work_func(struct work_struct *work) struct line *line = container_of(work, struct line, work.work); struct linereq *lr; u64 eflags, edflags = READ_ONCE(line->edflags); - int level = -1, diff_seqno; + int level = -1; +#ifdef CONFIG_HTE + int diff_seqno; if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) level = line->raw_level; +#endif if (level < 0) level = gpiod_get_raw_value_cansleep(line->desc); if (level < 0) { @@ -802,6 +843,7 @@ static void debounce_work_func(struct work_struct *work) lr = line->req; le.timestamp_ns = line_event_timestamp(line); le.offset = gpio_chip_hwgpio(line->desc); +#ifdef CONFIG_HTE if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) { /* discard events except the last one */ line->total_discard_seq -= 1; @@ -811,7 +853,9 @@ static void debounce_work_func(struct work_struct *work) le.line_seqno = line->line_seqno; le.seqno = (lr->num_lines == 1) ? le.line_seqno : atomic_add_return(diff_seqno, &lr->seqno); - } else { + } else +#endif /* CONFIG_HTE */ + { line->line_seqno++; le.line_seqno = line->line_seqno; le.seqno = (lr->num_lines == 1) ? @@ -823,32 +867,6 @@ static void debounce_work_func(struct work_struct *work) linereq_put_event(lr, &le); } -static int hte_edge_setup(struct line *line, u64 eflags) -{ - int ret; - unsigned long flags = 0; - struct hte_ts_desc *hdesc = &line->hdesc; - - if (eflags & GPIO_V2_LINE_FLAG_EDGE_RISING) - flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ? - HTE_FALLING_EDGE_TS : HTE_RISING_EDGE_TS; - if (eflags & GPIO_V2_LINE_FLAG_EDGE_FALLING) - flags |= test_bit(FLAG_ACTIVE_LOW, &line->desc->flags) ? - HTE_RISING_EDGE_TS : HTE_FALLING_EDGE_TS; - - line->total_discard_seq = 0; - - hte_init_line_attr(hdesc, desc_to_gpio(line->desc), flags, - NULL, line->desc); - - ret = hte_ts_get(NULL, hdesc, 0); - if (ret) - return ret; - - return hte_request_ts_ns(hdesc, process_hw_ts, - process_hw_ts_thread, line); -} - static int debounce_setup(struct line *line, unsigned int debounce_period_us) { unsigned long irqflags; @@ -869,7 +887,8 @@ static int debounce_setup(struct line *line, unsigned int debounce_period_us) if (level < 0) return level; - if (!test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags)) { + if (!(IS_ENABLED(CONFIG_HTE) && + test_bit(FLAG_EVENT_CLOCK_HTE, &line->desc->flags))) { irq = gpiod_to_irq(line->desc); if (irq < 0) return -ENXIO; @@ -927,8 +946,10 @@ static void edge_detector_stop(struct line *line) line->irq = 0; } +#ifdef CONFIG_HTE if (READ_ONCE(line->edflags) & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) hte_ts_put(&line->hdesc); +#endif cancel_delayed_work_sync(&line->work); WRITE_ONCE(line->sw_debounced, 0); @@ -966,7 +987,8 @@ static int edge_detector_setup(struct line *line, if (!eflags || READ_ONCE(line->sw_debounced)) return 0; - if (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE) + if (IS_ENABLED(CONFIG_HTE) && + (edflags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE)) return hte_edge_setup(line, edflags); irq = gpiod_to_irq(line->desc); @@ -1051,6 +1073,11 @@ static int gpio_v2_line_flags_validate(u64 flags) /* Return an error if an unknown flag is set */ if (flags & ~GPIO_V2_LINE_VALID_FLAGS) return -EINVAL; + + if (!IS_ENABLED(CONFIG_HTE) && + (flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE)) + return -EOPNOTSUPP; + /* * Do not allow both INPUT and OUTPUT flags to be set as they are * contradictory. @@ -1060,7 +1087,8 @@ static int gpio_v2_line_flags_validate(u64 flags) return -EINVAL; /* Only allow one event clock source */ - if ((flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME) && + if (IS_ENABLED(CONFIG_HTE) && + (flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME) && (flags & GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE)) return -EINVAL; From 10fcd2f180bcbfb3392fcc98670baff81c61bcf2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Jul 2022 01:02:50 +0300 Subject: [PATCH 1149/1436] gpio: 74xx-mmio: Make use of device properties Convert the module to be property provider agnostic and allow it to be used on non-OF platforms. Add mod_devicetable.h include. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-74xx-mmio.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c index 173e06758e6c..5e3c948ddb73 100644 --- a/drivers/gpio/gpio-74xx-mmio.c +++ b/drivers/gpio/gpio-74xx-mmio.c @@ -6,10 +6,11 @@ */ #include -#include -#include #include +#include +#include #include +#include #define MMIO_74XX_DIR_IN (0 << 8) #define MMIO_74XX_DIR_OUT (1 << 8) @@ -112,7 +113,7 @@ static int mmio_74xx_gpio_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->flags = (uintptr_t)of_device_get_match_data(&pdev->dev); + priv->flags = (uintptr_t)device_get_match_data(&pdev->dev); dat = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dat)) From d3054ba1db6270e14245efa28dbd1cf10207d4f2 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Jul 2022 01:02:51 +0300 Subject: [PATCH 1150/1436] gpio: 74xx-mmio: Check MMIO_74XX_DIR_IN flag in mmio_74xx_dir_in() It's logically better to check the IN in ->direction_input() and _OUT in ->direction_output(). While at it, replace ternary with plain if-conditional for the sake of consistency with mmio_74xx_dir_out(). Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-74xx-mmio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c index 5e3c948ddb73..b2cc8a55c257 100644 --- a/drivers/gpio/gpio-74xx-mmio.c +++ b/drivers/gpio/gpio-74xx-mmio.c @@ -88,7 +88,10 @@ static int mmio_74xx_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct mmio_74xx_gpio_priv *priv = gpiochip_get_data(gc); - return (priv->flags & MMIO_74XX_DIR_OUT) ? -ENOTSUPP : 0; + if (priv->flags & MMIO_74XX_DIR_IN) + return 0; + + return -ENOTSUPP; } static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) From 28ba057456412794198ba6c953aa2042147c2de5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 19 Jul 2022 01:02:52 +0300 Subject: [PATCH 1151/1436] gpio: 74xx-mmio: use bits.h macros for all masks Make use of the GENMASK() (far less error-prone, far more concise). Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-74xx-mmio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c index b2cc8a55c257..cd399898ed12 100644 --- a/drivers/gpio/gpio-74xx-mmio.c +++ b/drivers/gpio/gpio-74xx-mmio.c @@ -5,6 +5,7 @@ * Copyright (C) 2014 Alexander Shiyan */ +#include #include #include #include @@ -14,7 +15,7 @@ #define MMIO_74XX_DIR_IN (0 << 8) #define MMIO_74XX_DIR_OUT (1 << 8) -#define MMIO_74XX_BIT_CNT(x) ((x) & 0xff) +#define MMIO_74XX_BIT_CNT(x) ((x) & GENMASK(7, 0)) struct mmio_74xx_gpio_priv { struct gpio_chip gc; From c269df8c5ad316eac47a9078e7a2339e1956637a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Wed, 13 Jul 2022 15:14:18 +0200 Subject: [PATCH 1152/1436] gpiolib: add support for bias pull disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change prepares the gpio core to look at firmware flags and set 'FLAG_BIAS_DISABLE' if necessary. It works in similar way to 'GPIO_PULL_DOWN' and 'GPIO_PULL_UP'. Signed-off-by: Nuno Sá Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 8 ++++++-- include/linux/gpio/machine.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9535f48e18d1..0692ec84d3b0 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3945,9 +3945,11 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, if (lflags & GPIO_OPEN_SOURCE) set_bit(FLAG_OPEN_SOURCE, &desc->flags); - if ((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DOWN)) { + if (((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DOWN)) || + ((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DISABLE)) || + ((lflags & GPIO_PULL_DOWN) && (lflags & GPIO_PULL_DISABLE))) { gpiod_err(desc, - "both pull-up and pull-down enabled, invalid configuration\n"); + "multiple pull-up, pull-down or pull-disable enabled, invalid configuration\n"); return -EINVAL; } @@ -3955,6 +3957,8 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, set_bit(FLAG_PULL_UP, &desc->flags); else if (lflags & GPIO_PULL_DOWN) set_bit(FLAG_PULL_DOWN, &desc->flags); + else if (lflags & GPIO_PULL_DISABLE) + set_bit(FLAG_BIAS_DISABLE, &desc->flags); ret = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY)); if (ret < 0) diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h index 4d55da28e664..0b619eb7ae83 100644 --- a/include/linux/gpio/machine.h +++ b/include/linux/gpio/machine.h @@ -14,6 +14,7 @@ enum gpio_lookup_flags { GPIO_TRANSITORY = (1 << 3), GPIO_PULL_UP = (1 << 4), GPIO_PULL_DOWN = (1 << 5), + GPIO_PULL_DISABLE = (1 << 6), GPIO_LOOKUP_FLAGS_DEFAULT = GPIO_ACTIVE_HIGH | GPIO_PERSISTENT, }; From 31bea23119cda87088c6bd4085a1e442c6c5974c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Wed, 13 Jul 2022 15:14:19 +0200 Subject: [PATCH 1153/1436] gpiolib: of: support bias pull disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On top of looking at PULL_UP and PULL_DOWN flags, also look at PULL_DISABLE and set the appropriate GPIO flag. The GPIO core will then pass down this to controllers that support it. Signed-off-by: Nuno Sá Reviewed-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-of.c | 7 +++++++ include/linux/of_gpio.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index f80307be37d5..a037b50bef33 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -354,6 +354,9 @@ struct gpio_desc *gpiod_get_from_of_node(const struct device_node *node, if (flags & OF_GPIO_PULL_DOWN) lflags |= GPIO_PULL_DOWN; + if (flags & OF_GPIO_PULL_DISABLE) + lflags |= GPIO_PULL_DISABLE; + ret = gpiod_configure_flags(desc, propname, lflags, dflags); if (ret < 0) { gpiod_put(desc); @@ -556,6 +559,8 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, *flags |= GPIO_PULL_UP; if (of_flags & OF_GPIO_PULL_DOWN) *flags |= GPIO_PULL_DOWN; + if (of_flags & OF_GPIO_PULL_DISABLE) + *flags |= GPIO_PULL_DISABLE; return desc; } @@ -621,6 +626,8 @@ static struct gpio_desc *of_parse_own_gpio(struct device_node *np, *lflags |= GPIO_PULL_UP; if (xlate_flags & OF_GPIO_PULL_DOWN) *lflags |= GPIO_PULL_DOWN; + if (xlate_flags & OF_GPIO_PULL_DISABLE) + *lflags |= GPIO_PULL_DISABLE; if (of_property_read_bool(np, "input")) *dflags |= GPIOD_IN; diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 8bf2ea859653..a5166eb93437 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -29,6 +29,7 @@ enum of_gpio_flags { OF_GPIO_TRANSITORY = 0x8, OF_GPIO_PULL_UP = 0x10, OF_GPIO_PULL_DOWN = 0x20, + OF_GPIO_PULL_DISABLE = 0x40, }; #ifdef CONFIG_OF_GPIO From 6fd03f0248281b690e168a5a5c22cb3c98b96326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Wed, 13 Jul 2022 15:14:20 +0200 Subject: [PATCH 1154/1436] gpiolib: acpi: support bias pull disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On top of looking at PULL_UP and PULL_DOWN flags, also look at PULL_DISABLE and set the appropriate GPIO flag. The GPIO core will then pass down this to controllers that support it. Signed-off-by: Nuno Sá Acked-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-acpi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index c2523ac26fac..9be1376f9a62 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -687,6 +687,9 @@ int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags, case ACPI_PIN_CONFIG_PULLDOWN: *lookupflags |= GPIO_PULL_DOWN; break; + case ACPI_PIN_CONFIG_NOPULL: + *lookupflags |= GPIO_PULL_DISABLE; + break; default: break; } From d042656a2170ce1b0d1a72d81a99bc93f0170358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20S=C3=A1?= Date: Wed, 13 Jul 2022 15:14:21 +0200 Subject: [PATCH 1155/1436] dt-bindings: gpio: add pull-disable flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This extends the flags that can be used in GPIO specifiers to indicate that no bias is intended in the pin. Signed-off-by: Nuno Sá Reviewed-by: Linus Walleij Acked-by: Rob Herring Signed-off-by: Bartosz Golaszewski --- include/dt-bindings/gpio/gpio.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/dt-bindings/gpio/gpio.h b/include/dt-bindings/gpio/gpio.h index c029467e828b..5566e58196a2 100644 --- a/include/dt-bindings/gpio/gpio.h +++ b/include/dt-bindings/gpio/gpio.h @@ -39,4 +39,7 @@ /* Bit 5 express pull down */ #define GPIO_PULL_DOWN 32 +/* Bit 6 express pull disable */ +#define GPIO_PULL_DISABLE 64 + #endif From c4371c56397340134c1827ab70dbf817dbb1b99b Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Fri, 15 Jul 2022 16:19:59 +0200 Subject: [PATCH 1156/1436] gpio: remove VR41XX related gpio driver Commit d3164e2f3b0a ("MIPS: Remove VR41xx support") removed support for MIPS VR41xx platform, so remove exclusive drivers for this platform, too. Signed-off-by: Thomas Bogendoerfer Acked-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 6 - drivers/gpio/Makefile | 1 - drivers/gpio/gpio-vr41xx.c | 541 ------------------------------------- 3 files changed, 548 deletions(-) delete mode 100644 drivers/gpio/gpio-vr41xx.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 1d9316cecacd..cf6a2c745f3f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -691,12 +691,6 @@ config GPIO_VISCONTI help Say yes here to support GPIO on Tohisba Visconti. -config GPIO_VR41XX - tristate "NEC VR4100 series General-purpose I/O Unit support" - depends on CPU_VR41XX - help - Say yes here to support the NEC VR4100 series General-purpose I/O Unit. - config GPIO_VX855 tristate "VIA VX855/VX875 GPIO" depends on (X86 || COMPILE_TEST) && PCI diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 14352f6dfe8e..9d4805b2b60b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -169,7 +169,6 @@ obj-$(CONFIG_GPIO_VF610) += gpio-vf610.o obj-$(CONFIG_GPIO_VIPERBOARD) += gpio-viperboard.o obj-$(CONFIG_GPIO_VIRTIO) += gpio-virtio.o obj-$(CONFIG_GPIO_VISCONTI) += gpio-visconti.o -obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_WCD934X) += gpio-wcd934x.o obj-$(CONFIG_GPIO_WHISKEY_COVE) += gpio-wcove.o diff --git a/drivers/gpio/gpio-vr41xx.c b/drivers/gpio/gpio-vr41xx.c deleted file mode 100644 index 8d09b619c166..000000000000 --- a/drivers/gpio/gpio-vr41xx.c +++ /dev/null @@ -1,541 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Driver for NEC VR4100 series General-purpose I/O Unit. - * - * Copyright (C) 2002 MontaVista Software Inc. - * Author: Yoichi Yuasa - * Copyright (C) 2003-2009 Yoichi Yuasa - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -MODULE_AUTHOR("Yoichi Yuasa "); -MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver"); -MODULE_LICENSE("GPL"); - -#define GIUIOSELL 0x00 -#define GIUIOSELH 0x02 -#define GIUPIODL 0x04 -#define GIUPIODH 0x06 -#define GIUINTSTATL 0x08 -#define GIUINTSTATH 0x0a -#define GIUINTENL 0x0c -#define GIUINTENH 0x0e -#define GIUINTTYPL 0x10 -#define GIUINTTYPH 0x12 -#define GIUINTALSELL 0x14 -#define GIUINTALSELH 0x16 -#define GIUINTHTSELL 0x18 -#define GIUINTHTSELH 0x1a -#define GIUPODATL 0x1c -#define GIUPODATEN 0x1c -#define GIUPODATH 0x1e - #define PIOEN0 0x0100 - #define PIOEN1 0x0200 -#define GIUPODAT 0x1e -#define GIUFEDGEINHL 0x20 -#define GIUFEDGEINHH 0x22 -#define GIUREDGEINHL 0x24 -#define GIUREDGEINHH 0x26 - -#define GIUUSEUPDN 0x1e0 -#define GIUTERMUPDN 0x1e2 - -#define GPIO_HAS_PULLUPDOWN_IO 0x0001 -#define GPIO_HAS_OUTPUT_ENABLE 0x0002 -#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100 - -enum { - GPIO_INPUT, - GPIO_OUTPUT, -}; - -static DEFINE_SPINLOCK(giu_lock); -static unsigned long giu_flags; - -static void __iomem *giu_base; -static struct gpio_chip vr41xx_gpio_chip; - -#define giu_read(offset) readw(giu_base + (offset)) -#define giu_write(offset, value) writew((value), giu_base + (offset)) - -#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE) -#define GIUINT_HIGH_OFFSET 16 -#define GIUINT_HIGH_MAX 32 - -static inline u16 giu_set(u16 offset, u16 set) -{ - u16 data; - - data = giu_read(offset); - data |= set; - giu_write(offset, data); - - return data; -} - -static inline u16 giu_clear(u16 offset, u16 clear) -{ - u16 data; - - data = giu_read(offset); - data &= ~clear; - giu_write(offset, data); - - return data; -} - -static void ack_giuint_low(struct irq_data *d) -{ - giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(d->irq)); -} - -static void mask_giuint_low(struct irq_data *d) -{ - giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq)); -} - -static void mask_ack_giuint_low(struct irq_data *d) -{ - unsigned int pin; - - pin = GPIO_PIN_OF_IRQ(d->irq); - giu_clear(GIUINTENL, 1 << pin); - giu_write(GIUINTSTATL, 1 << pin); -} - -static void unmask_giuint_low(struct irq_data *d) -{ - giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(d->irq)); -} - -static unsigned int startup_giuint(struct irq_data *data) -{ - int ret; - - ret = gpiochip_lock_as_irq(&vr41xx_gpio_chip, irqd_to_hwirq(data)); - if (ret) { - dev_err(vr41xx_gpio_chip.parent, - "unable to lock HW IRQ %lu for IRQ\n", - data->hwirq); - return ret; - } - - /* Satisfy the .enable semantics by unmasking the line */ - unmask_giuint_low(data); - return 0; -} - -static void shutdown_giuint(struct irq_data *data) -{ - mask_giuint_low(data); - gpiochip_unlock_as_irq(&vr41xx_gpio_chip, data->hwirq); -} - -static struct irq_chip giuint_low_irq_chip = { - .name = "GIUINTL", - .irq_ack = ack_giuint_low, - .irq_mask = mask_giuint_low, - .irq_mask_ack = mask_ack_giuint_low, - .irq_unmask = unmask_giuint_low, - .irq_startup = startup_giuint, - .irq_shutdown = shutdown_giuint, -}; - -static void ack_giuint_high(struct irq_data *d) -{ - giu_write(GIUINTSTATH, - 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET)); -} - -static void mask_giuint_high(struct irq_data *d) -{ - giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET)); -} - -static void mask_ack_giuint_high(struct irq_data *d) -{ - unsigned int pin; - - pin = GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET; - giu_clear(GIUINTENH, 1 << pin); - giu_write(GIUINTSTATH, 1 << pin); -} - -static void unmask_giuint_high(struct irq_data *d) -{ - giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET)); -} - -static struct irq_chip giuint_high_irq_chip = { - .name = "GIUINTH", - .irq_ack = ack_giuint_high, - .irq_mask = mask_giuint_high, - .irq_mask_ack = mask_ack_giuint_high, - .irq_unmask = unmask_giuint_high, -}; - -static int giu_get_irq(unsigned int irq) -{ - u16 pendl, pendh, maskl, maskh; - int i; - - pendl = giu_read(GIUINTSTATL); - pendh = giu_read(GIUINTSTATH); - maskl = giu_read(GIUINTENL); - maskh = giu_read(GIUINTENH); - - maskl &= pendl; - maskh &= pendh; - - if (maskl) { - for (i = 0; i < 16; i++) { - if (maskl & (1 << i)) - return GIU_IRQ(i); - } - } else if (maskh) { - for (i = 0; i < 16; i++) { - if (maskh & (1 << i)) - return GIU_IRQ(i + GIUINT_HIGH_OFFSET); - } - } - - printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", - maskl, pendl, maskh, pendh); - - return -EINVAL; -} - -void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, - irq_signal_t signal) -{ - u16 mask; - - if (pin < GIUINT_HIGH_OFFSET) { - mask = 1 << pin; - if (trigger != IRQ_TRIGGER_LEVEL) { - giu_set(GIUINTTYPL, mask); - if (signal == IRQ_SIGNAL_HOLD) - giu_set(GIUINTHTSELL, mask); - else - giu_clear(GIUINTHTSELL, mask); - if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { - switch (trigger) { - case IRQ_TRIGGER_EDGE_FALLING: - giu_set(GIUFEDGEINHL, mask); - giu_clear(GIUREDGEINHL, mask); - break; - case IRQ_TRIGGER_EDGE_RISING: - giu_clear(GIUFEDGEINHL, mask); - giu_set(GIUREDGEINHL, mask); - break; - default: - giu_set(GIUFEDGEINHL, mask); - giu_set(GIUREDGEINHL, mask); - break; - } - } - irq_set_chip_and_handler(GIU_IRQ(pin), - &giuint_low_irq_chip, - handle_edge_irq); - } else { - giu_clear(GIUINTTYPL, mask); - giu_clear(GIUINTHTSELL, mask); - irq_set_chip_and_handler(GIU_IRQ(pin), - &giuint_low_irq_chip, - handle_level_irq); - } - giu_write(GIUINTSTATL, mask); - } else if (pin < GIUINT_HIGH_MAX) { - mask = 1 << (pin - GIUINT_HIGH_OFFSET); - if (trigger != IRQ_TRIGGER_LEVEL) { - giu_set(GIUINTTYPH, mask); - if (signal == IRQ_SIGNAL_HOLD) - giu_set(GIUINTHTSELH, mask); - else - giu_clear(GIUINTHTSELH, mask); - if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { - switch (trigger) { - case IRQ_TRIGGER_EDGE_FALLING: - giu_set(GIUFEDGEINHH, mask); - giu_clear(GIUREDGEINHH, mask); - break; - case IRQ_TRIGGER_EDGE_RISING: - giu_clear(GIUFEDGEINHH, mask); - giu_set(GIUREDGEINHH, mask); - break; - default: - giu_set(GIUFEDGEINHH, mask); - giu_set(GIUREDGEINHH, mask); - break; - } - } - irq_set_chip_and_handler(GIU_IRQ(pin), - &giuint_high_irq_chip, - handle_edge_irq); - } else { - giu_clear(GIUINTTYPH, mask); - giu_clear(GIUINTHTSELH, mask); - irq_set_chip_and_handler(GIU_IRQ(pin), - &giuint_high_irq_chip, - handle_level_irq); - } - giu_write(GIUINTSTATH, mask); - } -} -EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger); - -void vr41xx_set_irq_level(unsigned int pin, irq_level_t level) -{ - u16 mask; - - if (pin < GIUINT_HIGH_OFFSET) { - mask = 1 << pin; - if (level == IRQ_LEVEL_HIGH) - giu_set(GIUINTALSELL, mask); - else - giu_clear(GIUINTALSELL, mask); - giu_write(GIUINTSTATL, mask); - } else if (pin < GIUINT_HIGH_MAX) { - mask = 1 << (pin - GIUINT_HIGH_OFFSET); - if (level == IRQ_LEVEL_HIGH) - giu_set(GIUINTALSELH, mask); - else - giu_clear(GIUINTALSELH, mask); - giu_write(GIUINTSTATH, mask); - } -} -EXPORT_SYMBOL_GPL(vr41xx_set_irq_level); - -static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir) -{ - u16 offset, mask, reg; - unsigned long flags; - - if (pin >= chip->ngpio) - return -EINVAL; - - if (pin < 16) { - offset = GIUIOSELL; - mask = 1 << pin; - } else if (pin < 32) { - offset = GIUIOSELH; - mask = 1 << (pin - 16); - } else { - if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) { - offset = GIUPODATEN; - mask = 1 << (pin - 32); - } else { - switch (pin) { - case 48: - offset = GIUPODATH; - mask = PIOEN0; - break; - case 49: - offset = GIUPODATH; - mask = PIOEN1; - break; - default: - return -EINVAL; - } - } - } - - spin_lock_irqsave(&giu_lock, flags); - - reg = giu_read(offset); - if (dir == GPIO_OUTPUT) - reg |= mask; - else - reg &= ~mask; - giu_write(offset, reg); - - spin_unlock_irqrestore(&giu_lock, flags); - - return 0; -} - -static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin) -{ - u16 reg, mask; - - if (pin >= chip->ngpio) - return -EINVAL; - - if (pin < 16) { - reg = giu_read(GIUPIODL); - mask = 1 << pin; - } else if (pin < 32) { - reg = giu_read(GIUPIODH); - mask = 1 << (pin - 16); - } else if (pin < 48) { - reg = giu_read(GIUPODATL); - mask = 1 << (pin - 32); - } else { - reg = giu_read(GIUPODATH); - mask = 1 << (pin - 48); - } - - if (reg & mask) - return 1; - - return 0; -} - -static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin, - int value) -{ - u16 offset, mask, reg; - unsigned long flags; - - if (pin >= chip->ngpio) - return; - - if (pin < 16) { - offset = GIUPIODL; - mask = 1 << pin; - } else if (pin < 32) { - offset = GIUPIODH; - mask = 1 << (pin - 16); - } else if (pin < 48) { - offset = GIUPODATL; - mask = 1 << (pin - 32); - } else { - offset = GIUPODATH; - mask = 1 << (pin - 48); - } - - spin_lock_irqsave(&giu_lock, flags); - - reg = giu_read(offset); - if (value) - reg |= mask; - else - reg &= ~mask; - giu_write(offset, reg); - - spin_unlock_irqrestore(&giu_lock, flags); -} - - -static int vr41xx_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - return giu_set_direction(chip, offset, GPIO_INPUT); -} - -static int vr41xx_gpio_direction_output(struct gpio_chip *chip, unsigned offset, - int value) -{ - vr41xx_gpio_set(chip, offset, value); - - return giu_set_direction(chip, offset, GPIO_OUTPUT); -} - -static int vr41xx_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - if (offset >= chip->ngpio) - return -EINVAL; - - return GIU_IRQ_BASE + offset; -} - -static struct gpio_chip vr41xx_gpio_chip = { - .label = "vr41xx", - .owner = THIS_MODULE, - .direction_input = vr41xx_gpio_direction_input, - .get = vr41xx_gpio_get, - .direction_output = vr41xx_gpio_direction_output, - .set = vr41xx_gpio_set, - .to_irq = vr41xx_gpio_to_irq, -}; - -static int giu_probe(struct platform_device *pdev) -{ - unsigned int trigger, i, pin; - struct irq_chip *chip; - int irq; - - switch (pdev->id) { - case GPIO_50PINS_PULLUPDOWN: - giu_flags = GPIO_HAS_PULLUPDOWN_IO; - vr41xx_gpio_chip.ngpio = 50; - break; - case GPIO_36PINS: - vr41xx_gpio_chip.ngpio = 36; - break; - case GPIO_48PINS_EDGE_SELECT: - giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT; - vr41xx_gpio_chip.ngpio = 48; - break; - default: - dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id); - return -ENODEV; - } - - giu_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(giu_base)) - return PTR_ERR(giu_base); - - vr41xx_gpio_chip.parent = &pdev->dev; - - if (gpiochip_add_data(&vr41xx_gpio_chip, NULL)) - return -ENODEV; - - giu_write(GIUINTENL, 0); - giu_write(GIUINTENH, 0); - - trigger = giu_read(GIUINTTYPH) << 16; - trigger |= giu_read(GIUINTTYPL); - for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { - pin = GPIO_PIN_OF_IRQ(i); - if (pin < GIUINT_HIGH_OFFSET) - chip = &giuint_low_irq_chip; - else - chip = &giuint_high_irq_chip; - - if (trigger & (1 << pin)) - irq_set_chip_and_handler(i, chip, handle_edge_irq); - else - irq_set_chip_and_handler(i, chip, handle_level_irq); - - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0 || irq >= nr_irqs) - return -EBUSY; - - return cascade_irq(irq, giu_get_irq); -} - -static int giu_remove(struct platform_device *pdev) -{ - if (giu_base) { - giu_base = NULL; - } - - return 0; -} - -static struct platform_driver giu_device_driver = { - .probe = giu_probe, - .remove = giu_remove, - .driver = { - .name = "GIU", - }, -}; - -module_platform_driver(giu_device_driver); From 829b4c4183c2201d2c3981d55bdaeec201ec4098 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 19 Jul 2022 13:56:32 +0200 Subject: [PATCH 1157/1436] Revert "platform/chrome: cros_ec_typec: Get retimer handle" This reverts commit c76d09da77d69d7f737540985912ad2bca654713. The chrome platform driver changes need to come in through the platform tree due to some api changes that showed up there that cause build errors in linux-next Reported-by: Stephen Rothwell Link: https://lore.kernel.org/r/20220719160821.5e68e30b@oak.ozlabs.ibm.com Cc: Prashant Malani Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_ec_typec.c | 44 ++----------------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 38c4ac754ea9..39e6fd4491a9 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -54,7 +53,6 @@ struct cros_typec_port { struct usb_pd_identity c_identity; struct typec_switch *ori_sw; struct typec_mux *mux; - struct typec_retimer *retimer; struct usb_role_switch *role_sw; /* Variables keeping track of switch state. */ @@ -144,12 +142,6 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port, goto mux_err; } - port->retimer = fwnode_typec_retimer_get(fwnode); - if (IS_ERR(port->retimer)) { - dev_dbg(dev, "Retimer handle not found.\n"); - goto retimer_sw_err; - } - port->ori_sw = fwnode_typec_switch_get(fwnode); if (IS_ERR(port->ori_sw)) { dev_dbg(dev, "Orientation switch handle not found.\n"); @@ -167,8 +159,6 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port, role_sw_err: typec_switch_put(port->ori_sw); ori_sw_err: - typec_retimer_put(port->retimer); -retimer_sw_err: typec_mux_put(port->mux); mux_err: return -ENODEV; @@ -213,21 +203,6 @@ static void cros_typec_unregister_altmodes(struct cros_typec_data *typec, int po } } -/* - * Map the Type-C Mux state to retimer state and call the retimer set function. We need this - * because we re-use the Type-C mux state for retimers. - */ -static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_mux_state state) -{ - struct typec_retimer_state rstate = { - .alt = state.alt, - .mode = state.mode, - .data = state.data, - }; - - return typec_retimer_set(retimer, &rstate); -} - static int cros_typec_usb_disconnect_state(struct cros_typec_port *port) { port->state.alt = NULL; @@ -236,7 +211,6 @@ static int cros_typec_usb_disconnect_state(struct cros_typec_port *port) usb_role_switch_set_role(port->role_sw, USB_ROLE_NONE); typec_switch_set(port->ori_sw, TYPEC_ORIENTATION_NONE); - cros_typec_retimer_set(port->retimer, port->state); return typec_mux_set(port->mux, &port->state); } @@ -407,14 +381,9 @@ unregister_ports: static int cros_typec_usb_safe_state(struct cros_typec_port *port) { - int ret; port->state.mode = TYPEC_STATE_SAFE; - ret = cros_typec_retimer_set(port->retimer, port->state); - if (!ret) - ret = typec_mux_set(port->mux, &port->state); - - return ret; + return typec_mux_set(port->mux, &port->state); } /* @@ -511,11 +480,7 @@ static int cros_typec_enable_dp(struct cros_typec_data *typec, port->state.data = &dp_data; port->state.mode = TYPEC_MODAL_STATE(ffs(pd_ctrl->dp_mode)); - ret = cros_typec_retimer_set(port->retimer, port->state); - if (!ret) - ret = typec_mux_set(port->mux, &port->state); - - return ret; + return typec_mux_set(port->mux, &port->state); } static int cros_typec_enable_usb4(struct cros_typec_data *typec, @@ -604,10 +569,7 @@ static int cros_typec_configure_mux(struct cros_typec_data *typec, int port_num, } else if (port->mux_flags & USB_PD_MUX_USB_ENABLED) { port->state.alt = NULL; port->state.mode = TYPEC_STATE_USB; - - ret = cros_typec_retimer_set(port->retimer, port->state); - if (!ret) - ret = typec_mux_set(port->mux, &port->state); + ret = typec_mux_set(port->mux, &port->state); } else { dev_dbg(typec->dev, "Unrecognized mode requested, mux flags: %x\n", From 9169d2fd1f5778295ec4934acd99dc7b35a83fd5 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 19 Jul 2022 13:56:40 +0200 Subject: [PATCH 1158/1436] Revert "platform/chrome: cros_ec_typec: Cleanup switch handle return paths" This reverts commit 66fe238a9bcc158f75ddecf976d1ce7efe20f713. The chrome platform driver changes need to come in through the platform tree due to some api changes that showed up there that cause build errors in linux-next Reported-by: Stephen Rothwell Link: https://lore.kernel.org/r/20220719160821.5e68e30b@oak.ozlabs.ibm.com Cc: Prashant Malani Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_ec_typec.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c index 39e6fd4491a9..7cb2e35c4ded 100644 --- a/drivers/platform/chrome/cros_ec_typec.c +++ b/drivers/platform/chrome/cros_ec_typec.c @@ -157,10 +157,12 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port, return 0; role_sw_err: - typec_switch_put(port->ori_sw); + usb_role_switch_put(port->role_sw); ori_sw_err: - typec_mux_put(port->mux); + typec_switch_put(port->ori_sw); mux_err: + typec_mux_put(port->mux); + return -ENODEV; } From 3838896d374929638bdb143dc33aee21931ef903 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 19 Jul 2022 13:56:46 +0200 Subject: [PATCH 1159/1436] Revert "platform/chrome: cros_typec_switch: Register mode switches" This reverts commit f5434e30011e011b24852959365b7cbc61dd8c85. The chrome platform driver changes need to come in through the platform tree due to some api changes that showed up there that cause build errors in linux-next Reported-by: Stephen Rothwell Link: https://lore.kernel.org/r/20220719160821.5e68e30b@oak.ozlabs.ibm.com Cc: Prashant Malani Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_typec_switch.c | 40 --------------------- 1 file changed, 40 deletions(-) diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c index 024a2bb146b2..7c01957a032d 100644 --- a/drivers/platform/chrome/cros_typec_switch.c +++ b/drivers/platform/chrome/cros_typec_switch.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #define DRV_NAME "cros-typec-switch" @@ -23,7 +22,6 @@ /* Handles and other relevant data required for each port's switches. */ struct cros_typec_port { int port_num; - struct typec_mux_dev *mode_switch; struct typec_retimer *retimer; struct cros_typec_switch_data *sdata; }; @@ -149,15 +147,6 @@ static int cros_typec_configure_mux(struct cros_typec_switch_data *sdata, int po return -ETIMEDOUT; } -static int cros_typec_mode_switch_set(struct typec_mux_dev *mode_switch, - struct typec_mux_state *state) -{ - struct cros_typec_port *port = typec_mux_get_drvdata(mode_switch); - - /* Mode switches have index 0. */ - return cros_typec_configure_mux(port->sdata, port->port_num, 0, state->mode, state->alt); -} - static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) { struct cros_typec_port *port = typec_retimer_get_drvdata(retimer); @@ -174,27 +163,9 @@ static void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata) if (!sdata->ports[i]) continue; typec_retimer_unregister(sdata->ports[i]->retimer); - typec_mux_unregister(sdata->ports[i]->mode_switch); } } -static int cros_typec_register_mode_switch(struct cros_typec_port *port, - struct fwnode_handle *fwnode) -{ - struct typec_mux_desc mode_switch_desc = { - .fwnode = fwnode, - .drvdata = port, - .name = fwnode_get_name(fwnode), - .set = cros_typec_mode_switch_set, - }; - - port->mode_switch = typec_mux_register(port->sdata->dev, &mode_switch_desc); - if (IS_ERR(port->mode_switch)) - return PTR_ERR(port->mode_switch); - - return 0; -} - static int cros_typec_register_retimer(struct cros_typec_port *port, struct fwnode_handle *fwnode) { struct typec_retimer_desc retimer_desc = { @@ -264,17 +235,6 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) } dev_dbg(dev, "Retimer switch registered for index %llu\n", index); - - if (!fwnode_property_read_bool(fwnode, "mode-switch")) - continue; - - ret = cros_typec_register_mode_switch(port, fwnode); - if (ret) { - dev_err(dev, "Mode switch register failed\n"); - goto err_switch; - } - - dev_dbg(dev, "Mode switch registered for index %llu\n", index); } return 0; From e5b25ca94c294545a677905a1fb2c940eee84c67 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 19 Jul 2022 13:56:53 +0200 Subject: [PATCH 1160/1436] Revert "platform/chrome: cros_typec_switch: Add event check" This reverts commit bb53ad958012f5a8d88b3b7159c22b3b877601bb. The chrome platform driver changes need to come in through the platform tree due to some api changes that showed up there that cause build errors in linux-next Reported-by: Stephen Rothwell Link: https://lore.kernel.org/r/20220719160821.5e68e30b@oak.ozlabs.ibm.com Cc: Prashant Malani Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_typec_switch.c | 72 +-------------------- 1 file changed, 2 insertions(+), 70 deletions(-) diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c index 7c01957a032d..b50ecedce662 100644 --- a/drivers/platform/chrome/cros_typec_switch.c +++ b/drivers/platform/chrome/cros_typec_switch.c @@ -7,8 +7,6 @@ */ #include -#include -#include #include #include #include @@ -65,40 +63,6 @@ static int cros_typec_get_mux_state(unsigned long mode, struct typec_altmode *al return ret; } -static int cros_typec_send_clear_event(struct cros_typec_switch_data *sdata, int port_num, - u32 events_mask) -{ - struct ec_params_typec_control req = { - .port = port_num, - .command = TYPEC_CONTROL_COMMAND_CLEAR_EVENTS, - .clear_events_mask = events_mask, - }; - - return cros_ec_command(sdata->ec, 0, EC_CMD_TYPEC_CONTROL, &req, - sizeof(req), NULL, 0); -} - -static bool cros_typec_check_event(struct cros_typec_switch_data *sdata, int port_num, u32 mask) -{ - struct ec_response_typec_status resp; - struct ec_params_typec_status req = { - .port = port_num, - }; - int ret; - - ret = cros_ec_command(sdata->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req), - &resp, sizeof(resp)); - if (ret < 0) { - dev_warn(sdata->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num); - return false; - } - - if (resp.events & mask) - return true; - - return false; -} - /* * The Chrome EC treats both mode-switches and retimers as "muxes" for the purposes of the * host command API. This common function configures and verifies the retimer/mode-switch @@ -107,44 +71,12 @@ static bool cros_typec_check_event(struct cros_typec_switch_data *sdata, int por static int cros_typec_configure_mux(struct cros_typec_switch_data *sdata, int port_num, int index, unsigned long mode, struct typec_altmode *alt) { - unsigned long end; - u32 event_mask; - u8 mux_state; - int ret; + int ret = cros_typec_get_mux_state(mode, alt); - ret = cros_typec_get_mux_state(mode, alt); - if (ret < 0) - return ret; - mux_state = (u8)ret; - - /* Clear any old mux set done event. */ - if (index == 0) - event_mask = PD_STATUS_EVENT_MUX_0_SET_DONE; - else - event_mask = PD_STATUS_EVENT_MUX_1_SET_DONE; - - ret = cros_typec_send_clear_event(sdata, port_num, event_mask); if (ret < 0) return ret; - /* Send the set command. */ - ret = cros_typec_cmd_mux_set(sdata, port_num, index, mux_state); - if (ret < 0) - return ret; - - /* Check for the mux set done event. */ - end = jiffies + msecs_to_jiffies(1000); - do { - if (cros_typec_check_event(sdata, port_num, event_mask)) - return 0; - - usleep_range(500, 1000); - } while (time_before(jiffies, end)); - - dev_err(sdata->dev, "Timed out waiting for mux set done on index: %d, state: %d\n", - index, mux_state); - - return -ETIMEDOUT; + return cros_typec_cmd_mux_set(sdata, port_num, index, (u8)ret); } static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) From 182da120f21277e36f4de6d510290b112438bb2d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 19 Jul 2022 13:57:00 +0200 Subject: [PATCH 1161/1436] Revert "platform/chrome: cros_typec_switch: Set EC retimer" This reverts commit 34f375f0fdf67f8804142fa37a28e73426d4c1df. The chrome platform driver changes need to come in through the platform tree due to some api changes that showed up there that cause build errors in linux-next Reported-by: Stephen Rothwell Link: https://lore.kernel.org/r/20220719160821.5e68e30b@oak.ozlabs.ibm.com Cc: Prashant Malani Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_typec_switch.c | 56 +-------------------- 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c index b50ecedce662..0d319e315d57 100644 --- a/drivers/platform/chrome/cros_typec_switch.c +++ b/drivers/platform/chrome/cros_typec_switch.c @@ -9,10 +9,7 @@ #include #include #include -#include #include -#include -#include #include #define DRV_NAME "cros-typec-switch" @@ -31,60 +28,9 @@ struct cros_typec_switch_data { struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS]; }; -static int cros_typec_cmd_mux_set(struct cros_typec_switch_data *sdata, int port_num, u8 index, - u8 state) -{ - struct typec_usb_mux_set params = { - .mux_index = index, - .mux_flags = state, - }; - - struct ec_params_typec_control req = { - .port = port_num, - .command = TYPEC_CONTROL_COMMAND_USB_MUX_SET, - .mux_params = params, - }; - - return cros_ec_command(sdata->ec, 0, EC_CMD_TYPEC_CONTROL, &req, - sizeof(req), NULL, 0); -} - -static int cros_typec_get_mux_state(unsigned long mode, struct typec_altmode *alt) -{ - int ret = -EOPNOTSUPP; - - if (mode == TYPEC_STATE_SAFE) - ret = USB_PD_MUX_SAFE_MODE; - else if (mode == TYPEC_STATE_USB) - ret = USB_PD_MUX_USB_ENABLED; - else if (alt && alt->svid == USB_TYPEC_DP_SID) - ret = USB_PD_MUX_DP_ENABLED; - - return ret; -} - -/* - * The Chrome EC treats both mode-switches and retimers as "muxes" for the purposes of the - * host command API. This common function configures and verifies the retimer/mode-switch - * according to the provided setting. - */ -static int cros_typec_configure_mux(struct cros_typec_switch_data *sdata, int port_num, int index, - unsigned long mode, struct typec_altmode *alt) -{ - int ret = cros_typec_get_mux_state(mode, alt); - - if (ret < 0) - return ret; - - return cros_typec_cmd_mux_set(sdata, port_num, index, (u8)ret); -} - static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) { - struct cros_typec_port *port = typec_retimer_get_drvdata(retimer); - - /* Retimers have index 1. */ - return cros_typec_configure_mux(port->sdata, port->port_num, 1, state->mode, state->alt); + return 0; } static void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata) From 1583afd4b0ef45ebdddb36f9dd390d96915a7f4f Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 19 Jul 2022 13:57:25 +0200 Subject: [PATCH 1162/1436] Revert "platform/chrome: cros_typec_switch: Add ACPI Kconfig dep" This reverts commit 88a15fbb47db483d06b12b1ae69f114b96361a96. The chrome platform driver changes need to come in through the platform tree due to some api changes that showed up there that cause build errors in linux-next Reported-by: Stephen Rothwell Link: https://lore.kernel.org/r/20220719160821.5e68e30b@oak.ozlabs.ibm.com Cc: Prashant Malani Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index 9d4fc505fa25..c62a514a087f 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -267,7 +267,7 @@ config CHROMEOS_PRIVACY_SCREEN config CROS_TYPEC_SWITCH tristate "ChromeOS EC Type-C Switch Control" - depends on MFD_CROS_EC_DEV && TYPEC && ACPI + depends on MFD_CROS_EC_DEV && TYPEC default MFD_CROS_EC_DEV help If you say Y here, you get support for configuring the Chrome OS EC Type C From 3d3e9b0db608608c049d286418f0c62c592ad280 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 19 Jul 2022 13:57:29 +0200 Subject: [PATCH 1163/1436] Revert "platform/chrome: cros_typec_switch: Add switch driver" This reverts commit e54369058f3da181fcc4c893f224a0c5a8a526b6. The chrome platform driver changes need to come in through the platform tree due to some api changes that showed up there that cause build errors in linux-next Reported-by: Stephen Rothwell Link: https://lore.kernel.org/r/20220719160821.5e68e30b@oak.ozlabs.ibm.com Cc: Prashant Malani Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 1 - drivers/platform/chrome/Kconfig | 11 -- drivers/platform/chrome/Makefile | 1 - drivers/platform/chrome/cros_typec_switch.c | 170 -------------------- 4 files changed, 183 deletions(-) delete mode 100644 drivers/platform/chrome/cros_typec_switch.c diff --git a/MAINTAINERS b/MAINTAINERS index 1d254110c354..8e44c1fa9b90 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4825,7 +4825,6 @@ M: Prashant Malani L: chrome-platform@lists.linux.dev S: Maintained F: drivers/platform/chrome/cros_ec_typec.c -F: drivers/platform/chrome/cros_typec_switch.c CHROMEOS EC USB PD NOTIFY DRIVER M: Prashant Malani diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index c62a514a087f..717299cbccac 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -265,17 +265,6 @@ config CHROMEOS_PRIVACY_SCREEN this should probably always be built into the kernel to avoid or minimize drm probe deferral. -config CROS_TYPEC_SWITCH - tristate "ChromeOS EC Type-C Switch Control" - depends on MFD_CROS_EC_DEV && TYPEC - default MFD_CROS_EC_DEV - help - If you say Y here, you get support for configuring the Chrome OS EC Type C - muxes and retimers. - - To compile this driver as a module, choose M here: the module will be - called cros_typec_switch. - source "drivers/platform/chrome/wilco_ec/Kconfig" endif # CHROMEOS_PLATFORMS diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index 0dcaf6a7ed27..52f5a2dde8b8 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o obj-$(CONFIG_CROS_EC) += cros_ec.o obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o obj-$(CONFIG_CROS_EC_ISHTP) += cros_ec_ishtp.o -obj-$(CONFIG_CROS_TYPEC_SWITCH) += cros_typec_switch.o obj-$(CONFIG_CROS_EC_RPMSG) += cros_ec_rpmsg.o obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_mec.o diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c deleted file mode 100644 index 0d319e315d57..000000000000 --- a/drivers/platform/chrome/cros_typec_switch.c +++ /dev/null @@ -1,170 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright 2022 Google LLC - * - * This driver provides the ability to configure Type C muxes and retimers which are controlled by - * the Chrome OS EC. - */ - -#include -#include -#include -#include -#include - -#define DRV_NAME "cros-typec-switch" - -/* Handles and other relevant data required for each port's switches. */ -struct cros_typec_port { - int port_num; - struct typec_retimer *retimer; - struct cros_typec_switch_data *sdata; -}; - -/* Driver-specific data. */ -struct cros_typec_switch_data { - struct device *dev; - struct cros_ec_device *ec; - struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS]; -}; - -static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) -{ - return 0; -} - -static void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata) -{ - int i; - - for (i = 0; i < EC_USB_PD_MAX_PORTS; i++) { - if (!sdata->ports[i]) - continue; - typec_retimer_unregister(sdata->ports[i]->retimer); - } -} - -static int cros_typec_register_retimer(struct cros_typec_port *port, struct fwnode_handle *fwnode) -{ - struct typec_retimer_desc retimer_desc = { - .fwnode = fwnode, - .drvdata = port, - .name = fwnode_get_name(fwnode), - .set = cros_typec_retimer_set, - }; - - port->retimer = typec_retimer_register(port->sdata->dev, &retimer_desc); - if (IS_ERR(port->retimer)) - return PTR_ERR(port->retimer); - - return 0; -} - -static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) -{ - struct cros_typec_port *port = NULL; - struct device *dev = sdata->dev; - struct fwnode_handle *fwnode; - struct acpi_device *adev; - unsigned long long index; - int ret = 0; - int nports; - - nports = device_get_child_node_count(dev); - if (nports == 0) { - dev_err(dev, "No switch devices found.\n"); - return -ENODEV; - } - - device_for_each_child_node(dev, fwnode) { - port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); - if (!port) { - ret = -ENOMEM; - goto err_switch; - } - - adev = to_acpi_device_node(fwnode); - if (!adev) { - dev_err(fwnode->dev, "Couldn't get ACPI device handle\n"); - ret = -ENODEV; - goto err_switch; - } - - ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); - if (ACPI_FAILURE(ret)) { - dev_err(fwnode->dev, "_ADR wasn't evaluated\n"); - ret = -ENODATA; - goto err_switch; - } - - if (index < 0 || index >= EC_USB_PD_MAX_PORTS) { - dev_err(fwnode->dev, "Invalid port index number: %llu", index); - ret = -EINVAL; - goto err_switch; - } - port->sdata = sdata; - port->port_num = index; - sdata->ports[index] = port; - - ret = cros_typec_register_retimer(port, fwnode); - if (ret) { - dev_err(dev, "Retimer switch register failed\n"); - goto err_switch; - } - - dev_dbg(dev, "Retimer switch registered for index %llu\n", index); - } - - return 0; -err_switch: - cros_typec_unregister_switches(sdata); - return ret; -} - -static int cros_typec_switch_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct cros_typec_switch_data *sdata; - - sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL); - if (!sdata) - return -ENOMEM; - - sdata->dev = dev; - sdata->ec = dev_get_drvdata(pdev->dev.parent); - - platform_set_drvdata(pdev, sdata); - - return cros_typec_register_switches(sdata); -} - -static int cros_typec_switch_remove(struct platform_device *pdev) -{ - struct cros_typec_switch_data *sdata = platform_get_drvdata(pdev); - - cros_typec_unregister_switches(sdata); - return 0; -} - -#ifdef CONFIG_ACPI -static const struct acpi_device_id cros_typec_switch_acpi_id[] = { - { "GOOG001A", 0 }, - {} -}; -MODULE_DEVICE_TABLE(acpi, cros_typec_switch_acpi_id); -#endif - -static struct platform_driver cros_typec_switch_driver = { - .driver = { - .name = DRV_NAME, - .acpi_match_table = ACPI_PTR(cros_typec_switch_acpi_id), - }, - .probe = cros_typec_switch_probe, - .remove = cros_typec_switch_remove, -}; - -module_platform_driver(cros_typec_switch_driver); - -MODULE_AUTHOR("Prashant Malani "); -MODULE_DESCRIPTION("Chrome OS EC Type C Switch control"); -MODULE_LICENSE("GPL"); From 32f02a211b0a192553075803b0b819027f96bb43 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 19 Jul 2022 13:57:48 +0200 Subject: [PATCH 1164/1436] Revert "platform/chrome: Add Type-C mux set command definitions" This reverts commit 28a6ed8e39f77f6ac613ec9b7461aa75e85fa79a. The chrome platform driver changes need to come in through the platform tree due to some api changes that showed up there that cause build errors in linux-next Reported-by: Stephen Rothwell Link: https://lore.kernel.org/r/20220719160821.5e68e30b@oak.ozlabs.ibm.com Cc: Prashant Malani Signed-off-by: Greg Kroah-Hartman --- include/linux/platform_data/cros_ec_commands.h | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/include/linux/platform_data/cros_ec_commands.h b/include/linux/platform_data/cros_ec_commands.h index a3945c5e7f50..8cfa8cfca77e 100644 --- a/include/linux/platform_data/cros_ec_commands.h +++ b/include/linux/platform_data/cros_ec_commands.h @@ -5722,21 +5722,8 @@ enum typec_control_command { TYPEC_CONTROL_COMMAND_EXIT_MODES, TYPEC_CONTROL_COMMAND_CLEAR_EVENTS, TYPEC_CONTROL_COMMAND_ENTER_MODE, - TYPEC_CONTROL_COMMAND_TBT_UFP_REPLY, - TYPEC_CONTROL_COMMAND_USB_MUX_SET, }; -/* Replies the AP may specify to the TBT EnterMode command as a UFP */ -enum typec_tbt_ufp_reply { - TYPEC_TBT_UFP_REPLY_NAK, - TYPEC_TBT_UFP_REPLY_ACK, -}; - -struct typec_usb_mux_set { - uint8_t mux_index; /* Index of the mux to set in the chain */ - uint8_t mux_flags; /* USB_PD_MUX_*-encoded USB mux state to set */ -} __ec_align1; - struct ec_params_typec_control { uint8_t port; uint8_t command; /* enum typec_control_command */ @@ -5750,8 +5737,6 @@ struct ec_params_typec_control { union { uint32_t clear_events_mask; uint8_t mode_to_enter; /* enum typec_mode */ - uint8_t tbt_ufp_reply; /* enum typec_tbt_ufp_reply */ - struct typec_usb_mux_set mux_params; uint8_t placeholder[128]; }; } __ec_align1; @@ -5830,9 +5815,6 @@ enum tcpc_cc_polarity { #define PD_STATUS_EVENT_SOP_DISC_DONE BIT(0) #define PD_STATUS_EVENT_SOP_PRIME_DISC_DONE BIT(1) #define PD_STATUS_EVENT_HARD_RESET BIT(2) -#define PD_STATUS_EVENT_DISCONNECTED BIT(3) -#define PD_STATUS_EVENT_MUX_0_SET_DONE BIT(4) -#define PD_STATUS_EVENT_MUX_1_SET_DONE BIT(5) struct ec_params_typec_status { uint8_t port; From ca2fd0609b5ddd15fe57c917a41508a7a9fc17e1 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:10 +0200 Subject: [PATCH 1165/1436] KVM: s390: pv: add mmu_notifier Add an mmu_notifier for protected VMs. The callback function is triggered when the mm is torn down, and will attempt to convert all protected vCPUs to non-protected. This allows the mm teardown to use the destroy page UVC instead of export. Also make KVM select CONFIG_MMU_NOTIFIER, needed to use mmu_notifiers. Signed-off-by: Claudio Imbrenda Acked-by: Janosch Frank Reviewed-by: Nico Boehr Link: https://lore.kernel.org/r/20220628135619.32410-10-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-10-imbrenda@linux.ibm.com> [frankja@linux.ibm.com: Conflict resolution for mmu_notifier.h include and struct kvm_s390_pv] Signed-off-by: Janosch Frank --- arch/s390/include/asm/kvm_host.h | 2 ++ arch/s390/kvm/Kconfig | 1 + arch/s390/kvm/kvm-s390.c | 10 ++++++++++ arch/s390/kvm/pv.c | 26 ++++++++++++++++++++++++++ 4 files changed, 39 insertions(+) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index fca4fcf72a2a..6f9fc8bb0303 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -929,6 +930,7 @@ struct kvm_s390_pv { unsigned long stor_base; void *stor_var; bool dumping; + struct mmu_notifier mmu_notifier; }; struct kvm_arch{ diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig index 2e84d3922f7c..33f4ff909476 100644 --- a/arch/s390/kvm/Kconfig +++ b/arch/s390/kvm/Kconfig @@ -34,6 +34,7 @@ config KVM select SRCU select KVM_VFIO select INTERVAL_TREE + select MMU_NOTIFIER help Support hosting paravirtualized guest machines using the SIE virtualization capability on the mainframe. This should work diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index d10c3b163cdc..5b77c43fbb01 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -3198,6 +3199,15 @@ void kvm_arch_destroy_vm(struct kvm *kvm) */ if (kvm_s390_pv_get_handle(kvm)) kvm_s390_pv_deinit_vm(kvm, &rc, &rrc); + /* + * Remove the mmu notifier only when the whole KVM VM is torn down, + * and only if one was registered to begin with. If the VM is + * currently not protected, but has been previously been protected, + * then it's possible that the notifier is still registered. + */ + if (kvm->arch.pv.mmu_notifier.ops) + mmu_notifier_unregister(&kvm->arch.pv.mmu_notifier, kvm->mm); + debug_unregister(kvm->arch.dbf); free_page((unsigned long)kvm->arch.sie_page2); if (!kvm_is_ucontrol(kvm)) diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index d18c5ccfa5dc..c063d1a9cf04 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "kvm-s390.h" static void kvm_s390_clear_pv_state(struct kvm *kvm) @@ -188,6 +189,26 @@ int kvm_s390_pv_deinit_vm(struct kvm *kvm, u16 *rc, u16 *rrc) return -EIO; } +static void kvm_s390_pv_mmu_notifier_release(struct mmu_notifier *subscription, + struct mm_struct *mm) +{ + struct kvm *kvm = container_of(subscription, struct kvm, arch.pv.mmu_notifier); + u16 dummy; + + /* + * No locking is needed since this is the last thread of the last user of this + * struct mm. + * When the struct kvm gets deinitialized, this notifier is also + * unregistered. This means that if this notifier runs, then the + * struct kvm is still valid. + */ + kvm_s390_cpus_from_pv(kvm, &dummy, &dummy); +} + +static const struct mmu_notifier_ops kvm_s390_pv_mmu_notifier_ops = { + .release = kvm_s390_pv_mmu_notifier_release, +}; + int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc) { struct uv_cb_cgc uvcb = { @@ -229,6 +250,11 @@ int kvm_s390_pv_init_vm(struct kvm *kvm, u16 *rc, u16 *rrc) return -EIO; } kvm->arch.gmap->guest_handle = uvcb.guest_handle; + /* Add the notifier only once. No races because we hold kvm->lock */ + if (kvm->arch.pv.mmu_notifier.ops != &kvm_s390_pv_mmu_notifier_ops) { + kvm->arch.pv.mmu_notifier.ops = &kvm_s390_pv_mmu_notifier_ops; + mmu_notifier_register(&kvm->arch.pv.mmu_notifier, kvm->mm); + } return 0; } From 9bf811dae443794594615625577277852edc181b Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:11 +0200 Subject: [PATCH 1166/1436] s390/mm: KVM: pv: when tearing down, try to destroy protected pages When ptep_get_and_clear_full is called for a mm teardown, we will now attempt to destroy the secure pages. This will be faster than export. In case it was not a teardown, or if for some reason the destroy page UVC failed, we try with an export page, like before. Signed-off-by: Claudio Imbrenda Acked-by: Janosch Frank Reviewed-by: Nico Boehr Link: https://lore.kernel.org/r/20220628135619.32410-11-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-11-imbrenda@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/include/asm/pgtable.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index f16403ba81ec..cf81acf3879c 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -1182,9 +1182,22 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, } else { res = ptep_xchg_lazy(mm, addr, ptep, __pte(_PAGE_INVALID)); } - /* At this point the reference through the mapping is still present */ - if (mm_is_protected(mm) && pte_present(res)) - uv_convert_owned_from_secure(pte_val(res) & PAGE_MASK); + /* Nothing to do */ + if (!mm_is_protected(mm) || !pte_present(res)) + return res; + /* + * At this point the reference through the mapping is still present. + * The notifier should have destroyed all protected vCPUs at this + * point, so the destroy should be successful. + */ + if (full && !uv_destroy_owned_page(pte_val(res) & PAGE_MASK)) + return res; + /* + * If something went wrong and the page could not be destroyed, or + * if this is not a mm teardown, the slower export is used as + * fallback instead. + */ + uv_convert_owned_from_secure(pte_val(res) & PAGE_MASK); return res; } From da15fbc646f377ebfe992c13053b93783fea0db2 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:12 +0200 Subject: [PATCH 1167/1436] KVM: s390: pv: refactoring of kvm_s390_pv_deinit_vm Refactor kvm_s390_pv_deinit_vm to improve readability and simplify the improvements that are coming in subsequent patches. No functional change intended. Signed-off-by: Claudio Imbrenda Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20220628135619.32410-12-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-12-imbrenda@linux.ibm.com> [frankja@linux.ibm.com: Dropped commit message line regarding review] Signed-off-by: Janosch Frank --- arch/s390/kvm/pv.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index c063d1a9cf04..4b64bf5bc3b0 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -176,17 +176,17 @@ int kvm_s390_pv_deinit_vm(struct kvm *kvm, u16 *rc, u16 *rrc) cc = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm), UVC_CMD_DESTROY_SEC_CONF, rc, rrc); WRITE_ONCE(kvm->arch.gmap->guest_handle, 0); - if (!cc) + if (!cc) { atomic_dec(&kvm->mm->context.protected_count); + kvm_s390_pv_dealloc_vm(kvm); + } else { + /* Intended memory leak on "impossible" error */ + s390_replace_asce(kvm->arch.gmap); + } KVM_UV_EVENT(kvm, 3, "PROTVIRT DESTROY VM: rc %x rrc %x", *rc, *rrc); WARN_ONCE(cc, "protvirt destroy vm failed rc %x rrc %x", *rc, *rrc); - /* Intended memory leak on "impossible" error */ - if (!cc) { - kvm_s390_pv_dealloc_vm(kvm); - return 0; - } - s390_replace_asce(kvm->arch.gmap); - return -EIO; + + return cc ? -EIO : 0; } static void kvm_s390_pv_mmu_notifier_release(struct mmu_notifier *subscription, From 7746f735f55205176a447e737fe15a5ba7a4d2d4 Mon Sep 17 00:00:00 2001 From: Claudio Imbrenda Date: Tue, 28 Jun 2022 15:56:13 +0200 Subject: [PATCH 1168/1436] KVM: s390: pv: destroy the configuration before its memory Move the Destroy Secure Configuration UVC before the loop to destroy the memory. If the protected VM has memory, it will be cleaned up and made accessible by the Destroy Secure Configuration UVC. The struct page for the relevant pages will still have the protected bit set, so the loop is still needed to clean that up. Switching the order of those two operations does not change the outcome, but it is significantly faster. Signed-off-by: Claudio Imbrenda Reviewed-by: Nico Boehr Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20220628135619.32410-13-imbrenda@linux.ibm.com Message-Id: <20220628135619.32410-13-imbrenda@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/kvm/pv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/s390/kvm/pv.c b/arch/s390/kvm/pv.c index 4b64bf5bc3b0..7cb7799a0acb 100644 --- a/arch/s390/kvm/pv.c +++ b/arch/s390/kvm/pv.c @@ -164,6 +164,9 @@ int kvm_s390_pv_deinit_vm(struct kvm *kvm, u16 *rc, u16 *rrc) { int cc; + cc = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm), + UVC_CMD_DESTROY_SEC_CONF, rc, rrc); + WRITE_ONCE(kvm->arch.gmap->guest_handle, 0); /* * if the mm still has a mapping, make all its pages accessible * before destroying the guest @@ -173,9 +176,6 @@ int kvm_s390_pv_deinit_vm(struct kvm *kvm, u16 *rc, u16 *rrc) mmput(kvm->mm); } - cc = uv_cmd_nodata(kvm_s390_pv_get_handle(kvm), - UVC_CMD_DESTROY_SEC_CONF, rc, rrc); - WRITE_ONCE(kvm->arch.gmap->guest_handle, 0); if (!cc) { atomic_dec(&kvm->mm->context.protected_count); kvm_s390_pv_dealloc_vm(kvm); From c3f0e5fd2d33d80c5a5a8b5e5d2bab2841709cc8 Mon Sep 17 00:00:00 2001 From: Nico Boehr Date: Mon, 18 Jul 2022 15:04:34 +0200 Subject: [PATCH 1169/1436] KVM: s390: pv: don't present the ecall interrupt twice When the SIGP interpretation facility is present and a VCPU sends an ecall to another VCPU in enabled wait, the sending VCPU receives a 56 intercept (partial execution), so KVM can wake up the receiving CPU. Note that the SIGP interpretation facility will take care of the interrupt delivery and KVM's only job is to wake the receiving VCPU. For PV, the sending VCPU will receive a 108 intercept (pv notify) and should continue like in the non-PV case, i.e. wake the receiving VCPU. For PV and non-PV guests the interrupt delivery will occur through the SIGP interpretation facility on SIE entry when SIE finds the X bit in the status field set. However, in handle_pv_notification(), there was no special handling for SIGP, which leads to interrupt injection being requested by KVM for the next SIE entry. This results in the interrupt being delivered twice: once by the SIGP interpretation facility and once by KVM through the IICTL. Add the necessary special handling in handle_pv_notification(), similar to handle_partial_execution(), which simply wakes the receiving VCPU and leave interrupt delivery to the SIGP interpretation facility. In contrast to external calls, emergency calls are not interpreted but also cause a 108 intercept, which is why we still need to call handle_instruction() for SIGP orders other than ecall. Since kvm_s390_handle_sigp_pei() is now called for all SIGP orders which cause a 108 intercept - even if they are actually handled by handle_instruction() - move the tracepoint in kvm_s390_handle_sigp_pei() to avoid possibly confusing trace messages. Signed-off-by: Nico Boehr Cc: # 5.7 Fixes: da24a0cc58ed ("KVM: s390: protvirt: Instruction emulation") Reviewed-by: Claudio Imbrenda Reviewed-by: Janosch Frank Reviewed-by: Christian Borntraeger Link: https://lore.kernel.org/r/20220718130434.73302-1-nrb@linux.ibm.com Message-Id: <20220718130434.73302-1-nrb@linux.ibm.com> Signed-off-by: Claudio Imbrenda --- arch/s390/kvm/intercept.c | 15 +++++++++++++++ arch/s390/kvm/sigp.c | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index 8bd42a20d924..88112065d941 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c @@ -528,12 +528,27 @@ static int handle_pv_uvc(struct kvm_vcpu *vcpu) static int handle_pv_notification(struct kvm_vcpu *vcpu) { + int ret; + if (vcpu->arch.sie_block->ipa == 0xb210) return handle_pv_spx(vcpu); if (vcpu->arch.sie_block->ipa == 0xb220) return handle_pv_sclp(vcpu); if (vcpu->arch.sie_block->ipa == 0xb9a4) return handle_pv_uvc(vcpu); + if (vcpu->arch.sie_block->ipa >> 8 == 0xae) { + /* + * Besides external call, other SIGP orders also cause a + * 108 (pv notify) intercept. In contrast to external call, + * these orders need to be emulated and hence the appropriate + * place to handle them is in handle_instruction(). + * So first try kvm_s390_handle_sigp_pei() and if that isn't + * successful, go on with handle_instruction(). + */ + ret = kvm_s390_handle_sigp_pei(vcpu); + if (!ret) + return ret; + } return handle_instruction(vcpu); } diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index 8aaee2892ec3..cb747bf6c798 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c @@ -480,9 +480,9 @@ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu) struct kvm_vcpu *dest_vcpu; u8 order_code = kvm_s390_get_base_disp_rs(vcpu, NULL); - trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr); - if (order_code == SIGP_EXTERNAL_CALL) { + trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr); + dest_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr); BUG_ON(dest_vcpu == NULL); From e385b0ba6a137f34953e746d70d543660c2de1a0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Jul 2022 16:03:14 +0200 Subject: [PATCH 1170/1436] of: overlay: Move devicetree_corrupt() check up There is no point in doing several preparatory steps in of_overlay_fdt_apply(), only to see of_overlay_apply() return early because of a corrupt device tree. Move the check for a corrupt device tree from of_overlay_apply() to of_overlay_fdt_apply(), to check for this as early as possible. Signed-off-by: Geert Uytterhoeven Reviewed-by: Frank Rowand Tested-by: Frank Rowand Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/c91ce7112eb5167ea46a43d8a980e76b920010ba.1657893306.git.geert+renesas@glider.be --- drivers/of/overlay.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 4044ddcb02c6..84a8d402009c 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -903,12 +903,6 @@ static int of_overlay_apply(struct overlay_changeset *ovcs) { int ret = 0, ret_revert, ret_tmp; - if (devicetree_corrupt()) { - pr_err("devicetree state suspect, refuse to apply overlay\n"); - ret = -EBUSY; - goto out; - } - ret = of_resolve_phandles(ovcs->overlay_root); if (ret) goto out; @@ -983,6 +977,11 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size, *ret_ovcs_id = 0; + if (devicetree_corrupt()) { + pr_err("devicetree state suspect, refuse to apply overlay\n"); + return -EBUSY; + } + if (overlay_fdt_size < sizeof(struct fdt_header) || fdt_check_header(overlay_fdt)) { pr_err("Invalid overlay_fdt header\n"); From e76f4a6107ebe4af5405bb1b94d0e717a40fd306 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 15 Jul 2022 16:03:15 +0200 Subject: [PATCH 1171/1436] of: overlay: Simplify of_overlay_fdt_apply() tail It does not hurt to fill in the changeset id while the mutex is still held. After doing so, the function tails for the success and failure cases become identical, so they can be unified. Signed-off-by: Geert Uytterhoeven Reviewed-by: Frank Rowand Tested-by: Frank Rowand Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/6a3357a8f7f29704350e3ffae768ee8a462b54d3.1657893306.git.geert+renesas@glider.be --- drivers/of/overlay.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 84a8d402009c..bd8ff4df723d 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c @@ -1043,20 +1043,15 @@ int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size, * goto err_free_ovcs. Instead, the caller of of_overlay_fdt_apply() * can call of_overlay_remove(); */ - - mutex_unlock(&of_mutex); - of_overlay_mutex_unlock(); - *ret_ovcs_id = ovcs->id; - - return ret; + goto out_unlock; err_free_ovcs: free_overlay_changeset(ovcs); +out_unlock: mutex_unlock(&of_mutex); of_overlay_mutex_unlock(); - return ret; } EXPORT_SYMBOL_GPL(of_overlay_fdt_apply); From d311664b90579c77c66bda18eb93affd4049b255 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 18 Jul 2022 05:09:06 +0000 Subject: [PATCH 1172/1436] platform/chrome: cros_ec_proto: add "cros_ec_" prefix to send_command() To be neat, add "cros_ec_" prefix to static function send_command(). Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220718050914.2267370-3-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 6923ea4401e5..b02fd1414e52 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -107,8 +107,7 @@ static int prepare_tx_legacy(struct cros_ec_device *ec_dev, return EC_MSG_TX_PROTO_BYTES + msg->outsize; } -static int send_command(struct cros_ec_device *ec_dev, - struct cros_ec_command *msg) +static int cros_ec_send_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) { int ret; int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg); @@ -255,7 +254,7 @@ static int cros_ec_get_host_event_wake_mask(struct cros_ec_device *ec_dev, uint3 msg->command = EC_CMD_HOST_EVENT_GET_WAKE_MASK; msg->insize = sizeof(*r); - ret = send_command(ec_dev, msg); + ret = cros_ec_send_command(ec_dev, msg); if (ret < 0) goto exit; @@ -295,7 +294,7 @@ static int cros_ec_get_proto_info(struct cros_ec_device *ec_dev, int devidx) msg->command = EC_CMD_PASSTHRU_OFFSET(devidx) | EC_CMD_GET_PROTOCOL_INFO; msg->insize = sizeof(*info); - ret = send_command(ec_dev, msg); + ret = cros_ec_send_command(ec_dev, msg); /* * Send command once again when timeout occurred. * Fingerprint MCU (FPMCU) is restarted during system boot which @@ -304,7 +303,7 @@ static int cros_ec_get_proto_info(struct cros_ec_device *ec_dev, int devidx) * attempt because we waited at least EC_MSG_DEADLINE_MS. */ if (ret == -ETIMEDOUT) - ret = send_command(ec_dev, msg); + ret = cros_ec_send_command(ec_dev, msg); if (ret < 0) { dev_dbg(ec_dev->dev, @@ -376,7 +375,7 @@ static int cros_ec_get_proto_info_legacy(struct cros_ec_device *ec_dev) params = (struct ec_params_hello *)msg->data; params->in_data = 0xa0b0c0d0; - ret = send_command(ec_dev, msg); + ret = cros_ec_send_command(ec_dev, msg); if (ret < 0) { dev_dbg(ec_dev->dev, "EC failed to respond to v2 hello: %d\n", ret); goto exit; @@ -453,7 +452,7 @@ static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev, pver = (struct ec_params_get_cmd_versions *)msg->data; pver->cmd = cmd; - ret = send_command(ec_dev, msg); + ret = cros_ec_send_command(ec_dev, msg); if (ret < 0) goto exit; @@ -634,7 +633,7 @@ int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) } } - ret = send_command(ec_dev, msg); + ret = cros_ec_send_command(ec_dev, msg); mutex_unlock(&ec_dev->lock); return ret; From 82f4def2d8224b45d7348daa943e5fc9d9c7163b Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 18 Jul 2022 05:09:07 +0000 Subject: [PATCH 1173/1436] platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_cmd_xfer() cros_ec_cmd_xfer() transfers the given command and data if any. It performs some sanity checks and calls cros_ec_send_command(). Add Kunit tests for cros_ec_cmd_xfer(). Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220718050914.2267370-4-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 149 +++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 1e2a1522c288..33721607a5b9 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -1535,6 +1535,151 @@ static void cros_ec_proto_test_query_all_default_wake_mask_return0(struct kunit } } +static void cros_ec_proto_test_cmd_xfer_normal(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct { + struct cros_ec_command msg; + u8 data[0x100]; + } __packed buf; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec_dev->max_passthru = 0xdd; + + buf.msg.version = 0; + buf.msg.command = EC_CMD_HELLO; + buf.msg.insize = 4; + buf.msg.outsize = 2; + buf.data[0] = 0x55; + buf.data[1] = 0xaa; + + { + u8 *data; + + mock = cros_kunit_ec_xfer_mock_add(test, 4); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (u8 *)mock->o_data; + data[0] = 0xaa; + data[1] = 0x55; + data[2] = 0xcc; + data[3] = 0x33; + } + + ret = cros_ec_cmd_xfer(ec_dev, &buf.msg); + KUNIT_EXPECT_EQ(test, ret, 4); + + { + u8 *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, 4); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 2); + + data = (u8 *)mock->i_data; + KUNIT_EXPECT_EQ(test, data[0], 0x55); + KUNIT_EXPECT_EQ(test, data[1], 0xaa); + + KUNIT_EXPECT_EQ(test, buf.data[0], 0xaa); + KUNIT_EXPECT_EQ(test, buf.data[1], 0x55); + KUNIT_EXPECT_EQ(test, buf.data[2], 0xcc); + KUNIT_EXPECT_EQ(test, buf.data[3], 0x33); + } +} + +static void cros_ec_proto_test_cmd_xfer_excess_msg_insize(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct { + struct cros_ec_command msg; + u8 data[0x100]; + } __packed buf; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec_dev->max_passthru = 0xdd; + + buf.msg.version = 0; + buf.msg.command = EC_CMD_HELLO; + buf.msg.insize = 0xee + 1; + buf.msg.outsize = 2; + + { + mock = cros_kunit_ec_xfer_mock_add(test, 0xcc); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + ret = cros_ec_cmd_xfer(ec_dev, &buf.msg); + KUNIT_EXPECT_EQ(test, ret, 0xcc); + + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_HELLO); + KUNIT_EXPECT_EQ(test, mock->msg.insize, 0xee); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 2); + } +} + +static void cros_ec_proto_test_cmd_xfer_excess_msg_outsize_without_passthru(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + struct { + struct cros_ec_command msg; + u8 data[0x100]; + } __packed buf; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec_dev->max_passthru = 0xdd; + + buf.msg.version = 0; + buf.msg.command = EC_CMD_HELLO; + buf.msg.insize = 4; + buf.msg.outsize = 0xff + 1; + + ret = cros_ec_cmd_xfer(ec_dev, &buf.msg); + KUNIT_EXPECT_EQ(test, ret, -EMSGSIZE); +} + +static void cros_ec_proto_test_cmd_xfer_excess_msg_outsize_with_passthru(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + struct { + struct cros_ec_command msg; + u8 data[0x100]; + } __packed buf; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec_dev->max_passthru = 0xdd; + + buf.msg.version = 0; + buf.msg.command = EC_CMD_PASSTHRU_OFFSET(CROS_EC_DEV_PD_INDEX) + EC_CMD_HELLO; + buf.msg.insize = 4; + buf.msg.outsize = 0xdd + 1; + + ret = cros_ec_cmd_xfer(ec_dev, &buf.msg); + KUNIT_EXPECT_EQ(test, ret, -EMSGSIZE); +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -1601,6 +1746,10 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_query_all_no_host_sleep_return0), KUNIT_CASE(cros_ec_proto_test_query_all_default_wake_mask_return_error), KUNIT_CASE(cros_ec_proto_test_query_all_default_wake_mask_return0), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_normal), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_excess_msg_insize), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_excess_msg_outsize_without_passthru), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_excess_msg_outsize_with_passthru), {} }; From da95f691311f1f364a482ac11db82dad42bc9742 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 18 Jul 2022 05:09:08 +0000 Subject: [PATCH 1174/1436] platform/chrome: cros_ec_proto: add Kunit tests for cros_ec_send_command() cros_ec_cmd_xfer() is the only exported function that calls static function cros_ec_send_command(). Add Kunit tests for cros_ec_send_command() through calling cros_ec_cmd_xfer(). Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220718050914.2267370-5-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 265 +++++++++++++++++++ drivers/platform/chrome/cros_kunit_util.c | 20 ++ drivers/platform/chrome/cros_kunit_util.h | 4 + 3 files changed, 289 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 33721607a5b9..64100fd81c6a 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -1680,6 +1680,262 @@ static void cros_ec_proto_test_cmd_xfer_excess_msg_outsize_with_passthru(struct KUNIT_EXPECT_EQ(test, ret, -EMSGSIZE); } +static void cros_ec_proto_test_cmd_xfer_protocol_v3_normal(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + ec_dev->proto_version = 3; + ec_dev->cmd_xfer = cros_kunit_ec_cmd_xfer_mock; + ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock; + + ret = cros_ec_cmd_xfer(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, 0); + + KUNIT_EXPECT_EQ(test, cros_kunit_ec_cmd_xfer_mock_called, 0); + KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 1); +} + +static void cros_ec_proto_test_cmd_xfer_protocol_v3_no_op(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + ec_dev->proto_version = 3; + ec_dev->cmd_xfer = cros_kunit_ec_cmd_xfer_mock; + ec_dev->pkt_xfer = NULL; + + ret = cros_ec_cmd_xfer(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, -EIO); +} + +static void cros_ec_proto_test_cmd_xfer_protocol_v2_normal(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + ec_dev->proto_version = 2; + ec_dev->cmd_xfer = cros_kunit_ec_cmd_xfer_mock; + ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock; + + ret = cros_ec_cmd_xfer(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, 0); + + KUNIT_EXPECT_EQ(test, cros_kunit_ec_cmd_xfer_mock_called, 1); + KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 0); +} + +static void cros_ec_proto_test_cmd_xfer_protocol_v2_no_op(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + ec_dev->proto_version = 2; + ec_dev->cmd_xfer = NULL; + ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock; + + ret = cros_ec_cmd_xfer(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, -EIO); +} + +static void cros_ec_proto_test_cmd_xfer_in_progress_normal(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock; + + /* For the first host command to return EC_RES_IN_PROGRESS. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For EC_CMD_GET_COMMS_STATUS. */ + { + struct ec_response_get_comms_status *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_comms_status *)mock->o_data; + data->flags = 0; + } + + ret = cros_ec_cmd_xfer(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, sizeof(struct ec_response_get_comms_status)); + + KUNIT_EXPECT_EQ(test, msg.result, EC_RES_SUCCESS); + + /* For the first host command to return EC_RES_IN_PROGRESS. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + } + + /* For EC_CMD_GET_COMMS_STATUS. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_COMMS_STATUS); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_comms_status)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } + + KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 2); +} + +static void cros_ec_proto_test_cmd_xfer_in_progress_retries_eagain(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock; + + /* For the first host command to return EC_RES_IN_PROGRESS. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For EC_CMD_GET_COMMS_STATUS EC_COMMAND_RETRIES times. */ + cros_kunit_ec_xfer_mock_default_ret = -EAGAIN; + + ret = cros_ec_cmd_xfer(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, -EAGAIN); + + /* For EC_CMD_GET_COMMS_STATUS EC_COMMAND_RETRIES times. */ + KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 51); +} + +static void cros_ec_proto_test_cmd_xfer_in_progress_retries_status_processing(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock; + + /* For the first host command to return EC_RES_IN_PROGRESS. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For EC_CMD_GET_COMMS_STATUS EC_COMMAND_RETRIES times. */ + { + struct ec_response_get_comms_status *data; + int i; + + for (i = 0; i < 50; ++i) { + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_comms_status *)mock->o_data; + data->flags |= EC_COMMS_STATUS_PROCESSING; + } + } + + ret = cros_ec_cmd_xfer(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, sizeof(struct ec_response_get_comms_status)); + + KUNIT_EXPECT_EQ(test, msg.result, EC_RES_SUCCESS); + + /* For EC_CMD_GET_COMMS_STATUS EC_COMMAND_RETRIES times. */ + KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 51); +} + +static void cros_ec_proto_test_cmd_xfer_in_progress_xfer_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + /* For the first host command to return EC_RES_IN_PROGRESS. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For EC_CMD_GET_COMMS_STATUS. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, -EIO, EC_RES_SUCCESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + ret = cros_ec_cmd_xfer(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, -EIO); +} + +static void cros_ec_proto_test_cmd_xfer_in_progress_return_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock; + + /* For the first host command to return EC_RES_IN_PROGRESS. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For EC_CMD_GET_COMMS_STATUS. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_INVALID_COMMAND, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + ret = cros_ec_cmd_xfer(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, 0); + + KUNIT_EXPECT_EQ(test, msg.result, EC_RES_INVALID_COMMAND); + + KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 2); +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -1750,6 +2006,15 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_cmd_xfer_excess_msg_insize), KUNIT_CASE(cros_ec_proto_test_cmd_xfer_excess_msg_outsize_without_passthru), KUNIT_CASE(cros_ec_proto_test_cmd_xfer_excess_msg_outsize_with_passthru), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v3_normal), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v3_no_op), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v2_normal), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_protocol_v2_no_op), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_normal), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_retries_eagain), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_retries_status_processing), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_xfer_error), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_return_error), {} }; diff --git a/drivers/platform/chrome/cros_kunit_util.c b/drivers/platform/chrome/cros_kunit_util.c index e031777dea87..3ede971e82ee 100644 --- a/drivers/platform/chrome/cros_kunit_util.c +++ b/drivers/platform/chrome/cros_kunit_util.c @@ -15,6 +15,10 @@ int cros_kunit_ec_xfer_mock_default_ret; EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_default_ret); +int cros_kunit_ec_cmd_xfer_mock_called; +EXPORT_SYMBOL_GPL(cros_kunit_ec_cmd_xfer_mock_called); +int cros_kunit_ec_pkt_xfer_mock_called; +EXPORT_SYMBOL_GPL(cros_kunit_ec_pkt_xfer_mock_called); static struct list_head cros_kunit_ec_xfer_mock_in; static struct list_head cros_kunit_ec_xfer_mock_out; @@ -46,6 +50,20 @@ int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_comman } EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock); +int cros_kunit_ec_cmd_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) +{ + ++cros_kunit_ec_cmd_xfer_mock_called; + return cros_kunit_ec_xfer_mock(ec_dev, msg); +} +EXPORT_SYMBOL_GPL(cros_kunit_ec_cmd_xfer_mock); + +int cros_kunit_ec_pkt_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) +{ + ++cros_kunit_ec_pkt_xfer_mock_called; + return cros_kunit_ec_xfer_mock(ec_dev, msg); +} +EXPORT_SYMBOL_GPL(cros_kunit_ec_pkt_xfer_mock); + struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size) { return cros_kunit_ec_xfer_mock_addx(test, size, EC_RES_SUCCESS, size); @@ -90,6 +108,8 @@ EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_next); void cros_kunit_mock_reset(void) { cros_kunit_ec_xfer_mock_default_ret = 0; + cros_kunit_ec_cmd_xfer_mock_called = 0; + cros_kunit_ec_pkt_xfer_mock_called = 0; INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_in); INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_out); } diff --git a/drivers/platform/chrome/cros_kunit_util.h b/drivers/platform/chrome/cros_kunit_util.h index 79c4525f873c..ae4080cb13f1 100644 --- a/drivers/platform/chrome/cros_kunit_util.h +++ b/drivers/platform/chrome/cros_kunit_util.h @@ -24,8 +24,12 @@ struct ec_xfer_mock { }; extern int cros_kunit_ec_xfer_mock_default_ret; +extern int cros_kunit_ec_cmd_xfer_mock_called; +extern int cros_kunit_ec_pkt_xfer_mock_called; int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg); +int cros_kunit_ec_cmd_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg); +int cros_kunit_ec_pkt_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg); struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size); struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test, int ret, int result, size_t size); From 810be30d27bdfe7923084a5550dfddeed28ac08b Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 18 Jul 2022 05:09:09 +0000 Subject: [PATCH 1175/1436] platform/chrome: cros_ec_proto: separate cros_ec_xfer_command() cros_ec_send_command() has extra logic to handle EC_RES_IN_PROGRESS. Separate the command transfer part into cros_ec_xfer_command() so that other functions can re-use it. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220718050914.2267370-6-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index b02fd1414e52..0cec013be3d3 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -107,7 +107,7 @@ static int prepare_tx_legacy(struct cros_ec_device *ec_dev, return EC_MSG_TX_PROTO_BYTES + msg->outsize; } -static int cros_ec_send_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) +static int cros_ec_xfer_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) { int ret; int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg); @@ -123,14 +123,21 @@ static int cros_ec_send_command(struct cros_ec_device *ec_dev, struct cros_ec_co * the EC is trying to use protocol v2, on an underlying * communication mechanism that does not support v2. */ - dev_err_once(ec_dev->dev, - "missing EC transfer API, cannot send command\n"); + dev_err_once(ec_dev->dev, "missing EC transfer API, cannot send command\n"); return -EIO; } trace_cros_ec_request_start(msg); ret = (*xfer_fxn)(ec_dev, msg); trace_cros_ec_request_done(msg, ret); + + return ret; +} + +static int cros_ec_send_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) +{ + int ret = cros_ec_xfer_command(ec_dev, msg); + if (msg->result == EC_RES_IN_PROGRESS) { int i; struct cros_ec_command *status_msg; From 0aad9aff6a6450f7ea5e980add1b33d40e5bed52 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 18 Jul 2022 05:09:10 +0000 Subject: [PATCH 1176/1436] platform/chrome: cros_ec_proto: separate cros_ec_wait_until_complete() EC returns EC_RES_IN_PROGRESS if the host command needs more time to complete. Whenever receives the return code, cros_ec_send_command() sends EC_CMD_GET_COMMS_STATUS to query the command status. Separate cros_ec_wait_until_complete() from cros_ec_send_command(). It sends EC_CMD_GET_COMMS_STATUS and waits until the previous command was completed, or encountered error, or timed out. Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220718050914.2267370-7-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 80 ++++++++++++------------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 0cec013be3d3..a6ad7f7956e6 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -134,52 +134,48 @@ static int cros_ec_xfer_command(struct cros_ec_device *ec_dev, struct cros_ec_co return ret; } +static int cros_ec_wait_until_complete(struct cros_ec_device *ec_dev, uint32_t *result) +{ + struct { + struct cros_ec_command msg; + struct ec_response_get_comms_status status; + } __packed buf; + struct cros_ec_command *msg = &buf.msg; + struct ec_response_get_comms_status *status = &buf.status; + int ret = 0, i; + + msg->version = 0; + msg->command = EC_CMD_GET_COMMS_STATUS; + msg->insize = sizeof(*status); + msg->outsize = 0; + + /* Query the EC's status until it's no longer busy or we encounter an error. */ + for (i = 0; i < EC_COMMAND_RETRIES; ++i) { + usleep_range(10000, 11000); + + ret = cros_ec_xfer_command(ec_dev, msg); + if (ret == -EAGAIN) + continue; + if (ret < 0) + return ret; + + *result = msg->result; + if (msg->result != EC_RES_SUCCESS) + return ret; + + if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) + return ret; + } + + return ret; +} + static int cros_ec_send_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) { int ret = cros_ec_xfer_command(ec_dev, msg); - if (msg->result == EC_RES_IN_PROGRESS) { - int i; - struct cros_ec_command *status_msg; - struct ec_response_get_comms_status *status; - - status_msg = kmalloc(sizeof(*status_msg) + sizeof(*status), - GFP_KERNEL); - if (!status_msg) - return -ENOMEM; - - status_msg->version = 0; - status_msg->command = EC_CMD_GET_COMMS_STATUS; - status_msg->insize = sizeof(*status); - status_msg->outsize = 0; - - /* - * Query the EC's status until it's no longer busy or - * we encounter an error. - */ - for (i = 0; i < EC_COMMAND_RETRIES; i++) { - usleep_range(10000, 11000); - - trace_cros_ec_request_start(status_msg); - ret = (*xfer_fxn)(ec_dev, status_msg); - trace_cros_ec_request_done(status_msg, ret); - if (ret == -EAGAIN) - continue; - if (ret < 0) - break; - - msg->result = status_msg->result; - if (status_msg->result != EC_RES_SUCCESS) - break; - - status = (struct ec_response_get_comms_status *) - status_msg->data; - if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) - break; - } - - kfree(status_msg); - } + if (msg->result == EC_RES_IN_PROGRESS) + ret = cros_ec_wait_until_complete(ec_dev, &msg->result); return ret; } From 00eb36d528729692d418e53c832971a798f85ceb Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 18 Jul 2022 05:09:11 +0000 Subject: [PATCH 1177/1436] platform/chrome: cros_ec_proto: change Kunit expectation when timed out While EC_COMMS_STATUS_PROCESSING flag is still on after it tries EC_COMMAND_RETRIES times for sending EC_CMD_GET_COMMS_STATUS, cros_ec_wait_until_complete() doesn't return an error code. Change the expectation to an error code. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220718050914.2267370-8-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 64100fd81c6a..fbb872040711 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -1870,9 +1870,7 @@ static void cros_ec_proto_test_cmd_xfer_in_progress_retries_status_processing(st } ret = cros_ec_cmd_xfer(ec_dev, &msg); - KUNIT_EXPECT_EQ(test, ret, sizeof(struct ec_response_get_comms_status)); - - KUNIT_EXPECT_EQ(test, msg.result, EC_RES_SUCCESS); + KUNIT_EXPECT_EQ(test, ret, -EAGAIN); /* For EC_CMD_GET_COMMS_STATUS EC_COMMAND_RETRIES times. */ KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 51); From 7f95d2b68b9a4f6624438f2d7dbad01c157b92a6 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 18 Jul 2022 05:09:12 +0000 Subject: [PATCH 1178/1436] platform/chrome: cros_ec_proto: return -EAGAIN when retries timed out While EC_COMMS_STATUS_PROCESSING flag is still on after it tries EC_COMMAND_RETRIES times for sending EC_CMD_GET_COMMS_STATUS, cros_ec_wait_until_complete() doesn't return an error code. Return -EAGAIN in the case instead. Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220718050914.2267370-9-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index a6ad7f7956e6..9dec475edc84 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -167,6 +167,9 @@ static int cros_ec_wait_until_complete(struct cros_ec_device *ec_dev, uint32_t * return ret; } + if (i >= EC_COMMAND_RETRIES) + ret = -EAGAIN; + return ret; } From 82c9b7ed8c5c5cb4ba2650c240fcd31cbdcfa0b5 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 18 Jul 2022 05:09:13 +0000 Subject: [PATCH 1179/1436] platform/chrome: cros_ec_proto: add Kunit test for empty payload cros_ec_wait_until_complete() sends EC_CMD_GET_COMMS_STATUS which expects to receive sizeof(struct ec_response_get_comms_status) from cros_ec_xfer_command(). Add Kunit test and expect to receive an error code when cros_ec_xfer_command() returns 0. Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220718050914.2267370-10-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index fbb872040711..d76e09b8a36a 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -1934,6 +1934,36 @@ static void cros_ec_proto_test_cmd_xfer_in_progress_return_error(struct kunit *t KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 2); } +static void cros_ec_proto_test_cmd_xfer_in_progress_return0(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + ec_dev->pkt_xfer = cros_kunit_ec_pkt_xfer_mock; + + /* For the first host command to return EC_RES_IN_PROGRESS. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, EC_RES_IN_PROGRESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For EC_CMD_GET_COMMS_STATUS. */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + ret = cros_ec_cmd_xfer(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, -EPROTO); + + KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 2); +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -2013,6 +2043,7 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_retries_status_processing), KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_xfer_error), KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_return_error), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_return0), {} }; From 3e1c715ea179201372384fad738680d524600985 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 18 Jul 2022 05:09:14 +0000 Subject: [PATCH 1180/1436] platform/chrome: cros_ec_proto: return -EPROTO if empty payload cros_ec_wait_until_complete() sends EC_CMD_GET_COMMS_STATUS which expects to receive sizeof(struct ec_response_get_comms_status) from cros_ec_xfer_command(). Return -EPROTO if cros_ec_xfer_command() returns 0. Reviewed-by: Guenter Roeck Signed-off-by: Tzung-Bi Shih Link: https://lore.kernel.org/r/20220718050914.2267370-11-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 9dec475edc84..05d2e8765a66 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -163,6 +163,11 @@ static int cros_ec_wait_until_complete(struct cros_ec_device *ec_dev, uint32_t * if (msg->result != EC_RES_SUCCESS) return ret; + if (ret == 0) { + ret = -EPROTO; + break; + } + if (!(status->flags & EC_COMMS_STATUS_PROCESSING)) return ret; } From 74bed42fd5fa4d3ac9883b27b0d761564f3b9bf9 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 22 Jun 2022 04:10:34 +0000 Subject: [PATCH 1181/1436] platform/chrome: cros_ec_proto: add Kunit tests for cmd_xfer_status cros_ec_cmd_xfer_status() calls cros_ec_cmd_xfer() and cros_ec_map_error(). Given that there are already test cases for cros_ec_cmd_xfer(), only add basic Kunit tests for cros_ec_cmd_xfer_status(). Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220622041040.202737-2-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index d76e09b8a36a..7949a2fa9c77 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -1964,6 +1964,46 @@ static void cros_ec_proto_test_cmd_xfer_in_progress_return0(struct kunit *test) KUNIT_EXPECT_EQ(test, cros_kunit_ec_pkt_xfer_mock_called, 2); } +static void cros_ec_proto_test_cmd_xfer_status_normal(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + /* For cros_ec_cmd_xfer(). */ + { + mock = cros_kunit_ec_xfer_mock_add(test, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + ret = cros_ec_cmd_xfer_status(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +static void cros_ec_proto_test_cmd_xfer_status_xfer_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct cros_ec_command msg; + + memset(&msg, 0, sizeof(msg)); + + /* For cros_ec_cmd_xfer(). */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, -EPROTO, EC_RES_SUCCESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + ret = cros_ec_cmd_xfer_status(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, -EPROTO); +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -2044,6 +2084,8 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_xfer_error), KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_return_error), KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_return0), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_normal), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_xfer_error), {} }; From 1242688fc2f080530b6414ef5f1ae63fb548a6b0 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 22 Jun 2022 04:10:35 +0000 Subject: [PATCH 1182/1436] platform/chrome: cros_ec_proto: add Kunit test for cros_ec_map_error() cros_ec_cmd_xfer_status() is the only exported function that calls static function cros_ec_map_error(). Add Kunit test for cros_ec_map_error() through calling cros_ec_cmd_xfer_status(). Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220622041040.202737-3-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 49 ++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 7949a2fa9c77..7fcda5e55378 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -2004,6 +2004,54 @@ static void cros_ec_proto_test_cmd_xfer_status_xfer_error(struct kunit *test) KUNIT_EXPECT_EQ(test, ret, -EPROTO); } +static void cros_ec_proto_test_cmd_xfer_status_return_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret, i; + struct cros_ec_command msg; + static const int map[] = { + [EC_RES_SUCCESS] = 0, + [EC_RES_INVALID_COMMAND] = -EOPNOTSUPP, + [EC_RES_ERROR] = -EIO, + [EC_RES_INVALID_PARAM] = -EINVAL, + [EC_RES_ACCESS_DENIED] = -EACCES, + [EC_RES_INVALID_RESPONSE] = -EPROTO, + [EC_RES_INVALID_VERSION] = -ENOPROTOOPT, + [EC_RES_INVALID_CHECKSUM] = -EBADMSG, + /* + * EC_RES_IN_PROGRESS is special because cros_ec_send_command() has extra logic to + * handle it. Note that default cros_kunit_ec_xfer_mock_default_ret == 0 thus + * cros_ec_xfer_command() in cros_ec_wait_until_complete() returns 0. As a result, + * it returns -EPROTO without calling cros_ec_map_error(). + */ + [EC_RES_IN_PROGRESS] = -EPROTO, + [EC_RES_UNAVAILABLE] = -ENODATA, + [EC_RES_TIMEOUT] = -ETIMEDOUT, + [EC_RES_OVERFLOW] = -EOVERFLOW, + [EC_RES_INVALID_HEADER] = -EBADR, + [EC_RES_REQUEST_TRUNCATED] = -EBADR, + [EC_RES_RESPONSE_TOO_BIG] = -EFBIG, + [EC_RES_BUS_ERROR] = -EFAULT, + [EC_RES_BUSY] = -EBUSY, + [EC_RES_INVALID_HEADER_VERSION] = -EBADMSG, + [EC_RES_INVALID_HEADER_CRC] = -EBADMSG, + [EC_RES_INVALID_DATA_CRC] = -EBADMSG, + [EC_RES_DUP_UNAVAILABLE] = -ENODATA, + }; + + memset(&msg, 0, sizeof(msg)); + + for (i = 0; i < ARRAY_SIZE(map); ++i) { + mock = cros_kunit_ec_xfer_mock_addx(test, 0, i, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + ret = cros_ec_cmd_xfer_status(ec_dev, &msg); + KUNIT_EXPECT_EQ(test, ret, map[i]); + } +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -2086,6 +2134,7 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_cmd_xfer_in_progress_return0), KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_normal), KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_xfer_error), + KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_return_error), {} }; From 2b7ed927953f30eaae0e622c670dcddce3bd3aa4 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 22 Jun 2022 04:10:36 +0000 Subject: [PATCH 1183/1436] platform/chrome: cros_ec_proto: add Kunit tests for get_next_event cros_ec_get_next_event() gets events from EC. It consists of 3 versions of event retrieval: 1. No MKBP event. 2. MKBP event version 0. 3. MKBP event version >0. Add Kunit tests for cros_ec_get_next_event(). Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220622041040.202737-4-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 266 +++++++++++++++++++ 1 file changed, 266 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 7fcda5e55378..e7d056ca62ec 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -5,6 +5,7 @@ #include +#include #include #include @@ -2052,6 +2053,265 @@ static void cros_ec_proto_test_cmd_xfer_status_return_error(struct kunit *test) } } +static void cros_ec_proto_test_get_next_event_no_mkbp_event(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + bool wake_event, more_events; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec_dev->mkbp_event_supported = 0; + + /* Set some garbage bytes. */ + wake_event = false; + more_events = true; + + /* For get_keyboard_state_event(). */ + { + union ec_response_get_next_data_v1 *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (union ec_response_get_next_data_v1 *)mock->o_data; + data->host_event = 0xbeef; + } + + ret = cros_ec_get_next_event(ec_dev, &wake_event, &more_events); + KUNIT_EXPECT_EQ(test, ret, sizeof(union ec_response_get_next_data_v1)); + + KUNIT_EXPECT_EQ(test, ec_dev->event_data.event_type, EC_MKBP_EVENT_KEY_MATRIX); + KUNIT_EXPECT_EQ(test, ec_dev->event_data.data.host_event, 0xbeef); + + KUNIT_EXPECT_TRUE(test, wake_event); + KUNIT_EXPECT_FALSE(test, more_events); + + /* For get_keyboard_state_event(). */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_MKBP_STATE); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(union ec_response_get_next_data_v1)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } +} + +static void cros_ec_proto_test_get_next_event_mkbp_event_ec_suspended(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + + ec_dev->mkbp_event_supported = 1; + ec_dev->suspended = true; + + ret = cros_ec_get_next_event(ec_dev, NULL, NULL); + KUNIT_EXPECT_EQ(test, ret, -EHOSTDOWN); +} + +static void cros_ec_proto_test_get_next_event_mkbp_event_version0(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + bool wake_event, more_events; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec_dev->mkbp_event_supported = 1; + + /* Set some garbage bytes. */ + wake_event = true; + more_events = false; + + /* For get_next_event_xfer(). */ + { + struct ec_response_get_next_event *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_next_event *)mock->o_data; + data->event_type = EC_MKBP_EVENT_SENSOR_FIFO | EC_MKBP_HAS_MORE_EVENTS; + data->data.sysrq = 0xbeef; + } + + ret = cros_ec_get_next_event(ec_dev, &wake_event, &more_events); + KUNIT_EXPECT_EQ(test, ret, sizeof(struct ec_response_get_next_event)); + + KUNIT_EXPECT_EQ(test, ec_dev->event_data.event_type, EC_MKBP_EVENT_SENSOR_FIFO); + KUNIT_EXPECT_EQ(test, ec_dev->event_data.data.sysrq, 0xbeef); + + KUNIT_EXPECT_FALSE(test, wake_event); + KUNIT_EXPECT_TRUE(test, more_events); + + /* For get_next_event_xfer(). */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_NEXT_EVENT); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_next_event)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } +} + +static void cros_ec_proto_test_get_next_event_mkbp_event_version2(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + bool wake_event, more_events; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec_dev->mkbp_event_supported = 3; + + /* Set some garbage bytes. */ + wake_event = false; + more_events = true; + + /* For get_next_event_xfer(). */ + { + struct ec_response_get_next_event_v1 *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_next_event_v1 *)mock->o_data; + data->event_type = EC_MKBP_EVENT_FINGERPRINT; + data->data.sysrq = 0xbeef; + } + + ret = cros_ec_get_next_event(ec_dev, &wake_event, &more_events); + KUNIT_EXPECT_EQ(test, ret, sizeof(struct ec_response_get_next_event_v1)); + + KUNIT_EXPECT_EQ(test, ec_dev->event_data.event_type, EC_MKBP_EVENT_FINGERPRINT); + KUNIT_EXPECT_EQ(test, ec_dev->event_data.data.sysrq, 0xbeef); + + KUNIT_EXPECT_TRUE(test, wake_event); + KUNIT_EXPECT_FALSE(test, more_events); + + /* For get_next_event_xfer(). */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 2); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_NEXT_EVENT); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_next_event_v1)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } +} + +static void cros_ec_proto_test_get_next_event_mkbp_event_host_event_rtc(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + bool wake_event; + struct ec_response_get_next_event_v1 *data; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec_dev->mkbp_event_supported = 3; + ec_dev->host_event_wake_mask = U32_MAX; + + /* Set some garbage bytes. */ + wake_event = true; + + /* For get_next_event_xfer(). */ + { + mock = cros_kunit_ec_xfer_mock_add(test, + sizeof(data->event_type) + + sizeof(data->data.host_event)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_next_event_v1 *)mock->o_data; + data->event_type = EC_MKBP_EVENT_HOST_EVENT; + put_unaligned_le32(EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC), &data->data.host_event); + } + + ret = cros_ec_get_next_event(ec_dev, &wake_event, NULL); + KUNIT_EXPECT_EQ(test, ret, sizeof(data->event_type) + sizeof(data->data.host_event)); + + KUNIT_EXPECT_EQ(test, ec_dev->event_data.event_type, EC_MKBP_EVENT_HOST_EVENT); + + KUNIT_EXPECT_FALSE(test, wake_event); + + /* For get_next_event_xfer(). */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 2); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_NEXT_EVENT); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_next_event_v1)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } +} + +static void cros_ec_proto_test_get_next_event_mkbp_event_host_event_masked(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + bool wake_event; + struct ec_response_get_next_event_v1 *data; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec_dev->mkbp_event_supported = 3; + ec_dev->host_event_wake_mask = U32_MAX & ~EC_HOST_EVENT_MASK(EC_HOST_EVENT_AC_DISCONNECTED); + + /* Set some garbage bytes. */ + wake_event = true; + + /* For get_next_event_xfer(). */ + { + mock = cros_kunit_ec_xfer_mock_add(test, + sizeof(data->event_type) + + sizeof(data->data.host_event)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_next_event_v1 *)mock->o_data; + data->event_type = EC_MKBP_EVENT_HOST_EVENT; + put_unaligned_le32(EC_HOST_EVENT_MASK(EC_HOST_EVENT_AC_DISCONNECTED), + &data->data.host_event); + } + + ret = cros_ec_get_next_event(ec_dev, &wake_event, NULL); + KUNIT_EXPECT_EQ(test, ret, sizeof(data->event_type) + sizeof(data->data.host_event)); + + KUNIT_EXPECT_EQ(test, ec_dev->event_data.event_type, EC_MKBP_EVENT_HOST_EVENT); + + KUNIT_EXPECT_FALSE(test, wake_event); + + /* For get_next_event_xfer(). */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 2); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_NEXT_EVENT); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_get_next_event_v1)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -2135,6 +2395,12 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_normal), KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_xfer_error), KUNIT_CASE(cros_ec_proto_test_cmd_xfer_status_return_error), + KUNIT_CASE(cros_ec_proto_test_get_next_event_no_mkbp_event), + KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_ec_suspended), + KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_version0), + KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_version2), + KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_host_event_rtc), + KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_host_event_masked), {} }; From 7cb1eb82642becd668665689c6eac2a639a81e1b Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 22 Jun 2022 04:10:37 +0000 Subject: [PATCH 1184/1436] platform/chrome: cros_ec_proto: add Kunit tests for get_host_event cros_ec_get_host_event() performs some sanity checks, parses `ec_dev->event_data.data.host_event`, and returns bitmap of EC_HOST_EVENT_*. Add Kunit tests for cros_ec_get_host_event(). Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220622041040.202737-5-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 59 ++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index e7d056ca62ec..880bdf54570b 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -2312,6 +2312,61 @@ static void cros_ec_proto_test_get_next_event_mkbp_event_host_event_masked(struc } } +static void cros_ec_proto_test_get_host_event_no_mkbp_event(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + + ec_dev->mkbp_event_supported = 0; + + ret = cros_ec_get_host_event(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +static void cros_ec_proto_test_get_host_event_not_host_event(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + + ec_dev->mkbp_event_supported = 1; + ec_dev->event_data.event_type = EC_MKBP_EVENT_FINGERPRINT; + + ret = cros_ec_get_host_event(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +static void cros_ec_proto_test_get_host_event_wrong_event_size(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + + ec_dev->mkbp_event_supported = 1; + ec_dev->event_data.event_type = EC_MKBP_EVENT_HOST_EVENT; + ec_dev->event_size = 0xff; + + ret = cros_ec_get_host_event(ec_dev); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +static void cros_ec_proto_test_get_host_event_normal(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + int ret; + + ec_dev->mkbp_event_supported = 1; + ec_dev->event_data.event_type = EC_MKBP_EVENT_HOST_EVENT; + ec_dev->event_size = sizeof(ec_dev->event_data.data.host_event); + put_unaligned_le32(EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC), + &ec_dev->event_data.data.host_event); + + ret = cros_ec_get_host_event(ec_dev); + KUNIT_EXPECT_EQ(test, ret, EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC)); +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -2401,6 +2456,10 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_version2), KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_host_event_rtc), KUNIT_CASE(cros_ec_proto_test_get_next_event_mkbp_event_host_event_masked), + KUNIT_CASE(cros_ec_proto_test_get_host_event_no_mkbp_event), + KUNIT_CASE(cros_ec_proto_test_get_host_event_not_host_event), + KUNIT_CASE(cros_ec_proto_test_get_host_event_wrong_event_size), + KUNIT_CASE(cros_ec_proto_test_get_host_event_normal), {} }; From 00238864435f97dc578cc8b2de7ecc95a1fca0b9 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 22 Jun 2022 04:10:38 +0000 Subject: [PATCH 1185/1436] platform/chrome: cros_ec_proto: add Kunit tests for check_features cros_ec_check_features() gets EC features if it hasn't had cache, and checks whether the given EC_FEATURE_* is supported or not. Add Kunit tests for cros_ec_check_features(). Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220622041040.202737-6-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 77 ++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 880bdf54570b..14b259d23e22 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -2367,6 +2367,81 @@ static void cros_ec_proto_test_get_host_event_normal(struct kunit *test) KUNIT_EXPECT_EQ(test, ret, EC_HOST_EVENT_MASK(EC_HOST_EVENT_RTC)); } +static void cros_ec_proto_test_check_features_cached(struct kunit *test) +{ + int ret, i; + struct cros_ec_dev ec; + + ec.features.flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FINGERPRINT); + ec.features.flags[1] = EC_FEATURE_MASK_0(EC_FEATURE_SCP); + + for (i = 0; i < EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK; ++i) { + ret = cros_ec_check_features(&ec, i); + switch (i) { + case EC_FEATURE_FINGERPRINT: + case EC_FEATURE_SCP: + KUNIT_EXPECT_TRUE(test, ret); + break; + default: + KUNIT_EXPECT_FALSE(test, ret); + break; + } + } +} + +static void cros_ec_proto_test_check_features_not_cached(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret, i; + struct cros_ec_dev ec; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec.ec_dev = ec_dev; + ec.dev = ec_dev->dev; + ec.cmd_offset = 0; + ec.features.flags[0] = -1; + ec.features.flags[1] = -1; + + /* For EC_CMD_GET_FEATURES. */ + { + struct ec_response_get_features *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_get_features *)mock->o_data; + data->flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FINGERPRINT); + data->flags[1] = EC_FEATURE_MASK_0(EC_FEATURE_SCP); + } + + for (i = 0; i < EC_FEATURE_TYPEC_MUX_REQUIRE_AP_ACK; ++i) { + ret = cros_ec_check_features(&ec, i); + switch (i) { + case EC_FEATURE_FINGERPRINT: + case EC_FEATURE_SCP: + KUNIT_EXPECT_TRUE(test, ret); + break; + default: + KUNIT_EXPECT_FALSE(test, ret); + break; + } + } + + /* For EC_CMD_GET_FEATURES. */ + { + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_GET_FEATURES); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_get_features)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, 0); + } +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -2460,6 +2535,8 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_get_host_event_not_host_event), KUNIT_CASE(cros_ec_proto_test_get_host_event_wrong_event_size), KUNIT_CASE(cros_ec_proto_test_get_host_event_normal), + KUNIT_CASE(cros_ec_proto_test_check_features_cached), + KUNIT_CASE(cros_ec_proto_test_check_features_not_cached), {} }; From 33f0fdba6066b504ee0b5f1480b1f93b06050df6 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 22 Jun 2022 04:10:39 +0000 Subject: [PATCH 1186/1436] platform/chrome: cros_ec_proto: add Kunit tests for get_sensor_count cros_ec_get_sensor_count() gets number of MEMS sensors. Add Kunit tests for cros_ec_get_sensor_count(). Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220622041040.202737-7-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 153 +++++++++++++++++++ drivers/platform/chrome/cros_kunit_util.c | 22 +++ drivers/platform/chrome/cros_kunit_util.h | 7 + 3 files changed, 182 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 14b259d23e22..7e6c606a5fda 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -2442,6 +2442,156 @@ static void cros_ec_proto_test_check_features_not_cached(struct kunit *test) } } +static void cros_ec_proto_test_get_sensor_count_normal(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct cros_ec_dev ec; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec.ec_dev = ec_dev; + ec.dev = ec_dev->dev; + ec.cmd_offset = 0; + + /* For EC_CMD_MOTION_SENSE_CMD. */ + { + struct ec_response_motion_sense *data; + + mock = cros_kunit_ec_xfer_mock_add(test, sizeof(*data)); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (struct ec_response_motion_sense *)mock->o_data; + data->dump.sensor_count = 0xbf; + } + + ret = cros_ec_get_sensor_count(&ec); + KUNIT_EXPECT_EQ(test, ret, 0xbf); + + /* For EC_CMD_MOTION_SENSE_CMD. */ + { + struct ec_params_motion_sense *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 1); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_MOTION_SENSE_CMD); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_motion_sense)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data)); + + data = (struct ec_params_motion_sense *)mock->i_data; + KUNIT_EXPECT_EQ(test, data->cmd, MOTIONSENSE_CMD_DUMP); + } +} + +static void cros_ec_proto_test_get_sensor_count_xfer_error(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + struct cros_ec_dev ec; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec.ec_dev = ec_dev; + ec.dev = ec_dev->dev; + ec.cmd_offset = 0; + + /* For EC_CMD_MOTION_SENSE_CMD. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, -EPROTO, EC_RES_SUCCESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + ret = cros_ec_get_sensor_count(&ec); + KUNIT_EXPECT_EQ(test, ret, -EPROTO); + + /* For EC_CMD_MOTION_SENSE_CMD. */ + { + struct ec_params_motion_sense *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 1); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_MOTION_SENSE_CMD); + KUNIT_EXPECT_EQ(test, mock->msg.insize, sizeof(struct ec_response_motion_sense)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data)); + + data = (struct ec_params_motion_sense *)mock->i_data; + KUNIT_EXPECT_EQ(test, data->cmd, MOTIONSENSE_CMD_DUMP); + } +} + +static void cros_ec_proto_test_get_sensor_count_legacy(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret, i; + struct cros_ec_dev ec; + struct { + u8 readmem_data; + int expected_result; + } test_data[] = { + { 0, 0 }, + { EC_MEMMAP_ACC_STATUS_PRESENCE_BIT, 2 }, + }; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + ec_dev->cmd_readmem = cros_kunit_readmem_mock; + ec.ec_dev = ec_dev; + ec.dev = ec_dev->dev; + ec.cmd_offset = 0; + + for (i = 0; i < ARRAY_SIZE(test_data); ++i) { + /* For EC_CMD_MOTION_SENSE_CMD. */ + { + mock = cros_kunit_ec_xfer_mock_addx(test, -EPROTO, EC_RES_SUCCESS, 0); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + } + + /* For readmem. */ + { + cros_kunit_readmem_mock_data = kunit_kzalloc(test, 1, GFP_KERNEL); + KUNIT_ASSERT_PTR_NE(test, cros_kunit_readmem_mock_data, NULL); + cros_kunit_readmem_mock_data[0] = test_data[i].readmem_data; + + cros_kunit_ec_xfer_mock_default_ret = 1; + } + + ret = cros_ec_get_sensor_count(&ec); + KUNIT_EXPECT_EQ(test, ret, test_data[i].expected_result); + + /* For EC_CMD_MOTION_SENSE_CMD. */ + { + struct ec_params_motion_sense *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 1); + KUNIT_EXPECT_EQ(test, mock->msg.command, EC_CMD_MOTION_SENSE_CMD); + KUNIT_EXPECT_EQ(test, mock->msg.insize, + sizeof(struct ec_response_motion_sense)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, sizeof(*data)); + + data = (struct ec_params_motion_sense *)mock->i_data; + KUNIT_EXPECT_EQ(test, data->cmd, MOTIONSENSE_CMD_DUMP); + } + + /* For readmem. */ + { + KUNIT_EXPECT_EQ(test, cros_kunit_readmem_mock_offset, EC_MEMMAP_ACC_STATUS); + } + } +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -2537,6 +2687,9 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_get_host_event_normal), KUNIT_CASE(cros_ec_proto_test_check_features_cached), KUNIT_CASE(cros_ec_proto_test_check_features_not_cached), + KUNIT_CASE(cros_ec_proto_test_get_sensor_count_normal), + KUNIT_CASE(cros_ec_proto_test_get_sensor_count_xfer_error), + KUNIT_CASE(cros_ec_proto_test_get_sensor_count_legacy), {} }; diff --git a/drivers/platform/chrome/cros_kunit_util.c b/drivers/platform/chrome/cros_kunit_util.c index 3ede971e82ee..d37c334b416d 100644 --- a/drivers/platform/chrome/cros_kunit_util.c +++ b/drivers/platform/chrome/cros_kunit_util.c @@ -105,6 +105,24 @@ struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void) } EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_next); +int cros_kunit_readmem_mock_offset; +EXPORT_SYMBOL_GPL(cros_kunit_readmem_mock_offset); +u8 *cros_kunit_readmem_mock_data; +EXPORT_SYMBOL_GPL(cros_kunit_readmem_mock_data); +int cros_kunit_readmem_mock_ret; +EXPORT_SYMBOL_GPL(cros_kunit_readmem_mock_ret); + +int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset, + unsigned int bytes, void *dest) +{ + cros_kunit_readmem_mock_offset = offset; + + memcpy(dest, cros_kunit_readmem_mock_data, bytes); + + return cros_kunit_readmem_mock_ret; +} +EXPORT_SYMBOL_GPL(cros_kunit_readmem_mock); + void cros_kunit_mock_reset(void) { cros_kunit_ec_xfer_mock_default_ret = 0; @@ -112,6 +130,10 @@ void cros_kunit_mock_reset(void) cros_kunit_ec_pkt_xfer_mock_called = 0; INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_in); INIT_LIST_HEAD(&cros_kunit_ec_xfer_mock_out); + + cros_kunit_readmem_mock_offset = 0; + cros_kunit_readmem_mock_data = NULL; + cros_kunit_readmem_mock_ret = 0; } EXPORT_SYMBOL_GPL(cros_kunit_mock_reset); diff --git a/drivers/platform/chrome/cros_kunit_util.h b/drivers/platform/chrome/cros_kunit_util.h index ae4080cb13f1..88134c9f1acf 100644 --- a/drivers/platform/chrome/cros_kunit_util.h +++ b/drivers/platform/chrome/cros_kunit_util.h @@ -35,6 +35,13 @@ struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test, int ret, int result, size_t size); struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void); +extern int cros_kunit_readmem_mock_offset; +extern u8 *cros_kunit_readmem_mock_data; +extern int cros_kunit_readmem_mock_ret; + +int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset, + unsigned int bytes, void *dest); + void cros_kunit_mock_reset(void); #endif From 9399b2cb20702fde2a5f9c6aec9cd70d21d40a00 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 22 Jun 2022 04:10:40 +0000 Subject: [PATCH 1187/1436] platform/chrome: cros_ec_proto: add Kunit test for cros_ec_cmd() cros_ec_cmd() is a wrapper of cros_ec_cmd_xfer_status(). Add Kunit test for cros_ec_cmd(). Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220622041040.202737-8-tzungbi@kernel.org --- drivers/platform/chrome/cros_ec_proto_test.c | 48 ++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c index 7e6c606a5fda..c6a83df91ae1 100644 --- a/drivers/platform/chrome/cros_ec_proto_test.c +++ b/drivers/platform/chrome/cros_ec_proto_test.c @@ -2592,6 +2592,53 @@ static void cros_ec_proto_test_get_sensor_count_legacy(struct kunit *test) } } +static void cros_ec_proto_test_ec_cmd(struct kunit *test) +{ + struct cros_ec_proto_test_priv *priv = test->priv; + struct cros_ec_device *ec_dev = &priv->ec_dev; + struct ec_xfer_mock *mock; + int ret; + u8 out[3], in[2]; + + ec_dev->max_request = 0xff; + ec_dev->max_response = 0xee; + + out[0] = 0xdd; + out[1] = 0xcc; + out[2] = 0xbb; + + { + u8 *data; + + mock = cros_kunit_ec_xfer_mock_add(test, 2); + KUNIT_ASSERT_PTR_NE(test, mock, NULL); + + data = (u8 *)mock->o_data; + data[0] = 0xaa; + data[1] = 0x99; + } + + ret = cros_ec_cmd(ec_dev, 0x88, 0x77, out, ARRAY_SIZE(out), in, ARRAY_SIZE(in)); + KUNIT_EXPECT_EQ(test, ret, 2); + + { + u8 *data; + + mock = cros_kunit_ec_xfer_mock_next(); + KUNIT_EXPECT_PTR_NE(test, mock, NULL); + + KUNIT_EXPECT_EQ(test, mock->msg.version, 0x88); + KUNIT_EXPECT_EQ(test, mock->msg.command, 0x77); + KUNIT_EXPECT_EQ(test, mock->msg.insize, ARRAY_SIZE(in)); + KUNIT_EXPECT_EQ(test, mock->msg.outsize, ARRAY_SIZE(out)); + + data = (u8 *)mock->i_data; + KUNIT_EXPECT_EQ(test, data[0], 0xdd); + KUNIT_EXPECT_EQ(test, data[1], 0xcc); + KUNIT_EXPECT_EQ(test, data[2], 0xbb); + } +} + static void cros_ec_proto_test_release(struct device *dev) { } @@ -2690,6 +2737,7 @@ static struct kunit_case cros_ec_proto_test_cases[] = { KUNIT_CASE(cros_ec_proto_test_get_sensor_count_normal), KUNIT_CASE(cros_ec_proto_test_get_sensor_count_xfer_error), KUNIT_CASE(cros_ec_proto_test_get_sensor_count_legacy), + KUNIT_CASE(cros_ec_proto_test_ec_cmd), {} }; From 7e76e4bc00999846c17604dc25486fffa542078d Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Mon, 18 Jul 2022 10:50:47 +0000 Subject: [PATCH 1188/1436] platform/chrome: cros_kbd_led_backlight: fix build warning drivers/platform/chrome/cros_kbd_led_backlight.c got a new build warning when using the randconfig in [1]: >>> warning: unused variable 'keyboard_led_drvdata_ec_pwm' The warning happens when CONFIG_CROS_EC is set but CONFIG_OF is not set. Reproduce: - mkdir build_dir - wget [1] -O build_dir/.config - COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 \ O=build_dir ARCH=s390 SHELL=/bin/bash drivers/platform/chrome/ Fix the warning by using __maybe_unused. Also use IS_ENABLED() because CROS_EC is a tristate. [1]: https://download.01.org/0day-ci/archive/20220717/202207170538.MR39dw8m-lkp@intel.com/config Fixes: 40f58143745e ("platform/chrome: cros_kbd_led_backlight: support EC PWM backend") Reported-by: kernel test robot Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220718105047.2356542-1-tzungbi@kernel.org --- drivers/platform/chrome/cros_kbd_led_backlight.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/platform/chrome/cros_kbd_led_backlight.c b/drivers/platform/chrome/cros_kbd_led_backlight.c index 5ad41c10412d..793fd3f1015d 100644 --- a/drivers/platform/chrome/cros_kbd_led_backlight.c +++ b/drivers/platform/chrome/cros_kbd_led_backlight.c @@ -119,7 +119,7 @@ static const struct keyboard_led_drvdata keyboard_led_drvdata_acpi = { #endif /* CONFIG_ACPI */ -#ifdef CONFIG_CROS_EC +#if IS_ENABLED(CONFIG_CROS_EC) static int keyboard_led_set_brightness_ec_pwm(struct led_classdev *cdev, @@ -180,18 +180,18 @@ static int keyboard_led_init_ec_pwm(struct platform_device *pdev) return 0; } -static const struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = { +static const __maybe_unused struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = { .init = keyboard_led_init_ec_pwm, .brightness_set_blocking = keyboard_led_set_brightness_ec_pwm, .brightness_get = keyboard_led_get_brightness_ec_pwm, .max_brightness = KEYBOARD_BACKLIGHT_MAX, }; -#else /* CONFIG_CROS_EC */ +#else /* IS_ENABLED(CONFIG_CROS_EC) */ -static const struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = {}; +static const __maybe_unused struct keyboard_led_drvdata keyboard_led_drvdata_ec_pwm = {}; -#endif /* CONFIG_CROS_EC */ +#endif /* IS_ENABLED(CONFIG_CROS_EC) */ static int keyboard_led_probe(struct platform_device *pdev) { From 0130337ec45bffd26ba3e782850da3b68f1eef9d Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Wed, 4 May 2022 14:29:08 +0200 Subject: [PATCH 1189/1436] KVM: s390: Cleanup ipte lock access and SIIF facility checks We can check if SIIF is enabled by testing the sclp_info struct instead of testing the sie control block eca variable as that facility is always enabled if available. Also let's cleanup all the ipte related struct member accesses which currently happen by referencing the KVM struct via the VCPU struct. Making the KVM struct the parameter to the ipte_* functions removes one level of indirection which makes the code more readable. Signed-off-by: Pierre Morel Reviewed-by: Janosch Frank Reviewed-by: David Hildenbrand Reviewed-by: Nico Boehr Link: https://lore.kernel.org/all/20220711084148.25017-2-pmorel@linux.ibm.com/ Signed-off-by: Janosch Frank --- arch/s390/kvm/gaccess.c | 96 ++++++++++++++++++++--------------------- arch/s390/kvm/gaccess.h | 6 +-- arch/s390/kvm/priv.c | 6 +-- 3 files changed, 54 insertions(+), 54 deletions(-) diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c index 227ed0009354..082ec5f2c3a5 100644 --- a/arch/s390/kvm/gaccess.c +++ b/arch/s390/kvm/gaccess.c @@ -262,77 +262,77 @@ struct aste { /* .. more fields there */ }; -int ipte_lock_held(struct kvm_vcpu *vcpu) +int ipte_lock_held(struct kvm *kvm) { - if (vcpu->arch.sie_block->eca & ECA_SII) { + if (sclp.has_siif) { int rc; - read_lock(&vcpu->kvm->arch.sca_lock); - rc = kvm_s390_get_ipte_control(vcpu->kvm)->kh != 0; - read_unlock(&vcpu->kvm->arch.sca_lock); + read_lock(&kvm->arch.sca_lock); + rc = kvm_s390_get_ipte_control(kvm)->kh != 0; + read_unlock(&kvm->arch.sca_lock); return rc; } - return vcpu->kvm->arch.ipte_lock_count != 0; + return kvm->arch.ipte_lock_count != 0; } -static void ipte_lock_simple(struct kvm_vcpu *vcpu) +static void ipte_lock_simple(struct kvm *kvm) { union ipte_control old, new, *ic; - mutex_lock(&vcpu->kvm->arch.ipte_mutex); - vcpu->kvm->arch.ipte_lock_count++; - if (vcpu->kvm->arch.ipte_lock_count > 1) + mutex_lock(&kvm->arch.ipte_mutex); + kvm->arch.ipte_lock_count++; + if (kvm->arch.ipte_lock_count > 1) goto out; retry: - read_lock(&vcpu->kvm->arch.sca_lock); - ic = kvm_s390_get_ipte_control(vcpu->kvm); + read_lock(&kvm->arch.sca_lock); + ic = kvm_s390_get_ipte_control(kvm); do { old = READ_ONCE(*ic); if (old.k) { - read_unlock(&vcpu->kvm->arch.sca_lock); + read_unlock(&kvm->arch.sca_lock); cond_resched(); goto retry; } new = old; new.k = 1; } while (cmpxchg(&ic->val, old.val, new.val) != old.val); - read_unlock(&vcpu->kvm->arch.sca_lock); + read_unlock(&kvm->arch.sca_lock); out: - mutex_unlock(&vcpu->kvm->arch.ipte_mutex); + mutex_unlock(&kvm->arch.ipte_mutex); } -static void ipte_unlock_simple(struct kvm_vcpu *vcpu) +static void ipte_unlock_simple(struct kvm *kvm) { union ipte_control old, new, *ic; - mutex_lock(&vcpu->kvm->arch.ipte_mutex); - vcpu->kvm->arch.ipte_lock_count--; - if (vcpu->kvm->arch.ipte_lock_count) + mutex_lock(&kvm->arch.ipte_mutex); + kvm->arch.ipte_lock_count--; + if (kvm->arch.ipte_lock_count) goto out; - read_lock(&vcpu->kvm->arch.sca_lock); - ic = kvm_s390_get_ipte_control(vcpu->kvm); + read_lock(&kvm->arch.sca_lock); + ic = kvm_s390_get_ipte_control(kvm); do { old = READ_ONCE(*ic); new = old; new.k = 0; } while (cmpxchg(&ic->val, old.val, new.val) != old.val); - read_unlock(&vcpu->kvm->arch.sca_lock); - wake_up(&vcpu->kvm->arch.ipte_wq); + read_unlock(&kvm->arch.sca_lock); + wake_up(&kvm->arch.ipte_wq); out: - mutex_unlock(&vcpu->kvm->arch.ipte_mutex); + mutex_unlock(&kvm->arch.ipte_mutex); } -static void ipte_lock_siif(struct kvm_vcpu *vcpu) +static void ipte_lock_siif(struct kvm *kvm) { union ipte_control old, new, *ic; retry: - read_lock(&vcpu->kvm->arch.sca_lock); - ic = kvm_s390_get_ipte_control(vcpu->kvm); + read_lock(&kvm->arch.sca_lock); + ic = kvm_s390_get_ipte_control(kvm); do { old = READ_ONCE(*ic); if (old.kg) { - read_unlock(&vcpu->kvm->arch.sca_lock); + read_unlock(&kvm->arch.sca_lock); cond_resched(); goto retry; } @@ -340,15 +340,15 @@ retry: new.k = 1; new.kh++; } while (cmpxchg(&ic->val, old.val, new.val) != old.val); - read_unlock(&vcpu->kvm->arch.sca_lock); + read_unlock(&kvm->arch.sca_lock); } -static void ipte_unlock_siif(struct kvm_vcpu *vcpu) +static void ipte_unlock_siif(struct kvm *kvm) { union ipte_control old, new, *ic; - read_lock(&vcpu->kvm->arch.sca_lock); - ic = kvm_s390_get_ipte_control(vcpu->kvm); + read_lock(&kvm->arch.sca_lock); + ic = kvm_s390_get_ipte_control(kvm); do { old = READ_ONCE(*ic); new = old; @@ -356,25 +356,25 @@ static void ipte_unlock_siif(struct kvm_vcpu *vcpu) if (!new.kh) new.k = 0; } while (cmpxchg(&ic->val, old.val, new.val) != old.val); - read_unlock(&vcpu->kvm->arch.sca_lock); + read_unlock(&kvm->arch.sca_lock); if (!new.kh) - wake_up(&vcpu->kvm->arch.ipte_wq); + wake_up(&kvm->arch.ipte_wq); } -void ipte_lock(struct kvm_vcpu *vcpu) +void ipte_lock(struct kvm *kvm) { - if (vcpu->arch.sie_block->eca & ECA_SII) - ipte_lock_siif(vcpu); + if (sclp.has_siif) + ipte_lock_siif(kvm); else - ipte_lock_simple(vcpu); + ipte_lock_simple(kvm); } -void ipte_unlock(struct kvm_vcpu *vcpu) +void ipte_unlock(struct kvm *kvm) { - if (vcpu->arch.sie_block->eca & ECA_SII) - ipte_unlock_siif(vcpu); + if (sclp.has_siif) + ipte_unlock_siif(kvm); else - ipte_unlock_simple(vcpu); + ipte_unlock_simple(kvm); } static int ar_translation(struct kvm_vcpu *vcpu, union asce *asce, u8 ar, @@ -1086,7 +1086,7 @@ int access_guest_with_key(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, try_storage_prot_override = storage_prot_override_applicable(vcpu); need_ipte_lock = psw_bits(*psw).dat && !asce.r; if (need_ipte_lock) - ipte_lock(vcpu); + ipte_lock(vcpu->kvm); /* * Since we do the access further down ultimately via a move instruction * that does key checking and returns an error in case of a protection @@ -1127,7 +1127,7 @@ int access_guest_with_key(struct kvm_vcpu *vcpu, unsigned long ga, u8 ar, } out_unlock: if (need_ipte_lock) - ipte_unlock(vcpu); + ipte_unlock(vcpu->kvm); if (nr_pages > ARRAY_SIZE(gpa_array)) vfree(gpas); return rc; @@ -1199,10 +1199,10 @@ int check_gva_range(struct kvm_vcpu *vcpu, unsigned long gva, u8 ar, rc = get_vcpu_asce(vcpu, &asce, gva, ar, mode); if (rc) return rc; - ipte_lock(vcpu); + ipte_lock(vcpu->kvm); rc = guest_range_to_gpas(vcpu, gva, ar, NULL, length, asce, mode, access_key); - ipte_unlock(vcpu); + ipte_unlock(vcpu->kvm); return rc; } @@ -1465,7 +1465,7 @@ int kvm_s390_shadow_fault(struct kvm_vcpu *vcpu, struct gmap *sg, * tables/pointers we read stay valid - unshadowing is however * always possible - only guest_table_lock protects us. */ - ipte_lock(vcpu); + ipte_lock(vcpu->kvm); rc = gmap_shadow_pgt_lookup(sg, saddr, &pgt, &dat_protection, &fake); if (rc) @@ -1499,7 +1499,7 @@ shadow_page: pte.p |= dat_protection; if (!rc) rc = gmap_shadow_page(sg, saddr, __pte(pte.val)); - ipte_unlock(vcpu); + ipte_unlock(vcpu->kvm); mmap_read_unlock(sg->mm); return rc; } diff --git a/arch/s390/kvm/gaccess.h b/arch/s390/kvm/gaccess.h index 1124ff282012..9408d6cc8e2c 100644 --- a/arch/s390/kvm/gaccess.h +++ b/arch/s390/kvm/gaccess.h @@ -440,9 +440,9 @@ int read_guest_real(struct kvm_vcpu *vcpu, unsigned long gra, void *data, return access_guest_real(vcpu, gra, data, len, 0); } -void ipte_lock(struct kvm_vcpu *vcpu); -void ipte_unlock(struct kvm_vcpu *vcpu); -int ipte_lock_held(struct kvm_vcpu *vcpu); +void ipte_lock(struct kvm *kvm); +void ipte_unlock(struct kvm *kvm); +int ipte_lock_held(struct kvm *kvm); int kvm_s390_check_low_addr_prot_real(struct kvm_vcpu *vcpu, unsigned long gra); /* MVPG PEI indication bits */ diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 83bb5cf97282..12c464c7cddf 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -442,7 +442,7 @@ static int handle_ipte_interlock(struct kvm_vcpu *vcpu) vcpu->stat.instruction_ipte_interlock++; if (psw_bits(vcpu->arch.sie_block->gpsw).pstate) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); - wait_event(vcpu->kvm->arch.ipte_wq, !ipte_lock_held(vcpu)); + wait_event(vcpu->kvm->arch.ipte_wq, !ipte_lock_held(vcpu->kvm)); kvm_s390_retry_instr(vcpu); VCPU_EVENT(vcpu, 4, "%s", "retrying ipte interlock operation"); return 0; @@ -1471,7 +1471,7 @@ static int handle_tprot(struct kvm_vcpu *vcpu) access_key = (operand2 & 0xf0) >> 4; if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT) - ipte_lock(vcpu); + ipte_lock(vcpu->kvm); ret = guest_translate_address_with_key(vcpu, address, ar, &gpa, GACC_STORE, access_key); @@ -1508,7 +1508,7 @@ static int handle_tprot(struct kvm_vcpu *vcpu) } if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_DAT) - ipte_unlock(vcpu); + ipte_unlock(vcpu->kvm); return ret; } From 24fe0195bc19306b2769b43b3e22bd35bd6fb061 Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 14 Jul 2022 12:18:23 +0200 Subject: [PATCH 1190/1436] KVM: s390: guest support for topology function We report a topology change to the guest for any CPU hotplug. The reporting to the guest is done using the Multiprocessor Topology-Change-Report (MTCR) bit of the utility entry in the guest's SCA which will be cleared during the interpretation of PTF. On every vCPU creation we set the MCTR bit to let the guest know the next time it uses the PTF with command 2 instruction that the topology changed and that it should use the STSI(15.1.x) instruction to get the topology details. STSI(15.1.x) gives information on the CPU configuration topology. Let's accept the interception of STSI with the function code 15 and let the userland part of the hypervisor handle it when userland supports the CPU Topology facility. Signed-off-by: Pierre Morel Reviewed-by: Nico Boehr Reviewed-by: Janis Schoetterl-Glausch Reviewed-by: Janosch Frank Link: https://lore.kernel.org/r/20220714101824.101601-2-pmorel@linux.ibm.com Message-Id: <20220714101824.101601-2-pmorel@linux.ibm.com> Signed-off-by: Janosch Frank --- arch/s390/include/asm/kvm_host.h | 18 +++++++++++++++--- arch/s390/kvm/kvm-s390.c | 31 +++++++++++++++++++++++++++++++ arch/s390/kvm/priv.c | 20 ++++++++++++++++---- arch/s390/kvm/vsie.c | 8 ++++++++ 4 files changed, 70 insertions(+), 7 deletions(-) diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 6f9fc8bb0303..f39092e0ceaa 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h @@ -95,19 +95,30 @@ union ipte_control { }; }; +union sca_utility { + __u16 val; + struct { + __u16 mtcr : 1; + __u16 reserved : 15; + }; +}; + struct bsca_block { union ipte_control ipte_control; __u64 reserved[5]; __u64 mcn; - __u64 reserved2; + union sca_utility utility; + __u8 reserved2[6]; struct bsca_entry cpu[KVM_S390_BSCA_CPU_SLOTS]; }; struct esca_block { union ipte_control ipte_control; - __u64 reserved1[7]; + __u64 reserved1[6]; + union sca_utility utility; + __u8 reserved2[6]; __u64 mcn[4]; - __u64 reserved2[20]; + __u64 reserved3[20]; struct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS]; }; @@ -251,6 +262,7 @@ struct kvm_s390_sie_block { #define ECB_SPECI 0x08 #define ECB_SRSI 0x04 #define ECB_HOSTPROTINT 0x02 +#define ECB_PTF 0x01 __u8 ecb; /* 0x0061 */ #define ECB2_CMMA 0x80 #define ECB2_IEP 0x20 diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 5b77c43fbb01..5d18b66a08c9 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -1763,6 +1763,32 @@ static int kvm_s390_get_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr) return ret; } +/** + * kvm_s390_update_topology_change_report - update CPU topology change report + * @kvm: guest KVM description + * @val: set or clear the MTCR bit + * + * Updates the Multiprocessor Topology-Change-Report bit to signal + * the guest with a topology change. + * This is only relevant if the topology facility is present. + * + * The SCA version, bsca or esca, doesn't matter as offset is the same. + */ +static void kvm_s390_update_topology_change_report(struct kvm *kvm, bool val) +{ + union sca_utility new, old; + struct bsca_block *sca; + + read_lock(&kvm->arch.sca_lock); + sca = kvm->arch.sca; + do { + old = READ_ONCE(sca->utility); + new = old; + new.mtcr = val; + } while (cmpxchg(&sca->utility.val, old.val, new.val) != old.val); + read_unlock(&kvm->arch.sca_lock); +} + static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) { int ret; @@ -3172,6 +3198,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) kvm_clear_async_pf_completion_queue(vcpu); if (!kvm_is_ucontrol(vcpu->kvm)) sca_del_vcpu(vcpu); + kvm_s390_update_topology_change_report(vcpu->kvm, 1); if (kvm_is_ucontrol(vcpu->kvm)) gmap_remove(vcpu->arch.gmap); @@ -3574,6 +3601,8 @@ static int kvm_s390_vcpu_setup(struct kvm_vcpu *vcpu) vcpu->arch.sie_block->ecb |= ECB_HOSTPROTINT; if (test_kvm_facility(vcpu->kvm, 9)) vcpu->arch.sie_block->ecb |= ECB_SRSI; + if (test_kvm_facility(vcpu->kvm, 11)) + vcpu->arch.sie_block->ecb |= ECB_PTF; if (test_kvm_facility(vcpu->kvm, 73)) vcpu->arch.sie_block->ecb |= ECB_TE; if (!kvm_is_ucontrol(vcpu->kvm)) @@ -3707,6 +3736,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) rc = kvm_s390_vcpu_setup(vcpu); if (rc) goto out_ucontrol_uninit; + + kvm_s390_update_topology_change_report(vcpu->kvm, 1); return 0; out_ucontrol_uninit: diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 12c464c7cddf..3335fa09b6f1 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c @@ -873,10 +873,18 @@ static int handle_stsi(struct kvm_vcpu *vcpu) if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); - if (fc > 3) { - kvm_s390_set_psw_cc(vcpu, 3); - return 0; - } + /* Bailout forbidden function codes */ + if (fc > 3 && fc != 15) + goto out_no_data; + + /* + * fc 15 is provided only with + * - PTF/CPU topology support through facility 15 + * - KVM_CAP_S390_USER_STSI + */ + if (fc == 15 && (!test_kvm_facility(vcpu->kvm, 11) || + !vcpu->kvm->arch.user_stsi)) + goto out_no_data; if (vcpu->run->s.regs.gprs[0] & 0x0fffff00 || vcpu->run->s.regs.gprs[1] & 0xffff0000) @@ -910,6 +918,10 @@ static int handle_stsi(struct kvm_vcpu *vcpu) goto out_no_data; handle_stsi_3_2_2(vcpu, (void *) mem); break; + case 15: /* fc 15 is fully handled in userspace */ + insert_stsi_usr_data(vcpu, operand2, ar, fc, sel1, sel2); + trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2); + return -EREMOTE; } if (kvm_s390_pv_cpu_is_protected(vcpu)) { memcpy((void *)sida_origin(vcpu->arch.sie_block), (void *)mem, diff --git a/arch/s390/kvm/vsie.c b/arch/s390/kvm/vsie.c index dada78b92691..94138f8f0c1c 100644 --- a/arch/s390/kvm/vsie.c +++ b/arch/s390/kvm/vsie.c @@ -503,6 +503,14 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) /* Host-protection-interruption introduced with ESOP */ if (test_kvm_cpu_feat(vcpu->kvm, KVM_S390_VM_CPU_FEAT_ESOP)) scb_s->ecb |= scb_o->ecb & ECB_HOSTPROTINT; + /* + * CPU Topology + * This facility only uses the utility field of the SCA and none of + * the cpu entries that are problematic with the other interpretation + * facilities so we can pass it through + */ + if (test_kvm_facility(vcpu->kvm, 11)) + scb_s->ecb |= scb_o->ecb & ECB_PTF; /* transactional execution */ if (test_kvm_facility(vcpu->kvm, 73) && wants_tx) { /* remap the prefix is tx is toggled on */ From f5ecfee94493475783074e86ded10a0499d779fc Mon Sep 17 00:00:00 2001 From: Pierre Morel Date: Thu, 14 Jul 2022 21:43:34 +0200 Subject: [PATCH 1191/1436] KVM: s390: resetting the Topology-Change-Report During a subsystem reset the Topology-Change-Report is cleared. Let's give userland the possibility to clear the MTCR in the case of a subsystem reset. To migrate the MTCR, we give userland the possibility to query the MTCR state. We indicate KVM support for the CPU topology facility with a new KVM capability: KVM_CAP_S390_CPU_TOPOLOGY. Signed-off-by: Pierre Morel Reviewed-by: Janis Schoetterl-Glausch Reviewed-by: Janosch Frank Message-Id: <20220714194334.127812-1-pmorel@linux.ibm.com> Link: https://lore.kernel.org/all/20220714194334.127812-1-pmorel@linux.ibm.com/ [frankja@linux.ibm.com: Simple conflict resolution in Documentation/virt/kvm/api.rst] Signed-off-by: Janosch Frank --- Documentation/virt/kvm/api.rst | 25 ++++++++++++++++ arch/s390/include/uapi/asm/kvm.h | 1 + arch/s390/kvm/kvm-s390.c | 51 ++++++++++++++++++++++++++++++++ include/uapi/linux/kvm.h | 1 + 4 files changed, 78 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 5be5cc59869d..3c4551a2f6d0 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -8269,6 +8269,31 @@ The capability has no effect if the nx_huge_pages module parameter is not set. This capability may only be set before any vCPUs are created. +8.39 KVM_CAP_S390_CPU_TOPOLOGY +------------------------------ + +:Capability: KVM_CAP_S390_CPU_TOPOLOGY +:Architectures: s390 +:Type: vm + +This capability indicates that KVM will provide the S390 CPU Topology +facility which consist of the interpretation of the PTF instruction for +the function code 2 along with interception and forwarding of both the +PTF instruction with function codes 0 or 1 and the STSI(15,1,x) +instruction to the userland hypervisor. + +The stfle facility 11, CPU Topology facility, should not be indicated +to the guest without this capability. + +When this capability is present, KVM provides a new attribute group +on vm fd, KVM_S390_VM_CPU_TOPOLOGY. +This new attribute allows to get, set or clear the Modified Change +Topology Report (MTCR) bit of the SCA through the kvm_device_attr +structure. + +When getting the Modified Change Topology Report value, the attr->addr +must point to a byte where the value will be stored or retrieved from. + 9. Known KVM API problems ========================= diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h index 7a6b14874d65..a73cf01a1606 100644 --- a/arch/s390/include/uapi/asm/kvm.h +++ b/arch/s390/include/uapi/asm/kvm.h @@ -74,6 +74,7 @@ struct kvm_s390_io_adapter_req { #define KVM_S390_VM_CRYPTO 2 #define KVM_S390_VM_CPU_MODEL 3 #define KVM_S390_VM_MIGRATION 4 +#define KVM_S390_VM_CPU_TOPOLOGY 5 /* kvm attributes for mem_ctrl */ #define KVM_S390_VM_MEM_ENABLE_CMMA 0 diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 5d18b66a08c9..edfd4bbd0cba 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -642,6 +642,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_S390_ZPCI_OP: r = kvm_s390_pci_interp_allowed(); break; + case KVM_CAP_S390_CPU_TOPOLOGY: + r = test_facility(11); + break; default: r = 0; } @@ -853,6 +856,20 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap) icpt_operexc_on_all_vcpus(kvm); r = 0; break; + case KVM_CAP_S390_CPU_TOPOLOGY: + r = -EINVAL; + mutex_lock(&kvm->lock); + if (kvm->created_vcpus) { + r = -EBUSY; + } else if (test_facility(11)) { + set_kvm_facility(kvm->arch.model.fac_mask, 11); + set_kvm_facility(kvm->arch.model.fac_list, 11); + r = 0; + } + mutex_unlock(&kvm->lock); + VM_EVENT(kvm, 3, "ENABLE: CAP_S390_CPU_TOPOLOGY %s", + r ? "(not available)" : "(success)"); + break; default: r = -EINVAL; break; @@ -1789,6 +1806,31 @@ static void kvm_s390_update_topology_change_report(struct kvm *kvm, bool val) read_unlock(&kvm->arch.sca_lock); } +static int kvm_s390_set_topo_change_indication(struct kvm *kvm, + struct kvm_device_attr *attr) +{ + if (!test_kvm_facility(kvm, 11)) + return -ENXIO; + + kvm_s390_update_topology_change_report(kvm, !!attr->attr); + return 0; +} + +static int kvm_s390_get_topo_change_indication(struct kvm *kvm, + struct kvm_device_attr *attr) +{ + u8 topo; + + if (!test_kvm_facility(kvm, 11)) + return -ENXIO; + + read_lock(&kvm->arch.sca_lock); + topo = ((struct bsca_block *)kvm->arch.sca)->utility.mtcr; + read_unlock(&kvm->arch.sca_lock); + + return put_user(topo, (u8 __user *)attr->addr); +} + static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) { int ret; @@ -1809,6 +1851,9 @@ static int kvm_s390_vm_set_attr(struct kvm *kvm, struct kvm_device_attr *attr) case KVM_S390_VM_MIGRATION: ret = kvm_s390_vm_set_migration(kvm, attr); break; + case KVM_S390_VM_CPU_TOPOLOGY: + ret = kvm_s390_set_topo_change_indication(kvm, attr); + break; default: ret = -ENXIO; break; @@ -1834,6 +1879,9 @@ static int kvm_s390_vm_get_attr(struct kvm *kvm, struct kvm_device_attr *attr) case KVM_S390_VM_MIGRATION: ret = kvm_s390_vm_get_migration(kvm, attr); break; + case KVM_S390_VM_CPU_TOPOLOGY: + ret = kvm_s390_get_topo_change_indication(kvm, attr); + break; default: ret = -ENXIO; break; @@ -1907,6 +1955,9 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) case KVM_S390_VM_MIGRATION: ret = 0; break; + case KVM_S390_VM_CPU_TOPOLOGY: + ret = test_kvm_facility(kvm, 11) ? 0 : -ENXIO; + break; default: ret = -ENXIO; break; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 20817dd7f2f1..7e06194129e3 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1168,6 +1168,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_X86_NOTIFY_VMEXIT 219 #define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220 #define KVM_CAP_S390_ZPCI_OP 221 +#define KVM_CAP_S390_CPU_TOPOLOGY 222 #ifdef KVM_CAP_IRQ_ROUTING From 2c05a0f29f41cbb1e31e94a53e7dacf0622706bb Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 20 Jul 2022 09:45:57 -0400 Subject: [PATCH 1192/1436] gpio: ws16c48: Implement and utilize register structures Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. Reviewed-by: Linus Walleij Cc: Paul Demetrotion Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-ws16c48.c | 120 +++++++++++++++++++++++++----------- 1 file changed, 84 insertions(+), 36 deletions(-) diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c index 5078631d8014..b098f2dc196b 100644 --- a/drivers/gpio/gpio-ws16c48.c +++ b/drivers/gpio/gpio-ws16c48.c @@ -4,7 +4,6 @@ * Copyright (C) 2016 William Breathitt Gray */ #include -#include #include #include #include @@ -17,8 +16,9 @@ #include #include #include +#include -#define WS16C48_EXTENT 16 +#define WS16C48_EXTENT 10 #define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT) static unsigned int base[MAX_NUM_WS16C48]; @@ -30,6 +30,20 @@ static unsigned int irq[MAX_NUM_WS16C48]; module_param_hw_array(irq, uint, irq, NULL, 0); MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers"); +/** + * struct ws16c48_reg - device register structure + * @port: Port 0 through 5 I/O + * @int_pending: Interrupt Pending + * @page_lock: Register page (Bits 7-6) and I/O port lock (Bits 5-0) + * @pol_enab_int_id: Interrupt polarity, enable, and ID + */ +struct ws16c48_reg { + u8 port[6]; + u8 int_pending; + u8 page_lock; + u8 pol_enab_int_id[3]; +}; + /** * struct ws16c48_gpio - GPIO device private data structure * @chip: instance of the gpio_chip @@ -38,7 +52,7 @@ MODULE_PARM_DESC(irq, "WinSystems WS16C48 interrupt line numbers"); * @lock: synchronization lock to prevent I/O race conditions * @irq_mask: I/O bits affected by interrupts * @flow_mask: IRQ flow type mask for the respective I/O bits - * @base: base port address of the GPIO device + * @reg: I/O address offset for the device registers */ struct ws16c48_gpio { struct gpio_chip chip; @@ -47,7 +61,7 @@ struct ws16c48_gpio { raw_spinlock_t lock; unsigned long irq_mask; unsigned long flow_mask; - void __iomem *base; + struct ws16c48_reg __iomem *reg; }; static int ws16c48_gpio_get_direction(struct gpio_chip *chip, unsigned offset) @@ -73,7 +87,7 @@ static int ws16c48_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ws16c48gpio->io_state[port] |= mask; ws16c48gpio->out_state[port] &= ~mask; - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port); + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); @@ -95,7 +109,7 @@ static int ws16c48_gpio_direction_output(struct gpio_chip *chip, ws16c48gpio->out_state[port] |= mask; else ws16c48gpio->out_state[port] &= ~mask; - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port); + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); @@ -118,7 +132,7 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset) return -EINVAL; } - port_state = ioread8(ws16c48gpio->base + port); + port_state = ioread8(ws16c48gpio->reg->port + port); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); @@ -131,14 +145,16 @@ static int ws16c48_gpio_get_multiple(struct gpio_chip *chip, struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip); unsigned long offset; unsigned long gpio_mask; - void __iomem *port_addr; + size_t index; + u8 __iomem *port_addr; unsigned long port_state; /* clear bits array to a clean slate */ bitmap_zero(bits, chip->ngpio); for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { - port_addr = ws16c48gpio->base + offset / 8; + index = offset / 8; + port_addr = ws16c48gpio->reg->port + index; port_state = ioread8(port_addr) & gpio_mask; bitmap_set_value8(bits, port_state, offset); @@ -166,7 +182,7 @@ static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ws16c48gpio->out_state[port] |= mask; else ws16c48gpio->out_state[port] &= ~mask; - iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->base + port); + iowrite8(ws16c48gpio->out_state[port], ws16c48gpio->reg->port + port); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -178,13 +194,13 @@ static void ws16c48_gpio_set_multiple(struct gpio_chip *chip, unsigned long offset; unsigned long gpio_mask; size_t index; - void __iomem *port_addr; + u8 __iomem *port_addr; unsigned long bitmask; unsigned long flags; for_each_set_clump8(offset, gpio_mask, mask, chip->ngpio) { index = offset / 8; - port_addr = ws16c48gpio->base + index; + port_addr = ws16c48gpio->reg->port + index; /* mask out GPIO configured for input */ gpio_mask &= ~ws16c48gpio->io_state[index]; @@ -219,10 +235,15 @@ static void ws16c48_irq_ack(struct irq_data *data) port_state = ws16c48gpio->irq_mask >> (8*port); - iowrite8(0x80, ws16c48gpio->base + 7); - iowrite8(port_state & ~mask, ws16c48gpio->base + 8 + port); - iowrite8(port_state | mask, ws16c48gpio->base + 8 + port); - iowrite8(0xC0, ws16c48gpio->base + 7); + /* Select Register Page 2; Unlock all I/O ports */ + iowrite8(0x80, &ws16c48gpio->reg->page_lock); + + /* Clear pending interrupt */ + iowrite8(port_state & ~mask, ws16c48gpio->reg->pol_enab_int_id + port); + iowrite8(port_state | mask, ws16c48gpio->reg->pol_enab_int_id + port); + + /* Select Register Page 3; Unlock all I/O ports */ + iowrite8(0xC0, &ws16c48gpio->reg->page_lock); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -235,6 +256,7 @@ static void ws16c48_irq_mask(struct irq_data *data) const unsigned long mask = BIT(offset); const unsigned port = offset / 8; unsigned long flags; + unsigned long port_state; /* only the first 3 ports support interrupts */ if (port > 2) @@ -243,10 +265,16 @@ static void ws16c48_irq_mask(struct irq_data *data) raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); ws16c48gpio->irq_mask &= ~mask; + port_state = ws16c48gpio->irq_mask >> (8 * port); - iowrite8(0x80, ws16c48gpio->base + 7); - iowrite8(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port); - iowrite8(0xC0, ws16c48gpio->base + 7); + /* Select Register Page 2; Unlock all I/O ports */ + iowrite8(0x80, &ws16c48gpio->reg->page_lock); + + /* Disable interrupt */ + iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); + + /* Select Register Page 3; Unlock all I/O ports */ + iowrite8(0xC0, &ws16c48gpio->reg->page_lock); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -259,6 +287,7 @@ static void ws16c48_irq_unmask(struct irq_data *data) const unsigned long mask = BIT(offset); const unsigned port = offset / 8; unsigned long flags; + unsigned long port_state; /* only the first 3 ports support interrupts */ if (port > 2) @@ -267,10 +296,16 @@ static void ws16c48_irq_unmask(struct irq_data *data) raw_spin_lock_irqsave(&ws16c48gpio->lock, flags); ws16c48gpio->irq_mask |= mask; + port_state = ws16c48gpio->irq_mask >> (8 * port); - iowrite8(0x80, ws16c48gpio->base + 7); - iowrite8(ws16c48gpio->irq_mask >> (8*port), ws16c48gpio->base + 8 + port); - iowrite8(0xC0, ws16c48gpio->base + 7); + /* Select Register Page 2; Unlock all I/O ports */ + iowrite8(0x80, &ws16c48gpio->reg->page_lock); + + /* Enable interrupt */ + iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); + + /* Select Register Page 3; Unlock all I/O ports */ + iowrite8(0xC0, &ws16c48gpio->reg->page_lock); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); } @@ -283,6 +318,7 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type) const unsigned long mask = BIT(offset); const unsigned port = offset / 8; unsigned long flags; + unsigned long port_state; /* only the first 3 ports support interrupts */ if (port > 2) @@ -304,9 +340,16 @@ static int ws16c48_irq_set_type(struct irq_data *data, unsigned flow_type) return -EINVAL; } - iowrite8(0x40, ws16c48gpio->base + 7); - iowrite8(ws16c48gpio->flow_mask >> (8*port), ws16c48gpio->base + 8 + port); - iowrite8(0xC0, ws16c48gpio->base + 7); + port_state = ws16c48gpio->flow_mask >> (8 * port); + + /* Select Register Page 1; Unlock all I/O ports */ + iowrite8(0x40, &ws16c48gpio->reg->page_lock); + + /* Set interrupt polarity */ + iowrite8(port_state, ws16c48gpio->reg->pol_enab_int_id + port); + + /* Select Register Page 3; Unlock all I/O ports */ + iowrite8(0xC0, &ws16c48gpio->reg->page_lock); raw_spin_unlock_irqrestore(&ws16c48gpio->lock, flags); @@ -325,25 +368,26 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id) { struct ws16c48_gpio *const ws16c48gpio = dev_id; struct gpio_chip *const chip = &ws16c48gpio->chip; + struct ws16c48_reg __iomem *const reg = ws16c48gpio->reg; unsigned long int_pending; unsigned long port; unsigned long int_id; unsigned long gpio; - int_pending = ioread8(ws16c48gpio->base + 6) & 0x7; + int_pending = ioread8(®->int_pending) & 0x7; if (!int_pending) return IRQ_NONE; /* loop until all pending interrupts are handled */ do { for_each_set_bit(port, &int_pending, 3) { - int_id = ioread8(ws16c48gpio->base + 8 + port); + int_id = ioread8(reg->pol_enab_int_id + port); for_each_set_bit(gpio, &int_id, 8) generic_handle_domain_irq(chip->irq.domain, gpio + 8*port); } - int_pending = ioread8(ws16c48gpio->base + 6) & 0x7; + int_pending = ioread8(®->int_pending) & 0x7; } while (int_pending); return IRQ_HANDLED; @@ -369,12 +413,16 @@ static int ws16c48_irq_init_hw(struct gpio_chip *gc) { struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(gc); - /* Disable IRQ by default */ - iowrite8(0x80, ws16c48gpio->base + 7); - iowrite8(0, ws16c48gpio->base + 8); - iowrite8(0, ws16c48gpio->base + 9); - iowrite8(0, ws16c48gpio->base + 10); - iowrite8(0xC0, ws16c48gpio->base + 7); + /* Select Register Page 2; Unlock all I/O ports */ + iowrite8(0x80, &ws16c48gpio->reg->page_lock); + + /* Disable interrupts for all lines */ + iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[0]); + iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[1]); + iowrite8(0, &ws16c48gpio->reg->pol_enab_int_id[2]); + + /* Select Register Page 3; Unlock all I/O ports */ + iowrite8(0xC0, &ws16c48gpio->reg->page_lock); return 0; } @@ -396,8 +444,8 @@ static int ws16c48_probe(struct device *dev, unsigned int id) return -EBUSY; } - ws16c48gpio->base = devm_ioport_map(dev, base[id], WS16C48_EXTENT); - if (!ws16c48gpio->base) + ws16c48gpio->reg = devm_ioport_map(dev, base[id], WS16C48_EXTENT); + if (!ws16c48gpio->reg) return -ENOMEM; ws16c48gpio->chip.label = name; From cc442e4db9cb851f18cd3ea0c933e016b29fafc3 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 20 Jul 2022 09:45:58 -0400 Subject: [PATCH 1193/1436] gpio: 104-idio-16: Implement and utilize register structures Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. Tested-by: Fred Eckert Reviewed-by: Linus Walleij Cc: John Hentges Cc: Jay Dolan Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-104-idio-16.c | 60 +++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c index 45f7ad8573e1..65a5f581d981 100644 --- a/drivers/gpio/gpio-104-idio-16.c +++ b/drivers/gpio/gpio-104-idio-16.c @@ -6,7 +6,7 @@ * This driver supports the following ACCES devices: 104-IDIO-16, * 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, and 104-IDO-8. */ -#include +#include #include #include #include @@ -19,6 +19,7 @@ #include #include #include +#include #define IDIO_16_EXTENT 8 #define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT) @@ -32,19 +33,42 @@ static unsigned int irq[MAX_NUM_IDIO_16]; module_param_hw_array(irq, uint, irq, NULL, 0); MODULE_PARM_DESC(irq, "ACCES 104-IDIO-16 interrupt line numbers"); +/** + * struct idio_16_reg - device registers structure + * @out0_7: Read: N/A + * Write: FET Drive Outputs 0-7 + * @in0_7: Read: Isolated Inputs 0-7 + * Write: Clear Interrupt + * @irq_ctl: Read: Enable IRQ + * Write: Disable IRQ + * @unused: N/A + * @out8_15: Read: N/A + * Write: FET Drive Outputs 8-15 + * @in8_15: Read: Isolated Inputs 8-15 + * Write: N/A + */ +struct idio_16_reg { + u8 out0_7; + u8 in0_7; + u8 irq_ctl; + u8 unused; + u8 out8_15; + u8 in8_15; +}; + /** * struct idio_16_gpio - GPIO device private data structure * @chip: instance of the gpio_chip * @lock: synchronization lock to prevent I/O race conditions * @irq_mask: I/O bits affected by interrupts - * @base: base port address of the GPIO device + * @reg: I/O address offset for the device registers * @out_state: output bits state */ struct idio_16_gpio { struct gpio_chip chip; raw_spinlock_t lock; unsigned long irq_mask; - void __iomem *base; + struct idio_16_reg __iomem *reg; unsigned int out_state; }; @@ -79,9 +103,9 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) return -EINVAL; if (offset < 24) - return !!(ioread8(idio16gpio->base + 1) & mask); + return !!(ioread8(&idio16gpio->reg->in0_7) & mask); - return !!(ioread8(idio16gpio->base + 5) & (mask>>8)); + return !!(ioread8(&idio16gpio->reg->in8_15) & (mask>>8)); } static int idio_16_gpio_get_multiple(struct gpio_chip *chip, @@ -91,9 +115,9 @@ static int idio_16_gpio_get_multiple(struct gpio_chip *chip, *bits = 0; if (*mask & GENMASK(23, 16)) - *bits |= (unsigned long)ioread8(idio16gpio->base + 1) << 16; + *bits |= (unsigned long)ioread8(&idio16gpio->reg->in0_7) << 16; if (*mask & GENMASK(31, 24)) - *bits |= (unsigned long)ioread8(idio16gpio->base + 5) << 24; + *bits |= (unsigned long)ioread8(&idio16gpio->reg->in8_15) << 24; return 0; } @@ -116,9 +140,9 @@ static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset, idio16gpio->out_state &= ~mask; if (offset > 7) - iowrite8(idio16gpio->out_state >> 8, idio16gpio->base + 4); + iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15); else - iowrite8(idio16gpio->out_state, idio16gpio->base); + iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7); raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } @@ -135,9 +159,9 @@ static void idio_16_gpio_set_multiple(struct gpio_chip *chip, idio16gpio->out_state |= *mask & *bits; if (*mask & 0xFF) - iowrite8(idio16gpio->out_state, idio16gpio->base); + iowrite8(idio16gpio->out_state, &idio16gpio->reg->out0_7); if ((*mask >> 8) & 0xFF) - iowrite8(idio16gpio->out_state >> 8, idio16gpio->base + 4); + iowrite8(idio16gpio->out_state >> 8, &idio16gpio->reg->out8_15); raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } @@ -158,7 +182,7 @@ static void idio_16_irq_mask(struct irq_data *data) if (!idio16gpio->irq_mask) { raw_spin_lock_irqsave(&idio16gpio->lock, flags); - iowrite8(0, idio16gpio->base + 2); + iowrite8(0, &idio16gpio->reg->irq_ctl); raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } @@ -177,7 +201,7 @@ static void idio_16_irq_unmask(struct irq_data *data) if (!prev_irq_mask) { raw_spin_lock_irqsave(&idio16gpio->lock, flags); - ioread8(idio16gpio->base + 2); + ioread8(&idio16gpio->reg->irq_ctl); raw_spin_unlock_irqrestore(&idio16gpio->lock, flags); } @@ -212,7 +236,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id) raw_spin_lock(&idio16gpio->lock); - iowrite8(0, idio16gpio->base + 1); + iowrite8(0, &idio16gpio->reg->in0_7); raw_spin_unlock(&idio16gpio->lock); @@ -232,8 +256,8 @@ static int idio_16_irq_init_hw(struct gpio_chip *gc) struct idio_16_gpio *const idio16gpio = gpiochip_get_data(gc); /* Disable IRQ by default */ - iowrite8(0, idio16gpio->base + 2); - iowrite8(0, idio16gpio->base + 1); + iowrite8(0, &idio16gpio->reg->irq_ctl); + iowrite8(0, &idio16gpio->reg->in0_7); return 0; } @@ -255,8 +279,8 @@ static int idio_16_probe(struct device *dev, unsigned int id) return -EBUSY; } - idio16gpio->base = devm_ioport_map(dev, base[id], IDIO_16_EXTENT); - if (!idio16gpio->base) + idio16gpio->reg = devm_ioport_map(dev, base[id], IDIO_16_EXTENT); + if (!idio16gpio->reg) return -ENOMEM; idio16gpio->chip.label = name; From fb38af4a3a79c354771f335c671b144348d6d6fa Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 20 Jul 2022 09:45:59 -0400 Subject: [PATCH 1194/1436] gpio: i8255: Introduce the Intel 8255 interface library module Exposes consumer library functions providing support for interfaces compatible with the venerable Intel 8255 Programmable Peripheral Interface (PPI). The Intel 8255 PPI first appeared in the early 1970s, initially for the Intel 8080 and later appearing in the original IBM-PC. The popularity of the original Intel 8255 chip led to many subsequent variants and clones of the interface in various chips and integrated circuits. Although still popular, interfaces compatible with the Intel 8255 PPI are nowdays typically found embedded in larger VLSI processing chips and FPGA components rather than as discrete ICs. A CONFIG_GPIO_I8255 Kconfig option is introduced by this patch. Modules wanting access to these i8255 library functions should select this Kconfig option, and import the I8255 symbol namespace. Tested-by: Fred Eckert Reviewed-by: Linus Walleij Cc: John Hentges Cc: Jay Dolan Cc: Andy Shevchenko Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- MAINTAINERS | 6 + drivers/gpio/Kconfig | 12 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-i8255.c | 287 ++++++++++++++++++++++++++++++++++++++ drivers/gpio/gpio-i8255.h | 46 ++++++ 5 files changed, 352 insertions(+) create mode 100644 drivers/gpio/gpio-i8255.c create mode 100644 drivers/gpio/gpio-i8255.h diff --git a/MAINTAINERS b/MAINTAINERS index 3405cb36cf02..960abc07304e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9902,6 +9902,12 @@ L: linux-fbdev@vger.kernel.org S: Maintained F: drivers/video/fbdev/i810/ +INTEL 8255 GPIO DRIVER +M: William Breathitt Gray +L: linux-gpio@vger.kernel.org +S: Maintained +F: drivers/gpio/gpio-i8255.c + INTEL ASoC DRIVERS M: Cezary Rojewski M: Pierre-Louis Bossart diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index cf6a2c745f3f..df484b72000d 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -824,6 +824,18 @@ endmenu menu "Port-mapped I/O GPIO drivers" depends on X86 # Unconditional I/O space access +config GPIO_I8255 + tristate + help + Enables support for the i8255 interface library functions. The i8255 + interface library provides functions to facilitate communication with + interfaces compatible with the venerable Intel 8255 Programmable + Peripheral Interface (PPI). The Intel 8255 PPI chip was first released + in the early 1970s but compatible interfaces are nowadays typically + found embedded in larger VLSI processing chips and FPGA components. + + If built as a module its name will be gpio-i8255. + config GPIO_104_DIO_48E tristate "ACCES 104-DIO-48E GPIO support" depends on PC104 diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9d4805b2b60b..a0985d30f51b 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_GPIO_GW_PLD) += gpio-gw-pld.o obj-$(CONFIG_GPIO_HISI) += gpio-hisi.o obj-$(CONFIG_GPIO_HLWD) += gpio-hlwd.o obj-$(CONFIG_HTC_EGPIO) += gpio-htc-egpio.o +obj-$(CONFIG_GPIO_I8255) += gpio-i8255.o obj-$(CONFIG_GPIO_ICH) += gpio-ich.o obj-$(CONFIG_GPIO_IDT3243X) += gpio-idt3243x.o obj-$(CONFIG_GPIO_IOP) += gpio-iop.o diff --git a/drivers/gpio/gpio-i8255.c b/drivers/gpio/gpio-i8255.c new file mode 100644 index 000000000000..9b97db418df1 --- /dev/null +++ b/drivers/gpio/gpio-i8255.c @@ -0,0 +1,287 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel 8255 Programmable Peripheral Interface + * Copyright (C) 2022 William Breathitt Gray + */ +#include +#include +#include +#include +#include +#include +#include + +#include "gpio-i8255.h" + +#define I8255_CONTROL_PORTC_LOWER_DIRECTION BIT(0) +#define I8255_CONTROL_PORTB_DIRECTION BIT(1) +#define I8255_CONTROL_PORTC_UPPER_DIRECTION BIT(3) +#define I8255_CONTROL_PORTA_DIRECTION BIT(4) +#define I8255_CONTROL_MODE_SET BIT(7) +#define I8255_PORTA 0 +#define I8255_PORTB 1 +#define I8255_PORTC 2 + +static int i8255_get_port(struct i8255 __iomem *const ppi, + const unsigned long io_port, const unsigned long mask) +{ + const unsigned long bank = io_port / 3; + const unsigned long ppi_port = io_port % 3; + + return ioread8(&ppi[bank].port[ppi_port]) & mask; +} + +static u8 i8255_direction_mask(const unsigned long offset) +{ + const unsigned long port_offset = offset % 8; + const unsigned long io_port = offset / 8; + const unsigned long ppi_port = io_port % 3; + + switch (ppi_port) { + case I8255_PORTA: + return I8255_CONTROL_PORTA_DIRECTION; + case I8255_PORTB: + return I8255_CONTROL_PORTB_DIRECTION; + case I8255_PORTC: + /* Port C can be configured by nibble */ + if (port_offset >= 4) + return I8255_CONTROL_PORTC_UPPER_DIRECTION; + return I8255_CONTROL_PORTC_LOWER_DIRECTION; + default: + /* Should never reach this path */ + return 0; + } +} + +static void i8255_set_port(struct i8255 __iomem *const ppi, + struct i8255_state *const state, + const unsigned long io_port, + const unsigned long mask, const unsigned long bits) +{ + const unsigned long bank = io_port / 3; + const unsigned long ppi_port = io_port % 3; + unsigned long flags; + unsigned long out_state; + + spin_lock_irqsave(&state[bank].lock, flags); + + out_state = ioread8(&ppi[bank].port[ppi_port]); + out_state = (out_state & ~mask) | (bits & mask); + iowrite8(out_state, &ppi[bank].port[ppi_port]); + + spin_unlock_irqrestore(&state[bank].lock, flags); +} + +/** + * i8255_direction_input - configure signal offset as input + * @ppi: Intel 8255 Programmable Peripheral Interface banks + * @state: devices states of the respective PPI banks + * @offset: signal offset to configure as input + * + * Configures a signal @offset as input for the respective Intel 8255 + * Programmable Peripheral Interface (@ppi) banks. The @state control_state + * values are updated to reflect the new configuration. + */ +void i8255_direction_input(struct i8255 __iomem *const ppi, + struct i8255_state *const state, + const unsigned long offset) +{ + const unsigned long io_port = offset / 8; + const unsigned long bank = io_port / 3; + unsigned long flags; + + spin_lock_irqsave(&state[bank].lock, flags); + + state[bank].control_state |= I8255_CONTROL_MODE_SET; + state[bank].control_state |= i8255_direction_mask(offset); + + iowrite8(state[bank].control_state, &ppi[bank].control); + + spin_unlock_irqrestore(&state[bank].lock, flags); +} +EXPORT_SYMBOL_NS_GPL(i8255_direction_input, I8255); + +/** + * i8255_direction_output - configure signal offset as output + * @ppi: Intel 8255 Programmable Peripheral Interface banks + * @state: devices states of the respective PPI banks + * @offset: signal offset to configure as output + * @value: signal value to output + * + * Configures a signal @offset as output for the respective Intel 8255 + * Programmable Peripheral Interface (@ppi) banks and sets the respective signal + * output to the desired @value. The @state control_state values are updated to + * reflect the new configuration. + */ +void i8255_direction_output(struct i8255 __iomem *const ppi, + struct i8255_state *const state, + const unsigned long offset, + const unsigned long value) +{ + const unsigned long io_port = offset / 8; + const unsigned long bank = io_port / 3; + unsigned long flags; + + spin_lock_irqsave(&state[bank].lock, flags); + + state[bank].control_state |= I8255_CONTROL_MODE_SET; + state[bank].control_state &= ~i8255_direction_mask(offset); + + iowrite8(state[bank].control_state, &ppi[bank].control); + + spin_unlock_irqrestore(&state[bank].lock, flags); + + i8255_set(ppi, state, offset, value); +} +EXPORT_SYMBOL_NS_GPL(i8255_direction_output, I8255); + +/** + * i8255_get - get signal value at signal offset + * @ppi: Intel 8255 Programmable Peripheral Interface banks + * @offset: offset of signal to get + * + * Returns the signal value (0=low, 1=high) for the signal at @offset for the + * respective Intel 8255 Programmable Peripheral Interface (@ppi) banks. + */ +int i8255_get(struct i8255 __iomem *const ppi, const unsigned long offset) +{ + const unsigned long io_port = offset / 8; + const unsigned long offset_mask = BIT(offset % 8); + + return !!i8255_get_port(ppi, io_port, offset_mask); +} +EXPORT_SYMBOL_NS_GPL(i8255_get, I8255); + +/** + * i8255_get_direction - get the I/O direction for a signal offset + * @state: devices states of the respective PPI banks + * @offset: offset of signal to get direction + * + * Returns the signal direction (0=output, 1=input) for the signal at @offset. + */ +int i8255_get_direction(const struct i8255_state *const state, + const unsigned long offset) +{ + const unsigned long io_port = offset / 8; + const unsigned long bank = io_port / 3; + + return !!(state[bank].control_state & i8255_direction_mask(offset)); +} +EXPORT_SYMBOL_NS_GPL(i8255_get_direction, I8255); + +/** + * i8255_get_multiple - get multiple signal values at multiple signal offsets + * @ppi: Intel 8255 Programmable Peripheral Interface banks + * @mask: mask of signals to get + * @bits: bitmap to store signal values + * @ngpio: number of GPIO signals of the respective PPI banks + * + * Stores in @bits the values (0=low, 1=high) for the signals defined by @mask + * for the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks. + */ +void i8255_get_multiple(struct i8255 __iomem *const ppi, + const unsigned long *const mask, + unsigned long *const bits, const unsigned long ngpio) +{ + unsigned long offset; + unsigned long port_mask; + unsigned long io_port; + unsigned long port_state; + + bitmap_zero(bits, ngpio); + + for_each_set_clump8(offset, port_mask, mask, ngpio) { + io_port = offset / 8; + port_state = i8255_get_port(ppi, io_port, port_mask); + + bitmap_set_value8(bits, port_state, offset); + } +} +EXPORT_SYMBOL_NS_GPL(i8255_get_multiple, I8255); + +/** + * i8255_mode0_output - configure all PPI ports to MODE 0 output mode + * @ppi: Intel 8255 Programmable Peripheral Interface bank + * + * Configures all Intel 8255 Programmable Peripheral Interface (@ppi) ports to + * MODE 0 (Basic Input/Output) output mode. + */ +void i8255_mode0_output(struct i8255 __iomem *const ppi) +{ + iowrite8(I8255_CONTROL_MODE_SET, &ppi->control); +} +EXPORT_SYMBOL_NS_GPL(i8255_mode0_output, I8255); + +/** + * i8255_set - set signal value at signal offset + * @ppi: Intel 8255 Programmable Peripheral Interface banks + * @state: devices states of the respective PPI banks + * @offset: offset of signal to set + * @value: value of signal to set + * + * Assigns output @value for the signal at @offset for the respective Intel 8255 + * Programmable Peripheral Interface (@ppi) banks. + */ +void i8255_set(struct i8255 __iomem *const ppi, struct i8255_state *const state, + const unsigned long offset, const unsigned long value) +{ + const unsigned long io_port = offset / 8; + const unsigned long port_offset = offset % 8; + const unsigned long mask = BIT(port_offset); + const unsigned long bits = value << port_offset; + + i8255_set_port(ppi, state, io_port, mask, bits); +} +EXPORT_SYMBOL_NS_GPL(i8255_set, I8255); + +/** + * i8255_set_multiple - set signal values at multiple signal offsets + * @ppi: Intel 8255 Programmable Peripheral Interface banks + * @state: devices states of the respective PPI banks + * @mask: mask of signals to set + * @bits: bitmap of signal output values + * @ngpio: number of GPIO signals of the respective PPI banks + * + * Assigns output values defined by @bits for the signals defined by @mask for + * the respective Intel 8255 Programmable Peripheral Interface (@ppi) banks. + */ +void i8255_set_multiple(struct i8255 __iomem *const ppi, + struct i8255_state *const state, + const unsigned long *const mask, + const unsigned long *const bits, + const unsigned long ngpio) +{ + unsigned long offset; + unsigned long port_mask; + unsigned long io_port; + unsigned long value; + + for_each_set_clump8(offset, port_mask, mask, ngpio) { + io_port = offset / 8; + value = bitmap_get_value8(bits, offset); + i8255_set_port(ppi, state, io_port, port_mask, value); + } +} +EXPORT_SYMBOL_NS_GPL(i8255_set_multiple, I8255); + +/** + * i8255_state_init - initialize i8255_state structure + * @state: devices states of the respective PPI banks + * @nbanks: number of Intel 8255 Programmable Peripheral Interface banks + * + * Initializes the @state of each Intel 8255 Programmable Peripheral Interface + * bank for use in i8255 library functions. + */ +void i8255_state_init(struct i8255_state *const state, + const unsigned long nbanks) +{ + unsigned long bank; + + for (bank = 0; bank < nbanks; bank++) + spin_lock_init(&state[bank].lock); +} +EXPORT_SYMBOL_NS_GPL(i8255_state_init, I8255); + +MODULE_AUTHOR("William Breathitt Gray"); +MODULE_DESCRIPTION("Intel 8255 Programmable Peripheral Interface"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/gpio-i8255.h b/drivers/gpio/gpio-i8255.h new file mode 100644 index 000000000000..d9084aae9446 --- /dev/null +++ b/drivers/gpio/gpio-i8255.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright 2022 William Breathitt Gray */ +#ifndef _I8255_H_ +#define _I8255_H_ + +#include +#include + +/** + * struct i8255 - Intel 8255 register structure + * @port: Port A, B, and C + * @control: Control register + */ +struct i8255 { + u8 port[3]; + u8 control; +}; + +/** + * struct i8255_state - Intel 8255 state structure + * @lock: synchronization lock for accessing device state + * @control_state: Control register state + */ +struct i8255_state { + spinlock_t lock; + u8 control_state; +}; + +void i8255_direction_input(struct i8255 __iomem *ppi, struct i8255_state *state, + unsigned long offset); +void i8255_direction_output(struct i8255 __iomem *ppi, + struct i8255_state *state, unsigned long offset, + unsigned long value); +int i8255_get(struct i8255 __iomem *ppi, unsigned long offset); +int i8255_get_direction(const struct i8255_state *state, unsigned long offset); +void i8255_get_multiple(struct i8255 __iomem *ppi, const unsigned long *mask, + unsigned long *bits, unsigned long ngpio); +void i8255_mode0_output(struct i8255 __iomem *const ppi); +void i8255_set(struct i8255 __iomem *ppi, struct i8255_state *state, + unsigned long offset, unsigned long value); +void i8255_set_multiple(struct i8255 __iomem *ppi, struct i8255_state *state, + const unsigned long *mask, const unsigned long *bits, + unsigned long ngpio); +void i8255_state_init(struct i8255_state *const state, unsigned long nbanks); + +#endif /* _I8255_H_ */ From 71b7b3972590908fd724f4622cd908ad02464ad8 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 20 Jul 2022 09:46:00 -0400 Subject: [PATCH 1195/1436] gpio: 104-dio-48e: Implement and utilize register structures Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. The 104-DIO-48E device features an Intel 8255 compatible GPIO interface, so the i8255 GPIO module is selected and utilized as well. Reviewed-by: Linus Walleij Cc: John Hentges Cc: Jay Dolan Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-104-dio-48e.c | 249 ++++++++++---------------------- 2 files changed, 75 insertions(+), 175 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index df484b72000d..d070bd9f4f94 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -841,6 +841,7 @@ config GPIO_104_DIO_48E depends on PC104 select ISA_BUS_API select GPIOLIB_IRQCHIP + select GPIO_I8255 help Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E, 104-DIO-24E). The base port addresses for the devices may be diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c index f118ad9bcd33..a41551870759 100644 --- a/drivers/gpio/gpio-104-dio-48e.c +++ b/drivers/gpio/gpio-104-dio-48e.c @@ -6,8 +6,7 @@ * This driver supports the following ACCES devices: 104-DIO-48E and * 104-DIO-24E. */ -#include -#include +#include #include #include #include @@ -20,6 +19,11 @@ #include #include #include +#include + +#include "gpio-i8255.h" + +MODULE_IMPORT_NS(I8255); #define DIO48E_EXTENT 16 #define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT) @@ -33,34 +37,54 @@ static unsigned int irq[MAX_NUM_DIO48E]; module_param_hw_array(irq, uint, irq, NULL, 0); MODULE_PARM_DESC(irq, "ACCES 104-DIO-48E interrupt line numbers"); +#define DIO48E_NUM_PPI 2 + +/** + * struct dio48e_reg - device register structure + * @ppi: Programmable Peripheral Interface groups + * @enable_buffer: Enable/Disable Buffer groups + * @unused1: Unused + * @enable_interrupt: Write: Enable Interrupt + * Read: Disable Interrupt + * @unused2: Unused + * @enable_counter: Write: Enable Counter/Timer Addressing + * Read: Disable Counter/Timer Addressing + * @unused3: Unused + * @clear_interrupt: Clear Interrupt + */ +struct dio48e_reg { + struct i8255 ppi[DIO48E_NUM_PPI]; + u8 enable_buffer[DIO48E_NUM_PPI]; + u8 unused1; + u8 enable_interrupt; + u8 unused2; + u8 enable_counter; + u8 unused3; + u8 clear_interrupt; +}; + /** * struct dio48e_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @io_state: bit I/O state (whether bit is set to input or output) - * @out_state: output bits state - * @control: Control registers state - * @lock: synchronization lock to prevent I/O race conditions - * @base: base port address of the GPIO device - * @irq_mask: I/O bits affected by interrupts + * @chip: instance of the gpio_chip + * @ppi_state: PPI device states + * @lock: synchronization lock to prevent I/O race conditions + * @reg: I/O address offset for the device registers + * @irq_mask: I/O bits affected by interrupts */ struct dio48e_gpio { struct gpio_chip chip; - unsigned char io_state[6]; - unsigned char out_state[6]; - unsigned char control[2]; + struct i8255_state ppi_state[DIO48E_NUM_PPI]; raw_spinlock_t lock; - void __iomem *base; + struct dio48e_reg __iomem *reg; unsigned char irq_mask; }; static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - const unsigned int port = offset / 8; - const unsigned int mask = BIT(offset % 8); - if (dio48egpio->io_state[port] & mask) - return GPIO_LINE_DIRECTION_IN; + if (i8255_get_direction(dio48egpio->ppi_state, offset)) + return GPIO_LINE_DIRECTION_IN; return GPIO_LINE_DIRECTION_OUT; } @@ -68,38 +92,9 @@ static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - const unsigned int io_port = offset / 8; - const unsigned int control_port = io_port / 3; - void __iomem *const control_addr = dio48egpio->base + 3 + control_port * 4; - unsigned long flags; - unsigned int control; - raw_spin_lock_irqsave(&dio48egpio->lock, flags); - - /* Check if configuring Port C */ - if (io_port == 2 || io_port == 5) { - /* Port C can be configured by nibble */ - if (offset % 8 > 3) { - dio48egpio->io_state[io_port] |= 0xF0; - dio48egpio->control[control_port] |= BIT(3); - } else { - dio48egpio->io_state[io_port] |= 0x0F; - dio48egpio->control[control_port] |= BIT(0); - } - } else { - dio48egpio->io_state[io_port] |= 0xFF; - if (io_port == 0 || io_port == 3) - dio48egpio->control[control_port] |= BIT(4); - else - dio48egpio->control[control_port] |= BIT(1); - } - - control = BIT(7) | dio48egpio->control[control_port]; - iowrite8(control, control_addr); - control &= ~BIT(7); - iowrite8(control, control_addr); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); + i8255_direction_input(dio48egpio->reg->ppi, dio48egpio->ppi_state, + offset); return 0; } @@ -108,48 +103,9 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int off int value) { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - const unsigned int io_port = offset / 8; - const unsigned int control_port = io_port / 3; - const unsigned int mask = BIT(offset % 8); - void __iomem *const control_addr = dio48egpio->base + 3 + control_port * 4; - const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port; - unsigned long flags; - unsigned int control; - raw_spin_lock_irqsave(&dio48egpio->lock, flags); - - /* Check if configuring Port C */ - if (io_port == 2 || io_port == 5) { - /* Port C can be configured by nibble */ - if (offset % 8 > 3) { - dio48egpio->io_state[io_port] &= 0x0F; - dio48egpio->control[control_port] &= ~BIT(3); - } else { - dio48egpio->io_state[io_port] &= 0xF0; - dio48egpio->control[control_port] &= ~BIT(0); - } - } else { - dio48egpio->io_state[io_port] &= 0x00; - if (io_port == 0 || io_port == 3) - dio48egpio->control[control_port] &= ~BIT(4); - else - dio48egpio->control[control_port] &= ~BIT(1); - } - - if (value) - dio48egpio->out_state[io_port] |= mask; - else - dio48egpio->out_state[io_port] &= ~mask; - - control = BIT(7) | dio48egpio->control[control_port]; - iowrite8(control, control_addr); - - iowrite8(dio48egpio->out_state[io_port], dio48egpio->base + out_port); - - control &= ~BIT(7); - iowrite8(control, control_addr); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); + i8255_direction_output(dio48egpio->reg->ppi, dio48egpio->ppi_state, + offset, value); return 0; } @@ -157,47 +113,16 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int off static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - const unsigned int port = offset / 8; - const unsigned int mask = BIT(offset % 8); - const unsigned int in_port = (port > 2) ? port + 1 : port; - unsigned long flags; - unsigned int port_state; - raw_spin_lock_irqsave(&dio48egpio->lock, flags); - - /* ensure that GPIO is set for input */ - if (!(dio48egpio->io_state[port] & mask)) { - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); - return -EINVAL; - } - - port_state = ioread8(dio48egpio->base + in_port); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); - - return !!(port_state & mask); + return i8255_get(dio48egpio->reg->ppi, offset); } -static const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; - static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - unsigned long offset; - unsigned long gpio_mask; - void __iomem *port_addr; - unsigned long port_state; - /* clear bits array to a clean slate */ - bitmap_zero(bits, chip->ngpio); - - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - port_addr = dio48egpio->base + ports[offset / 8]; - port_state = ioread8(port_addr) & gpio_mask; - - bitmap_set_value8(bits, port_state, offset); - } + i8255_get_multiple(dio48egpio->reg->ppi, mask, bits, chip->ngpio); return 0; } @@ -205,49 +130,17 @@ static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - const unsigned int port = offset / 8; - const unsigned int mask = BIT(offset % 8); - const unsigned int out_port = (port > 2) ? port + 1 : port; - unsigned long flags; - raw_spin_lock_irqsave(&dio48egpio->lock, flags); - - if (value) - dio48egpio->out_state[port] |= mask; - else - dio48egpio->out_state[port] &= ~mask; - - iowrite8(dio48egpio->out_state[port], dio48egpio->base + out_port); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); + i8255_set(dio48egpio->reg->ppi, dio48egpio->ppi_state, offset, value); } static void dio48e_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip); - unsigned long offset; - unsigned long gpio_mask; - size_t index; - void __iomem *port_addr; - unsigned long bitmask; - unsigned long flags; - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - index = offset / 8; - port_addr = dio48egpio->base + ports[index]; - - bitmask = bitmap_get_value8(bits, offset) & gpio_mask; - - raw_spin_lock_irqsave(&dio48egpio->lock, flags); - - /* update output state data and set device gpio register */ - dio48egpio->out_state[index] &= ~gpio_mask; - dio48egpio->out_state[index] |= bitmask; - iowrite8(dio48egpio->out_state[index], port_addr); - - raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); - } + i8255_set_multiple(dio48egpio->reg->ppi, dio48egpio->ppi_state, mask, + bits, chip->ngpio); } static void dio48e_irq_ack(struct irq_data *data) @@ -274,7 +167,7 @@ static void dio48e_irq_mask(struct irq_data *data) if (!dio48egpio->irq_mask) /* disable interrupts */ - ioread8(dio48egpio->base + 0xB); + ioread8(&dio48egpio->reg->enable_interrupt); raw_spin_unlock_irqrestore(&dio48egpio->lock, flags); } @@ -294,8 +187,8 @@ static void dio48e_irq_unmask(struct irq_data *data) if (!dio48egpio->irq_mask) { /* enable interrupts */ - iowrite8(0x00, dio48egpio->base + 0xF); - iowrite8(0x00, dio48egpio->base + 0xB); + iowrite8(0x00, &dio48egpio->reg->clear_interrupt); + iowrite8(0x00, &dio48egpio->reg->enable_interrupt); } if (offset == 19) @@ -341,7 +234,7 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id) raw_spin_lock(&dio48egpio->lock); - iowrite8(0x00, dio48egpio->base + 0xF); + iowrite8(0x00, &dio48egpio->reg->clear_interrupt); raw_spin_unlock(&dio48egpio->lock); @@ -373,11 +266,26 @@ static int dio48e_irq_init_hw(struct gpio_chip *gc) struct dio48e_gpio *const dio48egpio = gpiochip_get_data(gc); /* Disable IRQ by default */ - ioread8(dio48egpio->base + 0xB); + ioread8(&dio48egpio->reg->enable_interrupt); return 0; } +static void dio48e_init_ppi(struct i8255 __iomem *const ppi, + struct i8255_state *const ppi_state) +{ + const unsigned long ngpio = 24; + const unsigned long mask = GENMASK(ngpio - 1, 0); + const unsigned long bits = 0; + unsigned long i; + + /* Initialize all GPIO to output 0 */ + for (i = 0; i < DIO48E_NUM_PPI; i++) { + i8255_mode0_output(&ppi[i]); + i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio); + } +} + static int dio48e_probe(struct device *dev, unsigned int id) { struct dio48e_gpio *dio48egpio; @@ -395,8 +303,8 @@ static int dio48e_probe(struct device *dev, unsigned int id) return -EBUSY; } - dio48egpio->base = devm_ioport_map(dev, base[id], DIO48E_EXTENT); - if (!dio48egpio->base) + dio48egpio->reg = devm_ioport_map(dev, base[id], DIO48E_EXTENT); + if (!dio48egpio->reg) return -ENOMEM; dio48egpio->chip.label = name; @@ -425,17 +333,8 @@ static int dio48e_probe(struct device *dev, unsigned int id) raw_spin_lock_init(&dio48egpio->lock); - /* initialize all GPIO as output */ - iowrite8(0x80, dio48egpio->base + 3); - iowrite8(0x00, dio48egpio->base); - iowrite8(0x00, dio48egpio->base + 1); - iowrite8(0x00, dio48egpio->base + 2); - iowrite8(0x00, dio48egpio->base + 3); - iowrite8(0x80, dio48egpio->base + 7); - iowrite8(0x00, dio48egpio->base + 4); - iowrite8(0x00, dio48egpio->base + 5); - iowrite8(0x00, dio48egpio->base + 6); - iowrite8(0x00, dio48egpio->base + 7); + i8255_state_init(dio48egpio->ppi_state, DIO48E_NUM_PPI); + dio48e_init_ppi(dio48egpio->reg->ppi, dio48egpio->ppi_state); err = devm_gpiochip_add_data(dev, &dio48egpio->chip, dio48egpio); if (err) { From 3ce632fdd13abd23686c29e81a924d47365b2eca Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 20 Jul 2022 09:46:01 -0400 Subject: [PATCH 1196/1436] gpio: 104-idi-48: Implement and utilize register structures Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. The 104-IDI-48 device features an Intel 8255 compatible GPIO interface, so the i8255 GPIO module is selected and utilized as well. Reviewed-by: Linus Walleij Cc: John Hentges Cc: Jay Dolan Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-104-idi-48.c | 143 ++++++++++++++------------------- 2 files changed, 61 insertions(+), 83 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d070bd9f4f94..8f1d4d56f0aa 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -865,6 +865,7 @@ config GPIO_104_IDI_48 depends on PC104 select ISA_BUS_API select GPIOLIB_IRQCHIP + select GPIO_I8255 help Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A, 104-IDI-48AC, 104-IDI-48B, 104-IDI-48BC). The base port addresses for diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c index c1e4c3629e17..40be76efeed7 100644 --- a/drivers/gpio/gpio-104-idi-48.c +++ b/drivers/gpio/gpio-104-idi-48.c @@ -6,8 +6,7 @@ * This driver supports the following ACCES devices: 104-IDI-48A, * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC. */ -#include -#include +#include #include #include #include @@ -20,6 +19,11 @@ #include #include #include +#include + +#include "gpio-i8255.h" + +MODULE_IMPORT_NS(I8255); #define IDI_48_EXTENT 8 #define MAX_NUM_IDI_48 max_num_isa_dev(IDI_48_EXTENT) @@ -33,21 +37,34 @@ static unsigned int irq[MAX_NUM_IDI_48]; module_param_hw_array(irq, uint, irq, NULL, 0); MODULE_PARM_DESC(irq, "ACCES 104-IDI-48 interrupt line numbers"); +/** + * struct idi_48_reg - device register structure + * @port0: Port 0 Inputs + * @unused: Unused + * @port1: Port 1 Inputs + * @irq: Read: IRQ Status Register/IRQ Clear + * Write: IRQ Enable/Disable + */ +struct idi_48_reg { + u8 port0[3]; + u8 unused; + u8 port1[3]; + u8 irq; +}; + /** * struct idi_48_gpio - GPIO device private data structure * @chip: instance of the gpio_chip * @lock: synchronization lock to prevent I/O race conditions - * @ack_lock: synchronization lock to prevent IRQ handler race conditions * @irq_mask: input bits affected by interrupts - * @base: base port address of the GPIO device + * @reg: I/O address offset for the device registers * @cos_enb: Change-Of-State IRQ enable boundaries mask */ struct idi_48_gpio { struct gpio_chip chip; - raw_spinlock_t lock; - spinlock_t ack_lock; + spinlock_t lock; unsigned char irq_mask[6]; - void __iomem *base; + struct idi_48_reg __iomem *reg; unsigned char cos_enb; }; @@ -64,42 +81,18 @@ static int idi_48_gpio_direction_input(struct gpio_chip *chip, unsigned int offs static int idi_48_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - unsigned int i; - static const unsigned int register_offset[6] = { 0, 1, 2, 4, 5, 6 }; - void __iomem *port_addr; - unsigned int mask; + void __iomem *const ppi = idi48gpio->reg; - for (i = 0; i < 48; i += 8) - if (offset < i + 8) { - port_addr = idi48gpio->base + register_offset[i / 8]; - mask = BIT(offset - i); - - return !!(ioread8(port_addr) & mask); - } - - /* The following line should never execute since offset < 48 */ - return 0; + return i8255_get(ppi, offset); } static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); - unsigned long offset; - unsigned long gpio_mask; - static const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; - void __iomem *port_addr; - unsigned long port_state; + void __iomem *const ppi = idi48gpio->reg; - /* clear bits array to a clean slate */ - bitmap_zero(bits, chip->ngpio); - - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - port_addr = idi48gpio->base + ports[offset / 8]; - port_state = ioread8(port_addr) & gpio_mask; - - bitmap_set_value8(bits, port_state, offset); - } + i8255_get_multiple(ppi, mask, bits, chip->ngpio); return 0; } @@ -113,30 +106,24 @@ static void idi_48_irq_mask(struct irq_data *data) struct gpio_chip *chip = irq_data_get_irq_chip_data(data); struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); const unsigned int offset = irqd_to_hwirq(data); - unsigned int i; - unsigned int mask; - unsigned int boundary; + const unsigned long boundary = offset / 8; + const unsigned long mask = BIT(offset % 8); unsigned long flags; - for (i = 0; i < 48; i += 8) - if (offset < i + 8) { - mask = BIT(offset - i); - boundary = i / 8; + spin_lock_irqsave(&idi48gpio->lock, flags); - idi48gpio->irq_mask[boundary] &= ~mask; + idi48gpio->irq_mask[boundary] &= ~mask; - if (!idi48gpio->irq_mask[boundary]) { - idi48gpio->cos_enb &= ~BIT(boundary); + /* Exit early if there are still input lines with IRQ unmasked */ + if (idi48gpio->irq_mask[boundary]) + goto exit; - raw_spin_lock_irqsave(&idi48gpio->lock, flags); + idi48gpio->cos_enb &= ~BIT(boundary); - iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7); + iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); - raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); - } - - return; - } +exit: + spin_unlock_irqrestore(&idi48gpio->lock, flags); } static void idi_48_irq_unmask(struct irq_data *data) @@ -144,32 +131,27 @@ static void idi_48_irq_unmask(struct irq_data *data) struct gpio_chip *chip = irq_data_get_irq_chip_data(data); struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip); const unsigned int offset = irqd_to_hwirq(data); - unsigned int i; - unsigned int mask; - unsigned int boundary; + const unsigned long boundary = offset / 8; + const unsigned long mask = BIT(offset % 8); unsigned int prev_irq_mask; unsigned long flags; - for (i = 0; i < 48; i += 8) - if (offset < i + 8) { - mask = BIT(offset - i); - boundary = i / 8; - prev_irq_mask = idi48gpio->irq_mask[boundary]; + spin_lock_irqsave(&idi48gpio->lock, flags); - idi48gpio->irq_mask[boundary] |= mask; + prev_irq_mask = idi48gpio->irq_mask[boundary]; - if (!prev_irq_mask) { - idi48gpio->cos_enb |= BIT(boundary); + idi48gpio->irq_mask[boundary] |= mask; - raw_spin_lock_irqsave(&idi48gpio->lock, flags); + /* Exit early if IRQ was already unmasked for this boundary */ + if (prev_irq_mask) + goto exit; - iowrite8(idi48gpio->cos_enb, idi48gpio->base + 7); + idi48gpio->cos_enb |= BIT(boundary); - raw_spin_unlock_irqrestore(&idi48gpio->lock, flags); - } + iowrite8(idi48gpio->cos_enb, &idi48gpio->reg->irq); - return; - } +exit: + spin_unlock_irqrestore(&idi48gpio->lock, flags); } static int idi_48_irq_set_type(struct irq_data *data, unsigned int flow_type) @@ -200,17 +182,13 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) unsigned long gpio; struct gpio_chip *const chip = &idi48gpio->chip; - spin_lock(&idi48gpio->ack_lock); + spin_lock(&idi48gpio->lock); - raw_spin_lock(&idi48gpio->lock); - - cos_status = ioread8(idi48gpio->base + 7); - - raw_spin_unlock(&idi48gpio->lock); + cos_status = ioread8(&idi48gpio->reg->irq); /* IRQ Status (bit 6) is active low (0 = IRQ generated by device) */ if (cos_status & BIT(6)) { - spin_unlock(&idi48gpio->ack_lock); + spin_unlock(&idi48gpio->lock); return IRQ_NONE; } @@ -228,7 +206,7 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id) } } - spin_unlock(&idi48gpio->ack_lock); + spin_unlock(&idi48gpio->lock); return IRQ_HANDLED; } @@ -250,8 +228,8 @@ static int idi_48_irq_init_hw(struct gpio_chip *gc) struct idi_48_gpio *const idi48gpio = gpiochip_get_data(gc); /* Disable IRQ by default */ - iowrite8(0, idi48gpio->base + 7); - ioread8(idi48gpio->base + 7); + iowrite8(0, &idi48gpio->reg->irq); + ioread8(&idi48gpio->reg->irq); return 0; } @@ -273,8 +251,8 @@ static int idi_48_probe(struct device *dev, unsigned int id) return -EBUSY; } - idi48gpio->base = devm_ioport_map(dev, base[id], IDI_48_EXTENT); - if (!idi48gpio->base) + idi48gpio->reg = devm_ioport_map(dev, base[id], IDI_48_EXTENT); + if (!idi48gpio->reg) return -ENOMEM; idi48gpio->chip.label = name; @@ -298,8 +276,7 @@ static int idi_48_probe(struct device *dev, unsigned int id) girq->handler = handle_edge_irq; girq->init_hw = idi_48_irq_init_hw; - raw_spin_lock_init(&idi48gpio->lock); - spin_lock_init(&idi48gpio->ack_lock); + spin_lock_init(&idi48gpio->lock); err = devm_gpiochip_add_data(dev, &idi48gpio->chip, idi48gpio); if (err) { From 949506dc608f9820e0cee51b106c35fd3503bbb2 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Wed, 20 Jul 2022 09:46:02 -0400 Subject: [PATCH 1197/1436] gpio: gpio-mm: Implement and utilize register structures Reduce magic numbers and improve code readability by implementing and utilizing named register data structures. The GPIO-MM device features an Intel 8255 compatible GPIO interface, so the i8255 GPIO module is selected and utilized as well. Tested-by: Fred Eckert Reviewed-by: Linus Walleij Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- drivers/gpio/Kconfig | 1 + drivers/gpio/gpio-gpio-mm.c | 202 +++++++----------------------------- 2 files changed, 40 insertions(+), 163 deletions(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8f1d4d56f0aa..0642f579196f 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -886,6 +886,7 @@ config GPIO_GPIO_MM tristate "Diamond Systems GPIO-MM GPIO support" depends on PC104 select ISA_BUS_API + select GPIO_I8255 help Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12. diff --git a/drivers/gpio/gpio-gpio-mm.c b/drivers/gpio/gpio-gpio-mm.c index 097a06463d01..2689671b6b01 100644 --- a/drivers/gpio/gpio-gpio-mm.c +++ b/drivers/gpio/gpio-gpio-mm.c @@ -6,8 +6,6 @@ * This driver supports the following Diamond Systems devices: GPIO-MM and * GPIO-MM-12. */ -#include -#include #include #include #include @@ -17,7 +15,10 @@ #include #include #include -#include + +#include "gpio-i8255.h" + +MODULE_IMPORT_NS(I8255); #define GPIOMM_EXTENT 8 #define MAX_NUM_GPIOMM max_num_isa_dev(GPIOMM_EXTENT) @@ -27,32 +28,26 @@ static unsigned int num_gpiomm; module_param_hw_array(base, uint, ioport, &num_gpiomm, 0); MODULE_PARM_DESC(base, "Diamond Systems GPIO-MM base addresses"); +#define GPIOMM_NUM_PPI 2 + /** * struct gpiomm_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @io_state: bit I/O state (whether bit is set to input or output) - * @out_state: output bits state - * @control: Control registers state - * @lock: synchronization lock to prevent I/O race conditions - * @base: base port address of the GPIO device + * @chip: instance of the gpio_chip + * @ppi_state: Programmable Peripheral Interface group states + * @ppi: Programmable Peripheral Interface groups */ struct gpiomm_gpio { struct gpio_chip chip; - unsigned char io_state[6]; - unsigned char out_state[6]; - unsigned char control[2]; - spinlock_t lock; - void __iomem *base; + struct i8255_state ppi_state[GPIOMM_NUM_PPI]; + struct i8255 __iomem *ppi; }; static int gpiomm_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - const unsigned int port = offset / 8; - const unsigned int mask = BIT(offset % 8); - if (gpiommgpio->io_state[port] & mask) + if (i8255_get_direction(gpiommgpio->ppi_state, offset)) return GPIO_LINE_DIRECTION_IN; return GPIO_LINE_DIRECTION_OUT; @@ -62,35 +57,8 @@ static int gpiomm_gpio_direction_input(struct gpio_chip *chip, unsigned int offset) { struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - const unsigned int io_port = offset / 8; - const unsigned int control_port = io_port / 3; - unsigned long flags; - unsigned int control; - spin_lock_irqsave(&gpiommgpio->lock, flags); - - /* Check if configuring Port C */ - if (io_port == 2 || io_port == 5) { - /* Port C can be configured by nibble */ - if (offset % 8 > 3) { - gpiommgpio->io_state[io_port] |= 0xF0; - gpiommgpio->control[control_port] |= BIT(3); - } else { - gpiommgpio->io_state[io_port] |= 0x0F; - gpiommgpio->control[control_port] |= BIT(0); - } - } else { - gpiommgpio->io_state[io_port] |= 0xFF; - if (io_port == 0 || io_port == 3) - gpiommgpio->control[control_port] |= BIT(4); - else - gpiommgpio->control[control_port] |= BIT(1); - } - - control = BIT(7) | gpiommgpio->control[control_port]; - iowrite8(control, gpiommgpio->base + 3 + control_port*4); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); + i8255_direction_input(gpiommgpio->ppi, gpiommgpio->ppi_state, offset); return 0; } @@ -99,44 +67,9 @@ static int gpiomm_gpio_direction_output(struct gpio_chip *chip, unsigned int offset, int value) { struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - const unsigned int io_port = offset / 8; - const unsigned int control_port = io_port / 3; - const unsigned int mask = BIT(offset % 8); - const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port; - unsigned long flags; - unsigned int control; - spin_lock_irqsave(&gpiommgpio->lock, flags); - - /* Check if configuring Port C */ - if (io_port == 2 || io_port == 5) { - /* Port C can be configured by nibble */ - if (offset % 8 > 3) { - gpiommgpio->io_state[io_port] &= 0x0F; - gpiommgpio->control[control_port] &= ~BIT(3); - } else { - gpiommgpio->io_state[io_port] &= 0xF0; - gpiommgpio->control[control_port] &= ~BIT(0); - } - } else { - gpiommgpio->io_state[io_port] &= 0x00; - if (io_port == 0 || io_port == 3) - gpiommgpio->control[control_port] &= ~BIT(4); - else - gpiommgpio->control[control_port] &= ~BIT(1); - } - - if (value) - gpiommgpio->out_state[io_port] |= mask; - else - gpiommgpio->out_state[io_port] &= ~mask; - - control = BIT(7) | gpiommgpio->control[control_port]; - iowrite8(control, gpiommgpio->base + 3 + control_port*4); - - iowrite8(gpiommgpio->out_state[io_port], gpiommgpio->base + out_port); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); + i8255_direction_output(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, + value); return 0; } @@ -144,47 +77,16 @@ static int gpiomm_gpio_direction_output(struct gpio_chip *chip, static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - const unsigned int port = offset / 8; - const unsigned int mask = BIT(offset % 8); - const unsigned int in_port = (port > 2) ? port + 1 : port; - unsigned long flags; - unsigned int port_state; - spin_lock_irqsave(&gpiommgpio->lock, flags); - - /* ensure that GPIO is set for input */ - if (!(gpiommgpio->io_state[port] & mask)) { - spin_unlock_irqrestore(&gpiommgpio->lock, flags); - return -EINVAL; - } - - port_state = ioread8(gpiommgpio->base + in_port); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); - - return !!(port_state & mask); + return i8255_get(gpiommgpio->ppi, offset); } -static const size_t ports[] = { 0, 1, 2, 4, 5, 6 }; - static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - unsigned long offset; - unsigned long gpio_mask; - void __iomem *port_addr; - unsigned long port_state; - /* clear bits array to a clean slate */ - bitmap_zero(bits, chip->ngpio); - - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - port_addr = gpiommgpio->base + ports[offset / 8]; - port_state = ioread8(port_addr) & gpio_mask; - - bitmap_set_value8(bits, port_state, offset); - } + i8255_get_multiple(gpiommgpio->ppi, mask, bits, chip->ngpio); return 0; } @@ -193,49 +95,17 @@ static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - const unsigned int port = offset / 8; - const unsigned int mask = BIT(offset % 8); - const unsigned int out_port = (port > 2) ? port + 1 : port; - unsigned long flags; - spin_lock_irqsave(&gpiommgpio->lock, flags); - - if (value) - gpiommgpio->out_state[port] |= mask; - else - gpiommgpio->out_state[port] &= ~mask; - - iowrite8(gpiommgpio->out_state[port], gpiommgpio->base + out_port); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); + i8255_set(gpiommgpio->ppi, gpiommgpio->ppi_state, offset, value); } static void gpiomm_gpio_set_multiple(struct gpio_chip *chip, unsigned long *mask, unsigned long *bits) { struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip); - unsigned long offset; - unsigned long gpio_mask; - size_t index; - void __iomem *port_addr; - unsigned long bitmask; - unsigned long flags; - for_each_set_clump8(offset, gpio_mask, mask, ARRAY_SIZE(ports) * 8) { - index = offset / 8; - port_addr = gpiommgpio->base + ports[index]; - - bitmask = bitmap_get_value8(bits, offset) & gpio_mask; - - spin_lock_irqsave(&gpiommgpio->lock, flags); - - /* update output state data and set device gpio register */ - gpiommgpio->out_state[index] &= ~gpio_mask; - gpiommgpio->out_state[index] |= bitmask; - iowrite8(gpiommgpio->out_state[index], port_addr); - - spin_unlock_irqrestore(&gpiommgpio->lock, flags); - } + i8255_set_multiple(gpiommgpio->ppi, gpiommgpio->ppi_state, mask, bits, + chip->ngpio); } #define GPIOMM_NGPIO 48 @@ -250,6 +120,21 @@ static const char *gpiomm_names[GPIOMM_NGPIO] = { "Port 2C2", "Port 2C3", "Port 2C4", "Port 2C5", "Port 2C6", "Port 2C7", }; +static void gpiomm_init_dio(struct i8255 __iomem *const ppi, + struct i8255_state *const ppi_state) +{ + const unsigned long ngpio = 24; + const unsigned long mask = GENMASK(ngpio - 1, 0); + const unsigned long bits = 0; + unsigned long i; + + /* Initialize all GPIO to output 0 */ + for (i = 0; i < GPIOMM_NUM_PPI; i++) { + i8255_mode0_output(&ppi[i]); + i8255_set_multiple(&ppi[i], &ppi_state[i], &mask, &bits, ngpio); + } +} + static int gpiomm_probe(struct device *dev, unsigned int id) { struct gpiomm_gpio *gpiommgpio; @@ -266,8 +151,8 @@ static int gpiomm_probe(struct device *dev, unsigned int id) return -EBUSY; } - gpiommgpio->base = devm_ioport_map(dev, base[id], GPIOMM_EXTENT); - if (!gpiommgpio->base) + gpiommgpio->ppi = devm_ioport_map(dev, base[id], GPIOMM_EXTENT); + if (!gpiommgpio->ppi) return -ENOMEM; gpiommgpio->chip.label = name; @@ -284,7 +169,8 @@ static int gpiomm_probe(struct device *dev, unsigned int id) gpiommgpio->chip.set = gpiomm_gpio_set; gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple; - spin_lock_init(&gpiommgpio->lock); + i8255_state_init(gpiommgpio->ppi_state, GPIOMM_NUM_PPI); + gpiomm_init_dio(gpiommgpio->ppi, gpiommgpio->ppi_state); err = devm_gpiochip_add_data(dev, &gpiommgpio->chip, gpiommgpio); if (err) { @@ -292,16 +178,6 @@ static int gpiomm_probe(struct device *dev, unsigned int id) return err; } - /* initialize all GPIO as output */ - iowrite8(0x80, gpiommgpio->base + 3); - iowrite8(0x00, gpiommgpio->base); - iowrite8(0x00, gpiommgpio->base + 1); - iowrite8(0x00, gpiommgpio->base + 2); - iowrite8(0x80, gpiommgpio->base + 7); - iowrite8(0x00, gpiommgpio->base + 4); - iowrite8(0x00, gpiommgpio->base + 5); - iowrite8(0x00, gpiommgpio->base + 6); - return 0; } From f92dd1475b0644b4779eed6f937a1eebfb80d53d Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 20 Jul 2022 04:47:53 +0000 Subject: [PATCH 1198/1436] platform/chrome: merge Kunit utils and test cases Merge CROS_KUNIT and CROS_EC_PROTO_KUNIT_TEST so that when they're built as modules cros_kunit_util doesn't need to export the symbols. Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220720044754.4026295-2-tzungbi@kernel.org --- drivers/platform/chrome/Kconfig | 10 ++-------- drivers/platform/chrome/Makefile | 5 +++-- drivers/platform/chrome/cros_kunit_util.c | 14 -------------- 3 files changed, 5 insertions(+), 24 deletions(-) diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig index cae859f0bc06..c45fb376d653 100644 --- a/drivers/platform/chrome/Kconfig +++ b/drivers/platform/chrome/Kconfig @@ -269,17 +269,11 @@ source "drivers/platform/chrome/wilco_ec/Kconfig" # Kunit test cases config CROS_KUNIT - tristate - help - ChromeOS Kunit. - -config CROS_EC_PROTO_KUNIT_TEST - tristate "Kunit tests for ChromeOS EC protocol" if !KUNIT_ALL_TESTS + tristate "Kunit tests for ChromeOS" if !KUNIT_ALL_TESTS depends on KUNIT && CROS_EC default KUNIT_ALL_TESTS select CROS_EC_PROTO - select CROS_KUNIT help - Kunit tests for the ChromeOS Embedded Controller protocol. + ChromeOS Kunit tests. endif # CHROMEOS_PLATFORMS diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile index a06bc56d12a8..f7e74a845afc 100644 --- a/drivers/platform/chrome/Makefile +++ b/drivers/platform/chrome/Makefile @@ -32,5 +32,6 @@ obj-$(CONFIG_CROS_USBPD_NOTIFY) += cros_usbpd_notify.o obj-$(CONFIG_WILCO_EC) += wilco_ec/ # Kunit test cases -obj-$(CONFIG_CROS_KUNIT) += cros_kunit_util.o -obj-$(CONFIG_CROS_EC_PROTO_KUNIT_TEST) += cros_ec_proto_test.o +obj-$(CONFIG_CROS_KUNIT) += cros_kunit.o +cros_kunit-objs := cros_kunit_util.o +cros_kunit-objs += cros_ec_proto_test.o diff --git a/drivers/platform/chrome/cros_kunit_util.c b/drivers/platform/chrome/cros_kunit_util.c index d37c334b416d..090927d43035 100644 --- a/drivers/platform/chrome/cros_kunit_util.c +++ b/drivers/platform/chrome/cros_kunit_util.c @@ -14,11 +14,8 @@ #include "cros_kunit_util.h" int cros_kunit_ec_xfer_mock_default_ret; -EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_default_ret); int cros_kunit_ec_cmd_xfer_mock_called; -EXPORT_SYMBOL_GPL(cros_kunit_ec_cmd_xfer_mock_called); int cros_kunit_ec_pkt_xfer_mock_called; -EXPORT_SYMBOL_GPL(cros_kunit_ec_pkt_xfer_mock_called); static struct list_head cros_kunit_ec_xfer_mock_in; static struct list_head cros_kunit_ec_xfer_mock_out; @@ -48,27 +45,23 @@ int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_comman return mock->ret; } -EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock); int cros_kunit_ec_cmd_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) { ++cros_kunit_ec_cmd_xfer_mock_called; return cros_kunit_ec_xfer_mock(ec_dev, msg); } -EXPORT_SYMBOL_GPL(cros_kunit_ec_cmd_xfer_mock); int cros_kunit_ec_pkt_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) { ++cros_kunit_ec_pkt_xfer_mock_called; return cros_kunit_ec_xfer_mock(ec_dev, msg); } -EXPORT_SYMBOL_GPL(cros_kunit_ec_pkt_xfer_mock); struct ec_xfer_mock *cros_kunit_ec_xfer_mock_add(struct kunit *test, size_t size) { return cros_kunit_ec_xfer_mock_addx(test, size, EC_RES_SUCCESS, size); } -EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_add); struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test, int ret, int result, size_t size) @@ -91,7 +84,6 @@ struct ec_xfer_mock *cros_kunit_ec_xfer_mock_addx(struct kunit *test, return mock; } -EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_addx); struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void) { @@ -103,14 +95,10 @@ struct ec_xfer_mock *cros_kunit_ec_xfer_mock_next(void) return mock; } -EXPORT_SYMBOL_GPL(cros_kunit_ec_xfer_mock_next); int cros_kunit_readmem_mock_offset; -EXPORT_SYMBOL_GPL(cros_kunit_readmem_mock_offset); u8 *cros_kunit_readmem_mock_data; -EXPORT_SYMBOL_GPL(cros_kunit_readmem_mock_data); int cros_kunit_readmem_mock_ret; -EXPORT_SYMBOL_GPL(cros_kunit_readmem_mock_ret); int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset, unsigned int bytes, void *dest) @@ -121,7 +109,6 @@ int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset, return cros_kunit_readmem_mock_ret; } -EXPORT_SYMBOL_GPL(cros_kunit_readmem_mock); void cros_kunit_mock_reset(void) { @@ -135,6 +122,5 @@ void cros_kunit_mock_reset(void) cros_kunit_readmem_mock_data = NULL; cros_kunit_readmem_mock_ret = 0; } -EXPORT_SYMBOL_GPL(cros_kunit_mock_reset); MODULE_LICENSE("GPL"); From afef1e1a0223623d063a6df51dbc342c9517b948 Mon Sep 17 00:00:00 2001 From: Tzung-Bi Shih Date: Wed, 20 Jul 2022 04:47:54 +0000 Subject: [PATCH 1199/1436] platform/chrome: cros_kunit_util: add default value for `msg->result` Add default value for `msg->result` so that it won't be garbage bytes when the mock list is empty. Signed-off-by: Tzung-Bi Shih Reviewed-by: Guenter Roeck Link: https://lore.kernel.org/r/20220720044754.4026295-3-tzungbi@kernel.org --- drivers/platform/chrome/cros_kunit_util.c | 6 +++++- drivers/platform/chrome/cros_kunit_util.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/platform/chrome/cros_kunit_util.c b/drivers/platform/chrome/cros_kunit_util.c index 090927d43035..f0fda96b11bd 100644 --- a/drivers/platform/chrome/cros_kunit_util.c +++ b/drivers/platform/chrome/cros_kunit_util.c @@ -13,6 +13,7 @@ #include "cros_ec.h" #include "cros_kunit_util.h" +int cros_kunit_ec_xfer_mock_default_result; int cros_kunit_ec_xfer_mock_default_ret; int cros_kunit_ec_cmd_xfer_mock_called; int cros_kunit_ec_pkt_xfer_mock_called; @@ -25,8 +26,10 @@ int cros_kunit_ec_xfer_mock(struct cros_ec_device *ec_dev, struct cros_ec_comman struct ec_xfer_mock *mock; mock = list_first_entry_or_null(&cros_kunit_ec_xfer_mock_in, struct ec_xfer_mock, list); - if (!mock) + if (!mock) { + msg->result = cros_kunit_ec_xfer_mock_default_result; return cros_kunit_ec_xfer_mock_default_ret; + } list_del(&mock->list); @@ -112,6 +115,7 @@ int cros_kunit_readmem_mock(struct cros_ec_device *ec_dev, unsigned int offset, void cros_kunit_mock_reset(void) { + cros_kunit_ec_xfer_mock_default_result = 0; cros_kunit_ec_xfer_mock_default_ret = 0; cros_kunit_ec_cmd_xfer_mock_called = 0; cros_kunit_ec_pkt_xfer_mock_called = 0; diff --git a/drivers/platform/chrome/cros_kunit_util.h b/drivers/platform/chrome/cros_kunit_util.h index 88134c9f1acf..414002271c9c 100644 --- a/drivers/platform/chrome/cros_kunit_util.h +++ b/drivers/platform/chrome/cros_kunit_util.h @@ -23,6 +23,7 @@ struct ec_xfer_mock { u32 o_data_len; }; +extern int cros_kunit_ec_xfer_mock_default_result; extern int cros_kunit_ec_xfer_mock_default_ret; extern int cros_kunit_ec_cmd_xfer_mock_called; extern int cros_kunit_ec_pkt_xfer_mock_called; From 62ac2473553a00229e67bdf3cb023b62cf7f5a9a Mon Sep 17 00:00:00 2001 From: Harshit Mogalapalli Date: Mon, 20 Jun 2022 09:28:24 -0700 Subject: [PATCH 1200/1436] HID: mcp2221: prevent a buffer overflow in mcp_smbus_write() Smatch Warning: drivers/hid/hid-mcp2221.c:388 mcp_smbus_write() error: __memcpy() '&mcp->txbuf[5]' too small (59 vs 255) drivers/hid/hid-mcp2221.c:388 mcp_smbus_write() error: __memcpy() 'buf' too small (34 vs 255) The 'len' variable can take a value between 0-255 as it can come from data->block[0] and it is user data. So add an bound check to prevent a buffer overflow in memcpy(). Fixes: 67a95c21463d ("HID: mcp2221: add usb to i2c-smbus host bridge") Signed-off-by: Harshit Mogalapalli Signed-off-by: Jiri Kosina --- drivers/hid/hid-mcp2221.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c index 4211b9839209..de52e9f7bb8c 100644 --- a/drivers/hid/hid-mcp2221.c +++ b/drivers/hid/hid-mcp2221.c @@ -385,6 +385,9 @@ static int mcp_smbus_write(struct mcp2221 *mcp, u16 addr, data_len = 7; break; default: + if (len > I2C_SMBUS_BLOCK_MAX) + return -EINVAL; + memcpy(&mcp->txbuf[5], buf, len); data_len = len + 5; } From 92443a9ff1208cdcd932273e141d1ec6bdfb3c0c Mon Sep 17 00:00:00 2001 From: Jiang Jian Date: Tue, 21 Jun 2022 20:27:51 +0800 Subject: [PATCH 1201/1436] ID: intel-ish-hid: hid-client: drop unexpected word "the" in the comments there is an unexpected word "the" in the comments that need to be dropped file: drivers/hid/intel-ish-hid/ishtp-hid-client.c line: 331 * @device: Pointer to the the ishtp client device for which this message changed to * @device: Pointer to the ishtp client device for which this message Signed-off-by: Jiang Jian Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp-hid-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index 4338c9b68a43..e3d70c5460e9 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -328,7 +328,7 @@ do_get_report: /** * ish_cl_event_cb() - bus driver callback for incoming message/packet - * @device: Pointer to the the ishtp client device for which this message + * @device: Pointer to the ishtp client device for which this message * is targeted * * Remove the packet from the list and process the message by calling From 4df4b0fe960c9cbad55d52dbe1b5ced51a2b4fd4 Mon Sep 17 00:00:00 2001 From: Lukas Bulwahn Date: Fri, 1 Jul 2022 13:27:20 +0200 Subject: [PATCH 1202/1436] HID: core: remove unneeded assignment in hid_process_report() Commit bebcc522fbee ("HID: core: for input reports, process the usages by priority list") split the iteration into two distinct loops in hid_process_report(). After this change, the variable field is only used while iterating in the second loop and the assignment of values to this variable in the first loop is simply not needed. Remove the unneeded assignment during retrieval. No functional change and no change in the resulting object code. This was discovered as a dead store with clang-analyzer. Signed-off-by: Lukas Bulwahn Reviewed-by: Tom Rix Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 00154a1cd2d8..b7f5566e338d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1662,7 +1662,7 @@ static void hid_process_report(struct hid_device *hid, /* first retrieve all incoming values in data */ for (a = 0; a < report->maxfield; a++) - hid_input_fetch_field(hid, field = report->field[a], data); + hid_input_fetch_field(hid, report->field[a], data); if (!list_empty(&report->field_entry_list)) { /* INPUT_REPORT, we have a priority list of fields */ From 06aa2a43c307cf4096f422dcb575e5d2913e528f Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:26 +0530 Subject: [PATCH 1203/1436] HID: amd_sfh: Add NULL check for hid device On removal of hid device during SFH set report may cause NULL pointer exception. Hence add NULL check for hid device before accessing. Fixes: 4b2c53d93a4b ("SFH:Transport Driver to add support of AMD Sensor Fusion Hub (SFH)") Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_hid.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c index 1089134030b0..1b18291fc5af 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c @@ -101,11 +101,15 @@ static int amdtp_wait_for_response(struct hid_device *hid) void amdtp_hid_wakeup(struct hid_device *hid) { - struct amdtp_hid_data *hid_data = hid->driver_data; - struct amdtp_cl_data *cli_data = hid_data->cli_data; + struct amdtp_hid_data *hid_data; + struct amdtp_cl_data *cli_data; - cli_data->request_done[cli_data->cur_hid_dev] = true; - wake_up_interruptible(&hid_data->hid_wait); + if (hid) { + hid_data = hid->driver_data; + cli_data = hid_data->cli_data; + cli_data->request_done[cli_data->cur_hid_dev] = true; + wake_up_interruptible(&hid_data->hid_wait); + } } static struct hid_ll_driver amdtp_hid_ll_driver = { From 6947f312e5055f64cbcf227fb8c0ab9648473794 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:27 +0530 Subject: [PATCH 1204/1436] HID: amd_sfh: Move common macros and structures Introduce common macros and structures to support multiple generations of AMD SOCs, move them to amd_sfh_common.h. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_common.h | 59 ++++++++++++++++++++++++ drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 42 +---------------- 2 files changed, 60 insertions(+), 41 deletions(-) create mode 100644 drivers/hid/amd-sfh-hid/amd_sfh_common.h diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h new file mode 100644 index 000000000000..40da53d5efd0 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * AMD MP2 common macros and structures + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Basavaraj Natikar + */ +#ifndef AMD_SFH_COMMON_H +#define AMD_SFH_COMMON_H + +#include +#include "amd_sfh_hid.h" + +#define PCI_DEVICE_ID_AMD_MP2 0x15E4 + +#define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4)) +#define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4)) + +#define SENSOR_ENABLED 4 +#define SENSOR_DISABLED 5 + +#define AMD_SFH_IDLE_LOOP 200 + +enum cmd_id { + NO_OP, + ENABLE_SENSOR, + DISABLE_SENSOR, + STOP_ALL_SENSORS = 8, +}; + +struct amd_mp2_sensor_info { + u8 sensor_idx; + u32 period; + dma_addr_t dma_address; +}; + +struct amd_mp2_dev { + struct pci_dev *pdev; + struct amdtp_cl_data *cl_data; + void __iomem *mmio; + const struct amd_mp2_ops *mp2_ops; + struct amd_input_data in_data; + /* mp2 active control status */ + u32 mp2_acs; +}; + +struct amd_mp2_ops { + void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info); + void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx); + void (*stop_all)(struct amd_mp2_dev *privdata); + int (*response)(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts); + void (*clear_intr)(struct amd_mp2_dev *privdata); + int (*init_intr)(struct amd_mp2_dev *privdata); + int (*discovery_status)(struct amd_mp2_dev *privdata); +}; + +#endif diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h index 8c760526132a..2feac14f5d3c 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h @@ -10,35 +10,20 @@ #ifndef PCIE_MP2_AMD_H #define PCIE_MP2_AMD_H -#include -#include "amd_sfh_hid.h" - -#define PCI_DEVICE_ID_AMD_MP2 0x15E4 - -#define ENABLE_SENSOR 1 -#define DISABLE_SENSOR 2 -#define STOP_ALL_SENSORS 8 +#include "amd_sfh_common.h" /* MP2 C2P Message Registers */ #define AMD_C2P_MSG0 0x10500 #define AMD_C2P_MSG1 0x10504 #define AMD_C2P_MSG2 0x10508 -#define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4)) -#define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4)) - /* MP2 P2C Message Registers */ #define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */ #define V2_STATUS 0x2 -#define SENSOR_ENABLED 4 -#define SENSOR_DISABLED 5 - #define HPD_IDX 16 -#define AMD_SFH_IDLE_LOOP 200 - #define SENSOR_DISCOVERY_STATUS_MASK GENMASK(5, 3) #define SENSOR_DISCOVERY_STATUS_SHIFT 3 @@ -96,22 +81,6 @@ enum sensor_idx { als_idx = 19 }; -struct amd_mp2_dev { - struct pci_dev *pdev; - struct amdtp_cl_data *cl_data; - void __iomem *mmio; - const struct amd_mp2_ops *mp2_ops; - struct amd_input_data in_data; - /* mp2 active control status */ - u32 mp2_acs; -}; - -struct amd_mp2_sensor_info { - u8 sensor_idx; - u32 period; - dma_addr_t dma_address; -}; - enum mem_use_type { USE_DRAM, USE_C2P_REG, @@ -140,13 +109,4 @@ void amd_mp2_suspend(struct amd_mp2_dev *mp2); void amd_mp2_resume(struct amd_mp2_dev *mp2); const char *get_sensor_name(int idx); -struct amd_mp2_ops { - void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info); - void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx); - void (*stop_all)(struct amd_mp2_dev *privdata); - int (*response)(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts); - void (*clear_intr)(struct amd_mp2_dev *privdata); - int (*init_intr)(struct amd_mp2_dev *privdata); - int (*discovery_status)(struct amd_mp2_dev *privdata); -}; #endif From 8c68db65727e1d1e9c75c3e98d08e18afec86f1f Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:28 +0530 Subject: [PATCH 1205/1436] HID: amd_sfh: Move request_list struct to header file request_list structure can be used in multiple files to support all AMD SOCs. Hence move request_list structure to header file. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_client.c | 10 ---------- drivers/hid/amd-sfh-hid/amd_sfh_hid.h | 9 +++++++++ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index 0f770a2b47ff..fac9e8a66120 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -18,16 +18,6 @@ #include "amd_sfh_pcie.h" #include "amd_sfh_hid.h" - -struct request_list { - struct hid_device *hid; - struct list_head list; - u8 report_id; - u8 sensor_idx; - u8 report_type; - u8 current_index; -}; - static struct request_list req_list; void amd_sfh_set_report(struct hid_device *hid, int report_id, diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h index ad264db63180..e2e4cc5fc946 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h @@ -15,6 +15,15 @@ #define AMD_SFH_HID_VENDOR 0x1022 #define AMD_SFH_HID_PRODUCT 0x0001 +struct request_list { + struct hid_device *hid; + struct list_head list; + u8 report_id; + u8 sensor_idx; + u8 report_type; + u8 current_index; +}; + struct amd_input_data { u32 *sensor_virt_addr[MAX_HID_DEVICES]; u8 *input_report[MAX_HID_DEVICES]; From c092e274e0fcaae44a9e80a1cc6243b66976ae68 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:29 +0530 Subject: [PATCH 1206/1436] HID: amd_sfh: Move request_list variable to client data request_list variable can be used in multiple files to support all AMD SOCs. Hence move request_list variable to client data. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_client.c | 12 +++++++----- drivers/hid/amd-sfh-hid/amd_sfh_hid.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index fac9e8a66120..e3b3db514c91 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -18,8 +18,6 @@ #include "amd_sfh_pcie.h" #include "amd_sfh_hid.h" -static struct request_list req_list; - void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type) { @@ -40,6 +38,7 @@ int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type) { struct amdtp_hid_data *hid_data = hid->driver_data; struct amdtp_cl_data *cli_data = hid_data->cli_data; + struct request_list *req_list = &cli_data->req_list; int i; for (i = 0; i < cli_data->num_hid_devices; i++) { @@ -56,7 +55,7 @@ int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type) new->report_id = report_id; cli_data->report_id[i] = report_id; cli_data->request_done[i] = false; - list_add(&new->list, &req_list.list); + list_add(&new->list, &req_list->list); break; } } @@ -67,13 +66,14 @@ int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type) static void amd_sfh_work(struct work_struct *work) { struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work); + struct request_list *req_list = &cli_data->req_list; struct amd_input_data *in_data = cli_data->in_data; struct request_list *req_node; u8 current_index, sensor_index; u8 report_id, node_type; u8 report_size = 0; - req_node = list_last_entry(&req_list.list, struct request_list, list); + req_node = list_last_entry(&req_list->list, struct request_list, list); list_del(&req_node->list); current_index = req_node->current_index; sensor_index = req_node->sensor_idx; @@ -154,19 +154,21 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) struct amd_input_data *in_data = &privdata->in_data; struct amdtp_cl_data *cl_data = privdata->cl_data; struct amd_mp2_sensor_info info; + struct request_list *req_list; struct device *dev; u32 feature_report_size; u32 input_report_size; int rc, i, status; u8 cl_idx; + req_list = &cl_data->req_list; dev = &privdata->pdev->dev; cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]); INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); - INIT_LIST_HEAD(&req_list.list); + INIT_LIST_HEAD(&req_list->list); cl_data->in_data = in_data; for (i = 0; i < cl_data->num_hid_devices; i++) { diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h index e2e4cc5fc946..ecdd2f48cfb8 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h @@ -52,6 +52,7 @@ struct amdtp_cl_data { struct amd_input_data *in_data; struct delayed_work work; struct delayed_work work_buffer; + struct request_list req_list; }; /** From 786aa1b961d1b25f9480ae147e84e146f46fdca2 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:30 +0530 Subject: [PATCH 1207/1436] HID: amd_sfh: Add descriptor operations in amd_mp2_ops Add dynamic descriptor operations as part of amd_mp2_ops structure to support all AMD SOCs and use wherever applicable. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_client.c | 33 +++++++++++-------- drivers/hid/amd-sfh-hid/amd_sfh_common.h | 7 +++- drivers/hid/amd-sfh-hid/amd_sfh_hid.h | 2 -- drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 4 +-- drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 1 + .../hid_descriptor/amd_sfh_hid_desc.c | 17 +++++++--- .../hid_descriptor/amd_sfh_hid_desc.h | 3 -- 7 files changed, 42 insertions(+), 25 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index e3b3db514c91..e9ccdad66d12 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -70,6 +70,8 @@ static void amd_sfh_work(struct work_struct *work) struct amd_input_data *in_data = cli_data->in_data; struct request_list *req_node; u8 current_index, sensor_index; + struct amd_mp2_ops *mp2_ops; + struct amd_mp2_dev *mp2; u8 report_id, node_type; u8 report_size = 0; @@ -81,9 +83,11 @@ static void amd_sfh_work(struct work_struct *work) node_type = req_node->report_type; kfree(req_node); + mp2 = container_of(in_data, struct amd_mp2_dev, in_data); + mp2_ops = mp2->mp2_ops; if (node_type == HID_FEATURE_REPORT) { - report_size = get_feature_report(sensor_index, report_id, - cli_data->feature_report[current_index]); + report_size = mp2_ops->get_feat_rep(sensor_index, report_id, + cli_data->feature_report[current_index]); if (report_size) hid_input_report(cli_data->hid_sensor_hubs[current_index], cli_data->report_type[current_index], @@ -92,7 +96,7 @@ static void amd_sfh_work(struct work_struct *work) pr_err("AMDSFH: Invalid report size\n"); } else if (node_type == HID_INPUT_REPORT) { - report_size = get_input_report(current_index, sensor_index, report_id, in_data); + report_size = mp2_ops->get_in_rep(current_index, sensor_index, report_id, in_data); if (report_size) hid_input_report(cli_data->hid_sensor_hubs[current_index], cli_data->report_type[current_index], @@ -109,13 +113,15 @@ static void amd_sfh_work_buffer(struct work_struct *work) { struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work); struct amd_input_data *in_data = cli_data->in_data; + struct amd_mp2_dev *mp2; u8 report_size; int i; for (i = 0; i < cli_data->num_hid_devices; i++) { if (cli_data->sensor_sts[i] == SENSOR_ENABLED) { - report_size = get_input_report - (i, cli_data->sensor_idx[i], cli_data->report_id[i], in_data); + mp2 = container_of(in_data, struct amd_mp2_dev, in_data); + report_size = mp2->mp2_ops->get_in_rep(i, cli_data->sensor_idx[i], + cli_data->report_id[i], in_data); hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT, in_data->input_report[i], report_size, 0); } @@ -153,6 +159,7 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) { struct amd_input_data *in_data = &privdata->in_data; struct amdtp_cl_data *cl_data = privdata->cl_data; + struct amd_mp2_ops *mp2_ops = privdata->mp2_ops; struct amd_mp2_sensor_info info; struct request_list *req_list; struct device *dev; @@ -163,6 +170,7 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) req_list = &cl_data->req_list; dev = &privdata->pdev->dev; + amd_sfh_set_desc_ops(mp2_ops); cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]); @@ -179,17 +187,17 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) cl_data->sensor_requested_cnt[i] = 0; cl_data->cur_hid_dev = i; cl_idx = cl_data->sensor_idx[i]; - cl_data->report_descr_sz[i] = get_descr_sz(cl_idx, descr_size); + cl_data->report_descr_sz[i] = mp2_ops->get_desc_sz(cl_idx, descr_size); if (!cl_data->report_descr_sz[i]) { rc = -EINVAL; goto cleanup; } - feature_report_size = get_descr_sz(cl_idx, feature_size); + feature_report_size = mp2_ops->get_desc_sz(cl_idx, feature_size); if (!feature_report_size) { rc = -EINVAL; goto cleanup; } - input_report_size = get_descr_sz(cl_idx, input_size); + input_report_size = mp2_ops->get_desc_sz(cl_idx, input_size); if (!input_report_size) { rc = -EINVAL; goto cleanup; @@ -214,17 +222,17 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) rc = -ENOMEM; goto cleanup; } - rc = get_report_descriptor(cl_idx, cl_data->report_descr[i]); + rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]); if (rc) return rc; - privdata->mp2_ops->start(privdata, info); + mp2_ops->start(privdata, info); status = amd_sfh_wait_for_response (privdata, cl_data->sensor_idx[i], SENSOR_ENABLED); if (status == SENSOR_ENABLED) { cl_data->sensor_sts[i] = SENSOR_ENABLED; rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data); if (rc) { - privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]); + mp2_ops->stop(privdata, cl_data->sensor_idx[i]); status = amd_sfh_wait_for_response (privdata, cl_data->sensor_idx[i], SENSOR_DISABLED); if (status != SENSOR_ENABLED) @@ -240,8 +248,7 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), cl_data->sensor_sts[i]); } - if (privdata->mp2_ops->discovery_status && - privdata->mp2_ops->discovery_status(privdata) == 0) { + if (mp2_ops->discovery_status && mp2_ops->discovery_status(privdata) == 0) { amd_sfh_hid_client_deinit(privdata); for (i = 0; i < cl_data->num_hid_devices; i++) { devm_kfree(dev, cl_data->feature_report[i]); diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h index 40da53d5efd0..d2a72ab64ebf 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h @@ -40,7 +40,7 @@ struct amd_mp2_dev { struct pci_dev *pdev; struct amdtp_cl_data *cl_data; void __iomem *mmio; - const struct amd_mp2_ops *mp2_ops; + struct amd_mp2_ops *mp2_ops; struct amd_input_data in_data; /* mp2 active control status */ u32 mp2_acs; @@ -54,6 +54,11 @@ struct amd_mp2_ops { void (*clear_intr)(struct amd_mp2_dev *privdata); int (*init_intr)(struct amd_mp2_dev *privdata); int (*discovery_status)(struct amd_mp2_dev *privdata); + int (*get_rep_desc)(int sensor_idx, u8 rep_desc[]); + u32 (*get_desc_sz)(int sensor_idx, int descriptor_name); + u8 (*get_feat_rep)(int sensor_idx, int report_id, u8 *feature_report); + u8 (*get_in_rep)(u8 current_index, int sensor_idx, int report_id, + struct amd_input_data *in_data); }; #endif diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h index ecdd2f48cfb8..3754fb423e3a 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h @@ -79,6 +79,4 @@ void amdtp_hid_remove(struct amdtp_cl_data *cli_data); int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type); void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type); void amdtp_hid_wakeup(struct hid_device *hid); -u8 get_input_report(u8 current_index, int sensor_idx, int report_id, - struct amd_input_data *in_data); #endif diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index dadc491bbf6b..f169b4413abb 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -244,7 +244,7 @@ static void amd_mp2_pci_remove(void *privdata) amd_sfh_clear_intr(mp2); } -static const struct amd_mp2_ops amd_sfh_ops_v2 = { +static struct amd_mp2_ops amd_sfh_ops_v2 = { .start = amd_start_sensor_v2, .stop = amd_stop_sensor_v2, .stop_all = amd_stop_all_sensor_v2, @@ -254,7 +254,7 @@ static const struct amd_mp2_ops amd_sfh_ops_v2 = { .discovery_status = amd_sfh_dis_sts_v2, }; -static const struct amd_mp2_ops amd_sfh_ops = { +static struct amd_mp2_ops amd_sfh_ops = { .start = amd_start_sensor, .stop = amd_stop_sensor, .stop_all = amd_stop_all_sensors, diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h index 2feac14f5d3c..71c114acdd2b 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h @@ -108,5 +108,6 @@ u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts); void amd_mp2_suspend(struct amd_mp2_dev *mp2); void amd_mp2_resume(struct amd_mp2_dev *mp2); const char *get_sensor_name(int idx); +void amd_sfh_set_desc_ops(struct amd_mp2_ops *mp2_ops); #endif diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c index 76095bd53c65..f9a8c02d5a7b 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c @@ -29,7 +29,7 @@ #define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM 0x04 #define ILLUMINANCE_MASK GENMASK(14, 0) -int get_report_descriptor(int sensor_idx, u8 *rep_desc) +static int get_report_descriptor(int sensor_idx, u8 *rep_desc) { switch (sensor_idx) { case accel_idx: /* accel */ @@ -63,7 +63,7 @@ int get_report_descriptor(int sensor_idx, u8 *rep_desc) return 0; } -u32 get_descr_sz(int sensor_idx, int descriptor_name) +static u32 get_descr_sz(int sensor_idx, int descriptor_name) { switch (sensor_idx) { case accel_idx: @@ -133,7 +133,7 @@ static void get_common_features(struct common_feature_property *common, int repo common->report_interval = HID_DEFAULT_REPORT_INTERVAL; } -u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report) +static u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report) { struct accel3_feature_report acc_feature; struct gyro_feature_report gyro_feature; @@ -200,7 +200,8 @@ static void get_common_inputs(struct common_input_property *common, int report_i common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM; } -u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_input_data *in_data) +static u8 get_input_report(u8 current_index, int sensor_idx, int report_id, + struct amd_input_data *in_data) { struct amd_mp2_dev *privdata = container_of(in_data, struct amd_mp2_dev, in_data); u32 *sensor_virt_addr = in_data->sensor_virt_addr[current_index]; @@ -267,3 +268,11 @@ u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_ } return report_size; } + +void amd_sfh_set_desc_ops(struct amd_mp2_ops *mp2_ops) +{ + mp2_ops->get_rep_desc = get_report_descriptor; + mp2_ops->get_feat_rep = get_feature_report; + mp2_ops->get_in_rep = get_input_report; + mp2_ops->get_desc_sz = get_descr_sz; +} diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h index 70b1b7abe2c6..ebd55675eb62 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h @@ -111,7 +111,4 @@ struct hpd_input_report { u8 human_presence; } __packed; -int get_report_descriptor(int sensor_idx, u8 rep_desc[]); -u32 get_descr_sz(int sensor_idx, int descriptor_name); -u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report); #endif From 9acadc7256b16333f8e3e1b120471a9cb545a7e8 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:31 +0530 Subject: [PATCH 1208/1436] HID: amd_sfh: Add PM operations in amd_mp2_ops Add PM operations as part of amd_mp2_ops structure to support all AMD SOCs and use wherever applicable. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_client.c | 54 ++++++++++++++++++++++++ drivers/hid/amd-sfh-hid/amd_sfh_common.h | 2 + drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 41 +----------------- 3 files changed, 58 insertions(+), 39 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index e9ccdad66d12..b198b564db7d 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -155,6 +155,57 @@ const char *get_sensor_name(int idx) } } +static void amd_sfh_resume(struct amd_mp2_dev *mp2) +{ + struct amdtp_cl_data *cl_data = mp2->cl_data; + struct amd_mp2_sensor_info info; + int i, status; + + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { + info.period = AMD_SFH_IDLE_LOOP; + info.sensor_idx = cl_data->sensor_idx[i]; + info.dma_address = cl_data->sensor_dma_addr[i]; + mp2->mp2_ops->start(mp2, info); + status = amd_sfh_wait_for_response + (mp2, cl_data->sensor_idx[i], SENSOR_ENABLED); + if (status == SENSOR_ENABLED) + cl_data->sensor_sts[i] = SENSOR_ENABLED; + dev_dbg(&mp2->pdev->dev, "resume sid 0x%x (%s) status 0x%x\n", + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), + cl_data->sensor_sts[i]); + } + } + + schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); + if (mp2->mp2_ops->clear_intr) + mp2->mp2_ops->clear_intr(mp2); +} + +static void amd_sfh_suspend(struct amd_mp2_dev *mp2) +{ + struct amdtp_cl_data *cl_data = mp2->cl_data; + int i, status; + + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_idx[i] != HPD_IDX && + cl_data->sensor_sts[i] == SENSOR_ENABLED) { + mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]); + status = amd_sfh_wait_for_response + (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED); + if (status != SENSOR_ENABLED) + cl_data->sensor_sts[i] = SENSOR_DISABLED; + dev_dbg(&mp2->pdev->dev, "suspend sid 0x%x (%s) status 0x%x\n", + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), + cl_data->sensor_sts[i]); + } + } + + cancel_delayed_work_sync(&cl_data->work_buffer); + if (mp2->mp2_ops->clear_intr) + mp2->mp2_ops->clear_intr(mp2); +} + int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) { struct amd_input_data *in_data = &privdata->in_data; @@ -172,6 +223,9 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) dev = &privdata->pdev->dev; amd_sfh_set_desc_ops(mp2_ops); + mp2_ops->suspend = amd_sfh_suspend; + mp2_ops->resume = amd_sfh_resume; + cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]); INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h index d2a72ab64ebf..2b45d507ead7 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h @@ -54,6 +54,8 @@ struct amd_mp2_ops { void (*clear_intr)(struct amd_mp2_dev *privdata); int (*init_intr)(struct amd_mp2_dev *privdata); int (*discovery_status)(struct amd_mp2_dev *privdata); + void (*suspend)(struct amd_mp2_dev *mp2); + void (*resume)(struct amd_mp2_dev *mp2); int (*get_rep_desc)(int sensor_idx, u8 rep_desc[]); u32 (*get_desc_sz)(int sensor_idx, int descriptor_name); u8 (*get_feat_rep)(int sensor_idx, int report_id, u8 *feature_report); diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index f169b4413abb..be9ac3778f37 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -339,28 +339,8 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i static int __maybe_unused amd_mp2_pci_resume(struct device *dev) { struct amd_mp2_dev *mp2 = dev_get_drvdata(dev); - struct amdtp_cl_data *cl_data = mp2->cl_data; - struct amd_mp2_sensor_info info; - int i, status; - for (i = 0; i < cl_data->num_hid_devices; i++) { - if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { - info.period = AMD_SFH_IDLE_LOOP; - info.sensor_idx = cl_data->sensor_idx[i]; - info.dma_address = cl_data->sensor_dma_addr[i]; - mp2->mp2_ops->start(mp2, info); - status = amd_sfh_wait_for_response - (mp2, cl_data->sensor_idx[i], SENSOR_ENABLED); - if (status == SENSOR_ENABLED) - cl_data->sensor_sts[i] = SENSOR_ENABLED; - dev_dbg(dev, "suspend sid 0x%x (%s) status 0x%x\n", - cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), - cl_data->sensor_sts[i]); - } - } - - schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); - amd_sfh_clear_intr(mp2); + mp2->mp2_ops->resume(mp2); return 0; } @@ -368,25 +348,8 @@ static int __maybe_unused amd_mp2_pci_resume(struct device *dev) static int __maybe_unused amd_mp2_pci_suspend(struct device *dev) { struct amd_mp2_dev *mp2 = dev_get_drvdata(dev); - struct amdtp_cl_data *cl_data = mp2->cl_data; - int i, status; - for (i = 0; i < cl_data->num_hid_devices; i++) { - if (cl_data->sensor_idx[i] != HPD_IDX && - cl_data->sensor_sts[i] == SENSOR_ENABLED) { - mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]); - status = amd_sfh_wait_for_response - (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED); - if (status != SENSOR_ENABLED) - cl_data->sensor_sts[i] = SENSOR_DISABLED; - dev_dbg(dev, "suspend sid 0x%x (%s) status 0x%x\n", - cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), - cl_data->sensor_sts[i]); - } - } - - cancel_delayed_work_sync(&cl_data->work_buffer); - amd_sfh_clear_intr(mp2); + mp2->mp2_ops->suspend(mp2); return 0; } From 722658f86a23e5aa46f321e370503f557b20b0c8 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:32 +0530 Subject: [PATCH 1209/1436] HID: amd_sfh: Add remove operation in amd_mp2_ops Add remove operation as part of amd_mp2_ops structure to support all AMD SOCs and use wherever applicable. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_common.h | 1 + drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h index 2b45d507ead7..afecf7d2bebe 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h @@ -56,6 +56,7 @@ struct amd_mp2_ops { int (*discovery_status)(struct amd_mp2_dev *privdata); void (*suspend)(struct amd_mp2_dev *mp2); void (*resume)(struct amd_mp2_dev *mp2); + void (*remove)(void *privdata); int (*get_rep_desc)(int sensor_idx, u8 rep_desc[]); u32 (*get_desc_sz)(int sensor_idx, int descriptor_name); u8 (*get_feat_rep)(int sensor_idx, int report_id, u8 *feature_report); diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index be9ac3778f37..62e6757f889d 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -252,12 +252,14 @@ static struct amd_mp2_ops amd_sfh_ops_v2 = { .clear_intr = amd_sfh_clear_intr_v2, .init_intr = amd_sfh_irq_init_v2, .discovery_status = amd_sfh_dis_sts_v2, + .remove = amd_mp2_pci_remove, }; static struct amd_mp2_ops amd_sfh_ops = { .start = amd_start_sensor, .stop = amd_stop_sensor, .stop_all = amd_stop_all_sensors, + .remove = amd_mp2_pci_remove, }; static void mp2_select_ops(struct amd_mp2_dev *privdata) @@ -333,7 +335,7 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i amd_sfh_clear_intr(privdata); - return devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata); + return devm_add_action_or_reset(&pdev->dev, privdata->mp2_ops->remove, privdata); } static int __maybe_unused amd_mp2_pci_resume(struct device *dev) From 87cb795291bb048d7f547db2f6b769bdb8e9be3b Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:33 +0530 Subject: [PATCH 1210/1436] HID: amd_sfh: Move global functions to static Move global functions declared from header files and make them as static functions wherever applicable. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_client.c | 4 ++-- drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 6 +++--- drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 7 ------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index b198b564db7d..1f59fabded85 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -129,7 +129,7 @@ static void amd_sfh_work_buffer(struct work_struct *work) schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); } -u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts) +static u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts) { if (mp2->mp2_ops->response) sensor_sts = mp2->mp2_ops->response(mp2, sid, sensor_sts); @@ -137,7 +137,7 @@ u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts) return sensor_sts; } -const char *get_sensor_name(int idx) +static const char *get_sensor_name(int idx) { switch (idx) { case accel_idx: diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index 62e6757f889d..c9a9ac11f124 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -136,7 +136,7 @@ static int amd_sfh_dis_sts_v2(struct amd_mp2_dev *privdata) SENSOR_DISCOVERY_STATUS_MASK) >> SENSOR_DISCOVERY_STATUS_SHIFT; } -void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) +static void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) { union sfh_cmd_param cmd_param; union sfh_cmd_base cmd_base; @@ -157,7 +157,7 @@ void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info i writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); } -void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx) +static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx) { union sfh_cmd_base cmd_base; @@ -171,7 +171,7 @@ void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx) writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); } -void amd_stop_all_sensors(struct amd_mp2_dev *privdata) +static void amd_stop_all_sensors(struct amd_mp2_dev *privdata) { union sfh_cmd_base cmd_base; diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h index 71c114acdd2b..dfb7cabd82ef 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h @@ -98,16 +98,9 @@ struct hpd_status { }; }; -void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info); -void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx); -void amd_stop_all_sensors(struct amd_mp2_dev *privdata); int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id); int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata); int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata); -u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts); -void amd_mp2_suspend(struct amd_mp2_dev *mp2); -void amd_mp2_resume(struct amd_mp2_dev *mp2); -const char *get_sensor_name(int idx); void amd_sfh_set_desc_ops(struct amd_mp2_ops *mp2_ops); #endif From e7f535eaf08f1ea7d8f4ad7c2de2de25d927fd38 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:34 +0530 Subject: [PATCH 1211/1436] HID: amd_sfh: Move amd_sfh_work to common interface amd_sfh_work can be used in multiple files to support all AMD SOCs. Hence move amd_sfh_work to common interface. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_client.c | 4 ++-- drivers/hid/amd-sfh-hid/amd_sfh_common.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index 1f59fabded85..8e686081c8fc 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -63,7 +63,7 @@ int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type) return 0; } -static void amd_sfh_work(struct work_struct *work) +void amd_sfh_work(struct work_struct *work) { struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work); struct request_list *req_list = &cli_data->req_list; @@ -109,7 +109,7 @@ static void amd_sfh_work(struct work_struct *work) amdtp_hid_wakeup(cli_data->hid_sensor_hubs[current_index]); } -static void amd_sfh_work_buffer(struct work_struct *work) +void amd_sfh_work_buffer(struct work_struct *work) { struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work); struct amd_input_data *in_data = cli_data->in_data; diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h index afecf7d2bebe..b3dd758ecca4 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h @@ -64,4 +64,6 @@ struct amd_mp2_ops { struct amd_input_data *in_data); }; +void amd_sfh_work(struct work_struct *work); +void amd_sfh_work_buffer(struct work_struct *work); #endif From 014730c40b793fd638b534356cb82c064b2955f5 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:35 +0530 Subject: [PATCH 1212/1436] HID: amd_sfh: Move interrupt handling to common interface Interrupt handling can be used in multiple files to support all AMD SOCs. Hence move interrupt handling to common interface. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_client.c | 6 ++---- drivers/hid/amd-sfh-hid/amd_sfh_common.h | 4 ++++ drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index 8e686081c8fc..f95e623040f3 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -178,8 +178,7 @@ static void amd_sfh_resume(struct amd_mp2_dev *mp2) } schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); - if (mp2->mp2_ops->clear_intr) - mp2->mp2_ops->clear_intr(mp2); + amd_sfh_clear_intr(mp2); } static void amd_sfh_suspend(struct amd_mp2_dev *mp2) @@ -202,8 +201,7 @@ static void amd_sfh_suspend(struct amd_mp2_dev *mp2) } cancel_delayed_work_sync(&cl_data->work_buffer); - if (mp2->mp2_ops->clear_intr) - mp2->mp2_ops->clear_intr(mp2); + amd_sfh_clear_intr(mp2); } int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h index b3dd758ecca4..1efb72ec116f 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h @@ -66,4 +66,8 @@ struct amd_mp2_ops { void amd_sfh_work(struct work_struct *work); void amd_sfh_work_buffer(struct work_struct *work); +void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata); +int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata); +void amd_sfh_clear_intr(struct amd_mp2_dev *privdata); +int amd_sfh_irq_init(struct amd_mp2_dev *privdata); #endif diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index c9a9ac11f124..1425b57f3580 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -92,7 +92,7 @@ static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata) writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); } -static void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata) +void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata) { if (readl(privdata->mmio + AMD_P2C_MSG(4))) { writel(0, privdata->mmio + AMD_P2C_MSG(4)); @@ -100,7 +100,7 @@ static void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata) } } -static void amd_sfh_clear_intr(struct amd_mp2_dev *privdata) +void amd_sfh_clear_intr(struct amd_mp2_dev *privdata) { if (privdata->mp2_ops->clear_intr) privdata->mp2_ops->clear_intr(privdata); @@ -113,7 +113,7 @@ static irqreturn_t amd_sfh_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata) +int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata) { int rc; @@ -279,7 +279,7 @@ static void mp2_select_ops(struct amd_mp2_dev *privdata) } } -static int amd_sfh_irq_init(struct amd_mp2_dev *privdata) +int amd_sfh_irq_init(struct amd_mp2_dev *privdata) { if (privdata->mp2_ops->init_intr) return privdata->mp2_ops->init_intr(privdata); From 93ce5e0231d79189be4d9e5f9295807b18941419 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Tue, 12 Jul 2022 23:48:36 +0530 Subject: [PATCH 1213/1436] HID: amd_sfh: Implement SFH1.1 functionality Newer AMD SOCs use SFH1.1 memory access with new PCI-id. Hence add new sfh1_1 sub directory to implement SFH1.1 functionality by defining new PCI id, interface functions, descriptor functions and handlers which invokes sfh1.1. Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/Makefile | 3 + drivers/hid/amd-sfh-hid/amd_sfh_common.h | 3 + drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 12 + drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c | 300 ++++++++++++++++ drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c | 324 ++++++++++++++++++ drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.h | 26 ++ .../amd-sfh-hid/sfh1_1/amd_sfh_interface.c | 73 ++++ .../amd-sfh-hid/sfh1_1/amd_sfh_interface.h | 154 +++++++++ 8 files changed, 895 insertions(+) create mode 100644 drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c create mode 100644 drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c create mode 100644 drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.h create mode 100644 drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c create mode 100644 drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h diff --git a/drivers/hid/amd-sfh-hid/Makefile b/drivers/hid/amd-sfh-hid/Makefile index 35e704da5612..0222170ab7ad 100644 --- a/drivers/hid/amd-sfh-hid/Makefile +++ b/drivers/hid/amd-sfh-hid/Makefile @@ -9,5 +9,8 @@ amd_sfh-objs := amd_sfh_hid.o amd_sfh-objs += amd_sfh_client.o amd_sfh-objs += amd_sfh_pcie.o amd_sfh-objs += hid_descriptor/amd_sfh_hid_desc.o +amd_sfh-objs += sfh1_1/amd_sfh_init.o +amd_sfh-objs += sfh1_1/amd_sfh_interface.o +amd_sfh-objs += sfh1_1/amd_sfh_desc.o ccflags-y += -I $(srctree)/$(src)/ diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_common.h b/drivers/hid/amd-sfh-hid/amd_sfh_common.h index 1efb72ec116f..2643bb14fee2 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_common.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_common.h @@ -14,6 +14,7 @@ #include "amd_sfh_hid.h" #define PCI_DEVICE_ID_AMD_MP2 0x15E4 +#define PCI_DEVICE_ID_AMD_MP2_1_1 0x164A #define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4)) #define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4)) @@ -40,6 +41,8 @@ struct amd_mp2_dev { struct pci_dev *pdev; struct amdtp_cl_data *cl_data; void __iomem *mmio; + void __iomem *vsbase; + const struct amd_sfh1_1_ops *sfh1_1_ops; struct amd_mp2_ops *mp2_ops; struct amd_input_data in_data; /* mp2 active control status */ diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index 1425b57f3580..c9fb844e3360 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -19,6 +19,7 @@ #include #include "amd_sfh_pcie.h" +#include "sfh1_1/amd_sfh_init.h" #define DRIVER_NAME "pcie_mp2_amd" #define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver" @@ -318,6 +319,14 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i if (!privdata->cl_data) return -ENOMEM; + privdata->sfh1_1_ops = (const struct amd_sfh1_1_ops *)id->driver_data; + if (privdata->sfh1_1_ops) { + rc = privdata->sfh1_1_ops->init(privdata); + if (rc) + return rc; + goto init_done; + } + mp2_select_ops(privdata); rc = amd_sfh_irq_init(privdata); @@ -333,6 +342,7 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i return rc; } +init_done: amd_sfh_clear_intr(privdata); return devm_add_action_or_reset(&pdev->dev, privdata->mp2_ops->remove, privdata); @@ -361,6 +371,8 @@ static SIMPLE_DEV_PM_OPS(amd_mp2_pm_ops, amd_mp2_pci_suspend, static const struct pci_device_id amd_mp2_pci_tbl[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2_1_1), + .driver_data = (kernel_ulong_t)&sfh1_1_ops }, { } }; MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl); diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c new file mode 100644 index 000000000000..0609fea581c9 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD MP2 1.1 descriptor interfaces + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Basavaraj Natikar + */ + +#include + +#include "amd_sfh_interface.h" +#include "../hid_descriptor/amd_sfh_hid_desc.h" +#include "../hid_descriptor/amd_sfh_hid_report_desc.h" + +#define SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41 +#define SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x51 +#define HID_DEFAULT_REPORT_INTERVAL 0x50 +#define HID_DEFAULT_MIN_VALUE 0X7F +#define HID_DEFAULT_MAX_VALUE 0x80 +#define HID_DEFAULT_SENSITIVITY 0x7F +#define HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM 0x01 +/* state enums */ +#define HID_USAGE_SENSOR_STATE_READY_ENUM 0x02 +#define HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM 0x05 +#define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM 0x04 + +static int get_report_desc(int sensor_idx, u8 *rep_desc) +{ + switch (sensor_idx) { + case ACCEL_IDX: /* accelerometer */ + memset(rep_desc, 0, sizeof(accel3_report_descriptor)); + memcpy(rep_desc, accel3_report_descriptor, + sizeof(accel3_report_descriptor)); + break; + case GYRO_IDX: /* gyroscope */ + memset(rep_desc, 0, sizeof(gyro3_report_descriptor)); + memcpy(rep_desc, gyro3_report_descriptor, + sizeof(gyro3_report_descriptor)); + break; + case MAG_IDX: /* magnetometer */ + memset(rep_desc, 0, sizeof(comp3_report_descriptor)); + memcpy(rep_desc, comp3_report_descriptor, + sizeof(comp3_report_descriptor)); + break; + case ALS_IDX: /* ambient light sensor */ + memset(rep_desc, 0, sizeof(als_report_descriptor)); + memcpy(rep_desc, als_report_descriptor, + sizeof(als_report_descriptor)); + break; + case HPD_IDX: /* HPD sensor */ + memset(rep_desc, 0, sizeof(hpd_report_descriptor)); + memcpy(rep_desc, hpd_report_descriptor, + sizeof(hpd_report_descriptor)); + break; + } + return 0; +} + +static void get_common_features(struct common_feature_property *common, int report_id) +{ + common->report_id = report_id; + common->connection_type = HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM; + common->report_state = SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM; + common->power_state = SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM; + common->sensor_state = HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM; + common->report_interval = HID_DEFAULT_REPORT_INTERVAL; +} + +static u8 get_feature_rep(int sensor_idx, int report_id, u8 *feature_report) +{ + struct magno_feature_report magno_feature; + struct accel3_feature_report acc_feature; + struct gyro_feature_report gyro_feature; + struct hpd_feature_report hpd_feature; + struct als_feature_report als_feature; + u8 report_size = 0; + + if (!feature_report) + return report_size; + + switch (sensor_idx) { + case ACCEL_IDX: /* accelerometer */ + get_common_features(&acc_feature.common_property, report_id); + acc_feature.accel_change_sesnitivity = HID_DEFAULT_SENSITIVITY; + acc_feature.accel_sensitivity_min = HID_DEFAULT_MIN_VALUE; + acc_feature.accel_sensitivity_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &acc_feature, sizeof(acc_feature)); + report_size = sizeof(acc_feature); + break; + case GYRO_IDX: /* gyroscope */ + get_common_features(&gyro_feature.common_property, report_id); + gyro_feature.gyro_change_sesnitivity = HID_DEFAULT_SENSITIVITY; + gyro_feature.gyro_sensitivity_min = HID_DEFAULT_MIN_VALUE; + gyro_feature.gyro_sensitivity_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &gyro_feature, sizeof(gyro_feature)); + report_size = sizeof(gyro_feature); + break; + case MAG_IDX: /* magnetometer */ + get_common_features(&magno_feature.common_property, report_id); + magno_feature.magno_headingchange_sensitivity = HID_DEFAULT_SENSITIVITY; + magno_feature.heading_min = HID_DEFAULT_MIN_VALUE; + magno_feature.heading_max = HID_DEFAULT_MAX_VALUE; + magno_feature.flux_change_sensitivity = HID_DEFAULT_MIN_VALUE; + magno_feature.flux_min = HID_DEFAULT_MIN_VALUE; + magno_feature.flux_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &magno_feature, sizeof(magno_feature)); + report_size = sizeof(magno_feature); + break; + case ALS_IDX: /* ambient light sensor */ + get_common_features(&als_feature.common_property, report_id); + als_feature.als_change_sesnitivity = HID_DEFAULT_SENSITIVITY; + als_feature.als_sensitivity_min = HID_DEFAULT_MIN_VALUE; + als_feature.als_sensitivity_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &als_feature, sizeof(als_feature)); + report_size = sizeof(als_feature); + break; + case HPD_IDX: /* human presence detection sensor */ + get_common_features(&hpd_feature.common_property, report_id); + memcpy(feature_report, &hpd_feature, sizeof(hpd_feature)); + report_size = sizeof(hpd_feature); + break; + } + return report_size; +} + +static void get_common_inputs(struct common_input_property *common, int report_id) +{ + common->report_id = report_id; + common->sensor_state = HID_USAGE_SENSOR_STATE_READY_ENUM; + common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM; +} + +static int float_to_int(u32 float32) +{ + int fraction, shift, mantissa, sign, exp, zeropre; + + mantissa = float32 & GENMASK(22, 0); + sign = (float32 & BIT(31)) ? -1 : 1; + exp = (float32 & ~BIT(31)) >> 23; + + if (!exp && !mantissa) + return 0; + + exp -= 127; + if (exp < 0) { + exp = -exp; + zeropre = (((BIT(23) + mantissa) * 100) >> 23) >> exp; + return zeropre >= 50 ? sign : 0; + } + + shift = 23 - exp; + float32 = BIT(exp) + (mantissa >> shift); + fraction = mantissa & GENMASK(shift - 1, 0); + + return (((fraction * 100) >> shift) >= 50) ? sign * (float32 + 1) : sign * float32; +} + +static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id, + struct amd_input_data *in_data) +{ + struct amd_mp2_dev *mp2 = container_of(in_data, struct amd_mp2_dev, in_data); + u8 *input_report = in_data->input_report[current_index]; + struct magno_input_report magno_input; + struct accel3_input_report acc_input; + struct gyro_input_report gyro_input; + struct als_input_report als_input; + struct hpd_input_report hpd_input; + struct sfh_accel_data accel_data; + struct sfh_gyro_data gyro_data; + struct sfh_mag_data mag_data; + struct sfh_als_data als_data; + struct hpd_status hpdstatus; + void __iomem *sensoraddr; + u8 report_size = 0; + + if (!input_report) + return report_size; + + switch (sensor_idx) { + case ACCEL_IDX: /* accelerometer */ + sensoraddr = mp2->vsbase + (ACCEL_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) + + OFFSET_SENSOR_DATA_DEFAULT; + memcpy_fromio(&accel_data, sensoraddr, sizeof(struct sfh_accel_data)); + get_common_inputs(&acc_input.common_property, report_id); + acc_input.in_accel_x_value = float_to_int(accel_data.acceldata.x) / 100; + acc_input.in_accel_y_value = float_to_int(accel_data.acceldata.y) / 100; + acc_input.in_accel_z_value = float_to_int(accel_data.acceldata.z) / 100; + memcpy(input_report, &acc_input, sizeof(acc_input)); + report_size = sizeof(acc_input); + break; + case GYRO_IDX: /* gyroscope */ + sensoraddr = mp2->vsbase + (GYRO_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) + + OFFSET_SENSOR_DATA_DEFAULT; + memcpy_fromio(&gyro_data, sensoraddr, sizeof(struct sfh_gyro_data)); + get_common_inputs(&gyro_input.common_property, report_id); + gyro_input.in_angel_x_value = float_to_int(gyro_data.gyrodata.x) / 1000; + gyro_input.in_angel_y_value = float_to_int(gyro_data.gyrodata.y) / 1000; + gyro_input.in_angel_z_value = float_to_int(gyro_data.gyrodata.z) / 1000; + memcpy(input_report, &gyro_input, sizeof(gyro_input)); + report_size = sizeof(gyro_input); + break; + case MAG_IDX: /* magnetometer */ + sensoraddr = mp2->vsbase + (MAG_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) + + OFFSET_SENSOR_DATA_DEFAULT; + memcpy_fromio(&mag_data, sensoraddr, sizeof(struct sfh_mag_data)); + get_common_inputs(&magno_input.common_property, report_id); + magno_input.in_magno_x = float_to_int(mag_data.magdata.x) / 100; + magno_input.in_magno_y = float_to_int(mag_data.magdata.y) / 100; + magno_input.in_magno_z = float_to_int(mag_data.magdata.z) / 100; + magno_input.in_magno_accuracy = mag_data.accuracy / 100; + memcpy(input_report, &magno_input, sizeof(magno_input)); + report_size = sizeof(magno_input); + break; + case ALS_IDX: + sensoraddr = mp2->vsbase + (ALS_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) + + OFFSET_SENSOR_DATA_DEFAULT; + memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data)); + get_common_inputs(&als_input.common_property, report_id); + als_input.illuminance_value = als_data.lux; + report_size = sizeof(als_input); + memcpy(input_report, &als_input, sizeof(als_input)); + break; + case HPD_IDX: + get_common_inputs(&hpd_input.common_property, report_id); + hpdstatus.val = readl(mp2->mmio + AMD_C2P_MSG(4)); + hpd_input.human_presence = hpdstatus.shpd.presence; + report_size = sizeof(hpd_input); + memcpy(input_report, &hpd_input, sizeof(hpd_input)); + break; + } + return report_size; +} + +static u32 get_desc_size(int sensor_idx, int descriptor_name) +{ + switch (sensor_idx) { + case ACCEL_IDX: + switch (descriptor_name) { + case descr_size: + return sizeof(accel3_report_descriptor); + case input_size: + return sizeof(struct accel3_input_report); + case feature_size: + return sizeof(struct accel3_feature_report); + } + break; + case GYRO_IDX: + switch (descriptor_name) { + case descr_size: + return sizeof(gyro3_report_descriptor); + case input_size: + return sizeof(struct gyro_input_report); + case feature_size: + return sizeof(struct gyro_feature_report); + } + break; + case MAG_IDX: + switch (descriptor_name) { + case descr_size: + return sizeof(comp3_report_descriptor); + case input_size: + return sizeof(struct magno_input_report); + case feature_size: + return sizeof(struct magno_feature_report); + } + break; + case ALS_IDX: + switch (descriptor_name) { + case descr_size: + return sizeof(als_report_descriptor); + case input_size: + return sizeof(struct als_input_report); + case feature_size: + return sizeof(struct als_feature_report); + } + break; + case HPD_IDX: + switch (descriptor_name) { + case descr_size: + return sizeof(hpd_report_descriptor); + case input_size: + return sizeof(struct hpd_input_report); + case feature_size: + return sizeof(struct hpd_feature_report); + } + break; + } + + return 0; +} + +void amd_sfh1_1_set_desc_ops(struct amd_mp2_ops *mp2_ops) +{ + mp2_ops->get_rep_desc = get_report_desc; + mp2_ops->get_feat_rep = get_feature_rep; + mp2_ops->get_desc_sz = get_desc_size; + mp2_ops->get_in_rep = get_input_rep; +} diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c new file mode 100644 index 000000000000..70436f9fad2f --- /dev/null +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD MP2 1.1 communication driver + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Basavaraj Natikar + */ + +#include +#include + +#include "amd_sfh_init.h" +#include "amd_sfh_interface.h" +#include "../hid_descriptor/amd_sfh_hid_desc.h" + +static int amd_sfh_get_sensor_num(struct amd_mp2_dev *mp2, u8 *sensor_id) +{ + struct sfh_sensor_list *slist; + struct sfh_base_info binfo; + int num_of_sensors = 0; + int i; + + memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info)); + slist = &binfo.sbase.s_list; + + for (i = 0; i < MAX_IDX; i++) { + switch (i) { + case ACCEL_IDX: + case GYRO_IDX: + case MAG_IDX: + case ALS_IDX: + case HPD_IDX: + if (BIT(i) & slist->sl.sensors) + sensor_id[num_of_sensors++] = i; + break; + } + } + + return num_of_sensors; +} + +static u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id) +{ + if (mp2->mp2_ops->response) + return mp2->mp2_ops->response(mp2, sid, cmd_id); + + return 0; +} + +static const char *get_sensor_name(int idx) +{ + switch (idx) { + case ACCEL_IDX: + return "accelerometer"; + case GYRO_IDX: + return "gyroscope"; + case MAG_IDX: + return "magnetometer"; + case ALS_IDX: + return "ALS"; + case HPD_IDX: + return "HPD"; + default: + return "unknown sensor type"; + } +} + +static int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata) +{ + struct amdtp_cl_data *cl_data = privdata->cl_data; + int i, status; + + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_sts[i] == SENSOR_ENABLED) { + privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]); + status = amd_sfh_wait_for_response + (privdata, cl_data->sensor_idx[i], DISABLE_SENSOR); + if (status == 0) + cl_data->sensor_sts[i] = SENSOR_DISABLED; + dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x (%s) status 0x%x\n", + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), + cl_data->sensor_sts[i]); + } + } + + cancel_delayed_work_sync(&cl_data->work); + cancel_delayed_work_sync(&cl_data->work_buffer); + amdtp_hid_remove(cl_data); + + return 0; +} + +static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata) +{ + struct amd_input_data *in_data = &privdata->in_data; + struct amdtp_cl_data *cl_data = privdata->cl_data; + struct amd_mp2_ops *mp2_ops = privdata->mp2_ops; + struct amd_mp2_sensor_info info; + struct request_list *req_list; + u32 feature_report_size; + u32 input_report_size; + struct device *dev; + int rc, i, status; + u8 cl_idx; + + req_list = &cl_data->req_list; + dev = &privdata->pdev->dev; + amd_sfh1_1_set_desc_ops(mp2_ops); + + cl_data->num_hid_devices = amd_sfh_get_sensor_num(privdata, &cl_data->sensor_idx[0]); + + INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); + INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); + INIT_LIST_HEAD(&req_list->list); + cl_data->in_data = in_data; + + for (i = 0; i < cl_data->num_hid_devices; i++) { + cl_data->sensor_sts[i] = SENSOR_DISABLED; + cl_data->sensor_requested_cnt[i] = 0; + cl_data->cur_hid_dev = i; + cl_idx = cl_data->sensor_idx[i]; + + cl_data->report_descr_sz[i] = mp2_ops->get_desc_sz(cl_idx, descr_size); + if (!cl_data->report_descr_sz[i]) { + rc = -EINVAL; + goto cleanup; + } + feature_report_size = mp2_ops->get_desc_sz(cl_idx, feature_size); + if (!feature_report_size) { + rc = -EINVAL; + goto cleanup; + } + input_report_size = mp2_ops->get_desc_sz(cl_idx, input_size); + if (!input_report_size) { + rc = -EINVAL; + goto cleanup; + } + cl_data->feature_report[i] = devm_kzalloc(dev, feature_report_size, GFP_KERNEL); + if (!cl_data->feature_report[i]) { + rc = -ENOMEM; + goto cleanup; + } + in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL); + if (!in_data->input_report[i]) { + rc = -ENOMEM; + goto cleanup; + } + + info.sensor_idx = cl_idx; + + cl_data->report_descr[i] = + devm_kzalloc(dev, cl_data->report_descr_sz[i], GFP_KERNEL); + if (!cl_data->report_descr[i]) { + rc = -ENOMEM; + goto cleanup; + } + rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]); + if (rc) + return rc; + + writel(0, privdata->mmio + AMD_P2C_MSG(0)); + mp2_ops->start(privdata, info); + status = amd_sfh_wait_for_response + (privdata, cl_data->sensor_idx[i], ENABLE_SENSOR); + + status = (status == 0) ? SENSOR_ENABLED : SENSOR_DISABLED; + + if (status == SENSOR_ENABLED) { + cl_data->sensor_sts[i] = SENSOR_ENABLED; + rc = amdtp_hid_probe(i, cl_data); + if (rc) { + mp2_ops->stop(privdata, cl_data->sensor_idx[i]); + status = amd_sfh_wait_for_response + (privdata, cl_data->sensor_idx[i], DISABLE_SENSOR); + if (status == 0) + status = SENSOR_DISABLED; + if (status != SENSOR_ENABLED) + cl_data->sensor_sts[i] = SENSOR_DISABLED; + dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n", + cl_data->sensor_idx[i], + get_sensor_name(cl_data->sensor_idx[i]), + cl_data->sensor_sts[i]); + goto cleanup; + } + } + dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n", + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), + cl_data->sensor_sts[i]); + } + + schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); + return 0; + +cleanup: + amd_sfh_hid_client_deinit(privdata); + for (i = 0; i < cl_data->num_hid_devices; i++) { + devm_kfree(dev, cl_data->feature_report[i]); + devm_kfree(dev, in_data->input_report[i]); + devm_kfree(dev, cl_data->report_descr[i]); + } + return rc; +} + +static void amd_sfh_resume(struct amd_mp2_dev *mp2) +{ + struct amdtp_cl_data *cl_data = mp2->cl_data; + struct amd_mp2_sensor_info info; + int i, status; + + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { + info.sensor_idx = cl_data->sensor_idx[i]; + mp2->mp2_ops->start(mp2, info); + status = amd_sfh_wait_for_response + (mp2, cl_data->sensor_idx[i], ENABLE_SENSOR); + if (status == 0) + status = SENSOR_ENABLED; + if (status == SENSOR_ENABLED) + cl_data->sensor_sts[i] = SENSOR_ENABLED; + dev_dbg(&mp2->pdev->dev, "resume sid 0x%x (%s) status 0x%x\n", + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), + cl_data->sensor_sts[i]); + } + } + + schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); + amd_sfh_clear_intr(mp2); +} + +static void amd_sfh_suspend(struct amd_mp2_dev *mp2) +{ + struct amdtp_cl_data *cl_data = mp2->cl_data; + int i, status; + + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_idx[i] != HPD_IDX && + cl_data->sensor_sts[i] == SENSOR_ENABLED) { + mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]); + status = amd_sfh_wait_for_response + (mp2, cl_data->sensor_idx[i], DISABLE_SENSOR); + if (status == 0) + status = SENSOR_DISABLED; + if (status != SENSOR_ENABLED) + cl_data->sensor_sts[i] = SENSOR_DISABLED; + dev_dbg(&mp2->pdev->dev, "suspend sid 0x%x (%s) status 0x%x\n", + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), + cl_data->sensor_sts[i]); + } + } + + cancel_delayed_work_sync(&cl_data->work_buffer); + amd_sfh_clear_intr(mp2); +} + +static void amd_mp2_pci_remove(void *privdata) +{ + struct amd_mp2_dev *mp2 = privdata; + + amd_sfh_hid_client_deinit(privdata); + mp2->mp2_ops->stop_all(mp2); + pci_intx(mp2->pdev, false); + amd_sfh_clear_intr(mp2); +} + +static void amd_sfh_set_ops(struct amd_mp2_dev *mp2) +{ + struct amd_mp2_ops *mp2_ops; + + sfh_interface_init(mp2); + mp2_ops = mp2->mp2_ops; + mp2_ops->clear_intr = amd_sfh_clear_intr_v2, + mp2_ops->init_intr = amd_sfh_irq_init_v2, + mp2_ops->suspend = amd_sfh_suspend; + mp2_ops->resume = amd_sfh_resume; + mp2_ops->remove = amd_mp2_pci_remove; +} + +int amd_sfh1_1_init(struct amd_mp2_dev *mp2) +{ + u32 phy_base = readl(mp2->mmio + AMD_C2P_MSG(22)); + struct device *dev = &mp2->pdev->dev; + struct sfh_base_info binfo; + int rc; + + phy_base <<= 21; + if (!devm_request_mem_region(dev, phy_base, 128 * 1024, "amd_sfh")) { + dev_err(dev, "can't reserve mmio registers\n"); + return -ENOMEM; + } + + mp2->vsbase = devm_ioremap(dev, phy_base, 128 * 1024); + if (!mp2->vsbase) { + dev_err(dev, "failed to remap vsbase\n"); + return -ENOMEM; + } + + /* Before accessing give time for SFH firmware for processing configuration */ + msleep(5000); + + memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info)); + if (binfo.sbase.fw_info.fw_ver == 0 || binfo.sbase.s_list.sl.sensors == 0) { + dev_err(dev, "failed to get sensors\n"); + return -EOPNOTSUPP; + } + dev_dbg(dev, "firmware version 0x%x\n", binfo.sbase.fw_info.fw_ver); + + amd_sfh_set_ops(mp2); + + rc = amd_sfh_irq_init(mp2); + if (rc) { + dev_err(dev, "amd_sfh_irq_init failed\n"); + return rc; + } + + rc = amd_sfh1_1_hid_client_init(mp2); + if (rc) { + dev_err(dev, "amd_sfh1_1_hid_client_init failed\n"); + return rc; + } + + return rc; +} diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.h b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.h new file mode 100644 index 000000000000..21c44990bbeb --- /dev/null +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * AMD MP2 1.1 initialization structures + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Basavaraj Natikar + */ + +#ifndef AMD_SFH_INIT_H +#define AMD_SFH_INIT_H + +#include "../amd_sfh_common.h" + +struct amd_sfh1_1_ops { + int (*init)(struct amd_mp2_dev *mp2); +}; + +int amd_sfh1_1_init(struct amd_mp2_dev *mp2); + +static const struct amd_sfh1_1_ops __maybe_unused sfh1_1_ops = { + .init = amd_sfh1_1_init, +}; + +#endif diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c new file mode 100644 index 000000000000..14a1578055b6 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD MP2 1.1 communication interfaces + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Basavaraj Natikar + */ +#include +#include "amd_sfh_interface.h" + +static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id) +{ + struct sfh_cmd_response cmd_resp; + + /* Get response with status within a max of 1600 ms timeout */ + if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp, + (cmd_resp.response.response == 0 && + cmd_resp.response.cmd_id == cmd_id && (sid == 0xff || + cmd_resp.response.sensor_id == sid)), 500, 1600000)) + return cmd_resp.response.response; + + return -1; +} + +static void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) +{ + struct sfh_cmd_base cmd_base; + + cmd_base.ul = 0; + cmd_base.cmd.cmd_id = ENABLE_SENSOR; + cmd_base.cmd.intr_disable = 0; + cmd_base.cmd.sensor_id = info.sensor_idx; + + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0)); +} + +static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx) +{ + struct sfh_cmd_base cmd_base; + + cmd_base.ul = 0; + cmd_base.cmd.cmd_id = DISABLE_SENSOR; + cmd_base.cmd.intr_disable = 0; + cmd_base.cmd.sensor_id = sensor_idx; + + writeq(0x0, privdata->mmio + AMD_C2P_MSG(1)); + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0)); +} + +static void amd_stop_all_sensor(struct amd_mp2_dev *privdata) +{ + struct sfh_cmd_base cmd_base; + + cmd_base.ul = 0; + cmd_base.cmd.cmd_id = STOP_ALL_SENSORS; + cmd_base.cmd.intr_disable = 0; + + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0)); +} + +static struct amd_mp2_ops amd_sfh_ops = { + .start = amd_start_sensor, + .stop = amd_stop_sensor, + .stop_all = amd_stop_all_sensor, + .response = amd_sfh_wait_response, +}; + +void sfh_interface_init(struct amd_mp2_dev *mp2) +{ + mp2->mp2_ops = &amd_sfh_ops; +} diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h new file mode 100644 index 000000000000..ae47a369dc05 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h @@ -0,0 +1,154 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * AMD MP2 1.1 communication interfaces + * + * Copyright (c) 2022, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Author: Basavaraj Natikar + */ + +#ifndef AMD_SFH_INTERFACE_H +#define AMD_SFH_INTERFACE_H + +#include "../amd_sfh_common.h" + +#define SENSOR_DATA_MEM_SIZE_DEFAULT 256 +#define TOTAL_STATIC_MEM_DEFAULT 1024 +#define OFFSET_SFH_INFO_BASE_DEFAULT 0 +#define OFFSET_SENSOR_DATA_DEFAULT (OFFSET_SFH_INFO_BASE_DEFAULT + \ + TOTAL_STATIC_MEM_DEFAULT) +enum sensor_index { + ACCEL_IDX, + GYRO_IDX, + MAG_IDX, + ALS_IDX = 4, + HPD_IDX = 5, + MAX_IDX = 15, +}; + +struct sfh_cmd_base { + union { + u32 ul; + struct { + u32 sensor_id : 4; + u32 cmd_id : 4; + u32 sub_cmd_id : 6; + u32 length : 12; + u32 rsvd : 5; + u32 intr_disable : 1; + } cmd; + }; +}; + +struct sfh_cmd_response { + union { + u32 resp; + struct { + u32 response : 8; + u32 sensor_id : 4; + u32 cmd_id : 4; + u32 sub_cmd : 6; + u32 rsvd2 : 10; + } response; + }; +}; + +struct sfh_platform_info { + union { + u32 pi; + struct { + u32 cust_id : 16; + u32 plat_id : 6; + u32 interface_id : 4; + u32 rsvd : 6; + } pinfo; + }; +}; + +struct sfh_firmware_info { + union { + u32 fw_ver; + struct { + u32 minor_rev : 8; + u32 major_rev : 8; + u32 minor_ver : 8; + u32 major_ver : 8; + } fver; + }; +}; + +struct sfh_sensor_list { + union { + u32 slist; + struct { + u32 sensors : 16; + u32 rsvd : 16; + } sl; + }; +}; + +struct sfh_base_info { + union { + u32 sfh_base[24]; + struct { + struct sfh_platform_info plat_info; + struct sfh_firmware_info fw_info; + struct sfh_sensor_list s_list; + } sbase; + }; +}; + +struct sfh_common_data { + u64 timestamp; + u32 intr_cnt; + u32 featvalid : 16; + u32 rsvd : 13; + u32 sensor_state : 3; +}; + +struct sfh_float32 { + u32 x; + u32 y; + u32 z; +}; + +struct sfh_accel_data { + struct sfh_common_data commondata; + struct sfh_float32 acceldata; + u32 accelstatus; +}; + +struct sfh_gyro_data { + struct sfh_common_data commondata; + struct sfh_float32 gyrodata; + u32 result; +}; + +struct sfh_mag_data { + struct sfh_common_data commondata; + struct sfh_float32 magdata; + u32 accuracy; +}; + +struct sfh_als_data { + struct sfh_common_data commondata; + u16 lux; +}; + +struct hpd_status { + union { + struct { + u32 distance : 16; + u32 probablity : 8; + u32 presence : 2; + u32 rsvd : 5; + u32 state : 1; + } shpd; + u32 val; + }; +}; + +void sfh_interface_init(struct amd_mp2_dev *mp2); +void amd_sfh1_1_set_desc_ops(struct amd_mp2_ops *mp2_ops); +#endif From 12ffcd757860ed541f0dbb86bbd0ddac642e2e43 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 15 Jul 2022 13:43:12 +0800 Subject: [PATCH 1214/1436] HID: lg-g15: Fix comment typo The double `with' is duplicated in line 769, remove one. Signed-off-by: Jason Wang Reviewed-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/hid-lg-g15.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-lg-g15.c b/drivers/hid/hid-lg-g15.c index b2a08233f8d5..c8f82bcbf1ab 100644 --- a/drivers/hid/hid-lg-g15.c +++ b/drivers/hid/hid-lg-g15.c @@ -766,7 +766,7 @@ static int lg_g15_probe(struct hid_device *hdev, const struct hid_device_id *id) /* * Some models have multiple interfaces, we want the interface with - * with the f000.0000 application input report. + * the f000.0000 application input report. */ rep_enum = &hdev->report_enum[HID_INPUT_REPORT]; list_for_each_entry(rep, &rep_enum->report_list, list) { From ab5f3404b7762b88403fbddbdda6b1b464bd6cbc Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 12 Jul 2022 15:17:05 -0700 Subject: [PATCH 1215/1436] HID: nintendo: Add missing array termination joycon_dpad_inputs_jc[] is unterminated. This may result in odd warnings such as input: input_set_capability: invalid code 3077588140 for type 1 or in kernel crashes in nintendo_hid_probe(). Terminate the array to fix the problem. Fixes: 2af16c1f846bd ("HID: nintendo: add nintendo switch controller driver") Cc: Daniel J. Ogorchock Signed-off-by: Guenter Roeck Reviewed-by: Dmitry Torokhov Cc: stable@vger.kernel.org Signed-off-by: Jiri Kosina --- drivers/hid/hid-nintendo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index dcd0f16de7b5..55ede76ab3e4 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -1585,6 +1585,7 @@ static const unsigned int joycon_button_inputs_r[] = { /* We report joy-con d-pad inputs as buttons and pro controller as a hat. */ static const unsigned int joycon_dpad_inputs_jc[] = { BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT, + 0 /* 0 signals end of array */ }; static int joycon_input_create(struct joycon_ctlr *ctlr) From 94b179052f95c294d83e9c9c34f7833cf3cd4305 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Fri, 15 Jul 2022 16:05:19 -0700 Subject: [PATCH 1216/1436] HID: wacom: Force pen out of prox if no events have been received in a while Prox-out events may not be reliably sent by some AES firmware. This can cause problems for users, particularly due to arbitration logic disabling touch input while the pen is in prox. This commit adds a timer which is reset every time a new prox event is received. When the timer expires we check to see if the pen is still in prox and force it out if necessary. This is patterend off of the same solution used by 'hid-letsketch' driver which has a similar problem. Link: https://github.com/linuxwacom/input-wacom/issues/310 Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom.h | 3 +++ drivers/hid/wacom_sys.c | 2 ++ drivers/hid/wacom_wac.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index 203d27d198b8..3f8b24a57014 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -91,6 +91,7 @@ #include #include #include +#include #include /* @@ -167,6 +168,7 @@ struct wacom { struct delayed_work init_work; struct wacom_remote *remote; struct work_struct mode_change_work; + struct timer_list idleprox_timer; bool generic_has_leds; struct wacom_leds { struct wacom_group_leds *groups; @@ -239,4 +241,5 @@ struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group, struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur); int wacom_equivalent_usage(int usage); int wacom_initialize_leds(struct wacom *wacom); +void wacom_idleprox_timeout(struct timer_list *list); #endif diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 98384b911288..194a2e327591 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -2781,6 +2781,7 @@ static int wacom_probe(struct hid_device *hdev, INIT_WORK(&wacom->battery_work, wacom_battery_work); INIT_WORK(&wacom->remote_work, wacom_remote_work); INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work); + timer_setup(&wacom->idleprox_timer, &wacom_idleprox_timeout, TIMER_DEFERRABLE); /* ask for the report descriptor to be loaded by HID */ error = hid_parse(hdev); @@ -2821,6 +2822,7 @@ static void wacom_remove(struct hid_device *hdev) cancel_work_sync(&wacom->battery_work); cancel_work_sync(&wacom->remote_work); cancel_work_sync(&wacom->mode_change_work); + del_timer_sync(&wacom->idleprox_timer); if (hdev->bus == BUS_BLUETOOTH) device_remove_file(&hdev->dev, &dev_attr_speed); diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index f8cc4bb3e3a7..d049239256a2 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -11,6 +11,7 @@ #include "wacom_wac.h" #include "wacom.h" #include +#include /* resolution for penabled devices */ #define WACOM_PL_RES 20 @@ -41,6 +42,43 @@ static int wacom_numbered_button_to_key(int n); static void wacom_update_led(struct wacom *wacom, int button_count, int mask, int group); + +static void wacom_force_proxout(struct wacom_wac *wacom_wac) +{ + struct input_dev *input = wacom_wac->pen_input; + + wacom_wac->shared->stylus_in_proximity = 0; + + input_report_key(input, BTN_TOUCH, 0); + input_report_key(input, BTN_STYLUS, 0); + input_report_key(input, BTN_STYLUS2, 0); + input_report_key(input, BTN_STYLUS3, 0); + input_report_key(input, wacom_wac->tool[0], 0); + if (wacom_wac->serial[0]) { + input_report_abs(input, ABS_MISC, 0); + } + input_report_abs(input, ABS_PRESSURE, 0); + + wacom_wac->tool[0] = 0; + wacom_wac->id[0] = 0; + wacom_wac->serial[0] = 0; + + input_sync(input); +} + +void wacom_idleprox_timeout(struct timer_list *list) +{ + struct wacom *wacom = from_timer(wacom, list, idleprox_timer); + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + + if (!wacom_wac->hid_data.sense_state) { + return; + } + + hid_warn(wacom->hdev, "%s: tool appears to be hung in-prox. forcing it out.\n", __func__); + wacom_force_proxout(wacom_wac); +} + /* * Percent of battery capacity for Graphire. * 8th value means AC online and show 100% capacity. @@ -2329,6 +2367,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field value = field->logical_maximum - value; break; case HID_DG_INRANGE: + mod_timer(&wacom->idleprox_timer, jiffies + msecs_to_jiffies(100)); wacom_wac->hid_data.inrange_state = value; if (!(features->quirks & WACOM_QUIRK_SENSE)) wacom_wac->hid_data.sense_state = value; From 3eb229f203c2bc42efbfbafba7f83c8deeca80c9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Jun 2022 09:52:46 +0200 Subject: [PATCH 1217/1436] dt-bindings: leds: lp50xx: correct reg/unit addresses in example The multi-led node defined address/size cells, so it is intended to have children with unit addresses. The second multi-led's reg property defined three LED indexes within one reg item, which is not correct - these are three separate items. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220607075247.58048-1-krzysztof.kozlowski@linaro.org --- .../devicetree/bindings/leds/leds-lp50xx.yaml | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml b/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml index f12fe5b53f30..29ce0cb7d449 100644 --- a/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml +++ b/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml @@ -99,35 +99,41 @@ examples: color = ; function = LED_FUNCTION_CHARGING; - led-0 { + led@0 { + reg = <0x0>; color = ; }; - led-1 { + led@1 { + reg = <0x1>; color = ; }; - led-2 { + led@2 { + reg = <0x2>; color = ; }; }; - multi-led@2 { + multi-led@3 { #address-cells = <1>; - #size-cells = <2>; - reg = <0x2 0x3 0x5>; + #size-cells = <0>; + reg = <0x3>, <0x4>, <0x5>; color = ; function = LED_FUNCTION_STANDBY; - led-6 { + led@3 { + reg = <0x3>; color = ; }; - led-7 { + led@4 { + reg = <0x4>; color = ; }; - led-8 { + led@5 { + reg = <0x5>; color = ; }; }; From 5b967e8eca4d6e6a150aa1d9591a22324887b3f9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 7 Jun 2022 09:52:47 +0200 Subject: [PATCH 1218/1436] dt-bindings: leds: fix indentation in examples The examples were mixing 4-space with 2- and 3-space indentations, so correct them to use 4-space one. No functional change. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220607075247.58048-2-krzysztof.kozlowski@linaro.org --- .../devicetree/bindings/leds/leds-lp50xx.yaml | 102 +++++----- .../devicetree/bindings/leds/leds-lp55xx.yaml | 192 +++++++++--------- .../bindings/leds/leds-pwm-multicolor.yaml | 30 +-- 3 files changed, 162 insertions(+), 162 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml b/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml index 29ce0cb7d449..d11898567313 100644 --- a/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml +++ b/Documentation/devicetree/bindings/leds/leds-lp50xx.yaml @@ -78,66 +78,66 @@ additionalProperties: false examples: - | - #include - #include + #include + #include - i2c { - #address-cells = <1>; - #size-cells = <0>; + i2c { + #address-cells = <1>; + #size-cells = <0>; - led-controller@14 { - compatible = "ti,lp5009"; - reg = <0x14>; - #address-cells = <1>; - #size-cells = <0>; - enable-gpios = <&gpio1 16>; - - multi-led@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0x1>; - color = ; - function = LED_FUNCTION_CHARGING; - - led@0 { - reg = <0x0>; - color = ; - }; - - led@1 { - reg = <0x1>; - color = ; - }; - - led@2 { - reg = <0x2>; - color = ; - }; - }; - - multi-led@3 { + led-controller@14 { + compatible = "ti,lp5009"; + reg = <0x14>; #address-cells = <1>; #size-cells = <0>; - reg = <0x3>, <0x4>, <0x5>; - color = ; - function = LED_FUNCTION_STANDBY; + enable-gpios = <&gpio1 16>; - led@3 { - reg = <0x3>; - color = ; + multi-led@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x1>; + color = ; + function = LED_FUNCTION_CHARGING; + + led@0 { + reg = <0x0>; + color = ; + }; + + led@1 { + reg = <0x1>; + color = ; + }; + + led@2 { + reg = <0x2>; + color = ; + }; }; - led@4 { - reg = <0x4>; - color = ; - }; + multi-led@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x3>, <0x4>, <0x5>; + color = ; + function = LED_FUNCTION_STANDBY; - led@5 { - reg = <0x5>; - color = ; + led@3 { + reg = <0x3>; + color = ; + }; + + led@4 { + reg = <0x4>; + color = ; + }; + + led@5 { + reg = <0x5>; + color = ; + }; }; - }; - }; + }; }; ... diff --git a/Documentation/devicetree/bindings/leds/leds-lp55xx.yaml b/Documentation/devicetree/bindings/leds/leds-lp55xx.yaml index f552cd143d5b..7ec676e53851 100644 --- a/Documentation/devicetree/bindings/leds/leds-lp55xx.yaml +++ b/Documentation/devicetree/bindings/leds/leds-lp55xx.yaml @@ -108,119 +108,119 @@ additionalProperties: false examples: - | - #include + #include - i2c { - #address-cells = <1>; - #size-cells = <0>; + i2c { + #address-cells = <1>; + #size-cells = <0>; - led-controller@32 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "ti,lp8501"; - reg = <0x32>; - clock-mode = /bits/ 8 <2>; - pwr-sel = /bits/ 8 <3>; /* D1~9 connected to VOUT */ + led-controller@32 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,lp8501"; + reg = <0x32>; + clock-mode = /bits/ 8 <2>; + pwr-sel = /bits/ 8 <3>; /* D1~9 connected to VOUT */ - led@0 { - reg = <0>; - chan-name = "d1"; - led-cur = /bits/ 8 <0x14>; - max-cur = /bits/ 8 <0x20>; - }; + led@0 { + reg = <0>; + chan-name = "d1"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; - led@1 { - reg = <1>; - chan-name = "d2"; - led-cur = /bits/ 8 <0x14>; - max-cur = /bits/ 8 <0x20>; - }; + led@1 { + reg = <1>; + chan-name = "d2"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; - led@2 { - reg = <2>; - chan-name = "d3"; - led-cur = /bits/ 8 <0x14>; - max-cur = /bits/ 8 <0x20>; - }; + led@2 { + reg = <2>; + chan-name = "d3"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; - led@3 { - reg = <3>; - chan-name = "d4"; - led-cur = /bits/ 8 <0x14>; - max-cur = /bits/ 8 <0x20>; - }; + led@3 { + reg = <3>; + chan-name = "d4"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; - led@4 { - reg = <4>; - chan-name = "d5"; - led-cur = /bits/ 8 <0x14>; - max-cur = /bits/ 8 <0x20>; - }; + led@4 { + reg = <4>; + chan-name = "d5"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; - led@5 { - reg = <5>; - chan-name = "d6"; - led-cur = /bits/ 8 <0x14>; - max-cur = /bits/ 8 <0x20>; - }; + led@5 { + reg = <5>; + chan-name = "d6"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; - led@6 { - reg = <6>; - chan-name = "d7"; - led-cur = /bits/ 8 <0x14>; - max-cur = /bits/ 8 <0x20>; - }; + led@6 { + reg = <6>; + chan-name = "d7"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; - led@7 { - reg = <7>; - chan-name = "d8"; - led-cur = /bits/ 8 <0x14>; - max-cur = /bits/ 8 <0x20>; - }; + led@7 { + reg = <7>; + chan-name = "d8"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; - led@8 { - reg = <8>; - chan-name = "d9"; - led-cur = /bits/ 8 <0x14>; - max-cur = /bits/ 8 <0x20>; - }; + led@8 { + reg = <8>; + chan-name = "d9"; + led-cur = /bits/ 8 <0x14>; + max-cur = /bits/ 8 <0x20>; + }; }; - led-controller@33 { - #address-cells = <1>; - #size-cells = <0>; - compatible = "national,lp5523"; - reg = <0x33>; - clock-mode = /bits/ 8 <0>; + led-controller@33 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "national,lp5523"; + reg = <0x33>; + clock-mode = /bits/ 8 <0>; - multi-led@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <0x2>; - color = ; - function = LED_FUNCTION_STANDBY; - linux,default-trigger = "heartbeat"; + multi-led@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0x2>; + color = ; + function = LED_FUNCTION_STANDBY; + linux,default-trigger = "heartbeat"; - led@0 { - led-cur = /bits/ 8 <50>; - max-cur = /bits/ 8 <100>; - reg = <0x0>; - color = ; - }; + led@0 { + led-cur = /bits/ 8 <50>; + max-cur = /bits/ 8 <100>; + reg = <0x0>; + color = ; + }; - led@1 { - led-cur = /bits/ 8 <50>; - max-cur = /bits/ 8 <100>; - reg = <0x1>; - color = ; - }; + led@1 { + led-cur = /bits/ 8 <50>; + max-cur = /bits/ 8 <100>; + reg = <0x1>; + color = ; + }; - led@6 { - led-cur = /bits/ 8 <50>; - max-cur = /bits/ 8 <100>; - reg = <0x6>; - color = ; - }; + led@6 { + led-cur = /bits/ 8 <50>; + max-cur = /bits/ 8 <100>; + reg = <0x6>; + color = ; + }; }; }; }; diff --git a/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml b/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml index 6625a528f727..fdaf04e03a8d 100644 --- a/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml +++ b/Documentation/devicetree/bindings/leds/leds-pwm-multicolor.yaml @@ -55,24 +55,24 @@ examples: compatible = "pwm-leds-multicolor"; multi-led { - color = ; - function = LED_FUNCTION_INDICATOR; - max-brightness = <65535>; + color = ; + function = LED_FUNCTION_INDICATOR; + max-brightness = <65535>; - led-red { - pwms = <&pwm1 0 1000000>; - color = ; - }; + led-red { + pwms = <&pwm1 0 1000000>; + color = ; + }; - led-green { - pwms = <&pwm2 0 1000000>; - color = ; - }; + led-green { + pwms = <&pwm2 0 1000000>; + color = ; + }; - led-blue { - pwms = <&pwm3 0 1000000>; - color = ; - }; + led-blue { + pwms = <&pwm3 0 1000000>; + color = ; + }; }; }; From e43232c0045e6a1a267468caddafb709cc1bbfd2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 21 Jul 2022 18:06:11 +0200 Subject: [PATCH 1219/1436] dt-bindings: leds: skyworks,aat1290: convert to dtschema Convert the Skyworks Solutions, Inc. AAT1290 Current Regulator bindings to DT Schema. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Rob Herring Acked-by: Jacek Anaszewski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220721160611.250274-1-krzysztof.kozlowski@linaro.org --- .../devicetree/bindings/leds/leds-aat1290.txt | 77 --------------- .../bindings/leds/skyworks,aat1290.yaml | 95 +++++++++++++++++++ 2 files changed, 95 insertions(+), 77 deletions(-) delete mode 100644 Documentation/devicetree/bindings/leds/leds-aat1290.txt create mode 100644 Documentation/devicetree/bindings/leds/skyworks,aat1290.yaml diff --git a/Documentation/devicetree/bindings/leds/leds-aat1290.txt b/Documentation/devicetree/bindings/leds/leds-aat1290.txt deleted file mode 100644 index 62ed17ec075b..000000000000 --- a/Documentation/devicetree/bindings/leds/leds-aat1290.txt +++ /dev/null @@ -1,77 +0,0 @@ -* Skyworks Solutions, Inc. AAT1290 Current Regulator for Flash LEDs - -The device is controlled through two pins: FL_EN and EN_SET. The pins when, -asserted high, enable flash strobe and movie mode (max 1/2 of flash current) -respectively. In order to add a capability of selecting the strobe signal source -(e.g. CPU or camera sensor) there is an additional switch required, independent -of the flash chip. The switch is controlled with pin control. - -Required properties: - -- compatible : Must be "skyworks,aat1290". -- flen-gpios : Must be device tree identifier of the flash device FL_EN pin. -- enset-gpios : Must be device tree identifier of the flash device EN_SET pin. - -Optional properties: -- pinctrl-names : Must contain entries: "default", "host", "isp". Entries - "default" and "host" must refer to the same pin configuration - node, which sets the host as a strobe signal provider. Entry - "isp" must refer to the pin configuration node, which sets the - ISP as a strobe signal provider. - -A discrete LED element connected to the device must be represented by a child -node - see Documentation/devicetree/bindings/leds/common.txt. - -Required properties of the LED child node: -- led-max-microamp : see Documentation/devicetree/bindings/leds/common.txt -- flash-max-microamp : see Documentation/devicetree/bindings/leds/common.txt - Maximum flash LED supply current can be calculated using - following formula: I = 1A * 162kohm / Rset. -- flash-max-timeout-us : see Documentation/devicetree/bindings/leds/common.txt - Maximum flash timeout can be calculated using following - formula: T = 8.82 * 10^9 * Ct. - -Optional properties of the LED child node: -- function : see Documentation/devicetree/bindings/leds/common.txt -- color : see Documentation/devicetree/bindings/leds/common.txt -- label : see Documentation/devicetree/bindings/leds/common.txt (deprecated) - -Example (by Ct = 220nF, Rset = 160kohm and exynos4412-trats2 board with -a switch that allows for routing strobe signal either from the host or from -the camera sensor): - -#include "exynos4412.dtsi" -#include - -led-controller { - compatible = "skyworks,aat1290"; - flen-gpios = <&gpj1 1 GPIO_ACTIVE_HIGH>; - enset-gpios = <&gpj1 2 GPIO_ACTIVE_HIGH>; - - pinctrl-names = "default", "host", "isp"; - pinctrl-0 = <&camera_flash_host>; - pinctrl-1 = <&camera_flash_host>; - pinctrl-2 = <&camera_flash_isp>; - - camera_flash: led { - function = LED_FUNCTION_FLASH; - color = ; - led-max-microamp = <520833>; - flash-max-microamp = <1012500>; - flash-max-timeout-us = <1940000>; - }; -}; - -&pinctrl_0 { - camera_flash_host: camera-flash-host { - samsung,pins = "gpj1-0"; - samsung,pin-function = <1>; - samsung,pin-val = <0>; - }; - - camera_flash_isp: camera-flash-isp { - samsung,pins = "gpj1-0"; - samsung,pin-function = <1>; - samsung,pin-val = <1>; - }; -}; diff --git a/Documentation/devicetree/bindings/leds/skyworks,aat1290.yaml b/Documentation/devicetree/bindings/leds/skyworks,aat1290.yaml new file mode 100644 index 000000000000..a6aaa92dbccd --- /dev/null +++ b/Documentation/devicetree/bindings/leds/skyworks,aat1290.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/skyworks,aat1290.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Skyworks Solutions, Inc. AAT1290 Current Regulator for Flash LEDs + +maintainers: + - Jacek Anaszewski + - Krzysztof Kozlowski + +description: | + The device is controlled through two pins:: FL_EN and EN_SET. The pins when, + asserted high, enable flash strobe and movie mode (max 1/2 of flash current) + respectively. In order to add a capability of selecting the strobe signal + source (e.g. CPU or camera sensor) there is an additional switch required, + independent of the flash chip. The switch is controlled with pin control. + +properties: + compatible: + const: skyworks,aat1290 + + enset-gpios: + maxItems: 1 + description: EN_SET pin + + flen-gpios: + maxItems: 1 + description: FL_EN pin + + led: + $ref: common.yaml# + unevaluatedProperties: false + + properties: + led-max-microamp: true + + flash-max-microamp: + description: | + Maximum flash LED supply current can be calculated using following + formula:: I = 1A * 162 kOhm / Rset. + + flash-max-timeout-us: + description: | + Maximum flash timeout can be calculated using following formula:: + T = 8.82 * 10^9 * Ct. + + required: + - flash-max-microamp + - flash-max-timeout-us + - led-max-microamp + + pinctrl-names: + items: + - const: default + - const: host + - const: isp + + pinctrl-0: true + pinctrl-1: true + pinctrl-2: true + +required: + - compatible + - enset-gpios + - flen-gpios + - led + +additionalProperties: false + +examples: + - | + #include + #include + + // Ct = 220 nF, Rset = 160 kOhm + led-controller { + compatible = "skyworks,aat1290"; + flen-gpios = <&gpj1 1 GPIO_ACTIVE_HIGH>; + enset-gpios = <&gpj1 2 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default", "host", "isp"; + pinctrl-0 = <&camera_flash_host>; + pinctrl-1 = <&camera_flash_host>; + pinctrl-2 = <&camera_flash_isp>; + + led { + function = LED_FUNCTION_FLASH; + color = ; + led-max-microamp = <520833>; + flash-max-microamp = <1012500>; + flash-max-timeout-us = <1940000>; + }; + }; From 3ed4b599ccede7f943d5d993ff50bfd8e8f8bd5f Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 19 Jul 2022 23:18:47 +0200 Subject: [PATCH 1220/1436] dt-bindings: leds: qcom-lpg: Add compatible for PM660L LPG block Document the availability of an LPG configuration for the PM660L PMIC in the Qualcomm Light Pulse Generator driver. Signed-off-by: Marijn Suijten Acked-by: Rob Herring Reviewed-by: Bhupesh Sharma Reviewed-by: Bjorn Andersson Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220719211848.1653920-1-marijn.suijten@somainline.org --- Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml index 409a4c7298e1..cd02811583ec 100644 --- a/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml +++ b/Documentation/devicetree/bindings/leds/leds-qcom-lpg.yaml @@ -17,6 +17,7 @@ description: > properties: compatible: enum: + - qcom,pm660l-lpg - qcom,pm8150b-lpg - qcom,pm8150l-lpg - qcom,pm8350c-pwm From dbc801b472c1ed5096d87f44a3e4acc180a44499 Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Tue, 12 Jul 2022 12:08:27 +0200 Subject: [PATCH 1221/1436] dt-bindings: leds: Convert is31fl319x to dtschema Convert leds-is31fl319x.txt to dtschema. Set license to the one recommended by DT project and set myself as maintainer. Reviewed-by: Rob Herring Signed-off-by: Vincent Knecht Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220712100841.1538395-2-vincent.knecht@mailoo.org --- .../bindings/leds/issi,is31fl319x.yaml | 113 ++++++++++++++++++ .../bindings/leds/leds-is31fl319x.txt | 61 ---------- 2 files changed, 113 insertions(+), 61 deletions(-) create mode 100644 Documentation/devicetree/bindings/leds/issi,is31fl319x.yaml delete mode 100644 Documentation/devicetree/bindings/leds/leds-is31fl319x.txt diff --git a/Documentation/devicetree/bindings/leds/issi,is31fl319x.yaml b/Documentation/devicetree/bindings/leds/issi,is31fl319x.yaml new file mode 100644 index 000000000000..0d684aeeb8cd --- /dev/null +++ b/Documentation/devicetree/bindings/leds/issi,is31fl319x.yaml @@ -0,0 +1,113 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/leds/issi,is31fl319x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ISSI LED controllers bindings for IS31FL319{0,1,3,6,9} + +maintainers: + - Vincent Knecht + +description: | + The IS31FL319X are LED controllers with I2C interface. + Previously known as Si-En SN319{0,1,3,6,9}. + + For more product information please see the links below: + https://lumissil.com/assets/pdf/core/IS31FL3190_DS.pdf + https://lumissil.com/assets/pdf/core/IS31FL3191_DS.pdf + https://lumissil.com/assets/pdf/core/IS31FL3193_DS.pdf + https://lumissil.com/assets/pdf/core/IS31FL3196_DS.pdf + https://lumissil.com/assets/pdf/core/IS31FL3199_DS.pdf + +properties: + compatible: + enum: + - issi,is31fl3190 + - issi,is31fl3191 + - issi,is31fl3193 + - issi,is31fl3196 + - issi,is31fl3199 + - si-en,sn3199 + + reg: + maxItems: 1 + + shutdown-gpios: + maxItems: 1 + description: GPIO attached to the SDB pin. + + audio-gain-db: + $ref: /schemas/types.yaml#/definitions/uint32 + default: 0 + description: Audio gain selection for external analog modulation input. + enum: [0, 3, 6, 9, 12, 15, 18, 21] + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + +patternProperties: + "^led@[1-9]$": + type: object + $ref: common.yaml# + + properties: + reg: + description: Index of the LED. + minimum: 1 + maximum: 9 + + led-max-microamp: + default: 20000 + enum: [5000, 10000, 15000, 20000, 25000, 30000, 35000, 40000] + description: + Note that a driver will take the lowest of all LED limits + since the chip has a single global setting. The lowest value + will be chosen due to the PWM specificity, where lower + brightness is achieved by reducing the duty-cycle of pulses + and not the current, which will always have its peak value + equal to led-max-microamp. + +required: + - compatible + - reg + - "#address-cells" + - "#size-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + i2c0 { + #address-cells = <1>; + #size-cells = <0>; + + led-controller@65 { + compatible = "issi,is31fl3196"; + reg = <0x65>; + #address-cells = <1>; + #size-cells = <0>; + + shutdown-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>; + + led@1 { + reg = <1>; + label = "red:aux"; + led-max-microamp = <10000>; + }; + + led@5 { + reg = <5>; + label = "green:power"; + linux,default-trigger = "default-on"; + }; + }; + }; +... + diff --git a/Documentation/devicetree/bindings/leds/leds-is31fl319x.txt b/Documentation/devicetree/bindings/leds/leds-is31fl319x.txt deleted file mode 100644 index 676d43ec8169..000000000000 --- a/Documentation/devicetree/bindings/leds/leds-is31fl319x.txt +++ /dev/null @@ -1,61 +0,0 @@ -LEDs connected to is31fl319x LED controller chip - -Required properties: -- compatible : Should be any of - "issi,is31fl3190" - "issi,is31fl3191" - "issi,is31fl3193" - "issi,is31fl3196" - "issi,is31fl3199" - "si-en,sn3199". -- #address-cells: Must be 1. -- #size-cells: Must be 0. -- reg: 0x64, 0x65, 0x66, or 0x67. - -Optional properties: -- audio-gain-db : audio gain selection for external analog modulation input. - Valid values: 0 - 21, step by 3 (rounded down) - Default: 0 -- shutdown-gpios : Specifier of the GPIO connected to SDB pin of the chip. - -Each led is represented as a sub-node of the issi,is31fl319x device. -There can be less leds subnodes than the chip can support but not more. - -Required led sub-node properties: -- reg : number of LED line - Valid values: 1 - number of leds supported by the chip variant. - -Optional led sub-node properties: -- label : see Documentation/devicetree/bindings/leds/common.txt. -- linux,default-trigger : - see Documentation/devicetree/bindings/leds/common.txt. -- led-max-microamp : (optional) - Valid values: 5000 - 40000, step by 5000 (rounded down) - Default: 20000 (20 mA) - Note: a driver will take the lowest of all led limits since the - chip has a single global setting. The lowest value will be chosen - due to the PWM specificity, where lower brightness is achieved - by reducing the dury-cycle of pulses and not the current, which - will always have its peak value equal to led-max-microamp. - -Examples: - -fancy_leds: leds@65 { - compatible = "issi,is31fl3196"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x65>; - shutdown-gpios = <&gpio0 11 GPIO_ACTIVE_HIGH>; - - red_aux: led@1 { - label = "red:aux"; - reg = <1>; - led-max-microamp = <10000>; - }; - - green_power: led@5 { - label = "green:power"; - reg = <5>; - linux,default-trigger = "default-on"; - }; -}; From fce43d8f75109dddcfa3870efca0b62750b929d7 Mon Sep 17 00:00:00 2001 From: Vincent Knecht Date: Tue, 12 Jul 2022 12:08:28 +0200 Subject: [PATCH 1222/1436] dt-bindings: leds: is31fl319x: Document variants specificities Add si-en compatibles for all chip variants and add conditionals depending on compatibles to document variants specs: - possible reg addresses - whether audio-gain-db is supported or not - maximum number of leds - led-max-microamp values Reviewed-by: Rob Herring Signed-off-by: Vincent Knecht Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220712100841.1538395-3-vincent.knecht@mailoo.org --- .../bindings/leds/issi,is31fl319x.yaml | 84 ++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/leds/issi,is31fl319x.yaml b/Documentation/devicetree/bindings/leds/issi,is31fl319x.yaml index 0d684aeeb8cd..940333f2d69c 100644 --- a/Documentation/devicetree/bindings/leds/issi,is31fl319x.yaml +++ b/Documentation/devicetree/bindings/leds/issi,is31fl319x.yaml @@ -28,6 +28,10 @@ properties: - issi,is31fl3193 - issi,is31fl3196 - issi,is31fl3199 + - si-en,sn3190 + - si-en,sn3191 + - si-en,sn3193 + - si-en,sn3196 - si-en,sn3199 reg: @@ -61,8 +65,6 @@ patternProperties: maximum: 9 led-max-microamp: - default: 20000 - enum: [5000, 10000, 15000, 20000, 25000, 30000, 35000, 40000] description: Note that a driver will take the lowest of all LED limits since the chip has a single global setting. The lowest value @@ -71,6 +73,84 @@ patternProperties: and not the current, which will always have its peak value equal to led-max-microamp. +allOf: + - if: + properties: + compatible: + contains: + enum: + - issi,is31fl3190 + - issi,is31fl3191 + - issi,is31fl3193 + - si-en,sn3190 + - si-en,sn3191 + - si-en,sn3193 + then: + properties: + reg: + enum: [0x68, 0x69, 0x6a, 0x6b] + + audio-gain-db: false + + patternProperties: + "^led@[1-9]$": + properties: + led-max-microamp: + default: 42000 + enum: [5000, 10000, 17500, 30000, 42000] + else: + properties: + reg: + enum: [0x64, 0x65, 0x66, 0x67] + + patternProperties: + "^led@[1-9]$": + properties: + led-max-microamp: + default: 20000 + enum: [5000, 10000, 15000, 20000, 25000, 30000, 35000, 40000] + - if: + properties: + compatible: + contains: + enum: + - issi,is31fl3190 + - issi,is31fl3191 + - si-en,sn3190 + - si-en,sn3191 + then: + patternProperties: + "^led@[1-9]$": + properties: + reg: + maximum: 1 + - if: + properties: + compatible: + contains: + enum: + - issi,is31fl3193 + - si-en,sn3193 + then: + patternProperties: + "^led@[1-9]$": + properties: + reg: + maximum: 3 + - if: + properties: + compatible: + contains: + enum: + - issi,is31fl3196 + - si-en,sn3196 + then: + patternProperties: + "^led@[1-9]$": + properties: + reg: + maximum: 6 + required: - compatible - reg From 12e5bde18d7f6ca4ee5fbd7c6f060d0674bf3237 Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Thu, 21 Jul 2022 09:17:46 +0800 Subject: [PATCH 1223/1436] dt-bindings: Fix typo in comment Fix typo in the comment Signed-off-by: Slark Xiao Reviewed-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220721011746.19663-1-slark_xiao@163.com --- Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt | 2 +- Documentation/devicetree/bindings/clock/ti/davinci/pll.txt | 2 +- Documentation/devicetree/bindings/fpga/fpga-region.txt | 2 +- Documentation/devicetree/bindings/gpio/gpio-pisosr.txt | 2 +- Documentation/devicetree/bindings/net/qcom-emac.txt | 2 +- .../bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml | 2 +- .../devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml | 2 +- .../devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml | 2 +- .../devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml | 2 +- .../devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml | 2 +- Documentation/devicetree/bindings/powerpc/fsl/cpus.txt | 2 +- Documentation/devicetree/bindings/powerpc/opal/power-mgt.txt | 2 +- Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt | 2 +- Documentation/devicetree/bindings/sound/tlv320adcx140.yaml | 4 ++-- .../devicetree/bindings/thermal/brcm,avs-ro-thermal.yaml | 2 +- .../devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt | 2 +- Documentation/devicetree/bindings/thermal/rcar-thermal.yaml | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt b/Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt index 94d50a949be1..c0e3c3a42bea 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,saw2.txt @@ -10,7 +10,7 @@ system, notifying them when a low power state is entered or exited. Multiple revisions of the SAW hardware are supported using these Device Nodes. SAW2 revisions differ in the register offset and configuration data. Also, the same revision of the SAW in different SoCs may have different configuration -data due the the differences in hardware capabilities. Hence the SoC name, the +data due the differences in hardware capabilities. Hence the SoC name, the version of the SAW hardware in that SoC and the distinction between cpu (big or Little) or cache, may be needed to uniquely identify the SAW register configuration and initialization data. The compatible string is used to diff --git a/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt b/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt index 36998e184821..c9894538315b 100644 --- a/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt +++ b/Documentation/devicetree/bindings/clock/ti/davinci/pll.txt @@ -15,7 +15,7 @@ Required properties: - for "ti,da850-pll1", shall be "clksrc" Optional properties: -- ti,clkmode-square-wave: Indicates that the the board is supplying a square +- ti,clkmode-square-wave: Indicates that the board is supplying a square wave input on the OSCIN pin instead of using a crystal oscillator. This property is only valid when compatible = "ti,da850-pll0". diff --git a/Documentation/devicetree/bindings/fpga/fpga-region.txt b/Documentation/devicetree/bindings/fpga/fpga-region.txt index 7d3515264838..6694ef29a267 100644 --- a/Documentation/devicetree/bindings/fpga/fpga-region.txt +++ b/Documentation/devicetree/bindings/fpga/fpga-region.txt @@ -330,7 +330,7 @@ succeeded. The Device Tree Overlay will contain: * "target-path" or "target" - The insertion point where the the contents of the overlay will go into the + The insertion point where the contents of the overlay will go into the live tree. target-path is a full path, while target is a phandle. * "ranges" The address space mapping from processor to FPGA bus(ses). diff --git a/Documentation/devicetree/bindings/gpio/gpio-pisosr.txt b/Documentation/devicetree/bindings/gpio/gpio-pisosr.txt index 414a01cdf715..fba3c61f6a5b 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-pisosr.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-pisosr.txt @@ -14,7 +14,7 @@ Optional properties: - ngpios : Number of used GPIO lines (0..n-1), default is 8. - load-gpios : GPIO pin specifier attached to load enable, this pin is pulsed before reading from the device to - load input pin values into the the device. + load input pin values into the device. For other required and optional properties of SPI slave nodes please refer to ../spi/spi-bus.txt. diff --git a/Documentation/devicetree/bindings/net/qcom-emac.txt b/Documentation/devicetree/bindings/net/qcom-emac.txt index 346e6c7f47b7..e6cb2291471c 100644 --- a/Documentation/devicetree/bindings/net/qcom-emac.txt +++ b/Documentation/devicetree/bindings/net/qcom-emac.txt @@ -14,7 +14,7 @@ MAC node: - mac-address : The 6-byte MAC address. If present, it is the default MAC address. - internal-phy : phandle to the internal PHY node -- phy-handle : phandle the the external PHY node +- phy-handle : phandle the external PHY node Internal PHY node: - compatible : Should be "qcom,fsm9900-emac-sgmii" or "qcom,qdf2432-emac-sgmii". diff --git a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml index 4d01f3124e1c..a90fa1baadab 100644 --- a/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml +++ b/Documentation/devicetree/bindings/phy/amlogic,meson-axg-mipi-pcie-analog.yaml @@ -16,7 +16,7 @@ description: |+ - compatible: Should be the following: "amlogic,meson-gx-hhi-sysctrl", "simple-mfd", "syscon" - Refer to the the bindings described in + Refer to the bindings described in Documentation/devicetree/bindings/mfd/syscon.yaml properties: diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml index c689bea7ce6e..d3a8911728d0 100644 --- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2400-pinctrl.yaml @@ -16,7 +16,7 @@ description: |+ - compatible: Should be one of the following: "aspeed,ast2400-scu", "syscon", "simple-mfd" - Refer to the the bindings described in + Refer to the bindings described in Documentation/devicetree/bindings/mfd/syscon.yaml properties: diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml index 9db904a528ee..5d2c1b1fb7fd 100644 --- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2500-pinctrl.yaml @@ -17,7 +17,7 @@ description: |+ "aspeed,ast2500-scu", "syscon", "simple-mfd" "aspeed,g5-scu", "syscon", "simple-mfd" - Refer to the the bindings described in + Refer to the bindings described in Documentation/devicetree/bindings/mfd/syscon.yaml properties: diff --git a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml index 3666ac5b6518..e92686d2f062 100644 --- a/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/aspeed,ast2600-pinctrl.yaml @@ -16,7 +16,7 @@ description: |+ - compatible: Should be one of the following: "aspeed,ast2600-scu", "syscon", "simple-mfd" - Refer to the the bindings described in + Refer to the bindings described in Documentation/devicetree/bindings/mfd/syscon.yaml properties: diff --git a/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml b/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml index f005abac7079..4e52ef33a986 100644 --- a/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml +++ b/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml @@ -17,7 +17,7 @@ description: |+ - compatible: Should be the following: "amlogic,meson-gx-hhi-sysctrl", "simple-mfd", "syscon" - Refer to the the bindings described in + Refer to the bindings described in Documentation/devicetree/bindings/mfd/syscon.yaml properties: diff --git a/Documentation/devicetree/bindings/powerpc/fsl/cpus.txt b/Documentation/devicetree/bindings/powerpc/fsl/cpus.txt index d63ab1dec16d..801c66069121 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/cpus.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/cpus.txt @@ -5,7 +5,7 @@ Copyright 2013 Freescale Semiconductor Inc. Power Architecture CPUs in Freescale SOCs are represented in device trees as per the definition in the Devicetree Specification. -In addition to the the Devicetree Specification definitions, the properties +In addition to the Devicetree Specification definitions, the properties defined below may be present on CPU nodes. PROPERTIES diff --git a/Documentation/devicetree/bindings/powerpc/opal/power-mgt.txt b/Documentation/devicetree/bindings/powerpc/opal/power-mgt.txt index 9d619e955576..d6658d3dd15e 100644 --- a/Documentation/devicetree/bindings/powerpc/opal/power-mgt.txt +++ b/Documentation/devicetree/bindings/powerpc/opal/power-mgt.txt @@ -39,7 +39,7 @@ otherwise. The length of all the property arrays must be the same. - ibm,cpu-idle-state-flags: Array of unsigned 32-bit values containing the values of the - flags associated with the the aforementioned idle-states. The + flags associated with the aforementioned idle-states. The flag bits are as follows: 0x00000001 /* Decrementer would stop */ 0x00000002 /* Needs timebase restore */ diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt index b677900b3aae..658f96fbc4fe 100644 --- a/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt +++ b/Documentation/devicetree/bindings/remoteproc/qcom,q6v5.txt @@ -37,7 +37,7 @@ on the Qualcomm Hexagon core. - interrupt-names: Usage: required Value type: - Definition: The interrupts needed depends on the the compatible + Definition: The interrupts needed depends on the compatible string: qcom,q6v5-pil: qcom,ipq8074-wcss-pil: diff --git a/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml b/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml index 2ad17b361db0..bc2fb1a80ed7 100644 --- a/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml +++ b/Documentation/devicetree/bindings/sound/tlv320adcx140.yaml @@ -68,9 +68,9 @@ properties: array is defined as . 0 - (default) Odd channel is latched on the negative edge and even - channel is latched on the the positive edge. + channel is latched on the positive edge. 1 - Odd channel is latched on the positive edge and even channel is - latched on the the negative edge. + latched on the negative edge. PDMIN1 - PDMCLK latching edge used for channel 1 and 2 data PDMIN2 - PDMCLK latching edge used for channel 3 and 4 data diff --git a/Documentation/devicetree/bindings/thermal/brcm,avs-ro-thermal.yaml b/Documentation/devicetree/bindings/thermal/brcm,avs-ro-thermal.yaml index 1ab5070c751d..89a2c32c0ab2 100644 --- a/Documentation/devicetree/bindings/thermal/brcm,avs-ro-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/brcm,avs-ro-thermal.yaml @@ -16,7 +16,7 @@ description: |+ - compatible: Should be one of the following: "brcm,bcm2711-avs-monitor", "syscon", "simple-mfd" - Refer to the the bindings described in + Refer to the bindings described in Documentation/devicetree/bindings/mfd/syscon.yaml properties: diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt index db880e7ed713..aea4a2a178b9 100644 --- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt @@ -96,7 +96,7 @@ critical trip point is reported back to the thermal framework to implement software shutdown. - the "hot" type trip points will be set to SOC_THERM hardware as the throttle -temperature. Once the the temperature of this thermal zone is higher +temperature. Once the temperature of this thermal zone is higher than it, it will trigger the HW throttle event. Example : diff --git a/Documentation/devicetree/bindings/thermal/rcar-thermal.yaml b/Documentation/devicetree/bindings/thermal/rcar-thermal.yaml index 927de79ab4b5..00dcbdd36144 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-thermal.yaml +++ b/Documentation/devicetree/bindings/thermal/rcar-thermal.yaml @@ -42,7 +42,7 @@ properties: description: Address ranges of the thermal registers. If more then one range is given the first one must be the common registers followed by each sensor - according the the datasheet. + according the datasheet. minItems: 1 maxItems: 4 From c7c7ce585370c927fe1d7daeb758dedcfddc573c Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 21 Jul 2022 05:03:27 +0200 Subject: [PATCH 1224/1436] dt-bindings: vendor-prefixes: add Densitron MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Densitron is a manufacturer of LCD panels. https://www.densitron.com Signed-off-by: Marek Vasut Cc: Guido Günther Cc: Jagan Teki Cc: Laurent Pinchart Cc: Linus Walleij Cc: Rob Herring Cc: Sam Ravnborg Cc: Thierry Reding Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220721030327.210950-1-marex@denx.de --- Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml index 7bd0a85c38f5..78dbd436e1df 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml @@ -312,6 +312,8 @@ patternProperties: description: Dell Inc. "^delta,.*": description: Delta Electronics, Inc. + "^densitron,.*": + description: Densitron Technologies Ltd "^denx,.*": description: Denx Software Engineering "^devantech,.*": From 4f46cc1b88b338692c581a77940649dd6974e04c Mon Sep 17 00:00:00 2001 From: Kuldeep Singh Date: Mon, 18 Apr 2022 02:34:36 +0530 Subject: [PATCH 1225/1436] dt-bindings: dma: Convert Qualcomm BAM DMA binding to json format Convert Qualcomm BAM DMA controller binding to DT schema format using json schema. Signed-off-by: Kuldeep Singh [robh: add back SoC mapping to compatible strings] Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220417210436.6203-7-singh.kuldeep87k@gmail.com --- .../devicetree/bindings/dma/qcom,bam-dma.yaml | 100 ++++++++++++++++++ .../devicetree/bindings/dma/qcom_bam_dma.txt | 52 --------- 2 files changed, 100 insertions(+), 52 deletions(-) create mode 100644 Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml delete mode 100644 Documentation/devicetree/bindings/dma/qcom_bam_dma.txt diff --git a/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml b/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml new file mode 100644 index 000000000000..9bf3a1b164f1 --- /dev/null +++ b/Documentation/devicetree/bindings/dma/qcom,bam-dma.yaml @@ -0,0 +1,100 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/dma/qcom,bam-dma.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm Technologies Inc BAM DMA controller + +maintainers: + - Andy Gross + - Bjorn Andersson + +allOf: + - $ref: "dma-controller.yaml#" + +properties: + compatible: + enum: + # APQ8064, IPQ8064 and MSM8960 + - qcom,bam-v1.3.0 + # MSM8974, APQ8074 and APQ8084 + - qcom,bam-v1.4.0 + # MSM8916 + - qcom,bam-v1.7.0 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: bam_clk + + "#dma-cells": + const: 1 + + interrupts: + maxItems: 1 + + iommus: + minItems: 1 + maxItems: 4 + + num-channels: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Indicates supported number of DMA channels in a remotely controlled bam. + + qcom,controlled-remotely: + type: boolean + description: + Indicates that the bam is controlled by remote proccessor i.e. execution + environment. + + qcom,ee: + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 0 + maximum: 7 + description: + Indicates the active Execution Environment identifier (0-7) used in the + secure world. + + qcom,num-ees: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + Indicates supported number of Execution Environments in a remotely + controlled bam. + + qcom,powered-remotely: + type: boolean + description: + Indicates that the bam is powered up by a remote processor but must be + initialized by the local processor. + + reg: + maxItems: 1 + +required: + - compatible + - "#dma-cells" + - interrupts + - qcom,ee + - reg + +additionalProperties: false + +examples: + - | + #include + #include + + dma-controller@f9944000 { + compatible = "qcom,bam-v1.4.0"; + reg = <0xf9944000 0x15000>; + interrupts = ; + clocks = <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "bam_clk"; + #dma-cells = <1>; + qcom,ee = <0>; + }; +... diff --git a/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt b/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt deleted file mode 100644 index 6e9a5497b3f2..000000000000 --- a/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt +++ /dev/null @@ -1,52 +0,0 @@ -QCOM BAM DMA controller - -Required properties: -- compatible: must be one of the following: - * "qcom,bam-v1.4.0" for MSM8974, APQ8074 and APQ8084 - * "qcom,bam-v1.3.0" for APQ8064, IPQ8064 and MSM8960 - * "qcom,bam-v1.7.0" for MSM8916 -- reg: Address range for DMA registers -- interrupts: Should contain the one interrupt shared by all channels -- #dma-cells: must be <1>, the cell in the dmas property of the client device - represents the channel number -- clocks: required clock -- clock-names: must contain "bam_clk" entry -- qcom,ee : indicates the active Execution Environment identifier (0-7) used in - the secure world. -- qcom,controlled-remotely : optional, indicates that the bam is controlled by - remote proccessor i.e. execution environment. -- qcom,powered-remotely : optional, indicates that the bam is powered up by - a remote processor but must be initialized by the local processor. -- num-channels : optional, indicates supported number of DMA channels in a - remotely controlled bam. -- qcom,num-ees : optional, indicates supported number of Execution Environments - in a remotely controlled bam. - -Example: - - uart-bam: dma@f9984000 = { - compatible = "qcom,bam-v1.4.0"; - reg = <0xf9984000 0x15000>; - interrupts = <0 94 0>; - clocks = <&gcc GCC_BAM_DMA_AHB_CLK>; - clock-names = "bam_clk"; - #dma-cells = <1>; - qcom,ee = <0>; - }; - -DMA clients must use the format described in the dma.txt file, using a two cell -specifier for each channel. - -Example: - serial@f991e000 { - compatible = "qcom,msm-uart"; - reg = <0xf991e000 0x1000> - <0xf9944000 0x19000>; - interrupts = <0 108 0>; - clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, - <&gcc GCC_BLSP1_AHB_CLK>; - clock-names = "core", "iface"; - - dmas = <&uart-bam 0>, <&uart-bam 1>; - dma-names = "rx", "tx"; - }; From e3899832bb7b3c1504998768cc2f753786c19e0a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 17 Jun 2022 13:44:19 +0200 Subject: [PATCH 1226/1436] dt-bindings: rtc: ds1307: Convert to json-schema Convert the DS1307 (and compatible) RTC bindings from the free-form text format to json-schema. Signed-off-by: Thierry Reding Reviewed-by: Rob Herring Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220617114420.1398259-1-thierry.reding@gmail.com --- .../devicetree/bindings/rtc/rtc-ds1307.txt | 52 --------- .../devicetree/bindings/rtc/rtc-ds1307.yaml | 102 ++++++++++++++++++ 2 files changed, 102 insertions(+), 52 deletions(-) delete mode 100644 Documentation/devicetree/bindings/rtc/rtc-ds1307.txt create mode 100644 Documentation/devicetree/bindings/rtc/rtc-ds1307.yaml diff --git a/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt b/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt deleted file mode 100644 index 36f610bb051e..000000000000 --- a/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt +++ /dev/null @@ -1,52 +0,0 @@ -Dallas DS1307 and compatible RTC - -Required properties: -- compatible: should be one of: - "dallas,ds1307", - "dallas,ds1308", - "dallas,ds1337", - "dallas,ds1338", - "dallas,ds1339", - "dallas,ds1388", - "dallas,ds1340", - "dallas,ds1341", - "maxim,ds3231", - "st,m41t0", - "st,m41t00", - "st,m41t11", - "microchip,mcp7940x", - "microchip,mcp7941x", - "pericom,pt7c4338", - "epson,rx8025", - "isil,isl12057" - "epson,rx8130" -- reg: I2C bus address of the device - -Optional properties: -- interrupts: rtc alarm interrupt. -- clock-output-names: From common clock binding to override the default output - clock name -- wakeup-source: Enables wake up of host system on alarm -- trickle-resistor-ohms : ds1339, ds1340 and ds 1388 only - Selected resistor for trickle charger - Possible values are 250, 2000, 4000 - Should be given if trickle charger should be enabled -- aux-voltage-chargeable: ds1339, ds1340, ds1388 and rx8130 only - Tells whether the battery/supercap of the RTC (if any) is - chargeable or not. - Possible values are 0 (not chargeable), 1 (chargeable) - -Deprecated properties: -- trickle-diode-disable : ds1339, ds1340 and ds1388 only - Do not use internal trickle charger diode - Should be given if internal trickle charger diode should be disabled - (superseded by aux-voltage-chargeable) - -Example: - ds1339: rtc@68 { - compatible = "dallas,ds1339"; - reg = <0x68>; - interrupt-parent = <&gpio4>; - interrupts = <20 0>; - trickle-resistor-ohms = <250>; - }; diff --git a/Documentation/devicetree/bindings/rtc/rtc-ds1307.yaml b/Documentation/devicetree/bindings/rtc/rtc-ds1307.yaml new file mode 100644 index 000000000000..98d10e680144 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/rtc-ds1307.yaml @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/rtc/rtc-ds1307.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Dallas DS1307 and compatible RTC + +maintainers: + - Alexandre Belloni + +properties: + compatible: + oneOf: + - enum: + - dallas,ds1307 + - dallas,ds1308 + - dallas,ds1337 + - dallas,ds1338 + - dallas,ds1339 + - dallas,ds1388 + - dallas,ds1340 + - dallas,ds1341 + - maxim,ds3231 + - st,m41t0 + - st,m41t00 + - st,m41t11 + - microchip,mcp7940x + - microchip,mcp7941x + - pericom,pt7c4338 + - epson,rx8025 + - isil,isl12057 + - epson,rx8130 + + - items: + - enum: + - st,m41t00 + - const: dallas,ds1338 + + reg: + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 2 + + interrupt-names: + maxItems: 2 + + "#clock-cells": + const: 1 + + clock-output-names: + description: From common clock binding to override the default output clock name. + + wakeup-source: + description: Enables wake up of host system on alarm. + + vcc-supply: true + +allOf: + - $ref: rtc.yaml + - if: + properties: + compatible: + contains: + enum: + - dallas,ds1339 + - dallas,ds1340 + - dallas,ds1388 + then: + properties: + trickle-resistor-ohms: + description: Selected resistor for trickle charger. Should be specified if trickle + charger should be enabled. + enum: [ 250, 2000, 4000 ] + + trickle-diode-disable: + description: Do not use internal trickle charger diode. Should be given if internal + trickle charger diode should be disabled (superseded by aux-voltage-chargeable) + deprecated: true + +unevaluatedProperties: false + +required: + - compatible + - reg + +examples: + - | + i2c { + #address-cells = <1>; + #size-cells = <0>; + + rtc@68 { + compatible = "dallas,ds1337"; + reg = <0x68>; + interrupt-parent = <&gpio4>; + interrupts = <20 0>; + trickle-resistor-ohms = <250>; + }; + }; From d6abb2282404c0877a6fcf620d34fd74ba17df3b Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 17 Jun 2022 13:44:20 +0200 Subject: [PATCH 1227/1436] dt-bindings: rtc: Add EM Microelectronic EM3027 bindings Document the bindings for the EM Microelectronic EM3027 RTC. Signed-off-by: Thierry Reding Reviewed-by: Rob Herring Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220617114420.1398259-2-thierry.reding@gmail.com --- Documentation/devicetree/bindings/rtc/trivial-rtc.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml index 13925bb78ec7..d9fc120c61cc 100644 --- a/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml +++ b/Documentation/devicetree/bindings/rtc/trivial-rtc.yaml @@ -30,6 +30,8 @@ properties: - dallas,ds1672 # Extremely Accurate I²C RTC with Integrated Crystal and SRAM - dallas,ds3232 + # EM Microelectronic EM3027 RTC + - emmicro,em3027 # I2C-BUS INTERFACE REAL TIME CLOCK MODULE - epson,rx8010 # I2C-BUS INTERFACE REAL TIME CLOCK MODULE From a0a2d10aad65afb1558d7b8ad5770dff75493d45 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Thu, 21 Jul 2022 11:25:08 -0400 Subject: [PATCH 1228/1436] MAINTAINERS: Update Intel 8255 GPIO driver file list The drivers/gpio/gpio-i8255.h header file is also maintained. Signed-off-by: William Breathitt Gray Signed-off-by: Bartosz Golaszewski --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 960abc07304e..2bd82ce171ca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9907,6 +9907,7 @@ M: William Breathitt Gray L: linux-gpio@vger.kernel.org S: Maintained F: drivers/gpio/gpio-i8255.c +F: drivers/gpio/gpio-i8255.h INTEL ASoC DRIVERS M: Cezary Rojewski From 11969d698f8cda31bd176ec346833ef97ea7c67e Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 20 Jul 2022 13:55:38 +0100 Subject: [PATCH 1229/1436] cacheinfo: Use atomic allocation for percpu cache attributes On couple of architectures like RISC-V and ARM64, we need to detect cache attribues quite early during the boot when the secondary CPUs start. So we will call detect_cache_attributes in the atomic context and since use of normal allocation can sleep, we will end up getting "sleeping in the atomic context" bug splat. In order avoid that, move the allocation to use atomic version in preparation to move the actual detection of cache attributes in the CPU hotplug path which is atomic. Cc: Ionela Voinescu Tested-by: Conor Dooley Signed-off-by: Sudeep Holla Link: https://lore.kernel.org/r/20220720-arch_topo_fixes-v3-1-43d696288e84@arm.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/cacheinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index 65d566ff24c4..4b5cd08c5a65 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -356,7 +356,7 @@ int detect_cache_attributes(unsigned int cpu) return -ENOENT; per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu), - sizeof(struct cacheinfo), GFP_KERNEL); + sizeof(struct cacheinfo), GFP_ATOMIC); if (per_cpu_cacheinfo(cpu) == NULL) { cache_leaves(cpu) = 0; return -ENOMEM; From 0c80f9e165f8f9cca743d7b6cbdb54362da297e0 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 20 Jul 2022 13:55:39 +0100 Subject: [PATCH 1230/1436] ACPI: PPTT: Leave the table mapped for the runtime usage Currently, everytime an information needs to be fetched from the PPTT, the table is mapped via acpi_get_table() and unmapped after the use via acpi_put_table() which is fine. However we do this at runtime especially when the CPU is hotplugged out and plugged in back since we re-populate the cache topology and other information. However, with the support to fetch LLC information from the PPTT in the cpuhotplug path which is executed in the atomic context, it is preferred to avoid mapping and unmapping of the PPTT for every single use as the acpi_get_table() might sleep waiting for a mutex. In order to avoid the same, the table is needs to just mapped once on the boot CPU and is never unmapped allowing it to be used at runtime with out the hassle of mapping and unmapping the table. Reported-by: Guenter Roeck Cc: Rafael J. Wysocki Signed-off-by: Sudeep Holla -- Hi Rafael, Sorry to bother you again on this PPTT changes. Guenter reported an issue with lockdep enabled in -next that include my cacheinfo/arch_topology changes to utilise LLC from PPTT in the CPU hotplug path. Please ack the change once you are happy so that I can get it merged with other fixes via Greg's tree. Regards, Sudeep Acked-by: Rafael J. Wysocki Link: https://lore.kernel.org/r/20220720-arch_topo_fixes-v3-2-43d696288e84@arm.com Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/pptt.c | 102 ++++++++++++++++++++------------------------ 1 file changed, 47 insertions(+), 55 deletions(-) diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c index dd3222a15c9c..c91342dcbcd6 100644 --- a/drivers/acpi/pptt.c +++ b/drivers/acpi/pptt.c @@ -533,21 +533,37 @@ static int topology_get_acpi_cpu_tag(struct acpi_table_header *table, return -ENOENT; } + +static struct acpi_table_header *acpi_get_pptt(void) +{ + static struct acpi_table_header *pptt; + acpi_status status; + + /* + * PPTT will be used at runtime on every CPU hotplug in path, so we + * don't need to call acpi_put_table() to release the table mapping. + */ + if (!pptt) { + status = acpi_get_table(ACPI_SIG_PPTT, 0, &pptt); + if (ACPI_FAILURE(status)) + acpi_pptt_warn_missing(); + } + + return pptt; +} + static int find_acpi_cpu_topology_tag(unsigned int cpu, int level, int flag) { struct acpi_table_header *table; - acpi_status status; int retval; - status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); - if (ACPI_FAILURE(status)) { - acpi_pptt_warn_missing(); + table = acpi_get_pptt(); + if (!table) return -ENOENT; - } + retval = topology_get_acpi_cpu_tag(table, cpu, level, flag); pr_debug("Topology Setup ACPI CPU %d, level %d ret = %d\n", cpu, level, retval); - acpi_put_table(table); return retval; } @@ -568,16 +584,13 @@ static int find_acpi_cpu_topology_tag(unsigned int cpu, int level, int flag) static int check_acpi_cpu_flag(unsigned int cpu, int rev, u32 flag) { struct acpi_table_header *table; - acpi_status status; u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu); struct acpi_pptt_processor *cpu_node = NULL; int ret = -ENOENT; - status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); - if (ACPI_FAILURE(status)) { - acpi_pptt_warn_missing(); - return ret; - } + table = acpi_get_pptt(); + if (!table) + return -ENOENT; if (table->revision >= rev) cpu_node = acpi_find_processor_node(table, acpi_cpu_id); @@ -585,8 +598,6 @@ static int check_acpi_cpu_flag(unsigned int cpu, int rev, u32 flag) if (cpu_node) ret = (cpu_node->flags & flag) != 0; - acpi_put_table(table); - return ret; } @@ -605,18 +616,15 @@ int acpi_find_last_cache_level(unsigned int cpu) u32 acpi_cpu_id; struct acpi_table_header *table; int number_of_levels = 0; - acpi_status status; + + table = acpi_get_pptt(); + if (!table) + return -ENOENT; pr_debug("Cache Setup find last level CPU=%d\n", cpu); acpi_cpu_id = get_acpi_id_for_cpu(cpu); - status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); - if (ACPI_FAILURE(status)) { - acpi_pptt_warn_missing(); - } else { - number_of_levels = acpi_find_cache_levels(table, acpi_cpu_id); - acpi_put_table(table); - } + number_of_levels = acpi_find_cache_levels(table, acpi_cpu_id); pr_debug("Cache Setup find last level level=%d\n", number_of_levels); return number_of_levels; @@ -638,20 +646,16 @@ int acpi_find_last_cache_level(unsigned int cpu) int cache_setup_acpi(unsigned int cpu) { struct acpi_table_header *table; - acpi_status status; + + table = acpi_get_pptt(); + if (!table) + return -ENOENT; pr_debug("Cache Setup ACPI CPU %d\n", cpu); - status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); - if (ACPI_FAILURE(status)) { - acpi_pptt_warn_missing(); - return -ENOENT; - } - cache_setup_acpi_cpu(table, cpu); - acpi_put_table(table); - return status; + return 0; } /** @@ -730,50 +734,38 @@ int find_acpi_cpu_topology_package(unsigned int cpu) int find_acpi_cpu_topology_cluster(unsigned int cpu) { struct acpi_table_header *table; - acpi_status status; struct acpi_pptt_processor *cpu_node, *cluster_node; u32 acpi_cpu_id; int retval; int is_thread; - status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); - if (ACPI_FAILURE(status)) { - acpi_pptt_warn_missing(); + table = acpi_get_pptt(); + if (!table) return -ENOENT; - } acpi_cpu_id = get_acpi_id_for_cpu(cpu); cpu_node = acpi_find_processor_node(table, acpi_cpu_id); - if (cpu_node == NULL || !cpu_node->parent) { - retval = -ENOENT; - goto put_table; - } + if (!cpu_node || !cpu_node->parent) + return -ENOENT; is_thread = cpu_node->flags & ACPI_PPTT_ACPI_PROCESSOR_IS_THREAD; cluster_node = fetch_pptt_node(table, cpu_node->parent); - if (cluster_node == NULL) { - retval = -ENOENT; - goto put_table; - } + if (!cluster_node) + return -ENOENT; + if (is_thread) { - if (!cluster_node->parent) { - retval = -ENOENT; - goto put_table; - } + if (!cluster_node->parent) + return -ENOENT; + cluster_node = fetch_pptt_node(table, cluster_node->parent); - if (cluster_node == NULL) { - retval = -ENOENT; - goto put_table; - } + if (!cluster_node) + return -ENOENT; } if (cluster_node->flags & ACPI_PPTT_ACPI_PROCESSOR_ID_VALID) retval = cluster_node->acpi_processor_id; else retval = ACPI_PTR_DIFF(cluster_node, table); -put_table: - acpi_put_table(table); - return retval; } From 3fcbf1c77d089fcf0331fd8f3cbbe6c436a3edbd Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 20 Jul 2022 13:55:40 +0100 Subject: [PATCH 1231/1436] arch_topology: Fix cache attributes detection in the CPU hotplug path init_cpu_topology() is called only once at the boot and all the cache attributes are detected early for all the possible CPUs. However when the CPUs are hotplugged out, the cacheinfo gets removed. While the attributes are added back when the CPUs are hotplugged back in as part of CPU hotplug state machine, it ends up called quite late after the update_siblings_masks() are called in the secondary_start_kernel() resulting in wrong llc_sibling_masks. Move the call to detect_cache_attributes() inside update_siblings_masks() to ensure the cacheinfo is updated before the LLC sibling masks are updated. This will fix the incorrect LLC sibling masks generated when the CPUs are hotplugged out and hotplugged back in again. Reported-by: Ionela Voinescu Tested-by: Geert Uytterhoeven Tested-by: Ionela Voinescu Reviewed-by: Conor Dooley Reviewed-by: Ionela Voinescu Signed-off-by: Sudeep Holla Link: https://lore.kernel.org/r/20220720-arch_topo_fixes-v3-3-43d696288e84@arm.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/arch_topology.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 441e14ac33a4..0424b59b695e 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -732,7 +732,11 @@ const struct cpumask *cpu_clustergroup_mask(int cpu) void update_siblings_masks(unsigned int cpuid) { struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; - int cpu; + int cpu, ret; + + ret = detect_cache_attributes(cpuid); + if (ret) + pr_info("Early cacheinfo failed, ret = %d\n", ret); /* update core and thread sibling masks */ for_each_online_cpu(cpu) { @@ -821,7 +825,7 @@ __weak int __init parse_acpi_topology(void) #if defined(CONFIG_ARM64) || defined(CONFIG_RISCV) void __init init_cpu_topology(void) { - int ret, cpu; + int ret; reset_cpu_topology(); ret = parse_acpi_topology(); @@ -836,13 +840,5 @@ void __init init_cpu_topology(void) reset_cpu_topology(); return; } - - for_each_possible_cpu(cpu) { - ret = detect_cache_attributes(cpu); - if (ret) { - pr_info("Early cacheinfo failed, ret = %d\n", ret); - break; - } - } } #endif From 1117d182c5d72abd7eb8b7d5e7b8c3373181c3ab Mon Sep 17 00:00:00 2001 From: Artem Borisov Date: Tue, 19 Jul 2022 17:53:24 +0300 Subject: [PATCH 1232/1436] HID: alps: Declare U1_UNICORN_LEGACY support U1_UNICORN_LEGACY id was added to the driver, but was not declared in the device id table, making it impossible to use. Fixes: 640e403 ("HID: alps: Add AUI1657 device ID") Signed-off-by: Artem Borisov Signed-off-by: Jiri Kosina --- drivers/hid/hid-alps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index 2b986d0dbde4..db146d0f7937 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -830,6 +830,8 @@ static const struct hid_device_id alps_id[] = { USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1) }, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, + USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY) }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_T4_BTNLESS) }, { } From 20afcc462579c0bd79a59ab2b87b82ffa833d118 Mon Sep 17 00:00:00 2001 From: Hilton Chain Date: Thu, 21 Jul 2022 22:34:23 +0800 Subject: [PATCH 1233/1436] HID: apple: Add "GANSS" to the non-Apple list While using the name "SONiX USB DEVICE" for wired mode, my GANSS keyboard uses "GANSS" for bluetooth mode as well, so adding this to the list. Signed-off-by: Hilton Chain Signed-off-by: Jiri Kosina --- drivers/hid/hid-apple.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 7fbde58e1219..6970797cdc56 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -320,7 +320,8 @@ static const struct apple_key_translation swapped_fn_leftctrl_keys[] = { static const struct apple_non_apple_keyboard non_apple_keyboards[] = { { "SONiX USB DEVICE" }, { "Keychron" }, - { "AONE" } + { "AONE" }, + { "GANSS" } }; static bool apple_is_non_apple_keyboard(struct hid_device *hdev) From fba4866241e07f8f545b3dcc72fbbadde485530d Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 19 Jul 2022 15:50:31 -0600 Subject: [PATCH 1234/1436] dt-bindings: PCI: fsl,imx6q-pcie: Add missing type for 'reset-gpio-active-high' 'reset-gpio-active-high' is missing a type definition and is not a common property. The type is boolean. Signed-off-by: Rob Herring Acked-by: Richard Zhu Link: https://lore.kernel.org/r/20220719215031.1875860-1-robh@kernel.org --- Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml index 252e5b72aee0..376e739bcad4 100644 --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml @@ -144,6 +144,7 @@ properties: description: If present then the reset sequence using the GPIO specified in the "reset-gpio" property is reversed (H=reset state, L=operation state) (optional required). + type: boolean vpcie-supply: description: Should specify the regulator in charge of PCIe port power. From a2310c74d418deca0f1d749c45f1f43162510f51 Mon Sep 17 00:00:00 2001 From: Liao Chang Date: Wed, 25 May 2022 16:02:41 +0800 Subject: [PATCH 1235/1436] csky/kprobe: reclaim insn_slot on kprobe unregistration On kprobe registration kernel allocate one insn_slot for new kprobe, but it forget to reclaim the insn_slot on unregistration, leading to a potential leakage. Reported-by: Chen Guokai Reviewed-by: Masami Hiramatsu (Google) Signed-off-by: Liao Chang Signed-off-by: Guo Ren --- arch/csky/kernel/probes/kprobes.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/csky/kernel/probes/kprobes.c b/arch/csky/kernel/probes/kprobes.c index 34ba684d5962..3c6e5c725d81 100644 --- a/arch/csky/kernel/probes/kprobes.c +++ b/arch/csky/kernel/probes/kprobes.c @@ -124,6 +124,10 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p) void __kprobes arch_remove_kprobe(struct kprobe *p) { + if (p->ainsn.api.insn) { + free_insn_slot(p->ainsn.api.insn, 0); + p->ainsn.api.insn = NULL; + } } static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) From 49a1a3cf7316e464e559850a965f3826b1562458 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 4 Jul 2022 21:06:46 +0200 Subject: [PATCH 1236/1436] csky: Use the bitmap API to allocate bitmaps Use bitmap_zalloc()/bitmap_free() instead of hand-writing them. It is less verbose and it improves the semantic. While at it, turn a bitmap_clear() into an equivalent bitmap_zero(). It is also less verbose. Signed-off-by: Christophe JAILLET Signed-off-by: Guo Ren --- arch/csky/mm/asid.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/csky/mm/asid.c b/arch/csky/mm/asid.c index b2e914745c1d..7fb6c417bbac 100644 --- a/arch/csky/mm/asid.c +++ b/arch/csky/mm/asid.c @@ -27,7 +27,7 @@ static void flush_context(struct asid_info *info) u64 asid; /* Update the list of reserved ASIDs and the ASID bitmap. */ - bitmap_clear(info->map, 0, NUM_CTXT_ASIDS(info)); + bitmap_zero(info->map, NUM_CTXT_ASIDS(info)); for_each_possible_cpu(i) { asid = atomic64_xchg_relaxed(&active_asid(info, i), 0); @@ -178,8 +178,7 @@ int asid_allocator_init(struct asid_info *info, */ WARN_ON(NUM_CTXT_ASIDS(info) - 1 <= num_possible_cpus()); atomic64_set(&info->generation, ASID_FIRST_VERSION(info)); - info->map = kcalloc(BITS_TO_LONGS(NUM_CTXT_ASIDS(info)), - sizeof(*info->map), GFP_KERNEL); + info->map = bitmap_zalloc(NUM_CTXT_ASIDS(info), GFP_KERNEL); if (!info->map) return -ENOMEM; From f54af50d7b6f9ddb54df422156864cfc59e32f8c Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 5 Jul 2022 14:00:15 +0800 Subject: [PATCH 1237/1436] csky: Correct position of _stext Correct position of _stext to prevent check_kernel_text_object warning [1]. [1] https://lore.kernel.org/linux-csky/YfLpNkmlvoR8iPcq@ls3530/ Signed-off-by: Guo Ren Signed-off-by: Guo Ren Cc: Helge Deller --- arch/csky/include/asm/sections.h | 10 ++++++++++ arch/csky/kernel/setup.c | 4 ++-- arch/csky/kernel/vmlinux.lds.S | 3 ++- 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 arch/csky/include/asm/sections.h diff --git a/arch/csky/include/asm/sections.h b/arch/csky/include/asm/sections.h new file mode 100644 index 000000000000..4192cba8445d --- /dev/null +++ b/arch/csky/include/asm/sections.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __ASM_SECTIONS_H +#define __ASM_SECTIONS_H + +#include + +extern char _start[]; + +#endif /* __ASM_SECTIONS_H */ diff --git a/arch/csky/kernel/setup.c b/arch/csky/kernel/setup.c index c64e7be2045b..106fbf0b6f3b 100644 --- a/arch/csky/kernel/setup.c +++ b/arch/csky/kernel/setup.c @@ -31,7 +31,7 @@ static void __init csky_memblock_init(void) unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0 }; signed long size; - memblock_reserve(__pa(_stext), _end - _stext); + memblock_reserve(__pa(_start), _end - _start); early_init_fdt_reserve_self(); early_init_fdt_scan_reserved_mem(); @@ -78,7 +78,7 @@ void __init setup_arch(char **cmdline_p) pr_info("Phys. mem: %ldMB\n", (unsigned long) memblock_phys_mem_size()/1024/1024); - setup_initial_init_mm(_stext, _etext, _edata, _end); + setup_initial_init_mm(_start, _etext, _edata, _end); parse_early_param(); diff --git a/arch/csky/kernel/vmlinux.lds.S b/arch/csky/kernel/vmlinux.lds.S index e8b1a4a49798..163a8cd8b9a6 100644 --- a/arch/csky/kernel/vmlinux.lds.S +++ b/arch/csky/kernel/vmlinux.lds.S @@ -22,7 +22,7 @@ SECTIONS { . = PAGE_OFFSET + PHYS_OFFSET_OFFSET; - _stext = .; + _start = .; __init_begin = .; HEAD_TEXT_SECTION INIT_TEXT_SECTION(PAGE_SIZE) @@ -33,6 +33,7 @@ SECTIONS .text : AT(ADDR(.text) - LOAD_OFFSET) { _text = .; + _stext = .; VBR_BASE IRQENTRY_TEXT SOFTIRQENTRY_TEXT From 01ab4649ef5a377074d2ad4bf2ba6d2270d2807b Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Tue, 5 Jul 2022 14:16:21 +0800 Subject: [PATCH 1238/1436] csky: Move HEAD_TEXT_SECTION out of __init_begin-end Prevent HEAD_TEXT_SECTION back into the buddy system. Signed-off-by: Guo Ren Signed-off-by: Guo Ren --- arch/csky/kernel/vmlinux.lds.S | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/csky/kernel/vmlinux.lds.S b/arch/csky/kernel/vmlinux.lds.S index 163a8cd8b9a6..68c980d08482 100644 --- a/arch/csky/kernel/vmlinux.lds.S +++ b/arch/csky/kernel/vmlinux.lds.S @@ -23,13 +23,8 @@ SECTIONS . = PAGE_OFFSET + PHYS_OFFSET_OFFSET; _start = .; - __init_begin = .; HEAD_TEXT_SECTION - INIT_TEXT_SECTION(PAGE_SIZE) - INIT_DATA_SECTION(PAGE_SIZE) - PERCPU_SECTION(L1_CACHE_BYTES) . = ALIGN(PAGE_SIZE); - __init_end = .; .text : AT(ADDR(.text) - LOAD_OFFSET) { _text = .; @@ -49,7 +44,12 @@ SECTIONS /* __init_begin __init_end must be page aligned for free_initmem */ . = ALIGN(PAGE_SIZE); - + __init_begin = .; + INIT_TEXT_SECTION(PAGE_SIZE) + INIT_DATA_SECTION(PAGE_SIZE) + PERCPU_SECTION(L1_CACHE_BYTES) + . = ALIGN(PAGE_SIZE); + __init_end = .; _sdata = .; RO_DATA(PAGE_SIZE) From b7423bb23cdd0ee4850279742158a64a4bb25ef0 Mon Sep 17 00:00:00 2001 From: Maxim Devaev Date: Sat, 23 Jul 2022 13:14:32 +0300 Subject: [PATCH 1239/1436] USB: docs: fixed table margin in configfs-usb-gadget-mass-storage After merging forced_eject patch, there was a broken margin in the configfs parameters table in the ABI documentation. This patch fixes it. Fixes: 421c8d9a20da ("usb: gadget: f_mass_storage: forced_eject attribute") Reported-by: Stephen Rothwell Signed-off-by: Maxim Devaev Link: https://lore.kernel.org/r/20220723101432.72178-1-mdevaev@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/configfs-usb-gadget-mass-storage | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-mass-storage b/Documentation/ABI/testing/configfs-usb-gadget-mass-storage index d899adb57e81..fc0328069267 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-mass-storage +++ b/Documentation/ABI/testing/configfs-usb-gadget-mass-storage @@ -19,7 +19,7 @@ KernelVersion: 3.13 Description: The attributes: - =========== ============================================== + ============ ============================================== file The path to the backing file for the LUN. Required if LUN is not marked as removable. ro Flag specifying access to the LUN shall be @@ -38,4 +38,4 @@ Description: regardless of whether the host has allowed it. Any non-zero number of bytes written will result in ejection. - =========== ============================================== + ============ ============================================== From 1a9c9657ba095e3b330daaef75e53329aa989195 Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Sat, 23 Jul 2022 11:40:32 +0530 Subject: [PATCH 1240/1436] HID: amd_sfh: Fix implicit declaration error on i386 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add depended header file to fix error on i386 due to implicit declaration of function ‘writeq’. Fixes: 93ce5e0231d7 ("HID: amd_sfh: Implement SFH1.1 functionality") Reported-by: Randy Dunlap Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c index 14a1578055b6..c6df959ec725 100644 --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c @@ -7,7 +7,9 @@ * * Author: Basavaraj Natikar */ +#include #include + #include "amd_sfh_interface.h" static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id) From 5d4d0f15657535f6a122ab26d47230b5c2b944af Mon Sep 17 00:00:00 2001 From: Basavaraj Natikar Date: Sat, 23 Jul 2022 11:40:33 +0530 Subject: [PATCH 1241/1436] HID: amd_sfh: Handle condition of "no sensors" Add a check for num_hid_devices to handle special case the situation of "no sensors". Fixes: 4b2c53d93a4b ("SFH:Transport Driver to add support of AMD Sensor Fusion Hub (SFH)") Signed-off-by: Basavaraj Natikar Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index f95e623040f3..8275bba63611 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -225,6 +225,8 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) mp2_ops->resume = amd_sfh_resume; cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]); + if (cl_data->num_hid_devices == 0) + return -ENODEV; INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); From b4023554b1fb49f73a09e5f346a5facbf27d7383 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 25 Jul 2022 09:58:35 +0200 Subject: [PATCH 1242/1436] USB: cdc: add control-signal defines Add defines for the Control Signal Bitmap Values from section 6.2.14 SetControlLineState of the CDC specification version 1.1. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220725075841.1187-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/usb/cdc.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/uapi/linux/usb/cdc.h b/include/uapi/linux/usb/cdc.h index 6d61550959ef..372c81425cae 100644 --- a/include/uapi/linux/usb/cdc.h +++ b/include/uapi/linux/usb/cdc.h @@ -271,6 +271,10 @@ struct usb_cdc_line_coding { __u8 bDataBits; } __attribute__ ((packed)); +/* Control Signal Bitmap Values from 6.2.14 SetControlLineState */ +#define USB_CDC_CTRL_DTR (1 << 0) +#define USB_CDC_CTRL_RTS (1 << 1) + /* table 62; bits in multicast filter */ #define USB_CDC_PACKET_TYPE_PROMISCUOUS (1 << 0) #define USB_CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */ From a0a3202b44a9fdf2a1f6330a0d176aee76c8631d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 25 Jul 2022 09:58:36 +0200 Subject: [PATCH 1243/1436] USB: cdc: add serial-state defines Add defines for the serial-state bitmap values from section 6.3.5 SerialState of the CDC specification version 1.1. Note that the bTxCarrier and bRxCarrier bits have been named after their RS-232 signal equivalents DSR and DCD. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220725075841.1187-3-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/usb/cdc.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/uapi/linux/usb/cdc.h b/include/uapi/linux/usb/cdc.h index 372c81425cae..78caa9bdc4ae 100644 --- a/include/uapi/linux/usb/cdc.h +++ b/include/uapi/linux/usb/cdc.h @@ -306,6 +306,15 @@ struct usb_cdc_notification { __le16 wLength; } __attribute__ ((packed)); +/* UART State Bitmap Values from 6.3.5 SerialState */ +#define USB_CDC_SERIAL_STATE_DCD (1 << 0) +#define USB_CDC_SERIAL_STATE_DSR (1 << 1) +#define USB_CDC_SERIAL_STATE_BREAK (1 << 2) +#define USB_CDC_SERIAL_STATE_RING_SIGNAL (1 << 3) +#define USB_CDC_SERIAL_STATE_FRAMING (1 << 4) +#define USB_CDC_SERIAL_STATE_PARITY (1 << 5) +#define USB_CDC_SERIAL_STATE_OVERRUN (1 << 6) + struct usb_cdc_speed_change { __le32 DLBitRRate; /* contains the downlink bit rate (IN pipe) */ __le32 ULBitRate; /* contains the uplink bit rate (OUT pipe) */ From 3fb975e66ce2c6eb50e8ad1963c19bee20302757 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 25 Jul 2022 09:58:37 +0200 Subject: [PATCH 1244/1436] USB: cdc-acm: use CDC control-line defines Use the new CDC control-line defines. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220725075841.1187-4-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 18 +++++++++--------- drivers/usb/class/cdc-acm.h | 7 ------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index fedf3065670e..741c8cd213cc 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -658,7 +658,7 @@ static void acm_port_dtr_rts(struct tty_port *port, int raise) int res; if (raise) - val = ACM_CTRL_DTR | ACM_CTRL_RTS; + val = USB_CDC_CTRL_DTR | USB_CDC_CTRL_RTS; else val = 0; @@ -903,8 +903,8 @@ static int acm_tty_tiocmget(struct tty_struct *tty) { struct acm *acm = tty->driver_data; - return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) | - (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) | + return (acm->ctrlout & USB_CDC_CTRL_DTR ? TIOCM_DTR : 0) | + (acm->ctrlout & USB_CDC_CTRL_RTS ? TIOCM_RTS : 0) | (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) | (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) | @@ -918,10 +918,10 @@ static int acm_tty_tiocmset(struct tty_struct *tty, unsigned int newctrl; newctrl = acm->ctrlout; - set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) | - (set & TIOCM_RTS ? ACM_CTRL_RTS : 0); - clear = (clear & TIOCM_DTR ? ACM_CTRL_DTR : 0) | - (clear & TIOCM_RTS ? ACM_CTRL_RTS : 0); + set = (set & TIOCM_DTR ? USB_CDC_CTRL_DTR : 0) | + (set & TIOCM_RTS ? USB_CDC_CTRL_RTS : 0); + clear = (clear & TIOCM_DTR ? USB_CDC_CTRL_DTR : 0) | + (clear & TIOCM_RTS ? USB_CDC_CTRL_RTS : 0); newctrl = (newctrl & ~clear) | set; @@ -1068,9 +1068,9 @@ static void acm_tty_set_termios(struct tty_struct *tty, if (C_BAUD(tty) == B0) { newline.dwDTERate = acm->line.dwDTERate; - newctrl &= ~ACM_CTRL_DTR; + newctrl &= ~USB_CDC_CTRL_DTR; } else if (termios_old && (termios_old->c_cflag & CBAUD) == B0) { - newctrl |= ACM_CTRL_DTR; + newctrl |= USB_CDC_CTRL_DTR; } if (newctrl != acm->ctrlout) diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index d26ecd15be60..da7e8b8aaf28 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -22,13 +22,6 @@ #define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE) -/* - * Output control lines. - */ - -#define ACM_CTRL_DTR 0x01 -#define ACM_CTRL_RTS 0x02 - /* * Input control lines and line errors. */ From 7333c87f7829dee2545fa5ba6476e971973263a0 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 25 Jul 2022 09:58:38 +0200 Subject: [PATCH 1245/1436] USB: cdc-acm: use CDC serial-state defines Use the new CDC serial-state defines. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220725075841.1187-5-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 24 ++++++++++++------------ drivers/usb/class/cdc-acm.h | 13 ------------- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 741c8cd213cc..483bcb1213f7 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -311,7 +311,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) dev_dbg(&acm->control->dev, "%s - serial state: 0x%x\n", __func__, newctrl); - if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { + if (!acm->clocal && (acm->ctrlin & ~newctrl & USB_CDC_SERIAL_STATE_DCD)) { dev_dbg(&acm->control->dev, "%s - calling hangup\n", __func__); tty_port_tty_hangup(&acm->port, false); @@ -322,25 +322,25 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) acm->ctrlin = newctrl; acm->oldcount = acm->iocount; - if (difference & ACM_CTRL_DSR) + if (difference & USB_CDC_SERIAL_STATE_DSR) acm->iocount.dsr++; - if (difference & ACM_CTRL_DCD) + if (difference & USB_CDC_SERIAL_STATE_DCD) acm->iocount.dcd++; - if (newctrl & ACM_CTRL_BRK) { + if (newctrl & USB_CDC_SERIAL_STATE_BREAK) { acm->iocount.brk++; tty_insert_flip_char(&acm->port, 0, TTY_BREAK); } - if (newctrl & ACM_CTRL_RI) + if (newctrl & USB_CDC_SERIAL_STATE_RING_SIGNAL) acm->iocount.rng++; - if (newctrl & ACM_CTRL_FRAMING) + if (newctrl & USB_CDC_SERIAL_STATE_FRAMING) acm->iocount.frame++; - if (newctrl & ACM_CTRL_PARITY) + if (newctrl & USB_CDC_SERIAL_STATE_PARITY) acm->iocount.parity++; - if (newctrl & ACM_CTRL_OVERRUN) + if (newctrl & USB_CDC_SERIAL_STATE_OVERRUN) acm->iocount.overrun++; spin_unlock_irqrestore(&acm->read_lock, flags); - if (newctrl & ACM_CTRL_BRK) + if (newctrl & USB_CDC_SERIAL_STATE_BREAK) tty_flip_buffer_push(&acm->port); if (difference) @@ -905,9 +905,9 @@ static int acm_tty_tiocmget(struct tty_struct *tty) return (acm->ctrlout & USB_CDC_CTRL_DTR ? TIOCM_DTR : 0) | (acm->ctrlout & USB_CDC_CTRL_RTS ? TIOCM_RTS : 0) | - (acm->ctrlin & ACM_CTRL_DSR ? TIOCM_DSR : 0) | - (acm->ctrlin & ACM_CTRL_RI ? TIOCM_RI : 0) | - (acm->ctrlin & ACM_CTRL_DCD ? TIOCM_CD : 0) | + (acm->ctrlin & USB_CDC_SERIAL_STATE_DSR ? TIOCM_DSR : 0) | + (acm->ctrlin & USB_CDC_SERIAL_STATE_RING_SIGNAL ? TIOCM_RI : 0) | + (acm->ctrlin & USB_CDC_SERIAL_STATE_DCD ? TIOCM_CD : 0) | TIOCM_CTS; } diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index da7e8b8aaf28..759ac15631d3 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -22,19 +22,6 @@ #define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE) -/* - * Input control lines and line errors. - */ - -#define ACM_CTRL_DCD 0x01 -#define ACM_CTRL_DSR 0x02 -#define ACM_CTRL_BRK 0x04 -#define ACM_CTRL_RI 0x08 - -#define ACM_CTRL_FRAMING 0x10 -#define ACM_CTRL_PARITY 0x20 -#define ACM_CTRL_OVERRUN 0x40 - /* * Internal driver structures. */ From 0752670685c47203484731bdfae9607f4da735c4 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 25 Jul 2022 09:58:39 +0200 Subject: [PATCH 1246/1436] staging: gdm724x: drop unused CDC defines This driver has a copy of some of the CDC defines but which are currently unused. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220725075841.1187-6-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/staging/gdm724x/gdm_tty.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/staging/gdm724x/gdm_tty.c b/drivers/staging/gdm724x/gdm_tty.c index 04df6f9f5403..cc6d80554c98 100644 --- a/drivers/staging/gdm724x/gdm_tty.c +++ b/drivers/staging/gdm724x/gdm_tty.c @@ -17,12 +17,6 @@ #define GDM_TTY_MAJOR 0 #define GDM_TTY_MINOR 32 -#define ACM_CTRL_DTR 0x01 -#define ACM_CTRL_RTS 0x02 -#define ACM_CTRL_DSR 0x02 -#define ACM_CTRL_RI 0x08 -#define ACM_CTRL_DCD 0x01 - #define WRITE_SIZE 2048 #define MUX_TX_MAX_SIZE 2048 From f4beed1e91326630a4ec3fb2e209f06a7ca2e983 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 25 Jul 2022 09:58:40 +0200 Subject: [PATCH 1247/1436] USB: gadget: f_acm: use CDC defines Use the new CDC control-line and serial-state defines. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220725075841.1187-7-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_acm.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c index 411eb489e0ff..cb523f118f04 100644 --- a/drivers/usb/gadget/function/f_acm.c +++ b/drivers/usb/gadget/function/f_acm.c @@ -57,18 +57,8 @@ struct f_acm { /* SetControlLineState request -- CDC 1.1 section 6.2.14 (INPUT) */ u16 port_handshake_bits; -#define ACM_CTRL_RTS (1 << 1) /* unused with full duplex */ -#define ACM_CTRL_DTR (1 << 0) /* host is ready for data r/w */ - /* SerialState notification -- CDC 1.1 section 6.3.5 (OUTPUT) */ u16 serial_state; -#define ACM_CTRL_OVERRUN (1 << 6) -#define ACM_CTRL_PARITY (1 << 5) -#define ACM_CTRL_FRAMING (1 << 4) -#define ACM_CTRL_RI (1 << 3) -#define ACM_CTRL_BRK (1 << 2) -#define ACM_CTRL_DSR (1 << 1) -#define ACM_CTRL_DCD (1 << 0) }; static inline struct f_acm *func_to_acm(struct usb_function *f) @@ -387,7 +377,7 @@ static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) value = 0; /* FIXME we should not allow data to flow until the - * host sets the ACM_CTRL_DTR bit; and when it clears + * host sets the USB_CDC_CTRL_DTR bit; and when it clears * that bit, we should return to that no-flow state. */ acm->port_handshake_bits = w_value; @@ -585,7 +575,7 @@ static void acm_connect(struct gserial *port) { struct f_acm *acm = port_to_acm(port); - acm->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD; + acm->serial_state |= USB_CDC_SERIAL_STATE_DSR | USB_CDC_SERIAL_STATE_DCD; acm_notify_serial_state(acm); } @@ -593,7 +583,7 @@ static void acm_disconnect(struct gserial *port) { struct f_acm *acm = port_to_acm(port); - acm->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD); + acm->serial_state &= ~(USB_CDC_SERIAL_STATE_DSR | USB_CDC_SERIAL_STATE_DCD); acm_notify_serial_state(acm); } @@ -603,9 +593,9 @@ static int acm_send_break(struct gserial *port, int duration) u16 state; state = acm->serial_state; - state &= ~ACM_CTRL_BRK; + state &= ~USB_CDC_SERIAL_STATE_BREAK; if (duration) - state |= ACM_CTRL_BRK; + state |= USB_CDC_SERIAL_STATE_BREAK; acm->serial_state = state; return acm_notify_serial_state(acm); From d5e22360e907dbf570116c3c08be0d3e5be43a23 Mon Sep 17 00:00:00 2001 From: Yan Xinyu Date: Mon, 25 Jul 2022 09:58:41 +0200 Subject: [PATCH 1248/1436] USB: serial: usb_wwan: replace DTR/RTS magic numbers with macros The usb_wwan_send_setup function generates DTR/RTS signals in compliance with CDC ACM standard. This patch changes magic numbers in this function to equivalent macros. Link: https://lore.kernel.org/r/20220722085040.704885-1-sdlyyxy@bupt.edu.cn [ johan: use the new CDC control-line defines ] Signed-off-by: Yan Xinyu Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20220725075841.1187-8-johan@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb_wwan.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index dab38b63eaf7..6129a6e26f2c 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include "usb-wwan.h" @@ -48,9 +49,9 @@ static int usb_wwan_send_setup(struct usb_serial_port *port) portdata = usb_get_serial_port_data(port); if (portdata->dtr_state) - val |= 0x01; + val |= USB_CDC_CTRL_DTR; if (portdata->rts_state) - val |= 0x02; + val |= USB_CDC_CTRL_RTS; ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; @@ -59,8 +60,9 @@ static int usb_wwan_send_setup(struct usb_serial_port *port) return res; res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - 0x22, 0x21, val, ifnum, NULL, 0, - USB_CTRL_SET_TIMEOUT); + USB_CDC_REQ_SET_CONTROL_LINE_STATE, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + val, ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT); usb_autopm_put_interface(port->serial->interface); From 688ee1d1785c1359f9040f615dd8e6054962bce2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 25 Jul 2022 10:44:57 +0200 Subject: [PATCH 1249/1436] USB: serial: fix tty-port initialized comments Fix up the tty-port initialized comments which got truncated and obfuscated when replacing the old ASYNCB_INITIALIZED flag. Fixes: d41861ca19c9 ("tty: Replace ASYNC_INITIALIZED bit and update atomically") Reviewed-by: Greg Kroah-Hartman Signed-off-by: Johan Hovold --- drivers/usb/serial/sierra.c | 3 ++- drivers/usb/serial/usb-serial.c | 2 +- drivers/usb/serial/usb_wwan.c | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 525c7f888c90..353b2549eaa8 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -735,7 +735,8 @@ static void sierra_close(struct usb_serial_port *port) /* * Need to take susp_lock to make sure port is not already being - * resumed, but no need to hold it due to initialized + * resumed, but no need to hold it due to the tty-port initialized + * flag. */ spin_lock_irq(&intfdata->susp_lock); if (--intfdata->open_ports == 0) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 24101bd7fcad..e35bea2235c1 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -295,7 +295,7 @@ static int serial_open(struct tty_struct *tty, struct file *filp) * * Shut down a USB serial port. Serialized against activate by the * tport mutex and kept to matching open/close pairs - * of calls by the initialized flag. + * of calls by the tty-port initialized flag. * * Not called if tty is console. */ diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index dab38b63eaf7..cc81ab7ef4da 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -388,7 +388,8 @@ void usb_wwan_close(struct usb_serial_port *port) /* * Need to take susp_lock to make sure port is not already being - * resumed, but no need to hold it due to initialized + * resumed, but no need to hold it due to the tty-port initialized + * flag. */ spin_lock_irq(&intfdata->susp_lock); if (--intfdata->open_ports == 0) From f8a855ed8d07f6f11c6b0d6a692f0220c64f8c21 Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Fri, 22 Jul 2022 18:53:31 -0700 Subject: [PATCH 1250/1436] of/fdt: Clean up early_init_dt_reserve_memory_arch() As of commit 18250b43f7b6 ("of: fdt: Remove early_init_dt_reserve_memory_arch() override capability") this is no longer an arch hook, so rename it to remove the confusing _arch suffix. Also remove some unnecessary indirection from all but one of the callers by calling memblock_reserve() directly instead. Signed-off-by: Peter Collingbourne Link: https://linux-review.googlesource.com/id/I3362bdd92ae6e47e8f5bac01aa228d32f9d01aad Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220723015331.1607029-1-pcc@google.com --- drivers/of/fdt.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 4610729d2297..872b7b54e197 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -477,8 +477,8 @@ void *initial_boot_params __ro_after_init; static u32 of_fdt_crc32; -static int __init early_init_dt_reserve_memory_arch(phys_addr_t base, - phys_addr_t size, bool nomap) +static int __init early_init_dt_reserve_memory(phys_addr_t base, + phys_addr_t size, bool nomap) { if (nomap) { /* @@ -525,7 +525,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, size = dt_mem_next_cell(dt_root_size_cells, &prop); if (size && - early_init_dt_reserve_memory_arch(base, size, nomap) == 0) { + early_init_dt_reserve_memory(base, size, nomap) == 0) { pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %lu MiB\n", uname, &base, (unsigned long)(size / SZ_1M)); if (!nomap) @@ -644,7 +644,7 @@ void __init early_init_fdt_scan_reserved_mem(void) fdt_get_mem_rsv(initial_boot_params, n, &base, &size); if (!size) break; - early_init_dt_reserve_memory_arch(base, size, false); + memblock_reserve(base, size); } fdt_scan_reserved_mem(); @@ -661,9 +661,8 @@ void __init early_init_fdt_reserve_self(void) return; /* Reserve the dtb region */ - early_init_dt_reserve_memory_arch(__pa(initial_boot_params), - fdt_totalsize(initial_boot_params), - false); + memblock_reserve(__pa(initial_boot_params), + fdt_totalsize(initial_boot_params)); } /** From 91118fa994a9c9e38b6aed0a4081849886c37ade Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 19 Jul 2022 15:52:01 -0600 Subject: [PATCH 1251/1436] dt-bindings: panel: raydium,rm67191: Add missing type to 'video-mode' 'video-mode' is missing a type definition and is not a common property. The type is 'uint32'. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220719215201.1877997-1-robh@kernel.org --- .../devicetree/bindings/display/panel/raydium,rm67191.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm67191.yaml b/Documentation/devicetree/bindings/display/panel/raydium,rm67191.yaml index 617aa8c8c03a..d62fd692bf10 100644 --- a/Documentation/devicetree/bindings/display/panel/raydium,rm67191.yaml +++ b/Documentation/devicetree/bindings/display/panel/raydium,rm67191.yaml @@ -38,6 +38,7 @@ properties: 0 - burst-mode 1 - non-burst with sync event 2 - non-burst with sync pulse + $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1, 2] required: From 6bf212c89c48458d8deef1c973678c62528dab04 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:34 -0700 Subject: [PATCH 1252/1436] arm64: stacktrace: Add shared header for common stack unwinding code In order to reuse the arm64 stack unwinding logic for the nVHE hypervisor stack, move the common code to a shared header (arch/arm64/include/asm/stacktrace/common.h). The nVHE hypervisor cannot safely link against kernel code, so we make use of the shared header to avoid duplicated logic later in this series. Signed-off-by: Kalesh Singh Reviewed-by: Mark Brown Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-2-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace.h | 35 +------ arch/arm64/include/asm/stacktrace/common.h | 105 +++++++++++++++++++++ arch/arm64/kernel/stacktrace.c | 57 ----------- 3 files changed, 106 insertions(+), 91 deletions(-) create mode 100644 arch/arm64/include/asm/stacktrace/common.h diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h index aec9315bf156..79f455b37c84 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -8,52 +8,19 @@ #include #include #include -#include #include #include #include #include -enum stack_type { - STACK_TYPE_UNKNOWN, - STACK_TYPE_TASK, - STACK_TYPE_IRQ, - STACK_TYPE_OVERFLOW, - STACK_TYPE_SDEI_NORMAL, - STACK_TYPE_SDEI_CRITICAL, - __NR_STACK_TYPES -}; - -struct stack_info { - unsigned long low; - unsigned long high; - enum stack_type type; -}; +#include extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk, const char *loglvl); DECLARE_PER_CPU(unsigned long *, irq_stack_ptr); -static inline bool on_stack(unsigned long sp, unsigned long size, - unsigned long low, unsigned long high, - enum stack_type type, struct stack_info *info) -{ - if (!low) - return false; - - if (sp < low || sp + size < sp || sp + size > high) - return false; - - if (info) { - info->low = low; - info->high = high; - info->type = type; - } - return true; -} - static inline bool on_irq_stack(unsigned long sp, unsigned long size, struct stack_info *info) { diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h new file mode 100644 index 000000000000..64ae4f6b06fe --- /dev/null +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Common arm64 stack unwinder code. + * + * Copyright (C) 2012 ARM Ltd. + */ +#ifndef __ASM_STACKTRACE_COMMON_H +#define __ASM_STACKTRACE_COMMON_H + +#include +#include +#include + +enum stack_type { + STACK_TYPE_UNKNOWN, + STACK_TYPE_TASK, + STACK_TYPE_IRQ, + STACK_TYPE_OVERFLOW, + STACK_TYPE_SDEI_NORMAL, + STACK_TYPE_SDEI_CRITICAL, + __NR_STACK_TYPES +}; + +struct stack_info { + unsigned long low; + unsigned long high; + enum stack_type type; +}; + +/* + * A snapshot of a frame record or fp/lr register values, along with some + * accounting information necessary for robust unwinding. + * + * @fp: The fp value in the frame record (or the real fp) + * @pc: The lr value in the frame record (or the real lr) + * + * @stacks_done: Stacks which have been entirely unwound, for which it is no + * longer valid to unwind to. + * + * @prev_fp: The fp that pointed to this frame record, or a synthetic value + * of 0. This is used to ensure that within a stack, each + * subsequent frame record is at an increasing address. + * @prev_type: The type of stack this frame record was on, or a synthetic + * value of STACK_TYPE_UNKNOWN. This is used to detect a + * transition from one stack to another. + * + * @kr_cur: When KRETPROBES is selected, holds the kretprobe instance + * associated with the most recently encountered replacement lr + * value. + * + * @task: The task being unwound. + */ +struct unwind_state { + unsigned long fp; + unsigned long pc; + DECLARE_BITMAP(stacks_done, __NR_STACK_TYPES); + unsigned long prev_fp; + enum stack_type prev_type; +#ifdef CONFIG_KRETPROBES + struct llist_node *kr_cur; +#endif + struct task_struct *task; +}; + +static inline bool on_stack(unsigned long sp, unsigned long size, + unsigned long low, unsigned long high, + enum stack_type type, struct stack_info *info) +{ + if (!low) + return false; + + if (sp < low || sp + size < sp || sp + size > high) + return false; + + if (info) { + info->low = low; + info->high = high; + info->type = type; + } + return true; +} + +static inline void unwind_init_common(struct unwind_state *state, + struct task_struct *task) +{ + state->task = task; +#ifdef CONFIG_KRETPROBES + state->kr_cur = NULL; +#endif + + /* + * Prime the first unwind. + * + * In unwind_next() we'll check that the FP points to a valid stack, + * which can't be STACK_TYPE_UNKNOWN, and the first unwind will be + * treated as a transition to whichever stack that happens to be. The + * prev_fp value won't be used, but we set it to 0 such that it is + * definitely not an accessible stack address. + */ + bitmap_zero(state->stacks_done, __NR_STACK_TYPES); + state->prev_fp = 0; + state->prev_type = STACK_TYPE_UNKNOWN; +} + +#endif /* __ASM_STACKTRACE_COMMON_H */ diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index fcaa151b81f1..94a5dd2ab8fd 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -18,63 +18,6 @@ #include #include -/* - * A snapshot of a frame record or fp/lr register values, along with some - * accounting information necessary for robust unwinding. - * - * @fp: The fp value in the frame record (or the real fp) - * @pc: The lr value in the frame record (or the real lr) - * - * @stacks_done: Stacks which have been entirely unwound, for which it is no - * longer valid to unwind to. - * - * @prev_fp: The fp that pointed to this frame record, or a synthetic value - * of 0. This is used to ensure that within a stack, each - * subsequent frame record is at an increasing address. - * @prev_type: The type of stack this frame record was on, or a synthetic - * value of STACK_TYPE_UNKNOWN. This is used to detect a - * transition from one stack to another. - * - * @kr_cur: When KRETPROBES is selected, holds the kretprobe instance - * associated with the most recently encountered replacement lr - * value. - * - * @task: The task being unwound. - */ -struct unwind_state { - unsigned long fp; - unsigned long pc; - DECLARE_BITMAP(stacks_done, __NR_STACK_TYPES); - unsigned long prev_fp; - enum stack_type prev_type; -#ifdef CONFIG_KRETPROBES - struct llist_node *kr_cur; -#endif - struct task_struct *task; -}; - -static void unwind_init_common(struct unwind_state *state, - struct task_struct *task) -{ - state->task = task; -#ifdef CONFIG_KRETPROBES - state->kr_cur = NULL; -#endif - - /* - * Prime the first unwind. - * - * In unwind_next() we'll check that the FP points to a valid stack, - * which can't be STACK_TYPE_UNKNOWN, and the first unwind will be - * treated as a transition to whichever stack that happens to be. The - * prev_fp value won't be used, but we set it to 0 such that it is - * definitely not an accessible stack address. - */ - bitmap_zero(state->stacks_done, __NR_STACK_TYPES); - state->prev_fp = 0; - state->prev_type = STACK_TYPE_UNKNOWN; -} - /* * Start an unwind from a pt_regs. * From 15a59f19a015185bff90a68f601caec151dea4b4 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:35 -0700 Subject: [PATCH 1253/1436] arm64: stacktrace: Factor out on_accessible_stack_common() Move common on_accessible_stack checks to stacktrace/common.h. This is used in the implementation of the nVHE hypervisor unwinder later in this series. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Reviewed-by: Mark Brown Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-3-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace.h | 6 ++---- arch/arm64/include/asm/stacktrace/common.h | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h index 79f455b37c84..43f4b4a6d383 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -65,8 +65,8 @@ static inline bool on_accessible_stack(const struct task_struct *tsk, unsigned long sp, unsigned long size, struct stack_info *info) { - if (info) - info->type = STACK_TYPE_UNKNOWN; + if (on_accessible_stack_common(tsk, sp, size, info)) + return true; if (on_task_stack(tsk, sp, size, info)) return true; @@ -74,8 +74,6 @@ static inline bool on_accessible_stack(const struct task_struct *tsk, return false; if (on_irq_stack(sp, size, info)) return true; - if (on_overflow_stack(sp, size, info)) - return true; if (on_sdei_stack(sp, size, info)) return true; diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h index 64ae4f6b06fe..f58b786460d3 100644 --- a/arch/arm64/include/asm/stacktrace/common.h +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -62,6 +62,9 @@ struct unwind_state { struct task_struct *task; }; +static inline bool on_overflow_stack(unsigned long sp, unsigned long size, + struct stack_info *info); + static inline bool on_stack(unsigned long sp, unsigned long size, unsigned long low, unsigned long high, enum stack_type type, struct stack_info *info) @@ -80,6 +83,21 @@ static inline bool on_stack(unsigned long sp, unsigned long size, return true; } +static inline bool on_accessible_stack_common(const struct task_struct *tsk, + unsigned long sp, + unsigned long size, + struct stack_info *info) +{ + if (info) + info->type = STACK_TYPE_UNKNOWN; + + /* + * Both the kernel and nvhe hypervisor make use of + * an overflow_stack + */ + return on_overflow_stack(sp, size, info); +} + static inline void unwind_init_common(struct unwind_state *state, struct task_struct *task) { From be63c647fd28d25484257f5f36a008db7d99991d Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:36 -0700 Subject: [PATCH 1254/1436] arm64: stacktrace: Factor out unwind_next_common() Move common unwind_next logic to stacktrace/common.h. This allows reusing the code in the implementation the nVHE hypervisor stack unwinder, later in this series. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Reviewed-by: Mark Brown Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-4-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace/common.h | 50 ++++++++++++++++++++++ arch/arm64/kernel/stacktrace.c | 41 ++---------------- 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h index f58b786460d3..0c5cbfdb56b5 100644 --- a/arch/arm64/include/asm/stacktrace/common.h +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -65,6 +65,10 @@ struct unwind_state { static inline bool on_overflow_stack(unsigned long sp, unsigned long size, struct stack_info *info); +static inline bool on_accessible_stack(const struct task_struct *tsk, + unsigned long sp, unsigned long size, + struct stack_info *info); + static inline bool on_stack(unsigned long sp, unsigned long size, unsigned long low, unsigned long high, enum stack_type type, struct stack_info *info) @@ -120,4 +124,50 @@ static inline void unwind_init_common(struct unwind_state *state, state->prev_type = STACK_TYPE_UNKNOWN; } +static inline int unwind_next_common(struct unwind_state *state, + struct stack_info *info) +{ + struct task_struct *tsk = state->task; + unsigned long fp = state->fp; + + if (fp & 0x7) + return -EINVAL; + + if (!on_accessible_stack(tsk, fp, 16, info)) + return -EINVAL; + + if (test_bit(info->type, state->stacks_done)) + return -EINVAL; + + /* + * As stacks grow downward, any valid record on the same stack must be + * at a strictly higher address than the prior record. + * + * Stacks can nest in several valid orders, e.g. + * + * TASK -> IRQ -> OVERFLOW -> SDEI_NORMAL + * TASK -> SDEI_NORMAL -> SDEI_CRITICAL -> OVERFLOW + * + * ... but the nesting itself is strict. Once we transition from one + * stack to another, it's never valid to unwind back to that first + * stack. + */ + if (info->type == state->prev_type) { + if (fp <= state->prev_fp) + return -EINVAL; + } else { + __set_bit(state->prev_type, state->stacks_done); + } + + /* + * Record this frame record's values and location. The prev_fp and + * prev_type are only meaningful to the next unwind_next() invocation. + */ + state->fp = READ_ONCE(*(unsigned long *)(fp)); + state->pc = READ_ONCE(*(unsigned long *)(fp + 8)); + state->prev_fp = fp; + state->prev_type = info->type; + + return 0; +} #endif /* __ASM_STACKTRACE_COMMON_H */ diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 94a5dd2ab8fd..834851939364 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -81,48 +81,15 @@ static int notrace unwind_next(struct unwind_state *state) struct task_struct *tsk = state->task; unsigned long fp = state->fp; struct stack_info info; + int err; /* Final frame; nothing to unwind */ if (fp == (unsigned long)task_pt_regs(tsk)->stackframe) return -ENOENT; - if (fp & 0x7) - return -EINVAL; - - if (!on_accessible_stack(tsk, fp, 16, &info)) - return -EINVAL; - - if (test_bit(info.type, state->stacks_done)) - return -EINVAL; - - /* - * As stacks grow downward, any valid record on the same stack must be - * at a strictly higher address than the prior record. - * - * Stacks can nest in several valid orders, e.g. - * - * TASK -> IRQ -> OVERFLOW -> SDEI_NORMAL - * TASK -> SDEI_NORMAL -> SDEI_CRITICAL -> OVERFLOW - * - * ... but the nesting itself is strict. Once we transition from one - * stack to another, it's never valid to unwind back to that first - * stack. - */ - if (info.type == state->prev_type) { - if (fp <= state->prev_fp) - return -EINVAL; - } else { - __set_bit(state->prev_type, state->stacks_done); - } - - /* - * Record this frame record's values and location. The prev_fp and - * prev_type are only meaningful to the next unwind_next() invocation. - */ - state->fp = READ_ONCE(*(unsigned long *)(fp)); - state->pc = READ_ONCE(*(unsigned long *)(fp + 8)); - state->prev_fp = fp; - state->prev_type = info.type; + err = unwind_next_common(state, &info); + if (err) + return err; state->pc = ptrauth_strip_insn_pac(state->pc); From 5b1b08619f50422c3e43d1fd7af257595a9e4a67 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:37 -0700 Subject: [PATCH 1255/1436] arm64: stacktrace: Handle frame pointer from different address spaces The unwinder code is made reusable so that it can be used to unwind various types of stacks. One usecase is unwinding the nVHE hyp stack from the host (EL1) in non-protected mode. This means that the unwinder must be able to translate HYP stack addresses to kernel addresses. Add a callback (stack_trace_translate_fp_fn) to allow specifying the translation function. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-5-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace/common.h | 29 +++++++++++++++++++--- arch/arm64/kernel/stacktrace.c | 2 +- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h index 0c5cbfdb56b5..b241edba5c76 100644 --- a/arch/arm64/include/asm/stacktrace/common.h +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -124,11 +124,25 @@ static inline void unwind_init_common(struct unwind_state *state, state->prev_type = STACK_TYPE_UNKNOWN; } +/* + * stack_trace_translate_fp_fn() - Translates a non-kernel frame pointer to + * a kernel address. + * + * @fp: the frame pointer to be updated to its kernel address. + * @type: the stack type associated with frame pointer @fp + * + * Returns true and success and @fp is updated to the corresponding + * kernel virtual address; otherwise returns false. + */ +typedef bool (*stack_trace_translate_fp_fn)(unsigned long *fp, + enum stack_type type); + static inline int unwind_next_common(struct unwind_state *state, - struct stack_info *info) + struct stack_info *info, + stack_trace_translate_fp_fn translate_fp) { + unsigned long fp = state->fp, kern_fp = fp; struct task_struct *tsk = state->task; - unsigned long fp = state->fp; if (fp & 0x7) return -EINVAL; @@ -139,6 +153,13 @@ static inline int unwind_next_common(struct unwind_state *state, if (test_bit(info->type, state->stacks_done)) return -EINVAL; + /* + * If fp is not from the current address space perform the necessary + * translation before dereferencing it to get the next fp. + */ + if (translate_fp && !translate_fp(&kern_fp, info->type)) + return -EINVAL; + /* * As stacks grow downward, any valid record on the same stack must be * at a strictly higher address than the prior record. @@ -163,8 +184,8 @@ static inline int unwind_next_common(struct unwind_state *state, * Record this frame record's values and location. The prev_fp and * prev_type are only meaningful to the next unwind_next() invocation. */ - state->fp = READ_ONCE(*(unsigned long *)(fp)); - state->pc = READ_ONCE(*(unsigned long *)(fp + 8)); + state->fp = READ_ONCE(*(unsigned long *)(kern_fp)); + state->pc = READ_ONCE(*(unsigned long *)(kern_fp + 8)); state->prev_fp = fp; state->prev_type = info->type; diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 834851939364..eef3cf6bf2d7 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -87,7 +87,7 @@ static int notrace unwind_next(struct unwind_state *state) if (fp == (unsigned long)task_pt_regs(tsk)->stackframe) return -ENOENT; - err = unwind_next_common(state, &info); + err = unwind_next_common(state, &info, NULL); if (err) return err; From f51e7146740514347d6c5526a2c393e224a19c0d Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:38 -0700 Subject: [PATCH 1256/1436] arm64: stacktrace: Factor out common unwind() Move unwind() to stacktrace/common.h, and as a result the kernel unwind_next() to asm/stacktrace.h. This allow reusing unwind() in the implementation of the nVHE HYP stack unwinder, later in the series. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Reviewed-by: Mark Brown Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-6-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace.h | 51 ++++++++++++++++ arch/arm64/include/asm/stacktrace/common.h | 19 ++++++ arch/arm64/kernel/stacktrace.c | 67 ---------------------- 3 files changed, 70 insertions(+), 67 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h index 43f4b4a6d383..ea828579a98b 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -80,4 +81,54 @@ static inline bool on_accessible_stack(const struct task_struct *tsk, return false; } +/* + * Unwind from one frame record (A) to the next frame record (B). + * + * We terminate early if the location of B indicates a malformed chain of frame + * records (e.g. a cycle), determined based on the location and fp value of A + * and the location (but not the fp value) of B. + */ +static inline int notrace unwind_next(struct unwind_state *state) +{ + struct task_struct *tsk = state->task; + unsigned long fp = state->fp; + struct stack_info info; + int err; + + /* Final frame; nothing to unwind */ + if (fp == (unsigned long)task_pt_regs(tsk)->stackframe) + return -ENOENT; + + err = unwind_next_common(state, &info, NULL); + if (err) + return err; + + state->pc = ptrauth_strip_insn_pac(state->pc); + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + if (tsk->ret_stack && + (state->pc == (unsigned long)return_to_handler)) { + unsigned long orig_pc; + /* + * This is a case where function graph tracer has + * modified a return address (LR) in a stack frame + * to hook a function return. + * So replace it to an original value. + */ + orig_pc = ftrace_graph_ret_addr(tsk, NULL, state->pc, + (void *)state->fp); + if (WARN_ON_ONCE(state->pc == orig_pc)) + return -EINVAL; + state->pc = orig_pc; + } +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +#ifdef CONFIG_KRETPROBES + if (is_kretprobe_trampoline(state->pc)) + state->pc = kretprobe_find_ret_addr(tsk, (void *)state->fp, &state->kr_cur); +#endif + + return 0; +} +NOKPROBE_SYMBOL(unwind_next); + #endif /* __ASM_STACKTRACE_H */ diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h index b241edba5c76..4b632141d91c 100644 --- a/arch/arm64/include/asm/stacktrace/common.h +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -9,6 +9,7 @@ #include #include +#include #include enum stack_type { @@ -69,6 +70,8 @@ static inline bool on_accessible_stack(const struct task_struct *tsk, unsigned long sp, unsigned long size, struct stack_info *info); +static inline int unwind_next(struct unwind_state *state); + static inline bool on_stack(unsigned long sp, unsigned long size, unsigned long low, unsigned long high, enum stack_type type, struct stack_info *info) @@ -191,4 +194,20 @@ static inline int unwind_next_common(struct unwind_state *state, return 0; } + +static inline void notrace unwind(struct unwind_state *state, + stack_trace_consume_fn consume_entry, + void *cookie) +{ + while (1) { + int ret; + + if (!consume_entry(cookie, state->pc)) + break; + ret = unwind_next(state); + if (ret < 0) + break; + } +} +NOKPROBE_SYMBOL(unwind); #endif /* __ASM_STACKTRACE_COMMON_H */ diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index eef3cf6bf2d7..9fa60ee48499 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -7,14 +7,12 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include @@ -69,71 +67,6 @@ static inline void unwind_init_from_task(struct unwind_state *state, state->pc = thread_saved_pc(task); } -/* - * Unwind from one frame record (A) to the next frame record (B). - * - * We terminate early if the location of B indicates a malformed chain of frame - * records (e.g. a cycle), determined based on the location and fp value of A - * and the location (but not the fp value) of B. - */ -static int notrace unwind_next(struct unwind_state *state) -{ - struct task_struct *tsk = state->task; - unsigned long fp = state->fp; - struct stack_info info; - int err; - - /* Final frame; nothing to unwind */ - if (fp == (unsigned long)task_pt_regs(tsk)->stackframe) - return -ENOENT; - - err = unwind_next_common(state, &info, NULL); - if (err) - return err; - - state->pc = ptrauth_strip_insn_pac(state->pc); - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - if (tsk->ret_stack && - (state->pc == (unsigned long)return_to_handler)) { - unsigned long orig_pc; - /* - * This is a case where function graph tracer has - * modified a return address (LR) in a stack frame - * to hook a function return. - * So replace it to an original value. - */ - orig_pc = ftrace_graph_ret_addr(tsk, NULL, state->pc, - (void *)state->fp); - if (WARN_ON_ONCE(state->pc == orig_pc)) - return -EINVAL; - state->pc = orig_pc; - } -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -#ifdef CONFIG_KRETPROBES - if (is_kretprobe_trampoline(state->pc)) - state->pc = kretprobe_find_ret_addr(tsk, (void *)state->fp, &state->kr_cur); -#endif - - return 0; -} -NOKPROBE_SYMBOL(unwind_next); - -static void notrace unwind(struct unwind_state *state, - stack_trace_consume_fn consume_entry, void *cookie) -{ - while (1) { - int ret; - - if (!consume_entry(cookie, state->pc)) - break; - ret = unwind_next(state); - if (ret < 0) - break; - } -} -NOKPROBE_SYMBOL(unwind); - static bool dump_backtrace_entry(void *arg, unsigned long where) { char *loglvl = arg; From 051ece6758cc10c2a6f1700ffe86d23fbb0b2553 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:39 -0700 Subject: [PATCH 1257/1436] arm64: stacktrace: Add description of stacktrace/common.h Add brief description on how to use stacktrace/common.h to implement a stack unwinder. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-7-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace/common.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h index 4b632141d91c..45474b383630 100644 --- a/arch/arm64/include/asm/stacktrace/common.h +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -2,6 +2,21 @@ /* * Common arm64 stack unwinder code. * + * To implement a new arm64 stack unwinder: + * 1) Include this header + * + * 2) Provide implementations for the following functions: + * on_overflow_stack(): Returns true if SP is on the overflow + * stack. + * on_accessible_stack(): Returns true is SP is on any accessible + * stack. + * unwind_next(): Performs validation checks on the frame + * pointer, and transitions unwind_state + * to the next frame. + * + * See: arch/arm64/include/asm/stacktrace.h for reference + * implementations. + * * Copyright (C) 2012 ARM Ltd. */ #ifndef __ASM_STACKTRACE_COMMON_H From 548ec3336f323db56260b312c232ab37285f0284 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:40 -0700 Subject: [PATCH 1258/1436] KVM: arm64: On stack overflow switch to hyp overflow_stack On hyp stack overflow switch to 16-byte aligned secondary stack. This provides us stack space to better handle overflows; and is used in a subsequent patch to dump the hypervisor stacktrace. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-8-kaleshsingh@google.com --- arch/arm64/kvm/hyp/nvhe/Makefile | 2 +- arch/arm64/kvm/hyp/nvhe/host.S | 9 ++------- arch/arm64/kvm/hyp/nvhe/stacktrace.c | 11 +++++++++++ 3 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 arch/arm64/kvm/hyp/nvhe/stacktrace.c diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile index f9fe4dc21b1f..524e7dad5739 100644 --- a/arch/arm64/kvm/hyp/nvhe/Makefile +++ b/arch/arm64/kvm/hyp/nvhe/Makefile @@ -14,7 +14,7 @@ lib-objs := $(addprefix ../../../lib/, $(lib-objs)) obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o \ hyp-main.o hyp-smp.o psci-relay.o early_alloc.o page_alloc.o \ - cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o + cache.o setup.o mm.o mem_protect.o sys_regs.o pkvm.o stacktrace.o obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \ ../fpsimd.o ../hyp-entry.o ../exception.o ../pgtable.o obj-$(CONFIG_DEBUG_LIST) += list_debug.o diff --git a/arch/arm64/kvm/hyp/nvhe/host.S b/arch/arm64/kvm/hyp/nvhe/host.S index ea6a397b64a6..b6c0188c4b35 100644 --- a/arch/arm64/kvm/hyp/nvhe/host.S +++ b/arch/arm64/kvm/hyp/nvhe/host.S @@ -177,13 +177,8 @@ SYM_FUNC_END(__host_hvc) b hyp_panic .L__hyp_sp_overflow\@: - /* - * Reset SP to the top of the stack, to allow handling the hyp_panic. - * This corrupts the stack but is ok, since we won't be attempting - * any unwinding here. - */ - ldr_this_cpu x0, kvm_init_params + NVHE_INIT_STACK_HYP_VA, x1 - mov sp, x0 + /* Switch to the overflow stack */ + adr_this_cpu sp, overflow_stack + OVERFLOW_STACK_SIZE, x0 b hyp_panic_bad_stack ASM_BUG() diff --git a/arch/arm64/kvm/hyp/nvhe/stacktrace.c b/arch/arm64/kvm/hyp/nvhe/stacktrace.c new file mode 100644 index 000000000000..a3d5b34e1249 --- /dev/null +++ b/arch/arm64/kvm/hyp/nvhe/stacktrace.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KVM nVHE hypervisor stack tracing support. + * + * Copyright (C) 2022 Google LLC + */ +#include +#include + +DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack) + __aligned(16); From 573e1e8275f7167ddd533c6e4e0f500f8be4d974 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:41 -0700 Subject: [PATCH 1259/1436] KVM: arm64: Stub implementation of non-protected nVHE HYP stack unwinder Add stub implementations of non-protected nVHE stack unwinder, for building. These are implemented later in this series. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-9-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace/nvhe.h | 47 ++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 arch/arm64/include/asm/stacktrace/nvhe.h diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h new file mode 100644 index 000000000000..1192ae0f80c1 --- /dev/null +++ b/arch/arm64/include/asm/stacktrace/nvhe.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * KVM nVHE hypervisor stack tracing support. + * + * The unwinder implementation depends on the nVHE mode: + * + * 1) Non-protected nVHE mode - the host can directly access the + * HYP stack pages and unwind the HYP stack in EL1. This saves having + * to allocate shared buffers for the host to read the unwinded + * stacktrace. + * + * Copyright (C) 2022 Google LLC + */ +#ifndef __ASM_STACKTRACE_NVHE_H +#define __ASM_STACKTRACE_NVHE_H + +#include + +static inline bool on_accessible_stack(const struct task_struct *tsk, + unsigned long sp, unsigned long size, + struct stack_info *info) +{ + return false; +} + +#ifndef __KVM_NVHE_HYPERVISOR__ +/* + * Conventional (non-protected) nVHE HYP stack unwinder + * + * In non-protected mode, the unwinding is done from kernel proper context + * (by the host in EL1). + */ + +static inline bool on_overflow_stack(unsigned long sp, unsigned long size, + struct stack_info *info) +{ + return false; +} + +static inline int notrace unwind_next(struct unwind_state *state) +{ + return 0; +} +NOKPROBE_SYMBOL(unwind_next); + +#endif /* !__KVM_NVHE_HYPERVISOR__ */ +#endif /* __ASM_STACKTRACE_NVHE_H */ From 879e5ac7b2e4db05799a905b5a07fc9e5dedf651 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:42 -0700 Subject: [PATCH 1260/1436] KVM: arm64: Prepare non-protected nVHE hypervisor stacktrace In non-protected nVHE mode (non-pKVM) the host can directly access hypervisor memory; and unwinding of the hypervisor stacktrace is done from EL1 to save on memory for shared buffers. To unwind the hypervisor stack from EL1 the host needs to know the starting point for the unwind and information that will allow it to translate hypervisor stack addresses to the corresponding kernel addresses. This patch sets up this book keeping. It is made use of later in the series. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-10-kaleshsingh@google.com --- arch/arm64/include/asm/kvm_asm.h | 16 +++++++++++ arch/arm64/kvm/hyp/nvhe/stacktrace.c | 41 ++++++++++++++++++++++++++++ arch/arm64/kvm/hyp/nvhe/switch.c | 6 ++++ 3 files changed, 63 insertions(+) diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 2e277f2ed671..53035763e48e 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -176,6 +176,22 @@ struct kvm_nvhe_init_params { unsigned long vtcr; }; +/* + * Used by the host in EL1 to dump the nVHE hypervisor backtrace on + * hyp_panic() in non-protected mode. + * + * @stack_base: hyp VA of the hyp_stack base. + * @overflow_stack_base: hyp VA of the hyp_overflow_stack base. + * @fp: hyp FP where the backtrace begins. + * @pc: hyp PC where the backtrace begins. + */ +struct kvm_nvhe_stacktrace_info { + unsigned long stack_base; + unsigned long overflow_stack_base; + unsigned long fp; + unsigned long pc; +}; + /* Translate a kernel address @ptr into its equivalent linear mapping */ #define kvm_ksym_ref(ptr) \ ({ \ diff --git a/arch/arm64/kvm/hyp/nvhe/stacktrace.c b/arch/arm64/kvm/hyp/nvhe/stacktrace.c index a3d5b34e1249..b8a280aa026a 100644 --- a/arch/arm64/kvm/hyp/nvhe/stacktrace.c +++ b/arch/arm64/kvm/hyp/nvhe/stacktrace.c @@ -4,8 +4,49 @@ * * Copyright (C) 2022 Google LLC */ +#include +#include #include #include DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack) __aligned(16); + +DEFINE_PER_CPU(struct kvm_nvhe_stacktrace_info, kvm_stacktrace_info); + +/* + * hyp_prepare_backtrace - Prepare non-protected nVHE backtrace. + * + * @fp : frame pointer at which to start the unwinding. + * @pc : program counter at which to start the unwinding. + * + * Save the information needed by the host to unwind the non-protected + * nVHE hypervisor stack in EL1. + */ +static void hyp_prepare_backtrace(unsigned long fp, unsigned long pc) +{ + struct kvm_nvhe_stacktrace_info *stacktrace_info = this_cpu_ptr(&kvm_stacktrace_info); + struct kvm_nvhe_init_params *params = this_cpu_ptr(&kvm_init_params); + + stacktrace_info->stack_base = (unsigned long)(params->stack_hyp_va - PAGE_SIZE); + stacktrace_info->overflow_stack_base = (unsigned long)this_cpu_ptr(overflow_stack); + stacktrace_info->fp = fp; + stacktrace_info->pc = pc; +} + +/* + * kvm_nvhe_prepare_backtrace - prepare to dump the nVHE backtrace + * + * @fp : frame pointer at which to start the unwinding. + * @pc : program counter at which to start the unwinding. + * + * Saves the information needed by the host to dump the nVHE hypervisor + * backtrace. + */ +void kvm_nvhe_prepare_backtrace(unsigned long fp, unsigned long pc) +{ + if (is_protected_kvm_enabled()) + return; + else + hyp_prepare_backtrace(fp, pc); +} diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c index 6db801db8f27..64e13445d0d9 100644 --- a/arch/arm64/kvm/hyp/nvhe/switch.c +++ b/arch/arm64/kvm/hyp/nvhe/switch.c @@ -34,6 +34,8 @@ DEFINE_PER_CPU(struct kvm_host_data, kvm_host_data); DEFINE_PER_CPU(struct kvm_cpu_context, kvm_hyp_ctxt); DEFINE_PER_CPU(unsigned long, kvm_hyp_vector); +extern void kvm_nvhe_prepare_backtrace(unsigned long fp, unsigned long pc); + static void __activate_traps(struct kvm_vcpu *vcpu) { u64 val; @@ -375,6 +377,10 @@ asmlinkage void __noreturn hyp_panic(void) __sysreg_restore_state_nvhe(host_ctxt); } + /* Prepare to dump kvm nvhe hyp stacktrace */ + kvm_nvhe_prepare_backtrace((unsigned long)__builtin_frame_address(0), + _THIS_IP_); + __hyp_do_panic(host_ctxt, spsr, elr, par); unreachable(); } From db129d486ebdf4e3168282236f9d9008b42cac7e Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:43 -0700 Subject: [PATCH 1261/1436] KVM: arm64: Implement non-protected nVHE hyp stack unwinder Implements the common framework necessary for unwind() to work for non-protected nVHE mode: - on_accessible_stack() - on_overflow_stack() - unwind_next() Non-protected nVHE unwind() is used to unwind and dump the hypervisor stacktrace by the host in EL1 Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-11-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace/common.h | 2 + arch/arm64/include/asm/stacktrace/nvhe.h | 76 +++++++++++++++++++++- arch/arm64/kvm/arm.c | 2 +- 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h index 45474b383630..3ebb69ea374a 100644 --- a/arch/arm64/include/asm/stacktrace/common.h +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -34,6 +34,7 @@ enum stack_type { STACK_TYPE_OVERFLOW, STACK_TYPE_SDEI_NORMAL, STACK_TYPE_SDEI_CRITICAL, + STACK_TYPE_HYP, __NR_STACK_TYPES }; @@ -186,6 +187,7 @@ static inline int unwind_next_common(struct unwind_state *state, * * TASK -> IRQ -> OVERFLOW -> SDEI_NORMAL * TASK -> SDEI_NORMAL -> SDEI_CRITICAL -> OVERFLOW + * HYP -> OVERFLOW * * ... but the nesting itself is strict. Once we transition from one * stack to another, it's never valid to unwind back to that first diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h index 1192ae0f80c1..21082fd4a0b7 100644 --- a/arch/arm64/include/asm/stacktrace/nvhe.h +++ b/arch/arm64/include/asm/stacktrace/nvhe.h @@ -16,10 +16,19 @@ #include +static inline bool on_hyp_stack(unsigned long sp, unsigned long size, + struct stack_info *info); + static inline bool on_accessible_stack(const struct task_struct *tsk, unsigned long sp, unsigned long size, struct stack_info *info) { + if (on_accessible_stack_common(tsk, sp, size, info)) + return true; + + if (on_hyp_stack(sp, size, info)) + return true; + return false; } @@ -31,15 +40,78 @@ static inline bool on_accessible_stack(const struct task_struct *tsk, * (by the host in EL1). */ +DECLARE_KVM_NVHE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack); +DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_stacktrace_info, kvm_stacktrace_info); +DECLARE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); + +/* + * kvm_nvhe_stack_kern_va - Convert KVM nVHE HYP stack addresses to a kernel VAs + * + * The nVHE hypervisor stack is mapped in the flexible 'private' VA range, to + * allow for guard pages below the stack. Consequently, the fixed offset address + * translation macros won't work here. + * + * The kernel VA is calculated as an offset from the kernel VA of the hypervisor + * stack base. + * + * Returns true on success and updates @addr to its corresponding kernel VA; + * otherwise returns false. + */ +static inline bool kvm_nvhe_stack_kern_va(unsigned long *addr, + enum stack_type type) +{ + struct kvm_nvhe_stacktrace_info *stacktrace_info; + unsigned long hyp_base, kern_base, hyp_offset; + + stacktrace_info = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); + + switch (type) { + case STACK_TYPE_HYP: + kern_base = (unsigned long)*this_cpu_ptr(&kvm_arm_hyp_stack_page); + hyp_base = (unsigned long)stacktrace_info->stack_base; + break; + case STACK_TYPE_OVERFLOW: + kern_base = (unsigned long)this_cpu_ptr_nvhe_sym(overflow_stack); + hyp_base = (unsigned long)stacktrace_info->overflow_stack_base; + break; + default: + return false; + } + + hyp_offset = *addr - hyp_base; + + *addr = kern_base + hyp_offset; + + return true; +} + static inline bool on_overflow_stack(unsigned long sp, unsigned long size, struct stack_info *info) { - return false; + struct kvm_nvhe_stacktrace_info *stacktrace_info + = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); + unsigned long low = (unsigned long)stacktrace_info->overflow_stack_base; + unsigned long high = low + OVERFLOW_STACK_SIZE; + + return on_stack(sp, size, low, high, STACK_TYPE_OVERFLOW, info); +} + +static inline bool on_hyp_stack(unsigned long sp, unsigned long size, + struct stack_info *info) +{ + struct kvm_nvhe_stacktrace_info *stacktrace_info + = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); + unsigned long low = (unsigned long)stacktrace_info->stack_base; + unsigned long high = low + PAGE_SIZE; + + return on_stack(sp, size, low, high, STACK_TYPE_HYP, info); } static inline int notrace unwind_next(struct unwind_state *state) { - return 0; + struct stack_info info; + + return unwind_next_common(state, &info, kvm_nvhe_stack_kern_va); } NOKPROBE_SYMBOL(unwind_next); diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index a0188144a122..6a64293108c5 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -49,7 +49,7 @@ DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized); DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector); -static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); +DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); unsigned long kvm_arm_hyp_percpu_base[NR_CPUS]; DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params); From 314a61dc31845c233e47c53db3fe6f34284034f4 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:44 -0700 Subject: [PATCH 1262/1436] KVM: arm64: Introduce hyp_dump_backtrace() In non-protected nVHE mode, unwinds and dumps the hypervisor backtrace from EL1. This is possible beacause the host can directly access the hypervisor stack pages in non-protected mode. The nVHE backtrace is dumped on hyp_panic(), before panicking the host. [ 101.498183] kvm [377]: nVHE call trace: [ 101.498363] kvm [377]: [] __kvm_nvhe_hyp_panic+0xac/0xf8 [ 101.499045] kvm [377]: [] __kvm_nvhe_hyp_panic_bad_stack+0x10/0x10 [ 101.499498] kvm [377]: [] __kvm_nvhe_recursive_death+0x24/0x34 . . . [ 101.524929] kvm [377]: [] __kvm_nvhe_recursive_death+0x24/0x34 [ 101.525062] kvm [377]: [] __kvm_nvhe_recursive_death+0x24/0x34 [ 101.525195] kvm [377]: [] __kvm_nvhe___kvm_vcpu_run+0x30/0x40c [ 101.525333] kvm [377]: [] __kvm_nvhe_handle___kvm_vcpu_run+0x30/0x48 [ 101.525468] kvm [377]: [] __kvm_nvhe_handle_trap+0xc4/0x128 [ 101.525602] kvm [377]: [] __kvm_nvhe___host_exit+0x64/0x64 [ 101.525745] kvm [377]: ---[ end nVHE call trace ]--- Signed-off-by: Kalesh Singh Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-12-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace/nvhe.h | 17 ++++++ arch/arm64/kvm/handle_exit.c | 69 ++++++++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h index 21082fd4a0b7..170fe7459f7c 100644 --- a/arch/arm64/include/asm/stacktrace/nvhe.h +++ b/arch/arm64/include/asm/stacktrace/nvhe.h @@ -16,6 +16,23 @@ #include +/* + * kvm_nvhe_unwind_init - Start an unwind from the given nVHE HYP fp and pc + * + * @state : unwind_state to initialize + * @fp : frame pointer at which to start the unwinding. + * @pc : program counter at which to start the unwinding. + */ +static inline void kvm_nvhe_unwind_init(struct unwind_state *state, + unsigned long fp, + unsigned long pc) +{ + unwind_init_common(state, NULL); + + state->fp = fp; + state->pc = pc; +} + static inline bool on_hyp_stack(unsigned long sp, unsigned long size, struct stack_info *info); diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index f66c0142b335..e83e6f735100 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -318,6 +319,71 @@ void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index) kvm_handle_guest_serror(vcpu, kvm_vcpu_get_esr(vcpu)); } +/* + * kvm_nvhe_dump_backtrace_entry - Symbolize and print an nVHE backtrace entry + * + * @arg : the hypervisor offset, used for address translation + * @where : the program counter corresponding to the stack frame + */ +static bool kvm_nvhe_dump_backtrace_entry(void *arg, unsigned long where) +{ + unsigned long va_mask = GENMASK_ULL(vabits_actual - 1, 0); + unsigned long hyp_offset = (unsigned long)arg; + + /* Mask tags and convert to kern addr */ + where = (where & va_mask) + hyp_offset; + kvm_err(" [<%016lx>] %pB\n", where, (void *)(where + kaslr_offset())); + + return true; +} + +static inline void kvm_nvhe_dump_backtrace_start(void) +{ + kvm_err("nVHE call trace:\n"); +} + +static inline void kvm_nvhe_dump_backtrace_end(void) +{ + kvm_err("---[ end nVHE call trace ]---\n"); +} + +/* + * hyp_dump_backtrace - Dump the non-protected nVHE backtrace. + * + * @hyp_offset: hypervisor offset, used for address translation. + * + * The host can directly access HYP stack pages in non-protected + * mode, so the unwinding is done directly from EL1. This removes + * the need for shared buffers between host and hypervisor for + * the stacktrace. + */ +static void hyp_dump_backtrace(unsigned long hyp_offset) +{ + struct kvm_nvhe_stacktrace_info *stacktrace_info; + struct unwind_state state; + + stacktrace_info = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); + + kvm_nvhe_unwind_init(&state, stacktrace_info->fp, stacktrace_info->pc); + + kvm_nvhe_dump_backtrace_start(); + unwind(&state, kvm_nvhe_dump_backtrace_entry, (void *)hyp_offset); + kvm_nvhe_dump_backtrace_end(); +} + +/* + * kvm_nvhe_dump_backtrace - Dump KVM nVHE hypervisor backtrace. + * + * @hyp_offset: hypervisor offset, used for address translation. + */ +static void kvm_nvhe_dump_backtrace(unsigned long hyp_offset) +{ + if (is_protected_kvm_enabled()) + return; + else + hyp_dump_backtrace(hyp_offset); +} + void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, u64 elr_virt, u64 elr_phys, u64 par, uintptr_t vcpu, @@ -353,6 +419,9 @@ void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, (void *)panic_addr); } + /* Dump the nVHE hypervisor backtrace */ + kvm_nvhe_dump_backtrace(hyp_offset); + /* * Hyp has panicked and we're going to handle that by panicking the * kernel. The kernel offset will be revealed in the panic so we're From 72adac1bd234002a65cef738e0eebfd6c2ce2e30 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:45 -0700 Subject: [PATCH 1263/1436] KVM: arm64: Add PROTECTED_NVHE_STACKTRACE Kconfig This can be used to disable stacktrace for the protected KVM nVHE hypervisor, in order to save on the associated memory usage. This option is disabled by default, since protected KVM is not widely used on platforms other than Android currently. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-13-kaleshsingh@google.com --- arch/arm64/kvm/Kconfig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 8a5fbbf084df..09c995869916 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -46,6 +46,21 @@ menuconfig KVM If unsure, say N. +config PROTECTED_NVHE_STACKTRACE + bool "Protected KVM hypervisor stacktraces" + depends on NVHE_EL2_DEBUG + default n + help + Say Y here to enable pKVM hypervisor stacktraces on hyp_panic() + + If you are not using protected nVHE (pKVM), say N. + + If using protected nVHE mode, but cannot afford the associated + memory cost (less than 0.75 page per CPU) of pKVM stacktraces, + say N. + + If unsure, say N. + config NVHE_EL2_DEBUG bool "Debug mode for non-VHE EL2 object" depends on KVM From 6928bcc84bc4bd9a24a1cb1986418c3de76e1d99 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:46 -0700 Subject: [PATCH 1264/1436] KVM: arm64: Allocate shared pKVM hyp stacktrace buffers In protected nVHE mode the host cannot directly access hypervisor memory, so we will dump the hypervisor stacktrace to a shared buffer with the host. The minimum size for the buffer required, assuming the min frame size of [x29, x30] (2 * sizeof(long)), is half the combined size of the hypervisor and overflow stacks plus an additional entry to delimit the end of the stacktrace. The stacktrace buffers are used later in the series to dump the nVHE hypervisor stacktrace when using protected-mode. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-14-kaleshsingh@google.com --- arch/arm64/include/asm/memory.h | 8 ++++++++ arch/arm64/kvm/hyp/nvhe/stacktrace.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 0af70d9abede..cab80a9a4086 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -113,6 +113,14 @@ #define OVERFLOW_STACK_SIZE SZ_4K +/* + * With the minimum frame size of [x29, x30], exactly half the combined + * sizes of the hyp and overflow stacks is the maximum size needed to + * save the unwinded stacktrace; plus an additional entry to delimit the + * end. + */ +#define NVHE_STACKTRACE_SIZE ((OVERFLOW_STACK_SIZE + PAGE_SIZE) / 2 + sizeof(long)) + /* * Alignment of kernel segments (e.g. .text, .data). * diff --git a/arch/arm64/kvm/hyp/nvhe/stacktrace.c b/arch/arm64/kvm/hyp/nvhe/stacktrace.c index b8a280aa026a..e2edda92a108 100644 --- a/arch/arm64/kvm/hyp/nvhe/stacktrace.c +++ b/arch/arm64/kvm/hyp/nvhe/stacktrace.c @@ -34,6 +34,10 @@ static void hyp_prepare_backtrace(unsigned long fp, unsigned long pc) stacktrace_info->pc = pc; } +#ifdef CONFIG_PROTECTED_NVHE_STACKTRACE +DEFINE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], pkvm_stacktrace); +#endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */ + /* * kvm_nvhe_prepare_backtrace - prepare to dump the nVHE backtrace * From 25aa73b6db1831527cd4f14bf0ddf8dceadec802 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:47 -0700 Subject: [PATCH 1265/1436] KVM: arm64: Stub implementation of pKVM HYP stack unwinder Add some stub implementations of protected nVHE stack unwinder, for building. These are implemented later in this series. Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-15-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace/nvhe.h | 35 ++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h index 170fe7459f7c..2ce59c058806 100644 --- a/arch/arm64/include/asm/stacktrace/nvhe.h +++ b/arch/arm64/include/asm/stacktrace/nvhe.h @@ -9,6 +9,10 @@ * to allocate shared buffers for the host to read the unwinded * stacktrace. * + * 2) pKVM (protected nVHE) mode - the host cannot directly access + * the HYP memory. The stack is unwinded in EL2 and dumped to a shared + * buffer where the host can read and print the stacktrace. + * * Copyright (C) 2022 Google LLC */ #ifndef __ASM_STACKTRACE_NVHE_H @@ -49,7 +53,34 @@ static inline bool on_accessible_stack(const struct task_struct *tsk, return false; } -#ifndef __KVM_NVHE_HYPERVISOR__ +#ifdef __KVM_NVHE_HYPERVISOR__ +/* + * Protected nVHE HYP stack unwinder + * + * In protected mode, the unwinding is done by the hypervisor in EL2. + */ + +#ifdef CONFIG_PROTECTED_NVHE_STACKTRACE +static inline bool on_overflow_stack(unsigned long sp, unsigned long size, + struct stack_info *info) +{ + return false; +} + +static inline bool on_hyp_stack(unsigned long sp, unsigned long size, + struct stack_info *info) +{ + return false; +} + +static inline int notrace unwind_next(struct unwind_state *state) +{ + return 0; +} +NOKPROBE_SYMBOL(unwind_next); +#endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */ + +#else /* !__KVM_NVHE_HYPERVISOR__ */ /* * Conventional (non-protected) nVHE HYP stack unwinder * @@ -132,5 +163,5 @@ static inline int notrace unwind_next(struct unwind_state *state) } NOKPROBE_SYMBOL(unwind_next); -#endif /* !__KVM_NVHE_HYPERVISOR__ */ +#endif /* __KVM_NVHE_HYPERVISOR__ */ #endif /* __ASM_STACKTRACE_NVHE_H */ From 871c5d931417d3c0e1aa32c9e04da1dc74703843 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:48 -0700 Subject: [PATCH 1266/1436] KVM: arm64: Save protected-nVHE (pKVM) hyp stacktrace In protected nVHE mode, the host cannot access private owned hypervisor memory. Also the hypervisor aims to remains simple to reduce the attack surface and does not provide any printk support. For the above reasons, the approach taken to provide hypervisor stacktraces in protected mode is: 1) Unwind and save the hyp stack addresses in EL2 to a shared buffer with the host (done in this patch). 2) Delegate the dumping and symbolization of the addresses to the host in EL1 (later patch in the series). On hyp_panic(), the hypervisor prepares the stacktrace before returning to the host. Signed-off-by: Kalesh Singh Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-16-kaleshsingh@google.com --- arch/arm64/kvm/hyp/nvhe/stacktrace.c | 55 +++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/hyp/nvhe/stacktrace.c b/arch/arm64/kvm/hyp/nvhe/stacktrace.c index e2edda92a108..900324b7a08f 100644 --- a/arch/arm64/kvm/hyp/nvhe/stacktrace.c +++ b/arch/arm64/kvm/hyp/nvhe/stacktrace.c @@ -35,7 +35,60 @@ static void hyp_prepare_backtrace(unsigned long fp, unsigned long pc) } #ifdef CONFIG_PROTECTED_NVHE_STACKTRACE +#include + DEFINE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], pkvm_stacktrace); + +/* + * pkvm_save_backtrace_entry - Saves a protected nVHE HYP stacktrace entry + * + * @arg : index of the entry in the stacktrace buffer + * @where : the program counter corresponding to the stack frame + * + * Save the return address of a stack frame to the shared stacktrace buffer. + * The host can access this shared buffer from EL1 to dump the backtrace. + */ +static bool pkvm_save_backtrace_entry(void *arg, unsigned long where) +{ + unsigned long *stacktrace = this_cpu_ptr(pkvm_stacktrace); + int size = NVHE_STACKTRACE_SIZE / sizeof(long); + int *idx = (int *)arg; + + /* + * Need 2 free slots: 1 for current entry and 1 for the + * delimiter. + */ + if (*idx > size - 2) + return false; + + stacktrace[*idx] = where; + stacktrace[++*idx] = 0UL; + + return true; +} + +/* + * pkvm_save_backtrace - Saves the protected nVHE HYP stacktrace + * + * @fp : frame pointer at which to start the unwinding. + * @pc : program counter at which to start the unwinding. + * + * Save the unwinded stack addresses to the shared stacktrace buffer. + * The host can access this shared buffer from EL1 to dump the backtrace. + */ +static void pkvm_save_backtrace(unsigned long fp, unsigned long pc) +{ + struct unwind_state state; + int idx = 0; + + kvm_nvhe_unwind_init(&state, fp, pc); + + unwind(&state, pkvm_save_backtrace_entry, &idx); +} +#else /* !CONFIG_PROTECTED_NVHE_STACKTRACE */ +static void pkvm_save_backtrace(unsigned long fp, unsigned long pc) +{ +} #endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */ /* @@ -50,7 +103,7 @@ DEFINE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], pkvm_stacktrac void kvm_nvhe_prepare_backtrace(unsigned long fp, unsigned long pc) { if (is_protected_kvm_enabled()) - return; + pkvm_save_backtrace(fp, pc); else hyp_prepare_backtrace(fp, pc); } From 75e9459e48d4867caf549e388bd4faabe1dbcbd3 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:49 -0700 Subject: [PATCH 1267/1436] KVM: arm64: Implement protected nVHE hyp stack unwinder Implements the common framework necessary for unwind() to work in the protected nVHE context: - on_accessible_stack() - on_overflow_stack() - unwind_next() Protected nVHE unwind() is used to unwind and save the hyp stack addresses to the shared stacktrace buffer. The host reads the entries in this buffer, symbolizes and dumps the stacktrace (later patch in the series). Signed-off-by: Kalesh Singh Reviewed-by: Fuad Tabba Tested-by: Fuad Tabba Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-17-kaleshsingh@google.com --- arch/arm64/include/asm/stacktrace/nvhe.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h index 2ce59c058806..600dbc2220b6 100644 --- a/arch/arm64/include/asm/stacktrace/nvhe.h +++ b/arch/arm64/include/asm/stacktrace/nvhe.h @@ -64,18 +64,27 @@ static inline bool on_accessible_stack(const struct task_struct *tsk, static inline bool on_overflow_stack(unsigned long sp, unsigned long size, struct stack_info *info) { - return false; + unsigned long low = (unsigned long)this_cpu_ptr(overflow_stack); + unsigned long high = low + OVERFLOW_STACK_SIZE; + + return on_stack(sp, size, low, high, STACK_TYPE_OVERFLOW, info); } static inline bool on_hyp_stack(unsigned long sp, unsigned long size, struct stack_info *info) { - return false; + struct kvm_nvhe_init_params *params = this_cpu_ptr(&kvm_init_params); + unsigned long high = params->stack_hyp_va; + unsigned long low = high - PAGE_SIZE; + + return on_stack(sp, size, low, high, STACK_TYPE_HYP, info); } static inline int notrace unwind_next(struct unwind_state *state) { - return 0; + struct stack_info info; + + return unwind_next_common(state, &info, NULL); } NOKPROBE_SYMBOL(unwind_next); #endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */ From 3a7e1b55aad45c0cf86bd4e2f212bb9a61905142 Mon Sep 17 00:00:00 2001 From: Kalesh Singh Date: Tue, 26 Jul 2022 00:37:50 -0700 Subject: [PATCH 1268/1436] KVM: arm64: Introduce pkvm_dump_backtrace() Dumps the pKVM hypervisor backtrace from EL1 by reading the unwinded addresses from the shared stacktrace buffer. The nVHE hyp backtrace is dumped on hyp_panic(), before panicking the host. [ 111.623091] kvm [367]: nVHE call trace: [ 111.623215] kvm [367]: [] __kvm_nvhe_hyp_panic+0xac/0xf8 [ 111.623448] kvm [367]: [] __kvm_nvhe_hyp_panic_bad_stack+0x10/0x10 [ 111.623642] kvm [367]: [] __kvm_nvhe_recursive_death+0x24/0x34 . . . [ 111.640366] kvm [367]: [] __kvm_nvhe_recursive_death+0x24/0x34 [ 111.640467] kvm [367]: [] __kvm_nvhe_recursive_death+0x24/0x34 [ 111.640574] kvm [367]: [] __kvm_nvhe___kvm_vcpu_run+0x30/0x40c [ 111.640676] kvm [367]: [] __kvm_nvhe_handle___kvm_vcpu_run+0x30/0x48 [ 111.640778] kvm [367]: [] __kvm_nvhe_handle_trap+0xc4/0x128 [ 111.640880] kvm [367]: [] __kvm_nvhe___host_exit+0x64/0x64 [ 111.640996] kvm [367]: ---[ end nVHE call trace ]--- Signed-off-by: Kalesh Singh Signed-off-by: Marc Zyngier Link: https://lore.kernel.org/r/20220726073750.3219117-18-kaleshsingh@google.com --- arch/arm64/kvm/handle_exit.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index e83e6f735100..c14fc4ba4422 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -371,6 +371,39 @@ static void hyp_dump_backtrace(unsigned long hyp_offset) kvm_nvhe_dump_backtrace_end(); } +#ifdef CONFIG_PROTECTED_NVHE_STACKTRACE +DECLARE_KVM_NVHE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], + pkvm_stacktrace); + +/* + * pkvm_dump_backtrace - Dump the protected nVHE HYP backtrace. + * + * @hyp_offset: hypervisor offset, used for address translation. + * + * Dumping of the pKVM HYP backtrace is done by reading the + * stack addresses from the shared stacktrace buffer, since the + * host cannot directly access hypervisor memory in protected + * mode. + */ +static void pkvm_dump_backtrace(unsigned long hyp_offset) +{ + unsigned long *stacktrace + = (unsigned long *) this_cpu_ptr_nvhe_sym(pkvm_stacktrace); + int i, size = NVHE_STACKTRACE_SIZE / sizeof(long); + + kvm_nvhe_dump_backtrace_start(); + /* The saved stacktrace is terminated by a null entry */ + for (i = 0; i < size && stacktrace[i]; i++) + kvm_nvhe_dump_backtrace_entry((void *)hyp_offset, stacktrace[i]); + kvm_nvhe_dump_backtrace_end(); +} +#else /* !CONFIG_PROTECTED_NVHE_STACKTRACE */ +static void pkvm_dump_backtrace(unsigned long hyp_offset) +{ + kvm_err("Cannot dump pKVM nVHE stacktrace: !CONFIG_PROTECTED_NVHE_STACKTRACE\n"); +} +#endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */ + /* * kvm_nvhe_dump_backtrace - Dump KVM nVHE hypervisor backtrace. * @@ -379,7 +412,7 @@ static void hyp_dump_backtrace(unsigned long hyp_offset) static void kvm_nvhe_dump_backtrace(unsigned long hyp_offset) { if (is_protected_kvm_enabled()) - return; + pkvm_dump_backtrace(hyp_offset); else hyp_dump_backtrace(hyp_offset); } From f2a2f2c9aed21944095c2f867640a9089759c7e7 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Thu, 21 Jul 2022 14:30:21 +0530 Subject: [PATCH 1269/1436] gpio: xilinx: add missing blank line after declarations Add a missing blank line. No functional changes. WARNING: Missing a blank line after declarations 128: FILE: drivers/gpio/gpio-xilinx.c:120: + void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32); + xgpio_set_value32(a, bit, xgpio_readreg(addr)); WARNING: Missing a blank line after declarations 136: FILE: drivers/gpio/gpio-xilinx.c:126: + void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32); + xgpio_writereg(addr, xgpio_get_value32(a, bit)); Signed-off-by: Shubhrajyoti Datta Reviewed-by: Michal Simek Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-xilinx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index b6d3a57e27ed..7f129e7eae78 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -117,12 +117,14 @@ static inline int xgpio_regoffset(struct xgpio_instance *chip, int ch) static void xgpio_read_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a) { void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32); + xgpio_set_value32(a, bit, xgpio_readreg(addr)); } static void xgpio_write_ch(struct xgpio_instance *chip, int reg, int bit, unsigned long *a) { void __iomem *addr = chip->regs + reg + xgpio_regoffset(chip, bit / 32); + xgpio_writereg(addr, xgpio_get_value32(a, bit)); } From 97c9a70f129f43f90b8b3fa7af8a02ed6c977a60 Mon Sep 17 00:00:00 2001 From: Binyi Han Date: Thu, 14 Jul 2022 23:17:54 -0700 Subject: [PATCH 1270/1436] staging: qlge: refine variable name tmp as a variable name don't have much information, change tmp to dma. Signed-off-by: Binyi Han Link: https://lore.kernel.org/r/20220715061754.GA6657@cloud-MacBookPro Signed-off-by: Greg Kroah-Hartman --- drivers/staging/qlge/qlge_main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c index 4b166c66cfc5..58d1920c4347 100644 --- a/drivers/staging/qlge/qlge_main.c +++ b/drivers/staging/qlge/qlge_main.c @@ -2955,7 +2955,7 @@ static int qlge_start_rx_ring(struct qlge_adapter *qdev, struct rx_ring *rx_ring void __iomem *doorbell_area = qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id)); int err = 0; - u64 tmp; + u64 dma; __le64 *base_indirect_ptr; int page_entries; @@ -3004,14 +3004,14 @@ static int qlge_start_rx_ring(struct qlge_adapter *qdev, struct rx_ring *rx_ring FLAGS_LI; /* Load irq delay values */ if (rx_ring->cq_id < qdev->rss_ring_count) { cqicb->flags |= FLAGS_LL; /* Load lbq values */ - tmp = (u64)rx_ring->lbq.base_dma; + dma = (u64)rx_ring->lbq.base_dma; base_indirect_ptr = rx_ring->lbq.base_indirect; for (page_entries = 0; page_entries < MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN); page_entries++) { - base_indirect_ptr[page_entries] = cpu_to_le64(tmp); - tmp += DB_PAGE_SIZE; + base_indirect_ptr[page_entries] = cpu_to_le64(dma); + dma += DB_PAGE_SIZE; } cqicb->lbq_addr = cpu_to_le64(rx_ring->lbq.base_indirect_dma); cqicb->lbq_buf_size = @@ -3021,14 +3021,14 @@ static int qlge_start_rx_ring(struct qlge_adapter *qdev, struct rx_ring *rx_ring rx_ring->lbq.next_to_clean = 0; cqicb->flags |= FLAGS_LS; /* Load sbq values */ - tmp = (u64)rx_ring->sbq.base_dma; + dma = (u64)rx_ring->sbq.base_dma; base_indirect_ptr = rx_ring->sbq.base_indirect; for (page_entries = 0; page_entries < MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN); page_entries++) { - base_indirect_ptr[page_entries] = cpu_to_le64(tmp); - tmp += DB_PAGE_SIZE; + base_indirect_ptr[page_entries] = cpu_to_le64(dma); + dma += DB_PAGE_SIZE; } cqicb->sbq_addr = cpu_to_le64(rx_ring->sbq.base_indirect_dma); From 6a74f103e3e0ce81ea29146070900d563b984e0f Mon Sep 17 00:00:00 2001 From: Sidong Yang Date: Mon, 25 Jul 2022 12:45:13 +0100 Subject: [PATCH 1271/1436] staging: pi433: remove duplicated comments Remove duplicated words in comments for readability. The words are duplicated from a sentence below. Signed-off-by: Sidong Yang Link: https://lore.kernel.org/r/20220725114513.85089-1-realwakka@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/pi433/pi433_if.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/pi433/pi433_if.c b/drivers/staging/pi433/pi433_if.c index 941aaa7eab2e..df02335fdbab 100644 --- a/drivers/staging/pi433/pi433_if.c +++ b/drivers/staging/pi433/pi433_if.c @@ -1406,7 +1406,7 @@ static int __init pi433_init(void) /* * Claim device numbers. Then register a class - * that will key udev/mdev to add/remove /dev nodes. Last, register + * that will key udev/mdev to add/remove /dev nodes. * Last, register the driver which manages those device numbers. */ status = alloc_chrdev_region(&pi433_dev, 0, N_PI433_MINORS, "pi433"); From 3cc664a99e2f6f06cccee1941b6ea221779031fb Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 15 Jul 2022 08:29:04 +0200 Subject: [PATCH 1272/1436] staging: r8188eu: remove HW_VAR_SET_OPMODE from SetHwReg8188EU() Remove the HW_VAR_SET_OPMODE case from SetHwReg8188EU() and move the functions that are called by that case to rtw_mlme_ext.c. This is part of the ongoing effort to get rid of SetHwReg8188EU(). Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220715062908.8547-2-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 103 +++++++++++++++- drivers/staging/r8188eu/hal/usb_halinit.c | 111 +----------------- drivers/staging/r8188eu/include/hal_intf.h | 1 - .../staging/r8188eu/include/rtw_mlme_ext.h | 2 + 4 files changed, 107 insertions(+), 110 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 771910763fec..0edcf84db16d 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -5674,6 +5674,107 @@ void clear_beacon_valid_bit(struct adapter *adapter) rtw_write8(adapter, REG_TDECTRL + 2, reg | BIT(0)); } +void rtw_resume_tx_beacon(struct adapter *adapt) +{ + struct hal_data_8188e *haldata = &adapt->haldata; + + /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ + /* which should be read from register to a global variable. */ + + rtw_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl) | BIT(6)); + haldata->RegFwHwTxQCtrl |= BIT(6); + rtw_write8(adapt, REG_TBTT_PROHIBIT + 1, 0xff); + haldata->RegReg542 |= BIT(0); + rtw_write8(adapt, REG_TBTT_PROHIBIT + 2, haldata->RegReg542); +} + +void rtw_stop_tx_beacon(struct adapter *adapt) +{ + struct hal_data_8188e *haldata = &adapt->haldata; + + /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ + /* which should be read from register to a global variable. */ + + rtw_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl) & (~BIT(6))); + haldata->RegFwHwTxQCtrl &= (~BIT(6)); + rtw_write8(adapt, REG_TBTT_PROHIBIT + 1, 0x64); + haldata->RegReg542 &= ~(BIT(0)); + rtw_write8(adapt, REG_TBTT_PROHIBIT + 2, haldata->RegReg542); + + /* todo: CheckFwRsvdPageContent(Adapter); 2010.06.23. Added by tynli. */ +} + +static void rtw_set_opmode(struct adapter *adapter, u8 mode) +{ + u8 val8; + int res; + + /* disable Port0 TSF update */ + res = rtw_read8(adapter, REG_BCN_CTRL, &val8); + if (res) + return; + + rtw_write8(adapter, REG_BCN_CTRL, val8 | BIT(4)); + + /* set net_type */ + res = rtw_read8(adapter, MSR, &val8); + if (res) + return; + + val8 &= 0x0c; + val8 |= mode; + rtw_write8(adapter, MSR, val8); + + if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) { + rtw_stop_tx_beacon(adapter); + + rtw_write8(adapter, REG_BCN_CTRL, 0x19);/* disable atim wnd */ + } else if (mode == _HW_STATE_ADHOC_) { + rtw_resume_tx_beacon(adapter); + rtw_write8(adapter, REG_BCN_CTRL, 0x1a); + } else if (mode == _HW_STATE_AP_) { + rtw_resume_tx_beacon(adapter); + + rtw_write8(adapter, REG_BCN_CTRL, 0x12); + + /* Set RCR */ + rtw_write32(adapter, REG_RCR, 0x7000208e);/* CBSSID_DATA must set to 0,reject ICV_ERR packet */ + /* enable to rx data frame */ + rtw_write16(adapter, REG_RXFLTMAP2, 0xFFFF); + /* enable to rx ps-poll */ + rtw_write16(adapter, REG_RXFLTMAP1, 0x0400); + + /* Beacon Control related register for first time */ + rtw_write8(adapter, REG_BCNDMATIM, 0x02); /* 2ms */ + + rtw_write8(adapter, REG_ATIMWND, 0x0a); /* 10ms */ + rtw_write16(adapter, REG_BCNTCFG, 0x00); + rtw_write16(adapter, REG_TBTT_PROHIBIT, 0xff04); + rtw_write16(adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);/* +32767 (~32ms) */ + + /* reset TSF */ + rtw_write8(adapter, REG_DUAL_TSF_RST, BIT(0)); + + /* BIT(3) - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 */ + res = rtw_read8(adapter, REG_MBID_NUM, &val8); + if (res) + return; + + rtw_write8(adapter, REG_MBID_NUM, val8 | BIT(3) | BIT(4)); + + /* enable BCN0 Function for if1 */ + /* don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) */ + rtw_write8(adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP | EN_BCN_FUNCTION | BIT(1))); + + /* dis BCN1 ATIM WND if if2 is station */ + res = rtw_read8(adapter, REG_BCN_CTRL_1, &val8); + if (res) + return; + + rtw_write8(adapter, REG_BCN_CTRL_1, val8 | BIT(0)); + } +} + /**************************************************************************** Following are some utitity fuctions for WiFi MLME @@ -7142,7 +7243,7 @@ u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf) type = _HW_STATE_NOLINK_; } - SetHwReg8188EU(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type)); + rtw_set_opmode(padapter, type); return H2C_SUCCESS; } diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index 421fe7c40390..b8fd73ac8f7c 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -963,117 +963,12 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) kfree(efuse_buf); } -static void ResumeTxBeacon(struct adapter *adapt) -{ - struct hal_data_8188e *haldata = &adapt->haldata; - - /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ - /* which should be read from register to a global variable. */ - - rtw_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl) | BIT(6)); - haldata->RegFwHwTxQCtrl |= BIT(6); - rtw_write8(adapt, REG_TBTT_PROHIBIT + 1, 0xff); - haldata->RegReg542 |= BIT(0); - rtw_write8(adapt, REG_TBTT_PROHIBIT + 2, haldata->RegReg542); -} - -static void StopTxBeacon(struct adapter *adapt) -{ - struct hal_data_8188e *haldata = &adapt->haldata; - - /* 2010.03.01. Marked by tynli. No need to call workitem beacause we record the value */ - /* which should be read from register to a global variable. */ - - rtw_write8(adapt, REG_FWHW_TXQ_CTRL + 2, (haldata->RegFwHwTxQCtrl) & (~BIT(6))); - haldata->RegFwHwTxQCtrl &= (~BIT(6)); - rtw_write8(adapt, REG_TBTT_PROHIBIT + 1, 0x64); - haldata->RegReg542 &= ~(BIT(0)); - rtw_write8(adapt, REG_TBTT_PROHIBIT + 2, haldata->RegReg542); - - /* todo: CheckFwRsvdPageContent(Adapter); 2010.06.23. Added by tynli. */ -} - -static void hw_var_set_opmode(struct adapter *Adapter, u8 *val) -{ - u8 val8; - u8 mode = *((u8 *)val); - int res; - - /* disable Port0 TSF update */ - res = rtw_read8(Adapter, REG_BCN_CTRL, &val8); - if (res) - return; - - rtw_write8(Adapter, REG_BCN_CTRL, val8 | BIT(4)); - - /* set net_type */ - res = rtw_read8(Adapter, MSR, &val8); - if (res) - return; - - val8 &= 0x0c; - val8 |= mode; - rtw_write8(Adapter, MSR, val8); - - if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) { - StopTxBeacon(Adapter); - - rtw_write8(Adapter, REG_BCN_CTRL, 0x19);/* disable atim wnd */ - } else if (mode == _HW_STATE_ADHOC_) { - ResumeTxBeacon(Adapter); - rtw_write8(Adapter, REG_BCN_CTRL, 0x1a); - } else if (mode == _HW_STATE_AP_) { - ResumeTxBeacon(Adapter); - - rtw_write8(Adapter, REG_BCN_CTRL, 0x12); - - /* Set RCR */ - rtw_write32(Adapter, REG_RCR, 0x7000208e);/* CBSSID_DATA must set to 0,reject ICV_ERR packet */ - /* enable to rx data frame */ - rtw_write16(Adapter, REG_RXFLTMAP2, 0xFFFF); - /* enable to rx ps-poll */ - rtw_write16(Adapter, REG_RXFLTMAP1, 0x0400); - - /* Beacon Control related register for first time */ - rtw_write8(Adapter, REG_BCNDMATIM, 0x02); /* 2ms */ - - rtw_write8(Adapter, REG_ATIMWND, 0x0a); /* 10ms */ - rtw_write16(Adapter, REG_BCNTCFG, 0x00); - rtw_write16(Adapter, REG_TBTT_PROHIBIT, 0xff04); - rtw_write16(Adapter, REG_TSFTR_SYN_OFFSET, 0x7fff);/* +32767 (~32ms) */ - - /* reset TSF */ - rtw_write8(Adapter, REG_DUAL_TSF_RST, BIT(0)); - - /* BIT(3) - If set 0, hw will clr bcnq when tx becon ok/fail or port 0 */ - res = rtw_read8(Adapter, REG_MBID_NUM, &val8); - if (res) - return; - - rtw_write8(Adapter, REG_MBID_NUM, val8 | BIT(3) | BIT(4)); - - /* enable BCN0 Function for if1 */ - /* don't enable update TSF0 for if1 (due to TSF update when beacon/probe rsp are received) */ - rtw_write8(Adapter, REG_BCN_CTRL, (DIS_TSF_UDT0_NORMAL_CHIP | EN_BCN_FUNCTION | BIT(1))); - - /* dis BCN1 ATIM WND if if2 is station */ - res = rtw_read8(Adapter, REG_BCN_CTRL_1, &val8); - if (res) - return; - - rtw_write8(Adapter, REG_BCN_CTRL_1, val8 | BIT(0)); - } -} - void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) { u8 reg; int res; switch (variable) { - case HW_VAR_SET_OPMODE: - hw_var_set_opmode(Adapter, val); - break; case HW_VAR_CORRECT_TSF: { u64 tsf; @@ -1084,7 +979,7 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) pmlmeinfo->bcn_interval * 1024) - 1024; /* us */ if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) - StopTxBeacon(Adapter); + rtw_stop_tx_beacon(Adapter); /* disable related TSF function */ res = rtw_read8(Adapter, REG_BCN_CTRL, ®); @@ -1104,7 +999,7 @@ void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) rtw_write8(Adapter, REG_BCN_CTRL, reg | BIT(3)); if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) - ResumeTxBeacon(Adapter); + rtw_resume_tx_beacon(Adapter); } break; default: @@ -1221,7 +1116,7 @@ void SetBeaconRelatedRegisters8188EUsb(struct adapter *adapt) _BeaconFunctionEnable(adapt, true, true); - ResumeTxBeacon(adapt); + rtw_resume_tx_beacon(adapt); res = rtw_read8(adapt, bcn_ctrl_reg, ®); if (res) diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index 819d0dc6e6dc..e1dfd621a5cb 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -9,7 +9,6 @@ #include "Hal8188EPhyCfg.h" enum hw_variables { - HW_VAR_SET_OPMODE, HW_VAR_CORRECT_TSF, }; diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h index c630700ea657..28416d1bd15c 100644 --- a/drivers/staging/r8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h @@ -532,6 +532,8 @@ unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr); unsigned int send_beacon(struct adapter *padapter); bool get_beacon_valid_bit(struct adapter *adapter); void clear_beacon_valid_bit(struct adapter *adapter); +void rtw_resume_tx_beacon(struct adapter *adapt); +void rtw_stop_tx_beacon(struct adapter *adapt); void start_clnt_assoc(struct adapter *padapter); void start_clnt_auth(struct adapter *padapter); From 0f83ff0129577f113242b207bdae284eb15696e5 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 15 Jul 2022 08:29:05 +0200 Subject: [PATCH 1273/1436] staging: r8188eu: remove unused parameter from correct_TSF() The parameter 'pmlmeext' of correct_TSF() is unused. Remove it. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220715062908.8547-3-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 4 ++-- drivers/staging/r8188eu/core/rtw_wlan_util.c | 2 +- drivers/staging/r8188eu/include/rtw_mlme_ext.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 0edcf84db16d..985cb3b4ba30 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -6893,7 +6893,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) if ((pmlmeinfo->state & 0x03) == WIFI_FW_STATION_STATE) { /* correcting TSF */ - correct_TSF(padapter, pmlmeext); + correct_TSF(padapter); } rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_CONNECT, 0); } @@ -6908,7 +6908,7 @@ void mlmeext_sta_add_event_callback(struct adapter *padapter, struct sta_info *p /* nothing to do */ } else { /* adhoc client */ /* correcting TSF */ - correct_TSF(padapter, pmlmeext); + correct_TSF(padapter); /* start beacon */ if (send_beacon(padapter) == _FAIL) { diff --git a/drivers/staging/r8188eu/core/rtw_wlan_util.c b/drivers/staging/r8188eu/core/rtw_wlan_util.c index b48e0b9dfd7b..7b705e2ea04a 100644 --- a/drivers/staging/r8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/r8188eu/core/rtw_wlan_util.c @@ -1586,7 +1586,7 @@ void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) pmlmeext->TSFValue |= le32_to_cpu(*pbuf); } -void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext) +void correct_TSF(struct adapter *padapter) { SetHwReg8188EU(padapter, HW_VAR_CORRECT_TSF, NULL); } diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h index 28416d1bd15c..2110affc180f 100644 --- a/drivers/staging/r8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h @@ -597,7 +597,7 @@ bool cckrates_included(unsigned char *rate, int ratelen); bool cckratesonly_included(unsigned char *rate, int ratelen); void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len); -void correct_TSF(struct adapter *padapter, struct mlme_ext_priv *pmlmeext); +void correct_TSF(struct adapter *padapter); struct cmd_hdl { uint parmsize; From 21b044c903384898b1972c35a7927ed184a46e47 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 15 Jul 2022 08:29:06 +0200 Subject: [PATCH 1274/1436] staging: r8188eu: remove unused parameter from update_TSF() The parameter 'len' of update_TSF() is unused. Remove it. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220715062908.8547-4-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 4 ++-- drivers/staging/r8188eu/core/rtw_wlan_util.c | 2 +- drivers/staging/r8188eu/include/rtw_mlme_ext.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 985cb3b4ba30..c23be5d9eaaf 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -582,7 +582,7 @@ unsigned int OnBeacon(struct adapter *padapter, struct recv_frame *precv_frame) pmlmeinfo->assoc_AP_vendor = check_assoc_AP(pframe + sizeof(struct ieee80211_hdr_3addr), len - sizeof(struct ieee80211_hdr_3addr)); /* update TSF Value */ - update_TSF(pmlmeext, pframe, len); + update_TSF(pmlmeext, pframe); /* start auth */ start_clnt_auth(padapter); @@ -625,7 +625,7 @@ unsigned int OnBeacon(struct adapter *padapter, struct recv_frame *precv_frame) } /* update TSF Value */ - update_TSF(pmlmeext, pframe, len); + update_TSF(pmlmeext, pframe); /* report sta add event */ report_add_sta_event(padapter, GetAddr2Ptr(pframe), cam_idx); diff --git a/drivers/staging/r8188eu/core/rtw_wlan_util.c b/drivers/staging/r8188eu/core/rtw_wlan_util.c index 7b705e2ea04a..9e920a320d71 100644 --- a/drivers/staging/r8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/r8188eu/core/rtw_wlan_util.c @@ -1571,7 +1571,7 @@ int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_l return _SUCCESS; } -void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) +void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe) { u8 *pIE; __le32 *pbuf; diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h index 2110affc180f..54384b4c6b1a 100644 --- a/drivers/staging/r8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h @@ -596,7 +596,7 @@ void addba_timer_hdl(struct sta_info *psta); bool cckrates_included(unsigned char *rate, int ratelen); bool cckratesonly_included(unsigned char *rate, int ratelen); -void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len); +void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe); void correct_TSF(struct adapter *padapter); struct cmd_hdl { From 7136ef70a067095ec207ad1d710fed44154d51a6 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 15 Jul 2022 08:29:07 +0200 Subject: [PATCH 1275/1436] staging: r8188eu: make update_TSF() and correct_TSF() static The functions update_TSF() and correct_TSF() are only used in rtw_mlme_ext.c. Make them static. Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220715062908.8547-5-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 20 +++++++++++++++++++ drivers/staging/r8188eu/core/rtw_wlan_util.c | 20 ------------------- .../staging/r8188eu/include/rtw_mlme_ext.h | 3 --- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index c23be5d9eaaf..7b69d9ad75e9 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -428,6 +428,26 @@ static u32 p2p_listen_state_process(struct adapter *padapter, unsigned char *da) return _SUCCESS; } +static void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe) +{ + u8 *pIE; + __le32 *pbuf; + + pIE = pframe + sizeof(struct ieee80211_hdr_3addr); + pbuf = (__le32 *)pIE; + + pmlmeext->TSFValue = le32_to_cpu(*(pbuf + 1)); + + pmlmeext->TSFValue = pmlmeext->TSFValue << 32; + + pmlmeext->TSFValue |= le32_to_cpu(*pbuf); +} + +static void correct_TSF(struct adapter *padapter) +{ + SetHwReg8188EU(padapter, HW_VAR_CORRECT_TSF, NULL); +} + /**************************************************************************** Following are the callback functions for each subtype of the management frames diff --git a/drivers/staging/r8188eu/core/rtw_wlan_util.c b/drivers/staging/r8188eu/core/rtw_wlan_util.c index 9e920a320d71..3a002cb6834f 100644 --- a/drivers/staging/r8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/r8188eu/core/rtw_wlan_util.c @@ -1571,26 +1571,6 @@ int update_sta_support_rate(struct adapter *padapter, u8 *pvar_ie, uint var_ie_l return _SUCCESS; } -void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe) -{ - u8 *pIE; - __le32 *pbuf; - - pIE = pframe + sizeof(struct ieee80211_hdr_3addr); - pbuf = (__le32 *)pIE; - - pmlmeext->TSFValue = le32_to_cpu(*(pbuf + 1)); - - pmlmeext->TSFValue = pmlmeext->TSFValue << 32; - - pmlmeext->TSFValue |= le32_to_cpu(*pbuf); -} - -void correct_TSF(struct adapter *padapter) -{ - SetHwReg8188EU(padapter, HW_VAR_CORRECT_TSF, NULL); -} - void beacon_timing_control(struct adapter *padapter) { SetBeaconRelatedRegisters8188EUsb(padapter); diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h index 54384b4c6b1a..bf952755ba35 100644 --- a/drivers/staging/r8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h @@ -596,9 +596,6 @@ void addba_timer_hdl(struct sta_info *psta); bool cckrates_included(unsigned char *rate, int ratelen); bool cckratesonly_included(unsigned char *rate, int ratelen); -void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe); -void correct_TSF(struct adapter *padapter); - struct cmd_hdl { uint parmsize; u8 (*h2cfuns)(struct adapter *padapter, u8 *pbuf); From b9ad667059d72713729761fa3d9e087cfa065e52 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Fri, 15 Jul 2022 08:29:08 +0200 Subject: [PATCH 1276/1436] staging: r8188eu: remove SetHwReg8188EU() Remove the case HW_VAR_CORRECT_TSF from SetHwReg8188EU() and move the functionality to the function that calls SetHwReg8188EU() with HW_VAR_CORRECT_TSF. SetHwReg8188EU() is empty now and we can finally remove it. Tested-by: Martin Kaiser Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220715062908.8547-6-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_mlme_ext.c | 34 +++++++++++++++- drivers/staging/r8188eu/hal/usb_halinit.c | 45 --------------------- drivers/staging/r8188eu/include/hal_intf.h | 6 --- 3 files changed, 33 insertions(+), 52 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_mlme_ext.c b/drivers/staging/r8188eu/core/rtw_mlme_ext.c index 7b69d9ad75e9..32d0e101d0c2 100644 --- a/drivers/staging/r8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/r8188eu/core/rtw_mlme_ext.c @@ -445,7 +445,39 @@ static void update_TSF(struct mlme_ext_priv *pmlmeext, u8 *pframe) static void correct_TSF(struct adapter *padapter) { - SetHwReg8188EU(padapter, HW_VAR_CORRECT_TSF, NULL); + u8 reg; + int res; + u64 tsf; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + + tsf = pmlmeext->TSFValue - do_div(pmlmeext->TSFValue, + pmlmeinfo->bcn_interval * 1024) - 1024; /* us */ + + if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || + ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) + rtw_stop_tx_beacon(padapter); + + /* disable related TSF function */ + res = rtw_read8(padapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(padapter, REG_BCN_CTRL, reg & (~BIT(3))); + + rtw_write32(padapter, REG_TSFTR, tsf); + rtw_write32(padapter, REG_TSFTR + 4, tsf >> 32); + + /* enable related TSF function */ + res = rtw_read8(padapter, REG_BCN_CTRL, ®); + if (res) + return; + + rtw_write8(padapter, REG_BCN_CTRL, reg | BIT(3)); + + if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || + ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) + rtw_resume_tx_beacon(padapter); } /**************************************************************************** diff --git a/drivers/staging/r8188eu/hal/usb_halinit.c b/drivers/staging/r8188eu/hal/usb_halinit.c index b8fd73ac8f7c..ff074d246dab 100644 --- a/drivers/staging/r8188eu/hal/usb_halinit.c +++ b/drivers/staging/r8188eu/hal/usb_halinit.c @@ -963,51 +963,6 @@ void ReadAdapterInfo8188EU(struct adapter *Adapter) kfree(efuse_buf); } -void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val) -{ - u8 reg; - int res; - - switch (variable) { - case HW_VAR_CORRECT_TSF: - { - u64 tsf; - struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - - tsf = pmlmeext->TSFValue - do_div(pmlmeext->TSFValue, - pmlmeinfo->bcn_interval * 1024) - 1024; /* us */ - - if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) - rtw_stop_tx_beacon(Adapter); - - /* disable related TSF function */ - res = rtw_read8(Adapter, REG_BCN_CTRL, ®); - if (res) - return; - - rtw_write8(Adapter, REG_BCN_CTRL, reg & (~BIT(3))); - - rtw_write32(Adapter, REG_TSFTR, tsf); - rtw_write32(Adapter, REG_TSFTR + 4, tsf >> 32); - - /* enable related TSF function */ - res = rtw_read8(Adapter, REG_BCN_CTRL, ®); - if (res) - return; - - rtw_write8(Adapter, REG_BCN_CTRL, reg | BIT(3)); - - if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) - rtw_resume_tx_beacon(Adapter); - } - break; - default: - break; - } - -} - void UpdateHalRAMask8188EUsb(struct adapter *adapt, u32 mac_id, u8 rssi_level) { u8 init_rate = 0; diff --git a/drivers/staging/r8188eu/include/hal_intf.h b/drivers/staging/r8188eu/include/hal_intf.h index e1dfd621a5cb..ab6856d8a090 100644 --- a/drivers/staging/r8188eu/include/hal_intf.h +++ b/drivers/staging/r8188eu/include/hal_intf.h @@ -8,10 +8,6 @@ #include "drv_types.h" #include "Hal8188EPhyCfg.h" -enum hw_variables { - HW_VAR_CORRECT_TSF, -}; - typedef s32 (*c2h_id_filter)(u8 id); void rtl8188eu_interface_configure(struct adapter *adapt); @@ -32,8 +28,6 @@ int rtl8188e_IOL_exec_cmds_sync(struct adapter *adapter, unsigned int rtl8188eu_inirp_init(struct adapter *Adapter); -void SetHwReg8188EU(struct adapter *Adapter, u8 variable, u8 *val); - uint rtw_hal_init(struct adapter *padapter); uint rtw_hal_deinit(struct adapter *padapter); void rtw_hal_stop(struct adapter *padapter); From 51ee8ea588bca025cb03b0caa922d78bdb8ba901 Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sun, 24 Jul 2022 17:33:48 +0200 Subject: [PATCH 1277/1436] staging: r8188eu: remove OnAtim prototype The OnAtim function was removed in commit 6d933902c609 ("staging: r8188eu: remove OnAtim"). Remove the prototype as well. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220724153349.138741-2-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/include/rtw_mlme_ext.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h index bf952755ba35..cb3db22654eb 100644 --- a/drivers/staging/r8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h @@ -552,8 +552,6 @@ unsigned int DoReserved(struct adapter *padapter, struct recv_frame *precv_frame); unsigned int OnBeacon(struct adapter *padapter, struct recv_frame *precv_frame); -unsigned int OnAtim(struct adapter *padapter, - struct recv_frame *precv_frame); unsigned int OnDisassoc(struct adapter *padapter, struct recv_frame *precv_frame); unsigned int OnAuth(struct adapter *padapter, From 123b3b754e3fb4f3c8632eb88e32a36d356513eb Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sun, 24 Jul 2022 17:33:49 +0200 Subject: [PATCH 1278/1436] staging: r8188eu: remove DoReserved prototype The DoReserved function was removed in commit 869ddbfccdea ("staging: r8188eu: remove dummy entries from OnAction_tbl"). Remove the prototype as well. Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Martin Kaiser Link: https://lore.kernel.org/r/20220724153349.138741-3-martin@kaiser.cx Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/include/rtw_mlme_ext.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/r8188eu/include/rtw_mlme_ext.h b/drivers/staging/r8188eu/include/rtw_mlme_ext.h index cb3db22654eb..343ce1ce4b3d 100644 --- a/drivers/staging/r8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/r8188eu/include/rtw_mlme_ext.h @@ -548,8 +548,6 @@ unsigned int OnProbeReq(struct adapter *padapter, struct recv_frame *precv_frame); unsigned int OnProbeRsp(struct adapter *padapter, struct recv_frame *precv_frame); -unsigned int DoReserved(struct adapter *padapter, - struct recv_frame *precv_frame); unsigned int OnBeacon(struct adapter *padapter, struct recv_frame *precv_frame); unsigned int OnDisassoc(struct adapter *padapter, From 47092381023050ab90c3f0603a587f798d37f194 Mon Sep 17 00:00:00 2001 From: Michael Straube Date: Sun, 24 Jul 2022 20:25:20 +0200 Subject: [PATCH 1279/1436] staging: r8188eu: make dump_chip_info() static The function dump_chip_info() is only used in rtl8188e_hal_init.c. Make it static to reduce the driver object file size by 281 bytes. before: text data bss dec hex filename 530606 43897 7072 581575 8dfc7 drivers/staging/r8188eu/r8188eu.o after: text data bss dec hex filename 530405 43817 7072 581294 8deae drivers/staging/r8188eu/r8188eu.o Tested-by: Philipp Hortmann # Edimax N150 Signed-off-by: Michael Straube Link: https://lore.kernel.org/r/20220724182520.7794-1-straube.linux@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/hal/hal_com.c | 39 ------------------- .../staging/r8188eu/hal/rtl8188e_hal_init.c | 39 +++++++++++++++++++ drivers/staging/r8188eu/include/hal_com.h | 3 -- 3 files changed, 39 insertions(+), 42 deletions(-) diff --git a/drivers/staging/r8188eu/hal/hal_com.c b/drivers/staging/r8188eu/hal/hal_com.c index e9a32dd84a8e..6a1cdc67335b 100644 --- a/drivers/staging/r8188eu/hal/hal_com.c +++ b/drivers/staging/r8188eu/hal/hal_com.c @@ -10,45 +10,6 @@ #define _HAL_INIT_C_ -void dump_chip_info(struct HAL_VERSION chip_vers) -{ - uint cnt = 0; - char buf[128]; - - cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8188E_"); - cnt += sprintf((buf + cnt), "%s_", IS_NORMAL_CHIP(chip_vers) ? - "Normal_Chip" : "Test_Chip"); - cnt += sprintf((buf + cnt), "%s_", IS_CHIP_VENDOR_TSMC(chip_vers) ? - "TSMC" : "UMC"); - - switch (chip_vers.CUTVersion) { - case A_CUT_VERSION: - cnt += sprintf((buf + cnt), "A_CUT_"); - break; - case B_CUT_VERSION: - cnt += sprintf((buf + cnt), "B_CUT_"); - break; - case C_CUT_VERSION: - cnt += sprintf((buf + cnt), "C_CUT_"); - break; - case D_CUT_VERSION: - cnt += sprintf((buf + cnt), "D_CUT_"); - break; - case E_CUT_VERSION: - cnt += sprintf((buf + cnt), "E_CUT_"); - break; - default: - cnt += sprintf((buf + cnt), "UNKNOWN_CUT(%d)_", chip_vers.CUTVersion); - break; - } - - cnt += sprintf((buf + cnt), "1T1R_"); - - cnt += sprintf((buf + cnt), "RomVer(%d)\n", 0); - - pr_info("%s", buf); -} - #define CHAN_PLAN_HW 0x80 u8 /* return the final channel plan decision */ diff --git a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c index fe477438899e..5b8f1a912bbb 100644 --- a/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/r8188eu/hal/rtl8188e_hal_init.c @@ -526,6 +526,45 @@ void rtl8188e_ReadEFuse(struct adapter *Adapter, u16 _size_byte, u8 *pbuf) Hal_EfuseReadEFuse88E(Adapter, 0, _size_byte, pbuf); } +static void dump_chip_info(struct HAL_VERSION chip_vers) +{ + uint cnt = 0; + char buf[128]; + + cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8188E_"); + cnt += sprintf((buf + cnt), "%s_", IS_NORMAL_CHIP(chip_vers) ? + "Normal_Chip" : "Test_Chip"); + cnt += sprintf((buf + cnt), "%s_", IS_CHIP_VENDOR_TSMC(chip_vers) ? + "TSMC" : "UMC"); + + switch (chip_vers.CUTVersion) { + case A_CUT_VERSION: + cnt += sprintf((buf + cnt), "A_CUT_"); + break; + case B_CUT_VERSION: + cnt += sprintf((buf + cnt), "B_CUT_"); + break; + case C_CUT_VERSION: + cnt += sprintf((buf + cnt), "C_CUT_"); + break; + case D_CUT_VERSION: + cnt += sprintf((buf + cnt), "D_CUT_"); + break; + case E_CUT_VERSION: + cnt += sprintf((buf + cnt), "E_CUT_"); + break; + default: + cnt += sprintf((buf + cnt), "UNKNOWN_CUT(%d)_", chip_vers.CUTVersion); + break; + } + + cnt += sprintf((buf + cnt), "1T1R_"); + + cnt += sprintf((buf + cnt), "RomVer(%d)\n", 0); + + pr_info("%s", buf); +} + void rtl8188e_read_chip_version(struct adapter *padapter) { u32 value32; diff --git a/drivers/staging/r8188eu/include/hal_com.h b/drivers/staging/r8188eu/include/hal_com.h index 56ba356b5371..d7e333f6ce39 100644 --- a/drivers/staging/r8188eu/include/hal_com.h +++ b/drivers/staging/r8188eu/include/hal_com.h @@ -131,9 +131,6 @@ #define REG_NOA_DESC_START 0x05E8 #define REG_NOA_DESC_COUNT 0x05EC -#include "HalVerDef.h" -void dump_chip_info(struct HAL_VERSION ChipVersion); - /* return the final channel plan decision */ u8 hal_com_get_channel_plan(struct adapter *padapter, u8 hw_channel_plan, From 2b5002e2cc1483b6333d31e21902b78a1997909e Mon Sep 17 00:00:00 2001 From: Phillip Potter Date: Mon, 25 Jul 2022 23:07:45 +0100 Subject: [PATCH 1280/1436] staging: r8188eu: convert rtw_pwr_wakeup to correct error code semantics Convert the rtw_pwr_wakeup function to use 0 on success and an appropriate error code on error. For the first failure block where ips_leave is invoked, use -ENOMEM as this is the main cause of failure here anyway. For the second failure block, use -EBUSY, as it seems the most appropriate. Finally, within the functions rtw_wx_set_mode, rtw_wx_set_wap, rtw_wx_set_scan and rtw_wx_set_essid, pass the error code on from rtw_pwr_wakeup as appropriate now that it is converted. This gets the driver closer to removal of the non-standard _SUCCESS and _FAIL definitions, which are inverted compared to the standard in-kernel error code mechanism. Tested-by: Philipp Hortmann # Edimax N150 Reviewed-by: Dan Carpenter Signed-off-by: Phillip Potter Link: https://lore.kernel.org/r/20220725220745.12739-1-phil@philpotter.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_p2p.c | 4 ++-- drivers/staging/r8188eu/core/rtw_pwrctrl.c | 10 ++++---- drivers/staging/r8188eu/os_dep/ioctl_linux.c | 24 +++++++------------- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_p2p.c b/drivers/staging/r8188eu/core/rtw_p2p.c index c306aafa183b..bd654d4ff8b4 100644 --- a/drivers/staging/r8188eu/core/rtw_p2p.c +++ b/drivers/staging/r8188eu/core/rtw_p2p.c @@ -1888,7 +1888,7 @@ int rtw_p2p_enable(struct adapter *padapter, enum P2P_ROLE role) if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT || role == P2P_ROLE_GO) { /* leave IPS/Autosuspend */ - if (rtw_pwr_wakeup(padapter) == _FAIL) { + if (rtw_pwr_wakeup(padapter)) { ret = _FAIL; goto exit; } @@ -1902,7 +1902,7 @@ int rtw_p2p_enable(struct adapter *padapter, enum P2P_ROLE role) init_wifidirect_info(padapter, role); } else if (role == P2P_ROLE_DISABLE) { - if (rtw_pwr_wakeup(padapter) == _FAIL) { + if (rtw_pwr_wakeup(padapter)) { ret = _FAIL; goto exit; } diff --git a/drivers/staging/r8188eu/core/rtw_pwrctrl.c b/drivers/staging/r8188eu/core/rtw_pwrctrl.c index cf9020a73933..8b1c50668dfe 100644 --- a/drivers/staging/r8188eu/core/rtw_pwrctrl.c +++ b/drivers/staging/r8188eu/core/rtw_pwrctrl.c @@ -381,24 +381,24 @@ int rtw_pwr_wakeup(struct adapter *padapter) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; unsigned long timeout = jiffies + msecs_to_jiffies(3000); unsigned long deny_time; - int ret = _SUCCESS; + int ret = 0; while (pwrpriv->ps_processing && time_before(jiffies, timeout)) msleep(10); /* I think this should be check in IPS, LPS, autosuspend functions... */ if (check_fwstate(pmlmepriv, _FW_LINKED)) { - ret = _SUCCESS; + ret = 0; goto exit; } if (pwrpriv->rf_pwrstate == rf_off && ips_leave(padapter) == _FAIL) { - ret = _FAIL; + ret = -ENOMEM; goto exit; } if (padapter->bDriverStopped || !padapter->bup || !padapter->hw_init_completed) { - ret = _FAIL; + ret = -EBUSY; goto exit; } @@ -439,7 +439,7 @@ int rtw_pm_set_ips(struct adapter *padapter, u8 mode) return 0; } else if (mode == IPS_NONE) { rtw_ips_mode_req(pwrctrlpriv, mode); - if ((padapter->bSurpriseRemoved == 0) && (rtw_pwr_wakeup(padapter) == _FAIL)) + if ((padapter->bSurpriseRemoved == 0) && rtw_pwr_wakeup(padapter)) return -EFAULT; } else { return -EINVAL; diff --git a/drivers/staging/r8188eu/os_dep/ioctl_linux.c b/drivers/staging/r8188eu/os_dep/ioctl_linux.c index 930bb4aea435..7f91dac2e41b 100644 --- a/drivers/staging/r8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/r8188eu/os_dep/ioctl_linux.c @@ -687,12 +687,9 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a, enum ndis_802_11_network_infra networkType; int ret = 0; - - - if (_FAIL == rtw_pwr_wakeup(padapter)) { - ret = -EPERM; + ret = rtw_pwr_wakeup(padapter); + if (ret) goto exit; - } if (!padapter->hw_init_completed) { ret = -EPERM; @@ -931,12 +928,9 @@ static int rtw_wx_set_wap(struct net_device *dev, struct wlan_network *pnetwork = NULL; enum ndis_802_11_auth_mode authmode; - - - if (_FAIL == rtw_pwr_wakeup(padapter)) { - ret = -1; + ret = rtw_pwr_wakeup(padapter); + if (ret) goto exit; - } if (!padapter->bup) { ret = -1; @@ -1049,10 +1043,9 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; struct wifidirect_info *pwdinfo = &padapter->wdinfo; - if (_FAIL == rtw_pwr_wakeup(padapter)) { - ret = -1; + ret = rtw_pwr_wakeup(padapter); + if (ret) goto exit; - } if (padapter->bDriverStopped) { ret = -1; @@ -1252,10 +1245,9 @@ static int rtw_wx_set_essid(struct net_device *dev, uint ret = 0, len; - if (_FAIL == rtw_pwr_wakeup(padapter)) { - ret = -1; + ret = rtw_pwr_wakeup(padapter); + if (ret) goto exit; - } if (!padapter->bup) { ret = -1; From ff50a91ee5e6db357c900dce280a7129dc9e363c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 15 Jul 2022 23:56:57 +0100 Subject: [PATCH 1281/1436] usb: phy: remove redundant store to variable var after & operation There is no need to store the result of the & operation back to the variable var. The store is redundant, replace &= with just &. Cleans up clang scan warning: drivers/usb/phy/phy-keystone.c:62:5: warning: Although the value stored to 'val' is used in the enclosing expression, the value is never actually read from 'val' [deadcode.DeadStores] Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20220715225657.353828-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/phy/phy-keystone.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index 358d05cb643d..f75912279b39 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -59,7 +59,7 @@ static void keystone_usbphy_shutdown(struct usb_phy *phy) val = keystone_usbphy_readl(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK); keystone_usbphy_writel(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK, - val &= ~PHY_REF_SSP_EN); + val & ~PHY_REF_SSP_EN); } static int keystone_usbphy_probe(struct platform_device *pdev) From cfed201e2db273562de152d22b74f74dee77e301 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 22 Jul 2022 09:25:42 +0300 Subject: [PATCH 1282/1436] usb: typec: anx7411: Fix an array out of bounds This should be ARRAY_SIZE() instead of sizeof(). ARRAY_SIZE is 4 and sizeof is 8. Fixes: fe6d8a9c8e64 ("usb: typec: anx7411: Add Analogix PD ANX7411 support") Reviewed-by: Xin Ji Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YtpC5s4/AD8vFz+X@kili Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/anx7411.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index b990376991f8..4f7a5cc968d0 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -992,7 +992,7 @@ static int anx7411_register_i2c_dummy_clients(struct anx7411_data *ctx, int i; u8 spi_addr; - for (i = 0; i < sizeof(anx7411_i2c_addr); i++) { + for (i = 0; i < ARRAY_SIZE(anx7411_i2c_addr); i++) { if (client->addr == (anx7411_i2c_addr[i].tcpc_address >> 1)) { spi_addr = anx7411_i2c_addr[i].spi_address >> 1; ctx->spi_client = i2c_new_dummy_device(client->adapter, From 9310bd4bf20ff9ab180a0158f917b1d9af3247dc Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 22 Jul 2022 09:29:07 +0300 Subject: [PATCH 1283/1436] usb: typec: anx7411: fix error checking in anx7411_get_gpio_irq() This is a minor bug which means that certain error messages are not printed. The devm_gpiod_get_optional() function can return either error pointers or NULL. It returns error pointers if there is an allocation failure, or a similar issue. It returns NULL if no GPIO was assigned to the requested function. Print an error in either case. The gpiod_to_irq() function never returns zero. It either returns a positive IRQ number or a negative error code. Fixes: fe6d8a9c8e64 ("usb: typec: anx7411: Add Analogix PD ANX7411 support") Reviewed-by: Xin Ji Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YtpDs8VsWIbl/Smd@kili Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/anx7411.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index 4f7a5cc968d0..311b56aaea9f 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -1326,13 +1326,13 @@ static void anx7411_get_gpio_irq(struct anx7411_data *ctx) struct device *dev = &ctx->tcpc_client->dev; ctx->intp_gpiod = devm_gpiod_get_optional(dev, "interrupt", GPIOD_IN); - if (!ctx->intp_gpiod) { + if (IS_ERR_OR_NULL(ctx->intp_gpiod)) { dev_err(dev, "no interrupt gpio property\n"); return; } ctx->intp_irq = gpiod_to_irq(ctx->intp_gpiod); - if (!ctx->intp_irq) + if (ctx->intp_irq < 0) dev_err(dev, "failed to get GPIO IRQ\n"); } From 0c25bab1abb43dbe2662e88f56e157ccac76f8c2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 22 Jul 2022 09:29:52 +0300 Subject: [PATCH 1284/1436] usb: typec: anx7411: use semi-colons instead of commas Semi colons and commas are equivalent in this context but semi-colons are better style. Reviewed-by: Xin Ji Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YtpD4MKBa43higNc@kili Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/anx7411.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index 311b56aaea9f..18a6a6a8b9eb 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -1421,12 +1421,12 @@ static int anx7411_psy_register(struct anx7411_data *ctx) psy_desc->type = POWER_SUPPLY_TYPE_USB; psy_desc->usb_types = anx7411_psy_usb_types; psy_desc->num_usb_types = ARRAY_SIZE(anx7411_psy_usb_types); - psy_desc->properties = anx7411_psy_props, - psy_desc->num_properties = ARRAY_SIZE(anx7411_psy_props), + psy_desc->properties = anx7411_psy_props; + psy_desc->num_properties = ARRAY_SIZE(anx7411_psy_props); - psy_desc->get_property = anx7411_psy_get_prop, - psy_desc->set_property = anx7411_psy_set_prop, - psy_desc->property_is_writeable = anx7411_psy_prop_writeable, + psy_desc->get_property = anx7411_psy_get_prop; + psy_desc->set_property = anx7411_psy_set_prop; + psy_desc->property_is_writeable = anx7411_psy_prop_writeable; ctx->usb_type = POWER_SUPPLY_USB_TYPE_C; ctx->psy = devm_power_supply_register(ctx->dev, psy_desc, &psy_cfg); From 67fb0cc02f89049e532b008faa35818c82aa0d62 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 21 Jul 2022 15:11:59 +0800 Subject: [PATCH 1285/1436] usb: typec: anx7411: Fix wrong pointer passed to PTR_ERR() It should be 'ctx->typec.amode[i]' passed to PTR_ERR() when typec_partner_register_altmode() failed. Fixes: fe6d8a9c8e64 ("usb: typec: anx7411: Add Analogix PD ANX7411 support") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220721071201.269344-1-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/anx7411.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index 18a6a6a8b9eb..e16c2d511e8f 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -549,6 +549,7 @@ static int anx7411_typec_register_altmode(struct anx7411_data *ctx, { struct device *dev = &ctx->spi_client->dev; struct typec_altmode_desc desc; + int err; int i; desc.svid = svid; @@ -569,8 +570,9 @@ static int anx7411_typec_register_altmode(struct anx7411_data *ctx, &desc); if (IS_ERR(ctx->typec.amode[i])) { dev_err(dev, "failed to register altmode\n"); + err = PTR_ERR(ctx->typec.amode[i]); ctx->typec.amode[i] = NULL; - return PTR_ERR(ctx->typec.amode); + return err; } return 0; From 5cda657679f8fcb2896e4ac0aa8e231f12f9fb04 Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 21 Jul 2022 15:12:00 +0800 Subject: [PATCH 1286/1436] usb: typec: anx7411: Fix return value check in anx7411_register_i2c_dummy_clients() If i2c_new_dummy_device() fails, it never return NULL pointer, replace NULL test with IS_ERR() to fix it. Fixes: fe6d8a9c8e64 ("usb: typec: anx7411: Add Analogix PD ANX7411 support") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220721071201.269344-2-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/anx7411.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index e16c2d511e8f..7692e26911b7 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -999,7 +999,7 @@ static int anx7411_register_i2c_dummy_clients(struct anx7411_data *ctx, spi_addr = anx7411_i2c_addr[i].spi_address >> 1; ctx->spi_client = i2c_new_dummy_device(client->adapter, spi_addr); - if (ctx->spi_client) + if (!IS_ERR(ctx->spi_client)) return 0; } } From d183a57cad920087a770c45721e98f45feea0fde Mon Sep 17 00:00:00 2001 From: Yang Yingliang Date: Thu, 21 Jul 2022 15:12:01 +0800 Subject: [PATCH 1287/1436] usb: typec: anx7411: Fix error return code in anx7411_i2c_probe() Add mising error return code when failed to get interrupt or failed to register psy. Fixes: fe6d8a9c8e64 ("usb: typec: anx7411: Add Analogix PD ANX7411 support") Signed-off-by: Yang Yingliang Link: https://lore.kernel.org/r/20220721071201.269344-3-yangyingliang@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/anx7411.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index 7692e26911b7..f8baa1e189b3 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -1483,12 +1483,14 @@ static int anx7411_i2c_probe(struct i2c_client *client, if (!plat->intp_irq) { dev_err(dev, "fail to get interrupt IRQ\n"); + ret = -EINVAL; goto free_typec_port; } plat->dev = dev; plat->psy_online = ANX7411_PSY_OFFLINE; - if (anx7411_psy_register(plat)) { + ret = anx7411_psy_register(plat); + if (ret) { dev_err(dev, "register psy\n"); goto free_typec_port; } From 23bb7b49597139d38f4da9392df28a24229697b6 Mon Sep 17 00:00:00 2001 From: Xin Ji Date: Fri, 22 Jul 2022 16:18:34 +0800 Subject: [PATCH 1288/1436] usb: typec: anx7411: fix passing zero to 'PTR_ERR' Fix anx7411_register_partner() warn: passing zero to 'PTR_ERR' Fixes: fe6d8a9c8e64 ("usb: typec: anx7411: Add Analogix PD ANX7411 support") Signed-off-by: Xin Ji Link: https://lore.kernel.org/r/20220722081836.3380885-1-xji@analogixsemi.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/anx7411.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/usb/typec/anx7411.c b/drivers/usb/typec/anx7411.c index f8baa1e189b3..c0f0842d443c 100644 --- a/drivers/usb/typec/anx7411.c +++ b/drivers/usb/typec/anx7411.c @@ -374,6 +374,7 @@ static int anx7411_register_partner(struct anx7411_data *ctx, int pd, int accessory) { struct typec_partner_desc desc; + struct typec_partner *partner; if (ctx->typec.partner) return 0; @@ -381,11 +382,11 @@ static int anx7411_register_partner(struct anx7411_data *ctx, desc.usb_pd = pd; desc.accessory = accessory; desc.identity = NULL; - ctx->typec.partner = typec_register_partner(ctx->typec.port, &desc); - if (IS_ERR(ctx->typec.partner)) { - ctx->typec.partner = NULL; - return PTR_ERR(ctx->typec.partner); - } + partner = typec_register_partner(ctx->typec.port, &desc); + if (IS_ERR(partner)) + return PTR_ERR(partner); + + ctx->typec.partner = partner; return 0; } From d7de14d74d6551f0d097430f9893ce82ad17e5b8 Mon Sep 17 00:00:00 2001 From: Alexey Sheplyakov Date: Fri, 22 Jul 2022 18:17:00 +0400 Subject: [PATCH 1289/1436] usb: xhci_plat_remove: avoid NULL dereference Since commit 4736ebd7fcaff1eb8481c140ba494962847d6e0a ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") xhci->shared_hcd can be NULL, which causes the following Oops on reboot: [ 710.124450] systemd-shutdown[1]: Rebooting. [ 710.298861] xhci-hcd xhci-hcd.2.auto: remove, state 4 [ 710.304217] usb usb3: USB disconnect, device number 1 [ 710.317441] xhci-hcd xhci-hcd.2.auto: USB bus 3 deregistered [ 710.323280] xhci-hcd xhci-hcd.2.auto: remove, state 1 [ 710.328401] usb usb2: USB disconnect, device number 1 [ 710.333515] usb 2-3: USB disconnect, device number 2 [ 710.467649] xhci-hcd xhci-hcd.2.auto: USB bus 2 deregistered [ 710.475450] Unable to handle kernel NULL pointer dereference at virtual address 00000000000003b8 [ 710.484425] Mem abort info: [ 710.487265] ESR = 0x0000000096000004 [ 710.491060] EC = 0x25: DABT (current EL), IL = 32 bits [ 710.496427] SET = 0, FnV = 0 [ 710.499525] EA = 0, S1PTW = 0 [ 710.502716] FSC = 0x04: level 0 translation fault [ 710.507648] Data abort info: [ 710.510577] ISV = 0, ISS = 0x00000004 [ 710.514462] CM = 0, WnR = 0 [ 710.517480] user pgtable: 4k pages, 48-bit VAs, pgdp=00000008b0050000 [ 710.523976] [00000000000003b8] pgd=0000000000000000, p4d=0000000000000000 [ 710.530961] Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 710.536551] Modules linked in: rfkill input_leds snd_soc_simple_card snd_soc_simple_card_utils snd_soc_nau8822 designware_i2s snd_soc_core dw_hdmi_ahb_audio snd_pcm_dmaengine arm_ccn panfrost ac97_bus gpu_sched snd_pcm at24 fuse configfs sdhci_of_dwcmshc sdhci_pltfm sdhci nvme led_class mmc_core nvme_core bt1_pvt polynomial tp_serio snd_seq_midi snd_seq_midi_event snd_seq snd_timer snd_rawmidi snd_seq_device snd soundcore efivarfs ipv6 [ 710.575286] CPU: 7 PID: 1 Comm: systemd-shutdow Not tainted 5.19.0-rc7-00043-gfd8619f4fd54 #1 [ 710.583822] Hardware name: T-Platforms TF307-MB/BM1BM1-A, BIOS 5.6 07/06/2022 [ 710.590972] pstate: 40000005 (nZcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 710.597949] pc : usb_remove_hcd+0x34/0x1e4 [ 710.602067] lr : xhci_plat_remove+0x74/0x140 [ 710.606351] sp : ffff800009f3b7c0 [ 710.609674] x29: ffff800009f3b7c0 x28: ffff000800960040 x27: 0000000000000000 [ 710.616833] x26: ffff800008dc22a0 x25: 0000000000000000 x24: 0000000000000000 [ 710.623992] x23: 0000000000000000 x22: ffff000805465810 x21: ffff000805465800 [ 710.631149] x20: ffff000800f80000 x19: 0000000000000000 x18: ffffffffffffffff [ 710.638307] x17: ffff000805096000 x16: ffff00080633b800 x15: ffff000806537a1c [ 710.645465] x14: 0000000000000001 x13: 0000000000000000 x12: ffff00080378d6f0 [ 710.652621] x11: ffff00080041a900 x10: ffff800009b204e8 x9 : ffff8000088abaa4 [ 710.659779] x8 : ffff000800960040 x7 : ffff800009409000 x6 : 0000000000000001 [ 710.666936] x5 : ffff800009241000 x4 : ffff800009241440 x3 : 0000000000000000 [ 710.674094] x2 : ffff000800960040 x1 : ffff000800960040 x0 : 0000000000000000 [ 710.681251] Call trace: [ 710.683704] usb_remove_hcd+0x34/0x1e4 [ 710.687467] xhci_plat_remove+0x74/0x140 [ 710.691400] platform_remove+0x34/0x70 [ 710.695165] device_remove+0x54/0x90 [ 710.698753] device_release_driver_internal+0x200/0x270 [ 710.703992] device_release_driver+0x24/0x30 [ 710.708273] bus_remove_device+0xe0/0x16c [ 710.712293] device_del+0x178/0x390 [ 710.715797] platform_device_del.part.0+0x24/0x90 [ 710.720514] platform_device_unregister+0x30/0x50 [ 710.725232] dwc3_host_exit+0x20/0x30 [ 710.728907] dwc3_remove+0x174/0x1b0 [ 710.732494] platform_remove+0x34/0x70 [ 710.736254] device_remove+0x54/0x90 [ 710.739840] device_release_driver_internal+0x200/0x270 [ 710.745078] device_release_driver+0x24/0x30 [ 710.749359] bus_remove_device+0xe0/0x16c [ 710.753380] device_del+0x178/0x390 [ 710.756881] platform_device_del.part.0+0x24/0x90 [ 710.761598] platform_device_unregister+0x30/0x50 [ 710.766314] of_platform_device_destroy+0xe8/0x100 [ 710.771119] device_for_each_child_reverse+0x70/0xc0 [ 710.776099] of_platform_depopulate+0x48/0x90 [ 710.780468] __dwc3_of_simple_teardown+0x28/0xe0 [ 710.785099] dwc3_of_simple_shutdown+0x20/0x30 [ 710.789555] platform_shutdown+0x30/0x40 [ 710.793490] device_shutdown+0x138/0x32c [ 710.797425] __do_sys_reboot+0x1c4/0x2ac [ 710.801362] __arm64_sys_reboot+0x30/0x40 [ 710.805383] invoke_syscall+0x50/0x120 [ 710.809146] el0_svc_common.constprop.0+0x68/0x124 [ 710.813950] do_el0_svc+0x3c/0xcc [ 710.817275] el0_svc+0x60/0x12c [ 710.820428] el0t_64_sync_handler+0xc0/0x13c [ 710.824710] el0t_64_sync+0x18c/0x190 [ 710.828386] Code: a9025bf5 f942c420 f9001fe0 d2800000 (b943ba62) [ 710.834498] ---[ end trace 0000000000000000 ]--- [ 710.875958] pstore: crypto_comp_compress failed, ret = -22! [ 710.895047] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 710.902757] Kernel Offset: disabled [ 710.906255] CPU features: 0x800,00004811,00001082 [ 710.910971] Memory Limit: none [ 710.927474] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]--- To avoid the problem check for NULL in usb_remove_hcd. Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports") Signed-off-by: Alexey Sheplyakov Link: https://lore.kernel.org/r/20220722141700.1271439-1-asheplyakov@basealt.ru Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 06eea8848ccc..41dcd41e550c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -3033,9 +3033,15 @@ EXPORT_SYMBOL_GPL(usb_add_hcd); */ void usb_remove_hcd(struct usb_hcd *hcd) { - struct usb_device *rhdev = hcd->self.root_hub; + struct usb_device *rhdev; bool rh_registered; + if (!hcd) { + pr_debug("%s: hcd is NULL\n", __func__); + return; + } + rhdev = hcd->self.root_hub; + dev_info(hcd->self.controller, "remove, state %x\n", hcd->state); usb_get_dev(rhdev); From 26c6c2f8a907c9e3a2f24990552a4d77235791e6 Mon Sep 17 00:00:00 2001 From: Weitao Wang Date: Tue, 26 Jul 2022 15:49:18 +0800 Subject: [PATCH 1290/1436] USB: HCD: Fix URB giveback issue in tasklet function Usb core introduce the mechanism of giveback of URB in tasklet context to reduce hardware interrupt handling time. On some test situation(such as FIO with 4KB block size), when tasklet callback function called to giveback URB, interrupt handler add URB node to the bh->head list also. If check bh->head list again after finish all URB giveback of local_list, then it may introduce a "dynamic balance" between giveback URB and add URB to bh->head list. This tasklet callback function may not exit for a long time, which will cause other tasklet function calls to be delayed. Some real-time applications(such as KB and Mouse) will see noticeable lag. In order to prevent the tasklet function from occupying the cpu for a long time at a time, new URBS will not be added to the local_list even though the bh->head list is not empty. But also need to ensure the left URB giveback to be processed in time, so add a member high_prio for structure giveback_urb_bh to prioritize tasklet and schelule this tasklet again if bh->head list is not empty. At the same time, we are able to prioritize tasklet through structure member high_prio. So, replace the local high_prio_bh variable with this structure member in usb_hcd_giveback_urb. Fixes: 94dfd7edfd5c ("USB: HCD: support giveback of URB in tasklet context") Cc: stable Reviewed-by: Alan Stern Signed-off-by: Weitao Wang Link: https://lore.kernel.org/r/20220726074918.5114-1-WeitaoWang-oc@zhaoxin.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 26 +++++++++++++++----------- include/linux/usb/hcd.h | 1 + 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 41dcd41e550c..a6a87c5d1b05 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1691,7 +1691,6 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t) spin_lock_irq(&bh->lock); bh->running = true; - restart: list_replace_init(&bh->head, &local_list); spin_unlock_irq(&bh->lock); @@ -1705,10 +1704,17 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t) bh->completing_ep = NULL; } - /* check if there are new URBs to giveback */ + /* + * giveback new URBs next time to prevent this function + * from not exiting for a long time. + */ spin_lock_irq(&bh->lock); - if (!list_empty(&bh->head)) - goto restart; + if (!list_empty(&bh->head)) { + if (bh->high_prio) + tasklet_hi_schedule(&bh->bh); + else + tasklet_schedule(&bh->bh); + } bh->running = false; spin_unlock_irq(&bh->lock); } @@ -1737,7 +1743,7 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t) void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) { struct giveback_urb_bh *bh; - bool running, high_prio_bh; + bool running; /* pass status to tasklet via unlinked */ if (likely(!urb->unlinked)) @@ -1748,13 +1754,10 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) return; } - if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) { + if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) bh = &hcd->high_prio_bh; - high_prio_bh = true; - } else { + else bh = &hcd->low_prio_bh; - high_prio_bh = false; - } spin_lock(&bh->lock); list_add_tail(&urb->urb_list, &bh->head); @@ -1763,7 +1766,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) if (running) ; - else if (high_prio_bh) + else if (bh->high_prio) tasklet_hi_schedule(&bh->bh); else tasklet_schedule(&bh->bh); @@ -2959,6 +2962,7 @@ int usb_add_hcd(struct usb_hcd *hcd, /* initialize tasklets */ init_giveback_urb_bh(&hcd->high_prio_bh); + hcd->high_prio_bh.high_prio = true; init_giveback_urb_bh(&hcd->low_prio_bh); /* enable irqs just before we start the controller, diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 2c1fc9212cf2..98d1921f02b1 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -66,6 +66,7 @@ struct giveback_urb_bh { bool running; + bool high_prio; spinlock_t lock; struct list_head head; struct tasklet_struct bh; From 2191c00855b03aa59c20e698be713d952d51fc18 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 21 Jul 2022 11:07:10 -0400 Subject: [PATCH 1291/1436] USB: gadget: Fix use-after-free Read in usb_udc_uevent() The syzbot fuzzer found a race between uevent callbacks and gadget driver unregistration that can cause a use-after-free bug: --------------------------------------------------------------- BUG: KASAN: use-after-free in usb_udc_uevent+0x11f/0x130 drivers/usb/gadget/udc/core.c:1732 Read of size 8 at addr ffff888078ce2050 by task udevd/2968 CPU: 1 PID: 2968 Comm: udevd Not tainted 5.19.0-rc4-next-20220628-syzkaller #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/29/2022 Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106 print_address_description mm/kasan/report.c:317 [inline] print_report.cold+0x2ba/0x719 mm/kasan/report.c:433 kasan_report+0xbe/0x1f0 mm/kasan/report.c:495 usb_udc_uevent+0x11f/0x130 drivers/usb/gadget/udc/core.c:1732 dev_uevent+0x290/0x770 drivers/base/core.c:2424 --------------------------------------------------------------- The bug occurs because usb_udc_uevent() dereferences udc->driver but does so without acquiring the udc_lock mutex, which protects this field. If the gadget driver is unbound from the udc concurrently with uevent processing, the driver structure may be accessed after it has been deallocated. To prevent the race, we make sure that the routine holds the mutex around the racing accesses. Link: CC: stable@vger.kernel.org # fc274c1e9973 Reported-and-tested-by: syzbot+b0de012ceb1e2a97891b@syzkaller.appspotmail.com Signed-off-by: Alan Stern Link: https://lore.kernel.org/r/YtlrnhHyrHsSky9m@rowland.harvard.edu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/core.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 7886497253cc..cafcf260394c 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1728,13 +1728,14 @@ static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env) return ret; } - if (udc->driver) { + mutex_lock(&udc_lock); + if (udc->driver) ret = add_uevent_var(env, "USB_UDC_DRIVER=%s", udc->driver->function); - if (ret) { - dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n"); - return ret; - } + mutex_unlock(&udc_lock); + if (ret) { + dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n"); + return ret; } return 0; From 86c4bb4f124eec79423b90ef138402bf0b809bce Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 16 Jul 2022 21:13:12 +0800 Subject: [PATCH 1292/1436] usb/atm: fix repeated words in comments Delete the redundant word 'was'. Signed-off-by: Jilin Yuan Link: https://lore.kernel.org/r/20220716131312.31767-1-yuanjilin@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/atm/ueagle-atm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 786299892c7f..5812f7ea7f90 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -9,7 +9,7 @@ * HISTORY : some part of the code was base on ueagle 1.3 BSD driver, * Damien Bergamini agree to put his code under a DUAL GPL/BSD license. * - * The rest of the code was was rewritten from scratch. + * The rest of the code was rewritten from scratch. */ #include From a7a9f4c0060e8f29a5fc2fe610575c3eabfc2253 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 16 Jul 2022 21:24:03 +0800 Subject: [PATCH 1293/1436] usb/core: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: Jilin Yuan Link: https://lore.kernel.org/r/20220716132403.35270-1-yuanjilin@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 2 +- drivers/usb/core/usb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index b87452e22835..7e7e119c253f 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1482,7 +1482,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) * @msg: Power Management message describing this state transition * * This is the central routine for resuming USB devices. It calls the - * the resume method for @udev and then calls the resume methods for all + * resume method for @udev and then calls the resume methods for all * the interface drivers in @udev. * * Autoresume requests originating from a child device or an interface diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 2f71636af6e1..11b15d7b357a 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -801,7 +801,7 @@ EXPORT_SYMBOL_GPL(usb_intf_get_dma_device); * is simple: * * When locking both a device and its parent, always lock the - * the parent first. + * parent first. */ /** From 973939279a20c1368bbd818b49ad2443689cd926 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 16 Jul 2022 21:36:24 +0800 Subject: [PATCH 1294/1436] usb/host: fix repeated words in comments Delete the redundant word 'the'. Delete the redundant word 'to'. Signed-off-by: Jilin Yuan Link: https://lore.kernel.org/r/20220716133624.41994-1-yuanjilin@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/uhci-grlib.c | 2 +- drivers/usb/host/uhci-hcd.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c index 0a201a73b196..3ef6d52839e5 100644 --- a/drivers/usb/host/uhci-grlib.c +++ b/drivers/usb/host/uhci-grlib.c @@ -43,7 +43,7 @@ static int uhci_grlib_init(struct usb_hcd *hcd) uhci->rh_numports = uhci_count_ports(hcd); - /* Set up pointers to to generic functions */ + /* Set up pointers to generic functions */ uhci->reset_hc = uhci_generic_reset_hc; uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc; /* No special actions need to be taken for the functions below */ diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h index 8ae5ccd26753..0688c3e5bfe2 100644 --- a/drivers/usb/host/uhci-hcd.h +++ b/drivers/usb/host/uhci-hcd.h @@ -314,7 +314,7 @@ struct uhci_td { * * There's a special skeleton QH for Isochronous QHs which never appears * on the schedule. Isochronous TDs go on the schedule before the - * the skeleton QHs. The hardware accesses them directly rather than + * skeleton QHs. The hardware accesses them directly rather than * through their QH, which is used only for bookkeeping purposes. * While the UHCI spec doesn't forbid the use of QHs for Isochronous, * it doesn't use them either. And the spec says that queues never From cd86f367eb6b5154230650c8f8c4003da0c12f54 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 16 Jul 2022 21:38:25 +0800 Subject: [PATCH 1295/1436] usb/image: fix repeated words in comments Delete the redundant word 'the'. Signed-off-by: Jilin Yuan Link: https://lore.kernel.org/r/20220716133825.43161-1-yuanjilin@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/image/mdc800.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index fc0e22cc6fda..67f098579fb4 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -38,7 +38,7 @@ * * version 0.7.3 * bugfix : The mdc800->state field gets set to READY after the - * the disconnect function sets it to NOT_CONNECTED. This makes the + * disconnect function sets it to NOT_CONNECTED. This makes the * driver running like the camera is connected and causes some * hang ups. * From 676cb83b11c3648f513e84cf3a8616e9e1539d44 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 16 Jul 2022 21:41:05 +0800 Subject: [PATCH 1296/1436] usb/misc: fix repeated words in comments Delete the redundant word 'with'. Signed-off-by: Jilin Yuan Link: https://lore.kernel.org/r/20220716134105.44710-1-yuanjilin@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbtest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 150090ee4ec1..ac0d75ac2d2f 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -2638,7 +2638,7 @@ usbtest_do_ioctl(struct usb_interface *intf, struct usbtest_param_32 *param) * different busses) to use when testing, and allocate one thread per * test. So discovery is simplified, and we have no device naming issues. * - * Don't use these only as stress/load tests. Use them along with with + * Don't use these only as stress/load tests. Use them along with * other USB bus activity: plugging, unplugging, mousing, mp3 playback, * video capture, and so on. Run different tests at different times, in * different sequences. Nothing here should interact with other devices, From d5851c2480253e6a58965d832d5ffbffba6c4729 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 16 Jul 2022 21:44:57 +0800 Subject: [PATCH 1297/1436] usb/musb: fix repeated words in comments Delete the redundant word 'mode'. Delete the redundant word 'than'. Signed-off-by: Jilin Yuan Link: https://lore.kernel.org/r/20220716134457.46535-1-yuanjilin@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_cppi41.c | 2 +- drivers/usb/musb/tusb6010.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 7fbb8a307145..c963cb8565f2 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -286,7 +286,7 @@ static void cppi41_dma_callback(void *private_data, * receive a FIFO empty interrupt so the only thing we can do is * to poll for the bit. On HS it usually takes 2us, on FS around * 110us - 150us depending on the transfer size. - * We spin on HS (no longer than than 25us and setup a timer on + * We spin on HS (no longer than 25us and setup a timer on * FS to check for the bit and complete the transfer. */ if (is_host_active(musb)) { diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 7ed4cc348d99..5609b4e84d40 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -495,7 +495,7 @@ done: } /* - * Maybe put TUSB6010 into idle mode mode depending on USB link status, + * Maybe put TUSB6010 into idle mode depending on USB link status, * like "disconnected" or "suspended". We'll be woken out of it by * connect, resume, or disconnect. * From 908d34aad1ef9214899ec07bfb2a9924f8ed52ff Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 16 Jul 2022 21:56:42 +0800 Subject: [PATCH 1298/1436] usb/typec/tcpm: fix repeated words in comments Delete the redundant word 'to'. Reviewed-by: Guenter Roeck Acked-by: Heikki Krogerus Signed-off-by: Jilin Yuan Link: https://lore.kernel.org/r/20220716135642.52460-1-yuanjilin@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/tcpm/tcpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index e1126a6c8e46..ea5a917c51b1 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -4520,7 +4520,7 @@ static void run_state_machine(struct tcpm_port *port) * The specification suggests that dual mode ports in sink * mode should transition to state PE_SRC_Transition_to_default. * See USB power delivery specification chapter 8.3.3.6.1.3. - * This would mean to to + * This would mean to * - turn off VCONN, reset power supply * - request hardware reset * - turn on VCONN From 13da6f41fbe01afc4937aabef87950223d52c83f Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 16 Jul 2022 12:17:55 +0800 Subject: [PATCH 1299/1436] USB: xhci: Fix comment typo The double `the' is duplicated in the comment, remove one. Signed-off-by: Jason Wang Link: https://lore.kernel.org/r/20220716041755.34016-1-wangborong@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 46d0b9ad6f74..ad81e9a508b1 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1964,7 +1964,7 @@ static void handle_port_status(struct xhci_hcd *xhci, /* * Check to see if xhci-hub.c is waiting on RExit to U0 transition (or - * RExit to a disconnect state). If so, let the the driver know it's + * RExit to a disconnect state). If so, let the driver know it's * out of the RExit state. */ if (!DEV_SUPERSPEED_ANY(portsc) && hcd->speed < HCD_USB3 && From 0c34043897736a3fac259564a6323a1f045100bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= Date: Mon, 25 Jul 2022 16:31:29 -0400 Subject: [PATCH 1300/1436] usb: typec: retimer: Add missing id check in match callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fwnode_connection_find_match() function handles two cases: named references and graph endpoints. In the second case, the match function passed in is called with the id to check for the match. However, the match function for the recently added type-c retimer class assumes the connection has already been matched (which is only true for the first case). The result is that with that change, all type-c nodes with graph endpoints defer probe indefinitely, independently of having a retimer connection or not. Add the missing check, like is done by the type-c mux and usb role switch code, to fix the issue. Fixes: ddaf8d96f93b ("usb: typec: Add support for retimers") Reviewed-by: Prashant Malani Signed-off-by: Nícolas F. R. A. Prado Link: https://lore.kernel.org/r/20220725203129.1973260-1-nfraprado@collabora.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/retimer.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/typec/retimer.c b/drivers/usb/typec/retimer.c index 051eaa7d2899..2003731f1bee 100644 --- a/drivers/usb/typec/retimer.c +++ b/drivers/usb/typec/retimer.c @@ -36,8 +36,13 @@ static int retimer_fwnode_match(struct device *dev, const void *fwnode) static void *typec_retimer_match(struct fwnode_handle *fwnode, const char *id, void *data) { - struct device *dev = class_find_device(&retimer_class, NULL, fwnode, - retimer_fwnode_match); + struct device *dev; + + if (id && !fwnode_property_present(fwnode, id)) + return NULL; + + dev = class_find_device(&retimer_class, NULL, fwnode, + retimer_fwnode_match); return dev ? to_typec_retimer(dev) : ERR_PTR(-EPROBE_DEFER); } From b2d0dd5155c437ec5aad2141d74a8fac97ef755f Mon Sep 17 00:00:00 2001 From: Chen Xingdi Date: Wed, 27 Jul 2022 11:11:46 +0800 Subject: [PATCH 1301/1436] usb: renesas-xhci: Do not print any log while fw verif success When drivers are working properly, they should be quiet. Signed-off-by: Chen Xingdi Link: https://lore.kernel.org/r/20220727031146.19345-1-chenxingdi@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-pci-renesas.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/usb/host/xhci-pci-renesas.c b/drivers/usb/host/xhci-pci-renesas.c index 52599d96634f..93f8b355bc70 100644 --- a/drivers/usb/host/xhci-pci-renesas.c +++ b/drivers/usb/host/xhci-pci-renesas.c @@ -120,7 +120,6 @@ static int renesas_fw_verify(const void *fw_data, size_t length) { u16 fw_version_pointer; - u16 fw_version; /* * The Firmware's Data Format is describe in @@ -150,9 +149,6 @@ static int renesas_fw_verify(const void *fw_data, return -EINVAL; } - fw_version = get_unaligned_le16(fw_data + fw_version_pointer); - pr_err("got firmware version: %02x.", fw_version); - return 0; } From fe3cc0cebe6091675c8bacd94e232a3203b939b8 Mon Sep 17 00:00:00 2001 From: Jilin Yuan Date: Sat, 16 Jul 2022 21:16:30 +0800 Subject: [PATCH 1302/1436] usb/chipidea: fix repeated words in comments Delete the redundant word 'power'. Acked-by: Peter Chen Signed-off-by: Jilin Yuan Link: https://lore.kernel.org/r/20220716131630.33151-1-yuanjilin@cdjrlc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/otg_fsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 6ed4b00dba96..61b157b9c662 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -459,7 +459,7 @@ static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on) struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm); if (on) { - /* Enable power power */ + /* Enable power */ hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, PORTSC_PP); if (ci->platdata->reg_vbus) { From c3ffc9c4ca44bfe9562166793d133e1fb0630ea6 Mon Sep 17 00:00:00 2001 From: Andrey Strachuk Date: Mon, 18 Jul 2022 19:00:52 +0300 Subject: [PATCH 1303/1436] usb: cdns3: change place of 'priv_ep' assignment in cdns3_gadget_ep_dequeue(), cdns3_gadget_ep_enable() If 'ep' is NULL, result of ep_to_cdns3_ep(ep) is invalid pointer and its dereference with priv_ep->cdns3_dev may cause panic. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: 7733f6c32e36 ("usb: cdns3: Add Cadence USB3 DRD Driver") Acked-by: Peter Chen Signed-off-by: Andrey Strachuk Link: https://lore.kernel.org/r/20220718160052.4188-1-strochuk@ispras.ru Signed-off-by: Greg Kroah-Hartman --- drivers/usb/cdns3/cdns3-gadget.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index 555caafe4f04..9ac7d0a8c5da 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -2285,14 +2285,15 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep, int val; priv_ep = ep_to_cdns3_ep(ep); - priv_dev = priv_ep->cdns3_dev; - comp_desc = priv_ep->endpoint.comp_desc; if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { dev_dbg(priv_dev->dev, "usbss: invalid parameters\n"); return -EINVAL; } + comp_desc = priv_ep->endpoint.comp_desc; + priv_dev = priv_ep->cdns3_dev; + if (!desc->wMaxPacketSize) { dev_err(priv_dev->dev, "usbss: missing wMaxPacketSize\n"); return -EINVAL; @@ -2600,7 +2601,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, struct usb_request *request) { struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); - struct cdns3_device *priv_dev = priv_ep->cdns3_dev; + struct cdns3_device *priv_dev; struct usb_request *req, *req_temp; struct cdns3_request *priv_req; struct cdns3_trb *link_trb; @@ -2611,6 +2612,8 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, if (!ep || !request || !ep->desc) return -EINVAL; + priv_dev = priv_ep->cdns3_dev; + spin_lock_irqsave(&priv_dev->lock, flags); priv_req = to_cdns3_request(request); From a7dc438b5e446afcd1b3b6651da28271400722f2 Mon Sep 17 00:00:00 2001 From: Linyu Yuan Date: Tue, 26 Jul 2022 14:45:49 +0800 Subject: [PATCH 1304/1436] usb: typec: ucsi: Acknowledge the GET_ERROR_STATUS command completion We found PPM will not send any notification after it report error status and OPM issue GET_ERROR_STATUS command to read the details about error. According UCSI spec, PPM may clear the Error Status Data after the OPM has acknowledged the command completion. This change add operation to acknowledge the command completion from PPM. Fixes: bdc62f2bae8f (usb: typec: ucsi: Simplified registration and I/O API) Cc: # 5.10 Signed-off-by: Jack Pham Signed-off-by: Linyu Yuan Link: https://lore.kernel.org/r/1658817949-4632-1-git-send-email-quic_linyyuan@quicinc.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index cbd862f9f2a1..1aea46493b85 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -76,6 +76,10 @@ static int ucsi_read_error(struct ucsi *ucsi) if (ret) return ret; + ret = ucsi_acknowledge_command(ucsi); + if (ret) + return ret; + switch (error) { case UCSI_ERROR_INCOMPATIBLE_PARTNER: return -EOPNOTSUPP; From b60fd9361b6e0041299e9e677603dd1df7c9677b Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 13 Jul 2022 14:08:40 +0200 Subject: [PATCH 1305/1436] dt-bindings: usb: typec: add bindings for stm32g0 controller Add DT schema documentation for the STM32G0 Type-C PD (Power Delivery) controller. STM32G0 provides an integrated USB Type-C and power delivery interface. It can be programmed with a firmware to handle UCSI protocol over I2C interface. A GPIO is used as an interrupt line. It may be used as a wakeup source, so use optional "wakeup-source" and "power-domains" properties to support wakeup. The firmware itself may be flashed or later updated (optional). Choice is let to the application to allow firmware update. A default firmware could be already programmed in production and be customized (to not allow it). So the firmware-name is made optional to represent this option. Reviewed-by: Rob Herring Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220713120842.560902-2-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/usb/st,typec-stm32g0.yaml | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/st,typec-stm32g0.yaml diff --git a/Documentation/devicetree/bindings/usb/st,typec-stm32g0.yaml b/Documentation/devicetree/bindings/usb/st,typec-stm32g0.yaml new file mode 100644 index 000000000000..1cb68cabe17d --- /dev/null +++ b/Documentation/devicetree/bindings/usb/st,typec-stm32g0.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/st,typec-stm32g0.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: STMicroelectronics STM32G0 USB Type-C PD controller + +description: | + The STM32G0 MCU can be programmed to control Type-C connector(s) through I2C + typically using the UCSI protocol over I2C, with a dedicated alert + (interrupt) pin. + +maintainers: + - Fabrice Gasnier + +properties: + compatible: + const: st,stm32g0-typec + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + connector: + type: object + $ref: /schemas/connector/usb-connector.yaml# + unevaluatedProperties: false + + firmware-name: + description: | + Should contain the name of the default firmware image + file located on the firmware search path + + wakeup-source: true + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - connector + +additionalProperties: false + +examples: + - | + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + + typec@53 { + compatible = "st,stm32g0-typec"; + reg = <0x53>; + /* Alert pin on GPIO PE12 */ + interrupts = <12 IRQ_TYPE_EDGE_FALLING>; + interrupt-parent = <&gpioe>; + + /* Example with one type-C connector */ + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + con_usb_c_ep: endpoint { + remote-endpoint = <&usb_ep>; + }; + }; + }; + }; + }; + }; + + usb { + usb-role-switch; + port { + usb_ep: endpoint { + remote-endpoint = <&con_usb_c_ep>; + }; + }; + }; +... From 72849d4fcee7cc9e6b98637738b722f78502525d Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 13 Jul 2022 14:08:41 +0200 Subject: [PATCH 1306/1436] usb: typec: ucsi: stm32g0: add support for stm32g0 controller STM32G0 provides an integrated USB Type-C and power delivery interface. It can be programmed with a firmware to handle UCSI protocol over I2C interface. A GPIO is used as an interrupt line. Type-C connector can be used as a wakeup source (typically to detect changes on the port, like attach or detach). PM suspend / resume routines are used to enable wake irqs, and signal a wakeup event in case the IRQ has fired while in suspend. The i2c core is doing the necessary initialization when the "wakeup-source" flag is provided. Note: the interrupt handler shouldn't be called before the i2c bus resumes. So, the interrupts are disabled during suspend period, and re-enabled upon resume, to avoid i2c transfer while suspended, from the irq handler. Acked-by: Heikki Krogerus Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220713120842.560902-3-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/Kconfig | 10 + drivers/usb/typec/ucsi/Makefile | 1 + drivers/usb/typec/ucsi/ucsi_stm32g0.c | 264 ++++++++++++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 drivers/usb/typec/ucsi/ucsi_stm32g0.c diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 5e9b37b3f25e..8f9c4b9f31f7 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -48,4 +48,14 @@ config UCSI_ACPI To compile the driver as a module, choose M here: the module will be called ucsi_acpi +config UCSI_STM32G0 + tristate "UCSI Interface Driver for STM32G0" + depends on I2C + help + This driver enables UCSI support on platforms that expose a STM32G0 + Type-C controller over I2C interface. + + To compile the driver as a module, choose M here: the module will be + called ucsi_stm32g0. + endif diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile index 8a8eb5cb8e0f..480d533d762f 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile @@ -17,3 +17,4 @@ endif obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o +obj-$(CONFIG_UCSI_STM32G0) += ucsi_stm32g0.o diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c new file mode 100644 index 000000000000..e3965cbff058 --- /dev/null +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +/* + * UCSI driver for STMicroelectronics STM32G0 Type-C PD controller + * + * Copyright (C) 2022, STMicroelectronics - All Rights Reserved + * Author: Fabrice Gasnier . + */ + +#include +#include +#include +#include + +#include "ucsi.h" + +struct ucsi_stm32g0 { + struct i2c_client *client; + struct completion complete; + struct device *dev; + unsigned long flags; + struct ucsi *ucsi; + bool suspended; + bool wakeup_event; +}; + +static int ucsi_stm32g0_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t len) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + struct i2c_client *client = g0->client; + u8 reg = offset; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = ®, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = val, + }, + }; + int ret; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(g0->dev, "i2c read %02x, %02x error: %d\n", client->addr, reg, ret); + + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +static int ucsi_stm32g0_async_write(struct ucsi *ucsi, unsigned int offset, const void *val, + size_t len) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + struct i2c_client *client = g0->client; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + } + }; + unsigned char *buf; + int ret; + + buf = kmalloc(len + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] = offset; + memcpy(&buf[1], val, len); + msg[0].len = len + 1; + msg[0].buf = buf; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + kfree(buf); + if (ret != ARRAY_SIZE(msg)) { + dev_err(g0->dev, "i2c write %02x, %02x error: %d\n", client->addr, offset, ret); + + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +static int ucsi_stm32g0_sync_write(struct ucsi *ucsi, unsigned int offset, const void *val, + size_t len) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + int ret; + + set_bit(COMMAND_PENDING, &g0->flags); + + ret = ucsi_stm32g0_async_write(ucsi, offset, val, len); + if (ret) + goto out_clear_bit; + + if (!wait_for_completion_timeout(&g0->complete, msecs_to_jiffies(5000))) + ret = -ETIMEDOUT; + +out_clear_bit: + clear_bit(COMMAND_PENDING, &g0->flags); + + return ret; +} + +static irqreturn_t ucsi_stm32g0_irq_handler(int irq, void *data) +{ + struct ucsi_stm32g0 *g0 = data; + u32 cci; + int ret; + + if (g0->suspended) + g0->wakeup_event = true; + + ret = ucsi_stm32g0_read(g0->ucsi, UCSI_CCI, &cci, sizeof(cci)); + if (ret) + return IRQ_NONE; + + if (UCSI_CCI_CONNECTOR(cci)) + ucsi_connector_change(g0->ucsi, UCSI_CCI_CONNECTOR(cci)); + + if (test_bit(COMMAND_PENDING, &g0->flags) && + cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE)) + complete(&g0->complete); + + return IRQ_HANDLED; +} + +static const struct ucsi_operations ucsi_stm32g0_ops = { + .read = ucsi_stm32g0_read, + .sync_write = ucsi_stm32g0_sync_write, + .async_write = ucsi_stm32g0_async_write, +}; + +static int ucsi_stm32g0_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct ucsi_stm32g0 *g0; + int ret; + + g0 = devm_kzalloc(dev, sizeof(*g0), GFP_KERNEL); + if (!g0) + return -ENOMEM; + + g0->dev = dev; + g0->client = client; + init_completion(&g0->complete); + i2c_set_clientdata(client, g0); + + g0->ucsi = ucsi_create(dev, &ucsi_stm32g0_ops); + if (IS_ERR(g0->ucsi)) + return PTR_ERR(g0->ucsi); + + ucsi_set_drvdata(g0->ucsi, g0); + + /* Request alert interrupt */ + ret = request_threaded_irq(client->irq, NULL, ucsi_stm32g0_irq_handler, IRQF_ONESHOT, + dev_name(&client->dev), g0); + if (ret) { + dev_err_probe(dev, ret, "request IRQ failed\n"); + goto destroy; + } + + ret = ucsi_register(g0->ucsi); + if (ret) { + dev_err_probe(dev, ret, "ucsi_register failed\n"); + goto freeirq; + } + + return 0; + +freeirq: + free_irq(client->irq, g0); +destroy: + ucsi_destroy(g0->ucsi); + + return ret; +} + +static int ucsi_stm32g0_remove(struct i2c_client *client) +{ + struct ucsi_stm32g0 *g0 = i2c_get_clientdata(client); + + ucsi_unregister(g0->ucsi); + free_irq(client->irq, g0); + ucsi_destroy(g0->ucsi); + + return 0; +} + +static int ucsi_stm32g0_suspend(struct device *dev) +{ + struct ucsi_stm32g0 *g0 = dev_get_drvdata(dev); + struct i2c_client *client = g0->client; + + /* Keep the interrupt disabled until the i2c bus has been resumed */ + disable_irq(client->irq); + + g0->suspended = true; + g0->wakeup_event = false; + + if (device_may_wakeup(dev) || device_wakeup_path(dev)) + enable_irq_wake(client->irq); + + return 0; +} + +static int ucsi_stm32g0_resume(struct device *dev) +{ + struct ucsi_stm32g0 *g0 = dev_get_drvdata(dev); + struct i2c_client *client = g0->client; + + if (device_may_wakeup(dev) || device_wakeup_path(dev)) + disable_irq_wake(client->irq); + + enable_irq(client->irq); + + /* Enforce any pending handler gets called to signal a wakeup_event */ + synchronize_irq(client->irq); + + if (g0->wakeup_event) + pm_wakeup_event(g0->dev, 0); + + g0->suspended = false; + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ucsi_stm32g0_pm_ops, ucsi_stm32g0_suspend, ucsi_stm32g0_resume); + +static const struct of_device_id __maybe_unused ucsi_stm32g0_typec_of_match[] = { + { .compatible = "st,stm32g0-typec" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ucsi_stm32g0_typec_of_match); + +static const struct i2c_device_id ucsi_stm32g0_typec_i2c_devid[] = { + {"stm32g0-typec", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, ucsi_stm32g0_typec_i2c_devid); + +static struct i2c_driver ucsi_stm32g0_i2c_driver = { + .driver = { + .name = "ucsi-stm32g0-i2c", + .of_match_table = of_match_ptr(ucsi_stm32g0_typec_of_match), + .pm = pm_sleep_ptr(&ucsi_stm32g0_pm_ops), + }, + .probe = ucsi_stm32g0_probe, + .remove = ucsi_stm32g0_remove, + .id_table = ucsi_stm32g0_typec_i2c_devid +}; +module_i2c_driver(ucsi_stm32g0_i2c_driver); + +MODULE_AUTHOR("Fabrice Gasnier "); +MODULE_DESCRIPTION("STMicroelectronics STM32G0 Type-C controller"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:ucsi-stm32g0"); From 2d945194cce11ce2800949c8746bc3e788d89067 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 13 Jul 2022 14:08:42 +0200 Subject: [PATCH 1307/1436] usb: typec: ucsi: stm32g0: add bootloader support STM32G0 comes with STM32 bootloader in its system memory. Add support for some I2C bootloader commands as described in application notes AN2606 and AN4221, to enable STM32G0 UCSI firmware update. Upon probing, the driver needs to know the STM32G0 state: - In bootloader mode, STM32 G0 answers at i2c addr 0x51. - In running mode, STM32 G0 firmware may answer at two address. - The main address specified in DT is used for UCSI. - 0x51 addr can be re-used for FW controls like getting software version or jump to booloader request. So probe using the main firmware i2c address first, before attempting bootloader address (e.g. check for blank, erased or previously aborted firmware update). Acked-by: Heikki Krogerus Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220713120842.560902-4-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/typec/ucsi/ucsi_stm32g0.c | 539 +++++++++++++++++++++++++- 1 file changed, 526 insertions(+), 13 deletions(-) diff --git a/drivers/usb/typec/ucsi/ucsi_stm32g0.c b/drivers/usb/typec/ucsi/ucsi_stm32g0.c index e3965cbff058..061551d464f1 100644 --- a/drivers/usb/typec/ucsi/ucsi_stm32g0.c +++ b/drivers/usb/typec/ucsi/ucsi_stm32g0.c @@ -6,23 +6,326 @@ * Author: Fabrice Gasnier . */ +#include +#include #include #include #include #include +#include #include "ucsi.h" +/* STM32G0 I2C bootloader addr: 0b1010001x (See AN2606) */ +#define STM32G0_I2C_BL_ADDR (0xa2 >> 1) + +/* STM32G0 I2C bootloader max data size */ +#define STM32G0_I2C_BL_SZ 256 + +/* STM32 I2C bootloader commands (See AN4221) */ +#define STM32_CMD_GVR 0x01 /* Gets the bootloader version */ +#define STM32_CMD_GVR_LEN 1 +#define STM32_CMD_RM 0x11 /* Reag memory */ +#define STM32_CMD_WM 0x31 /* Write memory */ +#define STM32_CMD_ADDR_LEN 5 /* Address len for go, mem write... */ +#define STM32_CMD_ERASE 0x44 /* Erase page, bank or all */ +#define STM32_CMD_ERASE_SPECIAL_LEN 3 +#define STM32_CMD_GLOBAL_MASS_ERASE 0xffff /* All-bank erase */ + +/* STM32 I2C bootloader answer status */ +#define STM32G0_I2C_BL_ACK 0x79 +#define STM32G0_I2C_BL_NACK 0x1f +#define STM32G0_I2C_BL_BUSY 0x76 + +/* STM32G0 flash definitions */ +#define STM32G0_USER_OPTION_BYTES 0x1fff7800 +#define STM32G0_USER_OB_NBOOT0 BIT(26) +#define STM32G0_USER_OB_NBOOT_SEL BIT(24) +#define STM32G0_USER_OB_BOOT_MAIN (STM32G0_USER_OB_NBOOT0 | STM32G0_USER_OB_NBOOT_SEL) +#define STM32G0_MAIN_MEM_ADDR 0x08000000 + +/* STM32 Firmware definitions: additional commands */ +#define STM32G0_FW_GETVER 0x00 /* Gets the firmware version */ +#define STM32G0_FW_GETVER_LEN 4 +#define STM32G0_FW_RSTGOBL 0x21 /* Reset and go to bootloader */ +#define STM32G0_FW_KEYWORD 0xa56959a6 + +/* ucsi_stm32g0_fw_info located at the end of the firmware */ +struct ucsi_stm32g0_fw_info { + u32 version; + u32 keyword; +}; + struct ucsi_stm32g0 { struct i2c_client *client; + struct i2c_client *i2c_bl; + bool in_bootloader; + u8 bl_version; struct completion complete; struct device *dev; unsigned long flags; + const char *fw_name; struct ucsi *ucsi; bool suspended; bool wakeup_event; }; +/* + * Bootloader commands helpers: + * - send command (2 bytes) + * - check ack + * Then either: + * - receive data + * - receive data + check ack + * - send data + check ack + * These operations depends on the command and have various length. + */ +static int ucsi_stm32g0_bl_check_ack(struct ucsi *ucsi) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + struct i2c_client *client = g0->i2c_bl; + unsigned char ack; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &ack, + }, + }; + int ret; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(g0->dev, "i2c bl ack (%02x), error: %d\n", client->addr, ret); + + return ret < 0 ? ret : -EIO; + } + + /* The 'ack' byte should contain bootloader answer: ack/nack/busy */ + switch (ack) { + case STM32G0_I2C_BL_ACK: + return 0; + case STM32G0_I2C_BL_NACK: + return -ENOENT; + case STM32G0_I2C_BL_BUSY: + return -EBUSY; + default: + dev_err(g0->dev, "i2c bl ack (%02x), invalid byte: %02x\n", + client->addr, ack); + return -EINVAL; + } +} + +static int ucsi_stm32g0_bl_cmd_check_ack(struct ucsi *ucsi, unsigned int cmd, bool check_ack) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + struct i2c_client *client = g0->i2c_bl; + unsigned char buf[2]; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + }, + }; + int ret; + + /* + * Send STM32 bootloader command format is two bytes: + * - command code + * - XOR'ed command code + */ + buf[0] = cmd; + buf[1] = cmd ^ 0xff; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_dbg(g0->dev, "i2c bl cmd %d (%02x), error: %d\n", cmd, client->addr, ret); + + return ret < 0 ? ret : -EIO; + } + + if (check_ack) + return ucsi_stm32g0_bl_check_ack(ucsi); + + return 0; +} + +static int ucsi_stm32g0_bl_cmd(struct ucsi *ucsi, unsigned int cmd) +{ + return ucsi_stm32g0_bl_cmd_check_ack(ucsi, cmd, true); +} + +static int ucsi_stm32g0_bl_rcv_check_ack(struct ucsi *ucsi, void *data, size_t len, bool check_ack) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + struct i2c_client *client = g0->i2c_bl; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = data, + }, + }; + int ret; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(g0->dev, "i2c bl rcv %02x, error: %d\n", client->addr, ret); + + return ret < 0 ? ret : -EIO; + } + + if (check_ack) + return ucsi_stm32g0_bl_check_ack(ucsi); + + return 0; +} + +static int ucsi_stm32g0_bl_rcv(struct ucsi *ucsi, void *data, size_t len) +{ + return ucsi_stm32g0_bl_rcv_check_ack(ucsi, data, len, true); +} + +static int ucsi_stm32g0_bl_rcv_woack(struct ucsi *ucsi, void *data, size_t len) +{ + return ucsi_stm32g0_bl_rcv_check_ack(ucsi, data, len, false); +} + +static int ucsi_stm32g0_bl_send(struct ucsi *ucsi, void *data, size_t len) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + struct i2c_client *client = g0->i2c_bl; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = len, + .buf = data, + }, + }; + int ret; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(g0->dev, "i2c bl send %02x, error: %d\n", client->addr, ret); + + return ret < 0 ? ret : -EIO; + } + + return ucsi_stm32g0_bl_check_ack(ucsi); +} + +/* Bootloader commands */ +static int ucsi_stm32g0_bl_get_version(struct ucsi *ucsi, u8 *bl_version) +{ + int ret; + + ret = ucsi_stm32g0_bl_cmd(ucsi, STM32_CMD_GVR); + if (ret) + return ret; + + return ucsi_stm32g0_bl_rcv(ucsi, bl_version, STM32_CMD_GVR_LEN); +} + +static int ucsi_stm32g0_bl_send_addr(struct ucsi *ucsi, u32 addr) +{ + u8 data8[STM32_CMD_ADDR_LEN]; + + /* Address format: 4 bytes addr (MSB first) + XOR'ed addr bytes */ + put_unaligned_be32(addr, data8); + data8[4] = data8[0] ^ data8[1] ^ data8[2] ^ data8[3]; + + return ucsi_stm32g0_bl_send(ucsi, data8, STM32_CMD_ADDR_LEN); +} + +static int ucsi_stm32g0_bl_global_mass_erase(struct ucsi *ucsi) +{ + u8 data8[4]; + u16 *data16 = (u16 *)&data8[0]; + int ret; + + data16[0] = STM32_CMD_GLOBAL_MASS_ERASE; + data8[2] = data8[0] ^ data8[1]; + + ret = ucsi_stm32g0_bl_cmd(ucsi, STM32_CMD_ERASE); + if (ret) + return ret; + + return ucsi_stm32g0_bl_send(ucsi, data8, STM32_CMD_ERASE_SPECIAL_LEN); +} + +static int ucsi_stm32g0_bl_write(struct ucsi *ucsi, u32 addr, const void *data, size_t len) +{ + u8 *data8; + int i, ret; + + if (!len || len > STM32G0_I2C_BL_SZ) + return -EINVAL; + + /* Write memory: len bytes -1, data up to 256 bytes + XOR'ed bytes */ + data8 = kmalloc(STM32G0_I2C_BL_SZ + 2, GFP_KERNEL); + if (!data8) + return -ENOMEM; + + ret = ucsi_stm32g0_bl_cmd(ucsi, STM32_CMD_WM); + if (ret) + goto free; + + ret = ucsi_stm32g0_bl_send_addr(ucsi, addr); + if (ret) + goto free; + + data8[0] = len - 1; + memcpy(data8 + 1, data, len); + data8[len + 1] = data8[0]; + for (i = 1; i <= len; i++) + data8[len + 1] ^= data8[i]; + + ret = ucsi_stm32g0_bl_send(ucsi, data8, len + 2); +free: + kfree(data8); + + return ret; +} + +static int ucsi_stm32g0_bl_read(struct ucsi *ucsi, u32 addr, void *data, size_t len) +{ + int ret; + + if (!len || len > STM32G0_I2C_BL_SZ) + return -EINVAL; + + ret = ucsi_stm32g0_bl_cmd(ucsi, STM32_CMD_RM); + if (ret) + return ret; + + ret = ucsi_stm32g0_bl_send_addr(ucsi, addr); + if (ret) + return ret; + + ret = ucsi_stm32g0_bl_cmd(ucsi, len - 1); + if (ret) + return ret; + + return ucsi_stm32g0_bl_rcv_woack(ucsi, data, len); +} + +/* Firmware commands (the same address as the bootloader) */ +static int ucsi_stm32g0_fw_cmd(struct ucsi *ucsi, unsigned int cmd) +{ + return ucsi_stm32g0_bl_cmd_check_ack(ucsi, cmd, false); +} + +static int ucsi_stm32g0_fw_rcv(struct ucsi *ucsi, void *data, size_t len) +{ + return ucsi_stm32g0_bl_rcv_woack(ucsi, data, len); +} + +/* UCSI ops */ static int ucsi_stm32g0_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t len) { struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); @@ -138,6 +441,191 @@ static const struct ucsi_operations ucsi_stm32g0_ops = { .async_write = ucsi_stm32g0_async_write, }; +static int ucsi_stm32g0_register(struct ucsi *ucsi) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + struct i2c_client *client = g0->client; + int ret; + + /* Request alert interrupt */ + ret = request_threaded_irq(client->irq, NULL, ucsi_stm32g0_irq_handler, IRQF_ONESHOT, + dev_name(g0->dev), g0); + if (ret) { + dev_err(g0->dev, "request IRQ failed: %d\n", ret); + return ret; + } + + ret = ucsi_register(ucsi); + if (ret) { + dev_err_probe(g0->dev, ret, "ucsi_register failed\n"); + free_irq(client->irq, g0); + return ret; + } + + return 0; +} + +static void ucsi_stm32g0_unregister(struct ucsi *ucsi) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + struct i2c_client *client = g0->client; + + ucsi_unregister(ucsi); + free_irq(client->irq, g0); +} + +static void ucsi_stm32g0_fw_cb(const struct firmware *fw, void *context) +{ + struct ucsi_stm32g0 *g0; + const u8 *data, *end; + const struct ucsi_stm32g0_fw_info *fw_info; + u32 addr = STM32G0_MAIN_MEM_ADDR, ob, fw_version; + int ret, size; + + if (!context) + return; + + g0 = ucsi_get_drvdata(context); + + if (!fw) + goto fw_release; + + fw_info = (struct ucsi_stm32g0_fw_info *)(fw->data + fw->size - sizeof(*fw_info)); + + if (!g0->in_bootloader) { + /* Read running firmware version */ + ret = ucsi_stm32g0_fw_cmd(g0->ucsi, STM32G0_FW_GETVER); + if (ret) { + dev_err(g0->dev, "Get version cmd failed %d\n", ret); + goto fw_release; + } + ret = ucsi_stm32g0_fw_rcv(g0->ucsi, &fw_version, + STM32G0_FW_GETVER_LEN); + if (ret) { + dev_err(g0->dev, "Get version failed %d\n", ret); + goto fw_release; + } + + /* Sanity check on keyword and firmware version */ + if (fw_info->keyword != STM32G0_FW_KEYWORD || fw_info->version == fw_version) + goto fw_release; + + dev_info(g0->dev, "Flashing FW: %08x (%08x cur)\n", fw_info->version, fw_version); + + /* Switch to bootloader mode */ + ucsi_stm32g0_unregister(g0->ucsi); + ret = ucsi_stm32g0_fw_cmd(g0->ucsi, STM32G0_FW_RSTGOBL); + if (ret) { + dev_err(g0->dev, "bootloader cmd failed %d\n", ret); + goto fw_release; + } + g0->in_bootloader = true; + + /* STM32G0 reboot delay */ + msleep(100); + } + + ret = ucsi_stm32g0_bl_global_mass_erase(g0->ucsi); + if (ret) { + dev_err(g0->dev, "Erase failed %d\n", ret); + goto fw_release; + } + + data = fw->data; + end = fw->data + fw->size; + while (data < end) { + if ((end - data) < STM32G0_I2C_BL_SZ) + size = end - data; + else + size = STM32G0_I2C_BL_SZ; + + ret = ucsi_stm32g0_bl_write(g0->ucsi, addr, data, size); + if (ret) { + dev_err(g0->dev, "Write failed %d\n", ret); + goto fw_release; + } + addr += size; + data += size; + } + + dev_dbg(g0->dev, "Configure to boot from main flash\n"); + + ret = ucsi_stm32g0_bl_read(g0->ucsi, STM32G0_USER_OPTION_BYTES, &ob, sizeof(ob)); + if (ret) { + dev_err(g0->dev, "read user option bytes failed %d\n", ret); + goto fw_release; + } + + dev_dbg(g0->dev, "STM32G0_USER_OPTION_BYTES 0x%08x\n", ob); + + /* Configure user option bytes to boot from main flash next time */ + ob |= STM32G0_USER_OB_BOOT_MAIN; + + /* Writing option bytes will also reset G0 for updates to be loaded */ + ret = ucsi_stm32g0_bl_write(g0->ucsi, STM32G0_USER_OPTION_BYTES, &ob, sizeof(ob)); + if (ret) { + dev_err(g0->dev, "write user option bytes failed %d\n", ret); + goto fw_release; + } + + dev_info(g0->dev, "Starting, option bytes:0x%08x\n", ob); + + /* STM32G0 FW boot delay */ + msleep(500); + + /* Register UCSI interface */ + if (!ucsi_stm32g0_register(g0->ucsi)) + g0->in_bootloader = false; + +fw_release: + release_firmware(fw); +} + +static int ucsi_stm32g0_probe_bootloader(struct ucsi *ucsi) +{ + struct ucsi_stm32g0 *g0 = ucsi_get_drvdata(ucsi); + int ret; + u16 ucsi_version; + + /* firmware-name is optional */ + if (device_property_present(g0->dev, "firmware-name")) { + ret = device_property_read_string(g0->dev, "firmware-name", &g0->fw_name); + if (ret < 0) + return dev_err_probe(g0->dev, ret, "Error reading firmware-name\n"); + } + + if (g0->fw_name) { + /* STM32G0 in bootloader mode communicates at reserved address 0x51 */ + g0->i2c_bl = i2c_new_dummy_device(g0->client->adapter, STM32G0_I2C_BL_ADDR); + if (IS_ERR(g0->i2c_bl)) { + ret = dev_err_probe(g0->dev, PTR_ERR(g0->i2c_bl), + "Failed to register booloader I2C address\n"); + return ret; + } + } + + /* + * Try to guess if the STM32G0 is running a UCSI firmware. First probe the UCSI FW at its + * i2c address. Fallback to bootloader i2c address only if firmware-name is specified. + */ + ret = ucsi_stm32g0_read(ucsi, UCSI_VERSION, &ucsi_version, sizeof(ucsi_version)); + if (!ret || !g0->fw_name) + return ret; + + /* Speculatively read the bootloader version that has a known length. */ + ret = ucsi_stm32g0_bl_get_version(ucsi, &g0->bl_version); + if (ret < 0) { + i2c_unregister_device(g0->i2c_bl); + return ret; + } + + /* Device in bootloader mode */ + g0->in_bootloader = true; + dev_info(g0->dev, "Bootloader Version 0x%02x\n", g0->bl_version); + + return 0; +} + static int ucsi_stm32g0_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct device *dev = &client->dev; @@ -159,24 +647,41 @@ static int ucsi_stm32g0_probe(struct i2c_client *client, const struct i2c_device ucsi_set_drvdata(g0->ucsi, g0); - /* Request alert interrupt */ - ret = request_threaded_irq(client->irq, NULL, ucsi_stm32g0_irq_handler, IRQF_ONESHOT, - dev_name(&client->dev), g0); - if (ret) { - dev_err_probe(dev, ret, "request IRQ failed\n"); + ret = ucsi_stm32g0_probe_bootloader(g0->ucsi); + if (ret < 0) goto destroy; + + /* + * Don't register in bootloader mode: wait for the firmware to be loaded and started before + * registering UCSI device. + */ + if (!g0->in_bootloader) { + ret = ucsi_stm32g0_register(g0->ucsi); + if (ret < 0) + goto freei2c; } - ret = ucsi_register(g0->ucsi); - if (ret) { - dev_err_probe(dev, ret, "ucsi_register failed\n"); - goto freeirq; + if (g0->fw_name) { + /* + * Asynchronously flash (e.g. bootloader mode) or update the running firmware, + * not to hang the boot process + */ + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, g0->fw_name, g0->dev, + GFP_KERNEL, g0->ucsi, ucsi_stm32g0_fw_cb); + if (ret < 0) { + dev_err_probe(dev, ret, "firmware request failed\n"); + goto unregister; + } } return 0; -freeirq: - free_irq(client->irq, g0); +unregister: + if (!g0->in_bootloader) + ucsi_stm32g0_unregister(g0->ucsi); +freei2c: + if (g0->fw_name) + i2c_unregister_device(g0->i2c_bl); destroy: ucsi_destroy(g0->ucsi); @@ -187,8 +692,10 @@ static int ucsi_stm32g0_remove(struct i2c_client *client) { struct ucsi_stm32g0 *g0 = i2c_get_clientdata(client); - ucsi_unregister(g0->ucsi); - free_irq(client->irq, g0); + if (!g0->in_bootloader) + ucsi_stm32g0_unregister(g0->ucsi); + if (g0->fw_name) + i2c_unregister_device(g0->i2c_bl); ucsi_destroy(g0->ucsi); return 0; @@ -199,6 +706,9 @@ static int ucsi_stm32g0_suspend(struct device *dev) struct ucsi_stm32g0 *g0 = dev_get_drvdata(dev); struct i2c_client *client = g0->client; + if (g0->in_bootloader) + return 0; + /* Keep the interrupt disabled until the i2c bus has been resumed */ disable_irq(client->irq); @@ -216,6 +726,9 @@ static int ucsi_stm32g0_resume(struct device *dev) struct ucsi_stm32g0 *g0 = dev_get_drvdata(dev); struct i2c_client *client = g0->client; + if (g0->in_bootloader) + return 0; + if (device_may_wakeup(dev) || device_wakeup_path(dev)) disable_irq_wake(client->irq); From 817f9ee0dad570a6ba6a285f662de657760094cd Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 26 Jul 2022 10:07:05 +0200 Subject: [PATCH 1308/1436] dt-bindings: usb: generic-ehci: allow usb-hcd schema properties Allow properties and usb-device child nodes as defined in usb-hcd.yaml, by using unevaluatedProperties: false. By the way, remove the "companion" property as it's redundant with usb-hcd.yaml. As example, this allows an onboard hub, to be described in generic-ehci controller node: usb { compatible = "generic-ehci"; #address-cells = <1>; #size-cells = <0>; /* onboard HUB */ hub@1 { compatible = "usb424,2514"; reg = <1>; vdd-supply = <&v3v3>; }; }; Without this, dtbs_check complains on '#address-cells', '#size-cells', 'hub@1' do not match any of the regexes: 'pinctrl-[0-9]+' From schema: ..../generic-ehci.yaml Reviewed-by: Rob Herring Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220726080708.162547-2-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/usb/generic-ehci.yaml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml index 1e84e1b7ab27..e50c1cfaa197 100644 --- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml @@ -130,11 +130,6 @@ properties: Set this flag to indicate that the hardware sometimes turns on the OC bit when an over-current isn't actually present. - companion: - $ref: /schemas/types.yaml#/definitions/phandle - description: - Phandle of a companion. - phys: minItems: 1 maxItems: 3 @@ -155,7 +150,7 @@ required: - reg - interrupts -additionalProperties: false +unevaluatedProperties: false examples: - | From 43993626de00f8faea2cf4d54aaea8f607331fcf Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 26 Jul 2022 10:07:06 +0200 Subject: [PATCH 1309/1436] usb: misc: onboard-hub: add support for Microchip USB2514B USB 2.0 hub Add support for Microchip USB2514B USB 2.0 hub to the onboard usb hub driver. Adopt the generic usb-device compatible ("usbVID,PID"). Some STM32MP1 boards have this hub on-board, with a supply that needs to be enabled for proper operation. Acked-by: Matthias Kaehlcke Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220726080708.162547-3-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/onboard_usb_hub.c | 2 ++ drivers/usb/misc/onboard_usb_hub.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c index 6b9b949d17d3..de3627af3c84 100644 --- a/drivers/usb/misc/onboard_usb_hub.c +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -309,6 +309,7 @@ static struct platform_driver onboard_hub_driver = { /************************** USB driver **************************/ +#define VENDOR_ID_MICROCHIP 0x0424 #define VENDOR_ID_REALTEK 0x0bda /* @@ -383,6 +384,7 @@ static void onboard_hub_usbdev_disconnect(struct usb_device *udev) } static const struct usb_device_id onboard_hub_id_table[] = { + { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */ { USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */ { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */ { USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 */ diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h index d3a5b6938582..3820669eb98c 100644 --- a/drivers/usb/misc/onboard_usb_hub.h +++ b/drivers/usb/misc/onboard_usb_hub.h @@ -7,6 +7,7 @@ #define _USB_MISC_ONBOARD_USB_HUB_H static const struct of_device_id onboard_hub_match[] = { + { .compatible = "usb424,2514" }, { .compatible = "usbbda,411" }, { .compatible = "usbbda,5411" }, { .compatible = "usbbda,414" }, From 0d0fb2b605c7512e67b328f3077d24ec5e4c5b38 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 26 Jul 2022 10:07:07 +0200 Subject: [PATCH 1310/1436] ARM: dts: stm32: add support for USB2514B onboard hub on stm32mp15xx-dkx Add support for USB2514B onboard hub on stm32mp15 DK boards. The HUB is supplied by a 3v3 PMIC regulator. Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220726080708.162547-4-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/stm32mp15xx-dkx.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi index 333c2af97130..8b48d3c89a04 100644 --- a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi @@ -677,6 +677,14 @@ &usbh_ehci { phys = <&usbphyc_port0>; status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + /* onboard HUB */ + hub@1 { + compatible = "usb424,2514"; + reg = <1>; + vdd-supply = <&v3v3>; + }; }; &usbotg_hs { From 76e960597635ee80d7c713f606b0f6ac9228d98e Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Tue, 26 Jul 2022 10:07:08 +0200 Subject: [PATCH 1311/1436] ARM: multi_v7_defconfig: enable USB onboard HUB driver Enable the USB onboard HUB driver, used on STM32MP1 boards. Signed-off-by: Fabrice Gasnier Link: https://lore.kernel.org/r/20220726080708.162547-5-fabrice.gasnier@foss.st.com Signed-off-by: Greg Kroah-Hartman --- arch/arm/configs/multi_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index ce9826bce29b..d0f16b7f682b 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -861,6 +861,7 @@ CONFIG_USB_CHIPIDEA_UDC=y CONFIG_USB_CHIPIDEA_HOST=y CONFIG_USB_ISP1760=y CONFIG_USB_HSIC_USB3503=y +CONFIG_USB_ONBOARD_HUB=m CONFIG_AB8500_USB=y CONFIG_KEYSTONE_USB_PHY=m CONFIG_NOP_USB_XCEIV=y From 40e58a8a7ca6ac7f03a5fbfdbc0119fc0caaa072 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 27 Jul 2022 11:37:59 +0200 Subject: [PATCH 1312/1436] dt-bindings: usb: Add binding for TI USB8041 hub controller The TI USB8041 is a USB 3.0 hub controller with 4 ports. This initial version of the binding only describes USB related aspects of the USB8041, it does not cover the option of connecting the controller as an i2c slave. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20220727093801.687361-1-alexander.stein@ew.tq-group.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/usb/ti,usb8041.yaml | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Documentation/devicetree/bindings/usb/ti,usb8041.yaml diff --git a/Documentation/devicetree/bindings/usb/ti,usb8041.yaml b/Documentation/devicetree/bindings/usb/ti,usb8041.yaml new file mode 100644 index 000000000000..e04fbd8ab0b7 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ti,usb8041.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: GPL-2.0-only or BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/usb/ti,usb8041.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Binding for the TI USB8041 USB 3.0 hub controller + +maintainers: + - Alexander Stein + +allOf: + - $ref: usb-device.yaml# + +properties: + compatible: + enum: + - usb451,8140 + - usb451,8142 + + reg: true + + reset-gpios: + items: + - description: GPIO specifier for GRST# pin. + + vdd-supply: + description: + VDD power supply to the hub + + peer-hub: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the peer hub on the controller. + +required: + - compatible + - reg + - peer-hub + +additionalProperties: false + +examples: + - | + #include + + usb { + dr_mode = "host"; + #address-cells = <1>; + #size-cells = <0>; + + /* 2.0 hub on port 1 */ + hub_2_0: hub@1 { + compatible = "usb451,8142"; + reg = <1>; + peer-hub = <&hub_3_0>; + reset-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>; + }; + + /* 3.0 hub on port 2 */ + hub_3_0: hub@2 { + compatible = "usb451,8140"; + reg = <2>; + peer-hub = <&hub_2_0>; + reset-gpios = <&gpio1 11 GPIO_ACTIVE_LOW>; + }; + }; From e0c6b1f3d7574dea3bec7deb18578e896d2cfaa2 Mon Sep 17 00:00:00 2001 From: Xuezhi Zhang Date: Wed, 27 Jul 2022 20:44:15 +0800 Subject: [PATCH 1313/1436] USB: usbsevseg: convert sysfs snprintf to sysfs_emit Fix the following coccincheck warning: drivers/usb/misc/usbsevseg.c:170:8-16: WARNING: use scnprintf or sprintf Signed-off-by: Xuezhi Zhang Link: https://lore.kernel.org/r/20220727124415.8340-1-zhangxuezhi3@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbsevseg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c index 4bc816bb09bb..c3114d9bd128 100644 --- a/drivers/usb/misc/usbsevseg.c +++ b/drivers/usb/misc/usbsevseg.c @@ -167,7 +167,7 @@ static ssize_t text_show(struct device *dev, struct usb_interface *intf = to_usb_interface(dev); struct usb_sevsegdev *mydev = usb_get_intfdata(intf); - return snprintf(buf, mydev->textlength, "%s\n", mydev->text); + return sysfs_emit(buf, "%s\n", mydev->text); } static ssize_t text_store(struct device *dev, From 40758e493f4d08093fbf58390f8a4bc55b501a49 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 27 Jul 2022 16:11:16 +0200 Subject: [PATCH 1314/1436] usb: misc: onboard_usb_hub: Add reset-gpio support Despite default reset upon probe, release reset line after powering up the hub and assert reset again before powering down. Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20220727141117.909361-1-alexander.stein@ew.tq-group.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/onboard_usb_hub.c | 28 ++++++++++++++++++++++++++++ drivers/usb/misc/onboard_usb_hub.h | 22 +++++++++++++++++----- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c index de3627af3c84..0c81417dd9a7 100644 --- a/drivers/usb/misc/onboard_usb_hub.c +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -38,6 +39,8 @@ struct usbdev_node { struct onboard_hub { struct regulator *vdd; struct device *dev; + const struct onboard_hub_pdata *pdata; + struct gpio_desc *reset_gpio; bool always_powered_in_suspend; bool is_powered_on; bool going_away; @@ -56,6 +59,9 @@ static int onboard_hub_power_on(struct onboard_hub *hub) return err; } + fsleep(hub->pdata->reset_us); + gpiod_set_value_cansleep(hub->reset_gpio, 0); + hub->is_powered_on = true; return 0; @@ -65,6 +71,11 @@ static int onboard_hub_power_off(struct onboard_hub *hub) { int err; + if (hub->reset_gpio) { + gpiod_set_value_cansleep(hub->reset_gpio, 1); + fsleep(hub->pdata->reset_us); + } + err = regulator_disable(hub->vdd); if (err) { dev_err(hub->dev, "failed to disable regulator: %d\n", err); @@ -219,6 +230,7 @@ static void onboard_hub_attach_usb_driver(struct work_struct *work) static int onboard_hub_probe(struct platform_device *pdev) { + const struct of_device_id *of_id; struct device *dev = &pdev->dev; struct onboard_hub *hub; int err; @@ -227,10 +239,26 @@ static int onboard_hub_probe(struct platform_device *pdev) if (!hub) return -ENOMEM; + of_id = of_match_device(onboard_hub_match, &pdev->dev); + if (!of_id) + return -ENODEV; + + hub->pdata = of_id->data; + if (!hub->pdata) + return -EINVAL; + hub->vdd = devm_regulator_get(dev, "vdd"); if (IS_ERR(hub->vdd)) return PTR_ERR(hub->vdd); + hub->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(hub->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(hub->reset_gpio), "failed to get reset GPIO\n"); + + if (hub->reset_gpio) + fsleep(hub->pdata->reset_us); + hub->dev = dev; mutex_init(&hub->lock); INIT_LIST_HEAD(&hub->udev_list); diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h index 3820669eb98c..562fa48fcf10 100644 --- a/drivers/usb/misc/onboard_usb_hub.h +++ b/drivers/usb/misc/onboard_usb_hub.h @@ -6,12 +6,24 @@ #ifndef _USB_MISC_ONBOARD_USB_HUB_H #define _USB_MISC_ONBOARD_USB_HUB_H +struct onboard_hub_pdata { + unsigned long reset_us; /* reset pulse width in us */ +}; + +static const struct onboard_hub_pdata microchip_usb424_data = { + .reset_us = 1, +}; + +static const struct onboard_hub_pdata realtek_rts5411_data = { + .reset_us = 0, +}; + static const struct of_device_id onboard_hub_match[] = { - { .compatible = "usb424,2514" }, - { .compatible = "usbbda,411" }, - { .compatible = "usbbda,5411" }, - { .compatible = "usbbda,414" }, - { .compatible = "usbbda,5414" }, + { .compatible = "usb424,2514", .data = µchip_usb424_data, }, + { .compatible = "usbbda,411", .data = &realtek_rts5411_data, }, + { .compatible = "usbbda,5411", .data = &realtek_rts5411_data, }, + { .compatible = "usbbda,414", .data = &realtek_rts5411_data, }, + { .compatible = "usbbda,5414", .data = &realtek_rts5411_data, }, {} }; From ed92f4353ef53e544db5311fd8efa0cd7fdc4e08 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 27 Jul 2022 16:11:17 +0200 Subject: [PATCH 1315/1436] usb: misc: onboard_usb_hub: Add TI USB8041 hub support This is a 4-port 3.0 USB hub. Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20220727141117.909361-2-alexander.stein@ew.tq-group.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/onboard_usb_hub.c | 3 +++ drivers/usb/misc/onboard_usb_hub.h | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c index 0c81417dd9a7..eb8aef25a22d 100644 --- a/drivers/usb/misc/onboard_usb_hub.c +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -339,6 +339,7 @@ static struct platform_driver onboard_hub_driver = { #define VENDOR_ID_MICROCHIP 0x0424 #define VENDOR_ID_REALTEK 0x0bda +#define VENDOR_ID_TI 0x0451 /* * Returns the onboard_hub platform device that is associated with the USB @@ -417,6 +418,8 @@ static const struct usb_device_id onboard_hub_id_table[] = { { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */ { USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 */ { USB_DEVICE(VENDOR_ID_REALTEK, 0x5414) }, /* RTS5414 USB 2.1 */ + { USB_DEVICE(VENDOR_ID_TI, 0x8140) }, /* TI USB8041 3.0 */ + { USB_DEVICE(VENDOR_ID_TI, 0x8142) }, /* TI USB8041 2.0 */ {} }; MODULE_DEVICE_TABLE(usb, onboard_hub_id_table); diff --git a/drivers/usb/misc/onboard_usb_hub.h b/drivers/usb/misc/onboard_usb_hub.h index 562fa48fcf10..34beab8bce3d 100644 --- a/drivers/usb/misc/onboard_usb_hub.h +++ b/drivers/usb/misc/onboard_usb_hub.h @@ -18,8 +18,14 @@ static const struct onboard_hub_pdata realtek_rts5411_data = { .reset_us = 0, }; +static const struct onboard_hub_pdata ti_tusb8041_data = { + .reset_us = 3000, +}; + static const struct of_device_id onboard_hub_match[] = { { .compatible = "usb424,2514", .data = µchip_usb424_data, }, + { .compatible = "usb451,8140", .data = &ti_tusb8041_data, }, + { .compatible = "usb451,8142", .data = &ti_tusb8041_data, }, { .compatible = "usbbda,411", .data = &realtek_rts5411_data, }, { .compatible = "usbbda,5411", .data = &realtek_rts5411_data, }, { .compatible = "usbbda,414", .data = &realtek_rts5411_data, }, From fe75ac871214e83b192fe64c8329489d8e1a6a14 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 19 Jul 2022 15:50:16 -0600 Subject: [PATCH 1316/1436] dt-bindings: power: supply: charger-manager: Add missing type for 'cm-battery-stat' 'cm-battery-stat' is missing a type definition and is not a common property. The type is boolean. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220719215017.1875530-1-robh@kernel.org --- .../devicetree/bindings/power/supply/charger-manager.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/power/supply/charger-manager.yaml b/Documentation/devicetree/bindings/power/supply/charger-manager.yaml index fbb2204769aa..5af1e0beaf29 100644 --- a/Documentation/devicetree/bindings/power/supply/charger-manager.yaml +++ b/Documentation/devicetree/bindings/power/supply/charger-manager.yaml @@ -50,6 +50,7 @@ properties: cm-battery-stat: description: battery status + $ref: /schemas/types.yaml#/definitions/uint32 enum: - 0 # battery always present - 1 # no battery From f9d88f93ec6d1f81e6907d0e18aa201bf649f4f7 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 19 Jul 2022 15:51:52 -0600 Subject: [PATCH 1317/1436] dt-bindings: iio/dac: adi,ad5766: Add missing type to 'output-range-microvolts' 'output-range-microvolts' is missing a type definition. '-microvolts' is not a standard unit (should be '-microvolt'). As the property is already in use, add a type reference. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220719215152.1877776-1-robh@kernel.org --- Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml b/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml index a8f7720d1e3e..29bd16dab546 100644 --- a/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml +++ b/Documentation/devicetree/bindings/iio/dac/adi,ad5766.yaml @@ -22,6 +22,8 @@ properties: - adi,ad5767 output-range-microvolts: + $ref: /schemas/types.yaml#/definitions/int32-array + maxItems: 2 description: Select converter output range. reg: From 99cab201fc634f2cdb1fd2c99be00df99ee04f6c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 26 Jul 2022 14:02:14 +0200 Subject: [PATCH 1318/1436] dt-bindings: power: reset: qcom,pon: use absolute path to other schema Absolute path to other DT schema is preferred over relative one. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Vinod Koul Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220726120215.101868-2-krzysztof.kozlowski@linaro.org --- Documentation/devicetree/bindings/power/reset/qcom,pon.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml index 353f155df0f4..e8ecb75155db 100644 --- a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml +++ b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml @@ -30,11 +30,11 @@ properties: pwrkey: type: object - $ref: "../../input/qcom,pm8941-pwrkey.yaml#" + $ref: /schemas/input/qcom,pm8941-pwrkey.yaml# resin: type: object - $ref: "../../input/qcom,pm8941-pwrkey.yaml#" + $ref: /schemas/input/qcom,pm8941-pwrkey.yaml# required: - compatible From 60320e6ef485079ded4c081326e96aaadbe96ae1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 26 Jul 2022 14:02:15 +0200 Subject: [PATCH 1319/1436] dt-bindings: watchdog: qcom,pm8916-wdt: convert to dtschema Convert the Qualcomm PM8916 watchdog timer controller bindings to DT schema and include them in parent device schema. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Vinod Koul Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220726120215.101868-3-krzysztof.kozlowski@linaro.org --- .../bindings/power/reset/qcom,pon.yaml | 4 ++ .../bindings/watchdog/qcom,pm8916-wdt.txt | 28 ---------- .../bindings/watchdog/qcom,pm8916-wdt.yaml | 51 +++++++++++++++++++ 3 files changed, 55 insertions(+), 28 deletions(-) delete mode 100644 Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.txt create mode 100644 Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.yaml diff --git a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml index e8ecb75155db..e7b436d2e757 100644 --- a/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml +++ b/Documentation/devicetree/bindings/power/reset/qcom,pon.yaml @@ -36,6 +36,10 @@ properties: type: object $ref: /schemas/input/qcom,pm8941-pwrkey.yaml# + watchdog: + type: object + $ref: /schemas/watchdog/qcom,pm8916-wdt.yaml + required: - compatible - reg diff --git a/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.txt b/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.txt deleted file mode 100644 index 6fb984f31982..000000000000 --- a/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.txt +++ /dev/null @@ -1,28 +0,0 @@ -QCOM PM8916 watchdog timer controller - -This pm8916 watchdog timer controller must be under pm8916-pon node. - -Required properties: -- compatible: should be "qcom,pm8916-wdt" - -Optional properties : -- interrupts : Watchdog pre-timeout (bark) interrupt. -- timeout-sec : Watchdog timeout value in seconds. - -Example: - - pm8916_0: pm8916@0 { - compatible = "qcom,pm8916", "qcom,spmi-pmic"; - reg = <0x0 SPMI_USID>; - - pon@800 { - compatible = "qcom,pm8916-pon"; - reg = <0x800>; - - watchdog { - compatible = "qcom,pm8916-wdt"; - interrupts = <0x0 0x8 6 IRQ_TYPE_EDGE_RISING>; - timeout-sec = <10>; - }; - }; - }; diff --git a/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.yaml new file mode 100644 index 000000000000..568eb8480fc3 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/watchdog/qcom,pm8916-wdt.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm PM8916 watchdog timer controller + +maintainers: + - Krzysztof Kozlowski + +allOf: + - $ref: watchdog.yaml# + +properties: + compatible: + const: qcom,pm8916-wdt + + interrupts: + maxItems: 1 + +required: + - compatible + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + #include + + pmic@0 { + compatible = "qcom,pm8916", "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; + #address-cells = <1>; + #size-cells = <0>; + + pon@800 { + compatible = "qcom,pm8916-pon"; + reg = <0x800>; + mode-bootloader = <0x2>; + mode-recovery = <0x1>; + + watchdog { + compatible = "qcom,pm8916-wdt"; + interrupts = <0x0 0x8 6 IRQ_TYPE_EDGE_RISING>; + timeout-sec = <60>; + }; + }; + }; From 03fe9cd05b9f38353208c23bd791dac47c912054 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 27 Jul 2022 15:29:01 +0100 Subject: [PATCH 1320/1436] KVM: arm64: Move PROTECTED_NVHE_STACKTRACE around Make the dependency with EL2_DEBUG more obvious by moving the stacktrace configurtion *after* it. Signed-off-by: Marc Zyngier Reviewed-by: Kalesh Singh Tested-by: Kalesh Singh Reviewed-by: Oliver Upton Link: https://lore.kernel.org/r/20220727142906.1856759-2-maz@kernel.org --- arch/arm64/kvm/Kconfig | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index 09c995869916..815cc118c675 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig @@ -46,21 +46,6 @@ menuconfig KVM If unsure, say N. -config PROTECTED_NVHE_STACKTRACE - bool "Protected KVM hypervisor stacktraces" - depends on NVHE_EL2_DEBUG - default n - help - Say Y here to enable pKVM hypervisor stacktraces on hyp_panic() - - If you are not using protected nVHE (pKVM), say N. - - If using protected nVHE mode, but cannot afford the associated - memory cost (less than 0.75 page per CPU) of pKVM stacktraces, - say N. - - If unsure, say N. - config NVHE_EL2_DEBUG bool "Debug mode for non-VHE EL2 object" depends on KVM @@ -71,4 +56,17 @@ config NVHE_EL2_DEBUG If unsure, say N. +config PROTECTED_NVHE_STACKTRACE + bool "Protected KVM hypervisor stacktraces" + depends on NVHE_EL2_DEBUG + default n + help + Say Y here to enable pKVM hypervisor stacktraces on hyp_panic() + + If using protected nVHE mode, but cannot afford the associated + memory cost (less than 0.75 page per CPU) of pKVM stacktraces, + say N. + + If unsure, or not using protected nVHE (pKVM), say N. + endif # VIRTUALIZATION From 9f5fee05f6897d0fe0e3a44ade71bb85cd97b2ef Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 27 Jul 2022 15:29:02 +0100 Subject: [PATCH 1321/1436] KVM: arm64: Move nVHE stacktrace unwinding into its own compilation unit The unwinding code doesn't really belong to the exit handling code. Instead, move it to a file (conveniently named stacktrace.c to confuse the reviewer), and move all the stacktrace-related stuff there. It will be joined by more code very soon. Signed-off-by: Marc Zyngier Reviewed-by: Kalesh Singh Tested-by: Kalesh Singh Reviewed-by: Oliver Upton Link: https://lore.kernel.org/r/20220727142906.1856759-3-maz@kernel.org --- arch/arm64/include/asm/stacktrace/nvhe.h | 2 + arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/handle_exit.c | 98 ------------------ arch/arm64/kvm/stacktrace.c | 120 +++++++++++++++++++++++ 4 files changed, 123 insertions(+), 99 deletions(-) create mode 100644 arch/arm64/kvm/stacktrace.c diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h index 600dbc2220b6..8a5cb96d7143 100644 --- a/arch/arm64/include/asm/stacktrace/nvhe.h +++ b/arch/arm64/include/asm/stacktrace/nvhe.h @@ -172,5 +172,7 @@ static inline int notrace unwind_next(struct unwind_state *state) } NOKPROBE_SYMBOL(unwind_next); +void kvm_nvhe_dump_backtrace(unsigned long hyp_offset); + #endif /* __KVM_NVHE_HYPERVISOR__ */ #endif /* __ASM_STACKTRACE_NVHE_H */ diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index aa127ae9f675..5e33c2d4645a 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -12,7 +12,7 @@ obj-$(CONFIG_KVM) += hyp/ kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \ inject_fault.o va_layout.o handle_exit.o \ - guest.o debug.o reset.o sys_regs.o \ + guest.o debug.o reset.o sys_regs.o stacktrace.o \ vgic-sys-reg-v3.o fpsimd.o pkvm.o \ arch_timer.o trng.o vmid.o \ vgic/vgic.o vgic/vgic-init.o \ diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index c14fc4ba4422..ef8b57953aa2 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -319,104 +319,6 @@ void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index) kvm_handle_guest_serror(vcpu, kvm_vcpu_get_esr(vcpu)); } -/* - * kvm_nvhe_dump_backtrace_entry - Symbolize and print an nVHE backtrace entry - * - * @arg : the hypervisor offset, used for address translation - * @where : the program counter corresponding to the stack frame - */ -static bool kvm_nvhe_dump_backtrace_entry(void *arg, unsigned long where) -{ - unsigned long va_mask = GENMASK_ULL(vabits_actual - 1, 0); - unsigned long hyp_offset = (unsigned long)arg; - - /* Mask tags and convert to kern addr */ - where = (where & va_mask) + hyp_offset; - kvm_err(" [<%016lx>] %pB\n", where, (void *)(where + kaslr_offset())); - - return true; -} - -static inline void kvm_nvhe_dump_backtrace_start(void) -{ - kvm_err("nVHE call trace:\n"); -} - -static inline void kvm_nvhe_dump_backtrace_end(void) -{ - kvm_err("---[ end nVHE call trace ]---\n"); -} - -/* - * hyp_dump_backtrace - Dump the non-protected nVHE backtrace. - * - * @hyp_offset: hypervisor offset, used for address translation. - * - * The host can directly access HYP stack pages in non-protected - * mode, so the unwinding is done directly from EL1. This removes - * the need for shared buffers between host and hypervisor for - * the stacktrace. - */ -static void hyp_dump_backtrace(unsigned long hyp_offset) -{ - struct kvm_nvhe_stacktrace_info *stacktrace_info; - struct unwind_state state; - - stacktrace_info = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); - - kvm_nvhe_unwind_init(&state, stacktrace_info->fp, stacktrace_info->pc); - - kvm_nvhe_dump_backtrace_start(); - unwind(&state, kvm_nvhe_dump_backtrace_entry, (void *)hyp_offset); - kvm_nvhe_dump_backtrace_end(); -} - -#ifdef CONFIG_PROTECTED_NVHE_STACKTRACE -DECLARE_KVM_NVHE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], - pkvm_stacktrace); - -/* - * pkvm_dump_backtrace - Dump the protected nVHE HYP backtrace. - * - * @hyp_offset: hypervisor offset, used for address translation. - * - * Dumping of the pKVM HYP backtrace is done by reading the - * stack addresses from the shared stacktrace buffer, since the - * host cannot directly access hypervisor memory in protected - * mode. - */ -static void pkvm_dump_backtrace(unsigned long hyp_offset) -{ - unsigned long *stacktrace - = (unsigned long *) this_cpu_ptr_nvhe_sym(pkvm_stacktrace); - int i, size = NVHE_STACKTRACE_SIZE / sizeof(long); - - kvm_nvhe_dump_backtrace_start(); - /* The saved stacktrace is terminated by a null entry */ - for (i = 0; i < size && stacktrace[i]; i++) - kvm_nvhe_dump_backtrace_entry((void *)hyp_offset, stacktrace[i]); - kvm_nvhe_dump_backtrace_end(); -} -#else /* !CONFIG_PROTECTED_NVHE_STACKTRACE */ -static void pkvm_dump_backtrace(unsigned long hyp_offset) -{ - kvm_err("Cannot dump pKVM nVHE stacktrace: !CONFIG_PROTECTED_NVHE_STACKTRACE\n"); -} -#endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */ - -/* - * kvm_nvhe_dump_backtrace - Dump KVM nVHE hypervisor backtrace. - * - * @hyp_offset: hypervisor offset, used for address translation. - */ -static void kvm_nvhe_dump_backtrace(unsigned long hyp_offset) -{ - if (is_protected_kvm_enabled()) - pkvm_dump_backtrace(hyp_offset); - else - hyp_dump_backtrace(hyp_offset); -} - void __noreturn __cold nvhe_hyp_panic_handler(u64 esr, u64 spsr, u64 elr_virt, u64 elr_phys, u64 par, uintptr_t vcpu, diff --git a/arch/arm64/kvm/stacktrace.c b/arch/arm64/kvm/stacktrace.c new file mode 100644 index 000000000000..9812aefdcfb4 --- /dev/null +++ b/arch/arm64/kvm/stacktrace.c @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * KVM nVHE hypervisor stack tracing support. + * + * The unwinder implementation depends on the nVHE mode: + * + * 1) Non-protected nVHE mode - the host can directly access the + * HYP stack pages and unwind the HYP stack in EL1. This saves having + * to allocate shared buffers for the host to read the unwinded + * stacktrace. + * + * 2) pKVM (protected nVHE) mode - the host cannot directly access + * the HYP memory. The stack is unwinded in EL2 and dumped to a shared + * buffer where the host can read and print the stacktrace. + * + * Copyright (C) 2022 Google LLC + */ + +#include +#include + +#include + +/* + * kvm_nvhe_dump_backtrace_entry - Symbolize and print an nVHE backtrace entry + * + * @arg : the hypervisor offset, used for address translation + * @where : the program counter corresponding to the stack frame + */ +static bool kvm_nvhe_dump_backtrace_entry(void *arg, unsigned long where) +{ + unsigned long va_mask = GENMASK_ULL(vabits_actual - 1, 0); + unsigned long hyp_offset = (unsigned long)arg; + + /* Mask tags and convert to kern addr */ + where = (where & va_mask) + hyp_offset; + kvm_err(" [<%016lx>] %pB\n", where, (void *)(where + kaslr_offset())); + + return true; +} + +static void kvm_nvhe_dump_backtrace_start(void) +{ + kvm_err("nVHE call trace:\n"); +} + +static void kvm_nvhe_dump_backtrace_end(void) +{ + kvm_err("---[ end nVHE call trace ]---\n"); +} + +/* + * hyp_dump_backtrace - Dump the non-protected nVHE backtrace. + * + * @hyp_offset: hypervisor offset, used for address translation. + * + * The host can directly access HYP stack pages in non-protected + * mode, so the unwinding is done directly from EL1. This removes + * the need for shared buffers between host and hypervisor for + * the stacktrace. + */ +static void hyp_dump_backtrace(unsigned long hyp_offset) +{ + struct kvm_nvhe_stacktrace_info *stacktrace_info; + struct unwind_state state; + + stacktrace_info = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); + + kvm_nvhe_unwind_init(&state, stacktrace_info->fp, stacktrace_info->pc); + + kvm_nvhe_dump_backtrace_start(); + unwind(&state, kvm_nvhe_dump_backtrace_entry, (void *)hyp_offset); + kvm_nvhe_dump_backtrace_end(); +} + +#ifdef CONFIG_PROTECTED_NVHE_STACKTRACE +DECLARE_KVM_NVHE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], + pkvm_stacktrace); + +/* + * pkvm_dump_backtrace - Dump the protected nVHE HYP backtrace. + * + * @hyp_offset: hypervisor offset, used for address translation. + * + * Dumping of the pKVM HYP backtrace is done by reading the + * stack addresses from the shared stacktrace buffer, since the + * host cannot directly access hypervisor memory in protected + * mode. + */ +static void pkvm_dump_backtrace(unsigned long hyp_offset) +{ + unsigned long *stacktrace + = (unsigned long *) this_cpu_ptr_nvhe_sym(pkvm_stacktrace); + int i, size = NVHE_STACKTRACE_SIZE / sizeof(long); + + kvm_nvhe_dump_backtrace_start(); + /* The saved stacktrace is terminated by a null entry */ + for (i = 0; i < size && stacktrace[i]; i++) + kvm_nvhe_dump_backtrace_entry((void *)hyp_offset, stacktrace[i]); + kvm_nvhe_dump_backtrace_end(); +} +#else /* !CONFIG_PROTECTED_NVHE_STACKTRACE */ +static void pkvm_dump_backtrace(unsigned long hyp_offset) +{ + kvm_err("Cannot dump pKVM nVHE stacktrace: !CONFIG_PROTECTED_NVHE_STACKTRACE\n"); +} +#endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */ + +/* + * kvm_nvhe_dump_backtrace - Dump KVM nVHE hypervisor backtrace. + * + * @hyp_offset: hypervisor offset, used for address translation. + */ +void kvm_nvhe_dump_backtrace(unsigned long hyp_offset) +{ + if (is_protected_kvm_enabled()) + pkvm_dump_backtrace(hyp_offset); + else + hyp_dump_backtrace(hyp_offset); +} From 4e00532f37365967e9896966b1fe61888e659259 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 27 Jul 2022 15:29:03 +0100 Subject: [PATCH 1322/1436] KVM: arm64: Make unwind()/on_accessible_stack() per-unwinder functions Having multiple versions of on_accessible_stack() (one per unwinder) makes it very hard to reason about what is used where due to the complexity of the various includes, the forward declarations, and the reliance on everything being 'inline'. Instead, move the code back where it should be. Each unwinder implements: - on_accessible_stack() as well as the helpers it depends on, - unwind()/unwind_next(), as they pass on_accessible_stack as a parameter to unwind_next_common() (which is the only common code here) This hardly results in any duplication, and makes it much easier to reason about the code. Signed-off-by: Marc Zyngier Reviewed-by: Kalesh Singh Tested-by: Kalesh Singh Reviewed-by: Oliver Upton Link: https://lore.kernel.org/r/20220727142906.1856759-4-maz@kernel.org --- arch/arm64/include/asm/stacktrace.h | 74 ------------------ arch/arm64/include/asm/stacktrace/common.h | 55 ++++--------- arch/arm64/include/asm/stacktrace/nvhe.h | 84 +------------------- arch/arm64/kernel/stacktrace.c | 90 ++++++++++++++++++++++ arch/arm64/kvm/hyp/nvhe/stacktrace.c | 52 +++++++++++++ arch/arm64/kvm/stacktrace.c | 55 +++++++++++++ 6 files changed, 213 insertions(+), 197 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h index ea828579a98b..6ebdcdff77f5 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -57,78 +57,4 @@ static inline bool on_overflow_stack(unsigned long sp, unsigned long size, struct stack_info *info) { return false; } #endif - -/* - * We can only safely access per-cpu stacks from current in a non-preemptible - * context. - */ -static inline bool on_accessible_stack(const struct task_struct *tsk, - unsigned long sp, unsigned long size, - struct stack_info *info) -{ - if (on_accessible_stack_common(tsk, sp, size, info)) - return true; - - if (on_task_stack(tsk, sp, size, info)) - return true; - if (tsk != current || preemptible()) - return false; - if (on_irq_stack(sp, size, info)) - return true; - if (on_sdei_stack(sp, size, info)) - return true; - - return false; -} - -/* - * Unwind from one frame record (A) to the next frame record (B). - * - * We terminate early if the location of B indicates a malformed chain of frame - * records (e.g. a cycle), determined based on the location and fp value of A - * and the location (but not the fp value) of B. - */ -static inline int notrace unwind_next(struct unwind_state *state) -{ - struct task_struct *tsk = state->task; - unsigned long fp = state->fp; - struct stack_info info; - int err; - - /* Final frame; nothing to unwind */ - if (fp == (unsigned long)task_pt_regs(tsk)->stackframe) - return -ENOENT; - - err = unwind_next_common(state, &info, NULL); - if (err) - return err; - - state->pc = ptrauth_strip_insn_pac(state->pc); - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - if (tsk->ret_stack && - (state->pc == (unsigned long)return_to_handler)) { - unsigned long orig_pc; - /* - * This is a case where function graph tracer has - * modified a return address (LR) in a stack frame - * to hook a function return. - * So replace it to an original value. - */ - orig_pc = ftrace_graph_ret_addr(tsk, NULL, state->pc, - (void *)state->fp); - if (WARN_ON_ONCE(state->pc == orig_pc)) - return -EINVAL; - state->pc = orig_pc; - } -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -#ifdef CONFIG_KRETPROBES - if (is_kretprobe_trampoline(state->pc)) - state->pc = kretprobe_find_ret_addr(tsk, (void *)state->fp, &state->kr_cur); -#endif - - return 0; -} -NOKPROBE_SYMBOL(unwind_next); - #endif /* __ASM_STACKTRACE_H */ diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h index 3ebb69ea374a..18046a7248a2 100644 --- a/arch/arm64/include/asm/stacktrace/common.h +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -79,15 +79,6 @@ struct unwind_state { struct task_struct *task; }; -static inline bool on_overflow_stack(unsigned long sp, unsigned long size, - struct stack_info *info); - -static inline bool on_accessible_stack(const struct task_struct *tsk, - unsigned long sp, unsigned long size, - struct stack_info *info); - -static inline int unwind_next(struct unwind_state *state); - static inline bool on_stack(unsigned long sp, unsigned long size, unsigned long low, unsigned long high, enum stack_type type, struct stack_info *info) @@ -106,21 +97,6 @@ static inline bool on_stack(unsigned long sp, unsigned long size, return true; } -static inline bool on_accessible_stack_common(const struct task_struct *tsk, - unsigned long sp, - unsigned long size, - struct stack_info *info) -{ - if (info) - info->type = STACK_TYPE_UNKNOWN; - - /* - * Both the kernel and nvhe hypervisor make use of - * an overflow_stack - */ - return on_overflow_stack(sp, size, info); -} - static inline void unwind_init_common(struct unwind_state *state, struct task_struct *task) { @@ -156,8 +132,22 @@ static inline void unwind_init_common(struct unwind_state *state, typedef bool (*stack_trace_translate_fp_fn)(unsigned long *fp, enum stack_type type); +/* + * on_accessible_stack_fn() - Check whether a stack range is on any + * of the possible stacks. + * + * @tsk: task whose stack is being unwound + * @sp: stack address being checked + * @size: size of the stack range being checked + * @info: stack unwinding context + */ +typedef bool (*on_accessible_stack_fn)(const struct task_struct *tsk, + unsigned long sp, unsigned long size, + struct stack_info *info); + static inline int unwind_next_common(struct unwind_state *state, struct stack_info *info, + on_accessible_stack_fn accessible, stack_trace_translate_fp_fn translate_fp) { unsigned long fp = state->fp, kern_fp = fp; @@ -166,7 +156,7 @@ static inline int unwind_next_common(struct unwind_state *state, if (fp & 0x7) return -EINVAL; - if (!on_accessible_stack(tsk, fp, 16, info)) + if (!accessible(tsk, fp, 16, info)) return -EINVAL; if (test_bit(info->type, state->stacks_done)) @@ -212,19 +202,4 @@ static inline int unwind_next_common(struct unwind_state *state, return 0; } -static inline void notrace unwind(struct unwind_state *state, - stack_trace_consume_fn consume_entry, - void *cookie) -{ - while (1) { - int ret; - - if (!consume_entry(cookie, state->pc)) - break; - ret = unwind_next(state); - if (ret < 0) - break; - } -} -NOKPROBE_SYMBOL(unwind); #endif /* __ASM_STACKTRACE_COMMON_H */ diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h index 8a5cb96d7143..a096216d8970 100644 --- a/arch/arm64/include/asm/stacktrace/nvhe.h +++ b/arch/arm64/include/asm/stacktrace/nvhe.h @@ -37,59 +37,7 @@ static inline void kvm_nvhe_unwind_init(struct unwind_state *state, state->pc = pc; } -static inline bool on_hyp_stack(unsigned long sp, unsigned long size, - struct stack_info *info); - -static inline bool on_accessible_stack(const struct task_struct *tsk, - unsigned long sp, unsigned long size, - struct stack_info *info) -{ - if (on_accessible_stack_common(tsk, sp, size, info)) - return true; - - if (on_hyp_stack(sp, size, info)) - return true; - - return false; -} - -#ifdef __KVM_NVHE_HYPERVISOR__ -/* - * Protected nVHE HYP stack unwinder - * - * In protected mode, the unwinding is done by the hypervisor in EL2. - */ - -#ifdef CONFIG_PROTECTED_NVHE_STACKTRACE -static inline bool on_overflow_stack(unsigned long sp, unsigned long size, - struct stack_info *info) -{ - unsigned long low = (unsigned long)this_cpu_ptr(overflow_stack); - unsigned long high = low + OVERFLOW_STACK_SIZE; - - return on_stack(sp, size, low, high, STACK_TYPE_OVERFLOW, info); -} - -static inline bool on_hyp_stack(unsigned long sp, unsigned long size, - struct stack_info *info) -{ - struct kvm_nvhe_init_params *params = this_cpu_ptr(&kvm_init_params); - unsigned long high = params->stack_hyp_va; - unsigned long low = high - PAGE_SIZE; - - return on_stack(sp, size, low, high, STACK_TYPE_HYP, info); -} - -static inline int notrace unwind_next(struct unwind_state *state) -{ - struct stack_info info; - - return unwind_next_common(state, &info, NULL); -} -NOKPROBE_SYMBOL(unwind_next); -#endif /* CONFIG_PROTECTED_NVHE_STACKTRACE */ - -#else /* !__KVM_NVHE_HYPERVISOR__ */ +#ifndef __KVM_NVHE_HYPERVISOR__ /* * Conventional (non-protected) nVHE HYP stack unwinder * @@ -142,36 +90,6 @@ static inline bool kvm_nvhe_stack_kern_va(unsigned long *addr, return true; } -static inline bool on_overflow_stack(unsigned long sp, unsigned long size, - struct stack_info *info) -{ - struct kvm_nvhe_stacktrace_info *stacktrace_info - = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); - unsigned long low = (unsigned long)stacktrace_info->overflow_stack_base; - unsigned long high = low + OVERFLOW_STACK_SIZE; - - return on_stack(sp, size, low, high, STACK_TYPE_OVERFLOW, info); -} - -static inline bool on_hyp_stack(unsigned long sp, unsigned long size, - struct stack_info *info) -{ - struct kvm_nvhe_stacktrace_info *stacktrace_info - = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); - unsigned long low = (unsigned long)stacktrace_info->stack_base; - unsigned long high = low + PAGE_SIZE; - - return on_stack(sp, size, low, high, STACK_TYPE_HYP, info); -} - -static inline int notrace unwind_next(struct unwind_state *state) -{ - struct stack_info info; - - return unwind_next_common(state, &info, kvm_nvhe_stack_kern_va); -} -NOKPROBE_SYMBOL(unwind_next); - void kvm_nvhe_dump_backtrace(unsigned long hyp_offset); #endif /* __KVM_NVHE_HYPERVISOR__ */ diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 9fa60ee48499..ce190ee18a20 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -67,6 +67,96 @@ static inline void unwind_init_from_task(struct unwind_state *state, state->pc = thread_saved_pc(task); } +/* + * We can only safely access per-cpu stacks from current in a non-preemptible + * context. + */ +static bool on_accessible_stack(const struct task_struct *tsk, + unsigned long sp, unsigned long size, + struct stack_info *info) +{ + if (info) + info->type = STACK_TYPE_UNKNOWN; + + if (on_task_stack(tsk, sp, size, info)) + return true; + if (tsk != current || preemptible()) + return false; + if (on_irq_stack(sp, size, info)) + return true; + if (on_overflow_stack(sp, size, info)) + return true; + if (on_sdei_stack(sp, size, info)) + return true; + + return false; +} + +/* + * Unwind from one frame record (A) to the next frame record (B). + * + * We terminate early if the location of B indicates a malformed chain of frame + * records (e.g. a cycle), determined based on the location and fp value of A + * and the location (but not the fp value) of B. + */ +static int notrace unwind_next(struct unwind_state *state) +{ + struct task_struct *tsk = state->task; + unsigned long fp = state->fp; + struct stack_info info; + int err; + + /* Final frame; nothing to unwind */ + if (fp == (unsigned long)task_pt_regs(tsk)->stackframe) + return -ENOENT; + + err = unwind_next_common(state, &info, on_accessible_stack, NULL); + if (err) + return err; + + state->pc = ptrauth_strip_insn_pac(state->pc); + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + if (tsk->ret_stack && + (state->pc == (unsigned long)return_to_handler)) { + unsigned long orig_pc; + /* + * This is a case where function graph tracer has + * modified a return address (LR) in a stack frame + * to hook a function return. + * So replace it to an original value. + */ + orig_pc = ftrace_graph_ret_addr(tsk, NULL, state->pc, + (void *)state->fp); + if (WARN_ON_ONCE(state->pc == orig_pc)) + return -EINVAL; + state->pc = orig_pc; + } +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +#ifdef CONFIG_KRETPROBES + if (is_kretprobe_trampoline(state->pc)) + state->pc = kretprobe_find_ret_addr(tsk, (void *)state->fp, &state->kr_cur); +#endif + + return 0; +} +NOKPROBE_SYMBOL(unwind_next); + +static void notrace unwind(struct unwind_state *state, + stack_trace_consume_fn consume_entry, void *cookie) +{ + while (1) { + int ret; + + if (!consume_entry(cookie, state->pc)) + break; + ret = unwind_next(state); + if (ret < 0) + break; + } +} +NOKPROBE_SYMBOL(unwind); + static bool dump_backtrace_entry(void *arg, unsigned long where) { char *loglvl = arg; diff --git a/arch/arm64/kvm/hyp/nvhe/stacktrace.c b/arch/arm64/kvm/hyp/nvhe/stacktrace.c index 900324b7a08f..acbe272ecb32 100644 --- a/arch/arm64/kvm/hyp/nvhe/stacktrace.c +++ b/arch/arm64/kvm/hyp/nvhe/stacktrace.c @@ -39,6 +39,58 @@ static void hyp_prepare_backtrace(unsigned long fp, unsigned long pc) DEFINE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], pkvm_stacktrace); +static bool on_overflow_stack(unsigned long sp, unsigned long size, + struct stack_info *info) +{ + unsigned long low = (unsigned long)this_cpu_ptr(overflow_stack); + unsigned long high = low + OVERFLOW_STACK_SIZE; + + return on_stack(sp, size, low, high, STACK_TYPE_OVERFLOW, info); +} + +static bool on_hyp_stack(unsigned long sp, unsigned long size, + struct stack_info *info) +{ + struct kvm_nvhe_init_params *params = this_cpu_ptr(&kvm_init_params); + unsigned long high = params->stack_hyp_va; + unsigned long low = high - PAGE_SIZE; + + return on_stack(sp, size, low, high, STACK_TYPE_HYP, info); +} + +static bool on_accessible_stack(const struct task_struct *tsk, + unsigned long sp, unsigned long size, + struct stack_info *info) +{ + if (info) + info->type = STACK_TYPE_UNKNOWN; + + return (on_overflow_stack(sp, size, info) || + on_hyp_stack(sp, size, info)); +} + +static int unwind_next(struct unwind_state *state) +{ + struct stack_info info; + + return unwind_next_common(state, &info, on_accessible_stack, NULL); +} + +static void notrace unwind(struct unwind_state *state, + stack_trace_consume_fn consume_entry, + void *cookie) +{ + while (1) { + int ret; + + if (!consume_entry(cookie, state->pc)) + break; + ret = unwind_next(state); + if (ret < 0) + break; + } +} + /* * pkvm_save_backtrace_entry - Saves a protected nVHE HYP stacktrace entry * diff --git a/arch/arm64/kvm/stacktrace.c b/arch/arm64/kvm/stacktrace.c index 9812aefdcfb4..4d5fec3175ff 100644 --- a/arch/arm64/kvm/stacktrace.c +++ b/arch/arm64/kvm/stacktrace.c @@ -21,6 +21,61 @@ #include +static bool on_overflow_stack(unsigned long sp, unsigned long size, + struct stack_info *info) +{ + struct kvm_nvhe_stacktrace_info *stacktrace_info + = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); + unsigned long low = (unsigned long)stacktrace_info->overflow_stack_base; + unsigned long high = low + OVERFLOW_STACK_SIZE; + + return on_stack(sp, size, low, high, STACK_TYPE_OVERFLOW, info); +} + +static bool on_hyp_stack(unsigned long sp, unsigned long size, + struct stack_info *info) +{ + struct kvm_nvhe_stacktrace_info *stacktrace_info + = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); + unsigned long low = (unsigned long)stacktrace_info->stack_base; + unsigned long high = low + PAGE_SIZE; + + return on_stack(sp, size, low, high, STACK_TYPE_HYP, info); +} + +static bool on_accessible_stack(const struct task_struct *tsk, + unsigned long sp, unsigned long size, + struct stack_info *info) +{ + if (info) + info->type = STACK_TYPE_UNKNOWN; + + return (on_overflow_stack(sp, size, info) || + on_hyp_stack(sp, size, info)); +} + +static int unwind_next(struct unwind_state *state) +{ + struct stack_info info; + + return unwind_next_common(state, &info, on_accessible_stack, + kvm_nvhe_stack_kern_va); +} + +static void unwind(struct unwind_state *state, + stack_trace_consume_fn consume_entry, void *cookie) +{ + while (1) { + int ret; + + if (!consume_entry(cookie, state->pc)) + break; + ret = unwind_next(state); + if (ret < 0) + break; + } +} + /* * kvm_nvhe_dump_backtrace_entry - Symbolize and print an nVHE backtrace entry * From 0e773da1e688a1425ef7deae58fa11c5c7e09533 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 27 Jul 2022 15:29:04 +0100 Subject: [PATCH 1323/1436] KVM: arm64: Move nVHE-only helpers into kvm/stacktrace.c kvm_nvhe_stack_kern_va() only makes sense as part of the nVHE unwinder, so simply move it there. Signed-off-by: Marc Zyngier Reviewed-by: Kalesh Singh Tested-by: Kalesh Singh Reviewed-by: Oliver Upton Link: https://lore.kernel.org/r/20220727142906.1856759-5-maz@kernel.org --- arch/arm64/include/asm/stacktrace/nvhe.h | 41 ------------------------ arch/arm64/kvm/stacktrace.c | 41 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h index a096216d8970..d5527b600390 100644 --- a/arch/arm64/include/asm/stacktrace/nvhe.h +++ b/arch/arm64/include/asm/stacktrace/nvhe.h @@ -49,47 +49,6 @@ DECLARE_KVM_NVHE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overf DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_stacktrace_info, kvm_stacktrace_info); DECLARE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page); -/* - * kvm_nvhe_stack_kern_va - Convert KVM nVHE HYP stack addresses to a kernel VAs - * - * The nVHE hypervisor stack is mapped in the flexible 'private' VA range, to - * allow for guard pages below the stack. Consequently, the fixed offset address - * translation macros won't work here. - * - * The kernel VA is calculated as an offset from the kernel VA of the hypervisor - * stack base. - * - * Returns true on success and updates @addr to its corresponding kernel VA; - * otherwise returns false. - */ -static inline bool kvm_nvhe_stack_kern_va(unsigned long *addr, - enum stack_type type) -{ - struct kvm_nvhe_stacktrace_info *stacktrace_info; - unsigned long hyp_base, kern_base, hyp_offset; - - stacktrace_info = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); - - switch (type) { - case STACK_TYPE_HYP: - kern_base = (unsigned long)*this_cpu_ptr(&kvm_arm_hyp_stack_page); - hyp_base = (unsigned long)stacktrace_info->stack_base; - break; - case STACK_TYPE_OVERFLOW: - kern_base = (unsigned long)this_cpu_ptr_nvhe_sym(overflow_stack); - hyp_base = (unsigned long)stacktrace_info->overflow_stack_base; - break; - default: - return false; - } - - hyp_offset = *addr - hyp_base; - - *addr = kern_base + hyp_offset; - - return true; -} - void kvm_nvhe_dump_backtrace(unsigned long hyp_offset); #endif /* __KVM_NVHE_HYPERVISOR__ */ diff --git a/arch/arm64/kvm/stacktrace.c b/arch/arm64/kvm/stacktrace.c index 4d5fec3175ff..417665854f86 100644 --- a/arch/arm64/kvm/stacktrace.c +++ b/arch/arm64/kvm/stacktrace.c @@ -21,6 +21,47 @@ #include +/* + * kvm_nvhe_stack_kern_va - Convert KVM nVHE HYP stack addresses to a kernel VAs + * + * The nVHE hypervisor stack is mapped in the flexible 'private' VA range, to + * allow for guard pages below the stack. Consequently, the fixed offset address + * translation macros won't work here. + * + * The kernel VA is calculated as an offset from the kernel VA of the hypervisor + * stack base. + * + * Returns true on success and updates @addr to its corresponding kernel VA; + * otherwise returns false. + */ +static bool kvm_nvhe_stack_kern_va(unsigned long *addr, + enum stack_type type) +{ + struct kvm_nvhe_stacktrace_info *stacktrace_info; + unsigned long hyp_base, kern_base, hyp_offset; + + stacktrace_info = this_cpu_ptr_nvhe_sym(kvm_stacktrace_info); + + switch (type) { + case STACK_TYPE_HYP: + kern_base = (unsigned long)*this_cpu_ptr(&kvm_arm_hyp_stack_page); + hyp_base = (unsigned long)stacktrace_info->stack_base; + break; + case STACK_TYPE_OVERFLOW: + kern_base = (unsigned long)this_cpu_ptr_nvhe_sym(overflow_stack); + hyp_base = (unsigned long)stacktrace_info->overflow_stack_base; + break; + default: + return false; + } + + hyp_offset = *addr - hyp_base; + + *addr = kern_base + hyp_offset; + + return true; +} + static bool on_overflow_stack(unsigned long sp, unsigned long size, struct stack_info *info) { From 62ae21627aa96f6ef361981dd181c74dc7aa314c Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Wed, 27 Jul 2022 15:29:05 +0100 Subject: [PATCH 1324/1436] KVM: arm64: Don't open code ARRAY_SIZE() Use ARRAY_SIZE() instead of an open-coded version. Signed-off-by: Oliver Upton Signed-off-by: Marc Zyngier Reviewed-by: Kalesh Singh Tested-by: Kalesh Singh Link: https://lore.kernel.org/r/20220727142906.1856759-6-maz@kernel.org --- arch/arm64/kvm/hyp/nvhe/stacktrace.c | 3 +-- arch/arm64/kvm/stacktrace.c | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/hyp/nvhe/stacktrace.c b/arch/arm64/kvm/hyp/nvhe/stacktrace.c index acbe272ecb32..58f645ad66bc 100644 --- a/arch/arm64/kvm/hyp/nvhe/stacktrace.c +++ b/arch/arm64/kvm/hyp/nvhe/stacktrace.c @@ -103,14 +103,13 @@ static void notrace unwind(struct unwind_state *state, static bool pkvm_save_backtrace_entry(void *arg, unsigned long where) { unsigned long *stacktrace = this_cpu_ptr(pkvm_stacktrace); - int size = NVHE_STACKTRACE_SIZE / sizeof(long); int *idx = (int *)arg; /* * Need 2 free slots: 1 for current entry and 1 for the * delimiter. */ - if (*idx > size - 2) + if (*idx > ARRAY_SIZE(pkvm_stacktrace) - 2) return false; stacktrace[*idx] = where; diff --git a/arch/arm64/kvm/stacktrace.c b/arch/arm64/kvm/stacktrace.c index 417665854f86..949d19d603fb 100644 --- a/arch/arm64/kvm/stacktrace.c +++ b/arch/arm64/kvm/stacktrace.c @@ -187,11 +187,13 @@ static void pkvm_dump_backtrace(unsigned long hyp_offset) { unsigned long *stacktrace = (unsigned long *) this_cpu_ptr_nvhe_sym(pkvm_stacktrace); - int i, size = NVHE_STACKTRACE_SIZE / sizeof(long); + int i; kvm_nvhe_dump_backtrace_start(); /* The saved stacktrace is terminated by a null entry */ - for (i = 0; i < size && stacktrace[i]; i++) + for (i = 0; + i < ARRAY_SIZE(kvm_nvhe_sym(pkvm_stacktrace)) && stacktrace[i]; + i++) kvm_nvhe_dump_backtrace_entry((void *)hyp_offset, stacktrace[i]); kvm_nvhe_dump_backtrace_end(); } From a4c750e2328a117dc9b19a2a61db0d4347902029 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 27 Jul 2022 15:29:06 +0100 Subject: [PATCH 1325/1436] arm64: Update 'unwinder howto' Implementing a new unwinder is a bit more involved than writing a couple of helpers, so let's not lure the reader into a false sense of comfort. Instead, let's point out what they should call into, and what sort of parameter they need to provide. Signed-off-by: Marc Zyngier Reviewed-by: Kalesh Singh Tested-by: Kalesh Singh Reviewed-by: Oliver Upton Link: https://lore.kernel.org/r/20220727142906.1856759-7-maz@kernel.org --- arch/arm64/include/asm/stacktrace/common.h | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace/common.h b/arch/arm64/include/asm/stacktrace/common.h index 18046a7248a2..f58eb944c46f 100644 --- a/arch/arm64/include/asm/stacktrace/common.h +++ b/arch/arm64/include/asm/stacktrace/common.h @@ -5,17 +5,11 @@ * To implement a new arm64 stack unwinder: * 1) Include this header * - * 2) Provide implementations for the following functions: - * on_overflow_stack(): Returns true if SP is on the overflow - * stack. - * on_accessible_stack(): Returns true is SP is on any accessible - * stack. - * unwind_next(): Performs validation checks on the frame - * pointer, and transitions unwind_state - * to the next frame. + * 2) Call into unwind_next_common() from your top level unwind + * function, passing it the validation and translation callbacks + * (though the later can be NULL if no translation is required). * - * See: arch/arm64/include/asm/stacktrace.h for reference - * implementations. + * See: arch/arm64/kernel/stacktrace.c for the reference implementation. * * Copyright (C) 2012 ARM Ltd. */ From 8288c99fc263bcafc5df5fa8c278b2eb8106364e Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 28 Jul 2022 08:49:37 +0200 Subject: [PATCH 1326/1436] usb: misc: onboard_usb_hub: Remove duplicated power_on delay onboard_hub_power_on() already ensures the reset pulse width delay, so there is no need to wait right after requesting GPIO as well. Fixes: 40758e493f4d ("usb: misc: onboard_usb_hub: Add reset-gpio support") Signed-off-by: Alexander Stein Link: https://lore.kernel.org/r/20220728064937.917935-1-alexander.stein@ew.tq-group.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/onboard_usb_hub.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/misc/onboard_usb_hub.c b/drivers/usb/misc/onboard_usb_hub.c index eb8aef25a22d..d1df153e7f5a 100644 --- a/drivers/usb/misc/onboard_usb_hub.c +++ b/drivers/usb/misc/onboard_usb_hub.c @@ -256,9 +256,6 @@ static int onboard_hub_probe(struct platform_device *pdev) if (IS_ERR(hub->reset_gpio)) return dev_err_probe(dev, PTR_ERR(hub->reset_gpio), "failed to get reset GPIO\n"); - if (hub->reset_gpio) - fsleep(hub->pdata->reset_us); - hub->dev = dev; mutex_init(&hub->lock); INIT_LIST_HEAD(&hub->udev_list); From 81e878887ff82a7dd42f22951391069a5d520627 Mon Sep 17 00:00:00 2001 From: Peter Suti Date: Wed, 27 Jul 2022 09:35:50 +0200 Subject: [PATCH 1327/1436] staging: fbtft: core: set smem_len before fb_deferred_io_init call The fbtft_framebuffer_alloc() calls fb_deferred_io_init() before initializing info->fix.smem_len. It is set to zero by the framebuffer_alloc() function. It will trigger a WARN_ON() at the start of fb_deferred_io_init() and the function will not do anything. Fixes: 856082f021a2 ("fbdev: defio: fix the pagelist corruption") Signed-off-by: Peter Suti Link: https://lore.kernel.org/r/20220727073550.1491126-1-peter.suti@streamunlimited.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/fbtft/fbtft-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index 9b3eaed80cdd..afaba94d1d1c 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -654,7 +654,6 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, fbdefio->delay = HZ / fps; fbdefio->sort_pagereflist = true; fbdefio->deferred_io = fbtft_deferred_io; - fb_deferred_io_init(info); snprintf(info->fix.id, sizeof(info->fix.id), "%s", dev->driver->name); info->fix.type = FB_TYPE_PACKED_PIXELS; @@ -665,6 +664,7 @@ struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display, info->fix.line_length = width * bpp / 8; info->fix.accel = FB_ACCEL_NONE; info->fix.smem_len = vmem_size; + fb_deferred_io_init(info); info->var.rotate = pdata->rotate; info->var.xres = width; From 899336721928914bfbda515457706616bf2e676d Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Thu, 28 Jul 2022 07:59:32 +0200 Subject: [PATCH 1328/1436] staging: vt6655: Rename MACvClearStckDS Rename MACvClearStckDS macro to vt6655_mac_clear_stck_ds to avoid CamelCase which is not accepted by checkpatch.pl and to clean up namespace. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/8ba4413d52e95406393755f48da065511b891f03.1658986804.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.c | 2 +- drivers/staging/vt6655/mac.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index a7f645f9ccf8..d7ee42df7062 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -518,7 +518,7 @@ void MACvInitialize(struct vnt_private *priv) { void __iomem *io_base = priv->port_offset; /* clear sticky bits */ - MACvClearStckDS(io_base); + vt6655_mac_clear_stck_ds(io_base); /* disable force PME-enable */ iowrite8(PME_OVR, io_base + MAC_REG_PMC1); /* only 3253 A */ diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index b307161818a0..fc587244a70d 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -577,7 +577,7 @@ do { \ iowrite32(DMACTL_RUN, iobase + MAC_REG_AC0DMACTL); \ } while (0) -#define MACvClearStckDS(iobase) \ +#define vt6655_mac_clear_stck_ds(iobase) \ do { \ unsigned char byOrgValue; \ byOrgValue = ioread8(iobase + MAC_REG_STICKHW); \ From c528bbb7dc062c707f6064eec1bccafb8490758f Mon Sep 17 00:00:00 2001 From: Philipp Hortmann Date: Thu, 28 Jul 2022 07:59:45 +0200 Subject: [PATCH 1329/1436] staging: vt6655: Convert macro vt6655_mac_clear_stck_ds to function Convert once used macro to static function. Multiline macros are not liked by kernel community. Rename variable byOrgValue to reg_value to avoid CamelCase which is not accepted by checkpatch.pl. Change variable declaration to u8 as this improves readability. Signed-off-by: Philipp Hortmann Link: https://lore.kernel.org/r/cbfe5cc170b68564ff45bb7f45c63de241c2a664.1658986804.git.philipp.g.hortmann@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/mac.c | 9 +++++++++ drivers/staging/vt6655/mac.h | 8 -------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index d7ee42df7062..dcc649532737 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -70,6 +70,15 @@ void vt6655_mac_word_reg_bits_off(void __iomem *iobase, const u8 reg_offset, con iowrite16(reg_value & ~(bit_mask), iobase + reg_offset); } +static void vt6655_mac_clear_stck_ds(void __iomem *iobase) +{ + u8 reg_value; + + reg_value = ioread8(iobase + MAC_REG_STICKHW); + reg_value = reg_value & 0xFC; + iowrite8(reg_value, iobase + MAC_REG_STICKHW); +} + /* * Description: * Test if all test bits off diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index fc587244a70d..0122c4603c66 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -577,14 +577,6 @@ do { \ iowrite32(DMACTL_RUN, iobase + MAC_REG_AC0DMACTL); \ } while (0) -#define vt6655_mac_clear_stck_ds(iobase) \ -do { \ - unsigned char byOrgValue; \ - byOrgValue = ioread8(iobase + MAC_REG_STICKHW); \ - byOrgValue = byOrgValue & 0xFC; \ - iowrite8(byOrgValue, iobase + MAC_REG_STICKHW); \ -} while (0) - #define MACvSelectPage0(iobase) \ iowrite8(0, iobase + MAC_REG_PAGE1SEL) From 321eaf317dec3710e7a4ad3b3c363d9314c15195 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 21 Jul 2022 14:43:52 +1000 Subject: [PATCH 1330/1436] docs: driver-api: firmware: add driver firmware guidelines. (v3) A recent snafu where Intel ignored upstream feedback on a firmware change, led to a late rc6 fix being required. In order to avoid this in the future we should document some expectations around linux-firmware. I was originally going to write this for drm, but it seems quite generic advice. v2: rewritten with suggestions from Thorsten Leemhuis v3: rewritten with suggestions from Mauro Acked-by: Luis Chamberlain Acked-by: Rodrigo Vivi Acked-by: Daniel Vetter Acked-by: Harry Wentland Signed-off-by: Dave Airlie Link: https://lore.kernel.org/r/20220721044352.3110507-1-airlied@gmail.com Signed-off-by: Greg Kroah-Hartman --- Documentation/driver-api/firmware/core.rst | 1 + .../firmware/firmware-usage-guidelines.rst | 44 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 Documentation/driver-api/firmware/firmware-usage-guidelines.rst diff --git a/Documentation/driver-api/firmware/core.rst b/Documentation/driver-api/firmware/core.rst index 1d1688cbc078..803cd574bbd7 100644 --- a/Documentation/driver-api/firmware/core.rst +++ b/Documentation/driver-api/firmware/core.rst @@ -13,4 +13,5 @@ documents these features. direct-fs-lookup fallback-mechanisms lookup-order + firmware-usage-guidelines diff --git a/Documentation/driver-api/firmware/firmware-usage-guidelines.rst b/Documentation/driver-api/firmware/firmware-usage-guidelines.rst new file mode 100644 index 000000000000..fdcfce42c6d2 --- /dev/null +++ b/Documentation/driver-api/firmware/firmware-usage-guidelines.rst @@ -0,0 +1,44 @@ +=================== +Firmware Guidelines +=================== + +Users switching to a newer kernel should *not* have to install newer +firmware files to keep their hardware working. At the same time updated +firmware files must not cause any regressions for users of older kernel +releases. + +Drivers that use firmware from linux-firmware should follow the rules in +this guide. (Where there is limited control of the firmware, +i.e. company doesn't support Linux, firmwares sourced from misc places, +then of course these rules will not apply strictly.) + +* Firmware files shall be designed in a way that it allows checking for + firmware ABI version changes. It is recommended that firmware files be + versioned with at least a major/minor version. It is suggested that + the firmware files in linux-firmware be named with some device + specific name, and just the major version. The firmware version should + be stored in the firmware header, or as an exception, as part of the + firmware file name, in order to let the driver detact any non-ABI + fixes/changes. The firmware files in linux-firmware should be + overwritten with the newest compatible major version. Newer major + version firmware shall remain compatible with all kernels that load + that major number. + +* If the kernel support for the hardware is normally inactive, or the + hardware isn't available for public consumption, this can + be ignored, until the first kernel release that enables that hardware. + This means no major version bumps without the kernel retaining + backwards compatibility for the older major versions. Minor version + bumps should not introduce new features that newer kernels depend on + non-optionally. + +* If a security fix needs lockstep firmware and kernel fixes in order to + be successful, then all supported major versions in the linux-firmware + repo that are required by currently supported stable/LTS kernels, + should be updated with the security fix. The kernel patches should + detect if the firmware is new enough to declare if the security issue + is fixed. All communications around security fixes should point at + both the firmware and kernel fixes. If a security fix requires + deprecating old major versions, then this should only be done as a + last option, and be stated clearly in all communications. + From 3fe4076482789c2c4a772f6676b246a0d96c99c4 Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Fri, 22 Jul 2022 18:05:18 +0800 Subject: [PATCH 1331/1436] kernfs: Fix typo 'the the' in comment Replace 'the the' with 'the' in the comment. Signed-off-by: Slark Xiao Link: https://lore.kernel.org/r/20220722100518.79741-1-slark_xiao@163.com Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index baff4b1d40c7..b3ec34386b43 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -307,7 +307,7 @@ static ssize_t kernfs_fop_read_iter(struct kiocb *iocb, struct iov_iter *iter) * There is no easy way for us to know if userspace is only doing a partial * write, so we don't support them. We expect the entire buffer to come on * the first write. Hint: if you're writing a value, first read the file, - * modify only the the value you're changing, then write entire buffer + * modify only the value you're changing, then write entire buffer * back. */ static ssize_t kernfs_fop_write_iter(struct kiocb *iocb, struct iov_iter *iter) From e3c1d6c8c59ae542e53c6ef4602eabc39c108575 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 26 Jul 2022 12:14:48 +0300 Subject: [PATCH 1332/1436] gpio: 74xx-mmio: Use bits instead of plain numbers for flags The initial code was misleading to use bitwise AND against plain number, and the commit d3054ba1db62 ("gpio: 74xx-mmio: Check MMIO_74XX_DIR_IN flag in mmio_74xx_dir_in()") missed that. Switch definitions to be defined bits for the correct comparison. Fixes: d3054ba1db62 ("gpio: 74xx-mmio: Check MMIO_74XX_DIR_IN flag in mmio_74xx_dir_in()") Reported-by: Dan Carpenter Signed-off-by: Andy Shevchenko Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpio-74xx-mmio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c index cd399898ed12..0464f1ecd20d 100644 --- a/drivers/gpio/gpio-74xx-mmio.c +++ b/drivers/gpio/gpio-74xx-mmio.c @@ -13,8 +13,8 @@ #include #include -#define MMIO_74XX_DIR_IN (0 << 8) -#define MMIO_74XX_DIR_OUT (1 << 8) +#define MMIO_74XX_DIR_IN BIT(8) +#define MMIO_74XX_DIR_OUT BIT(9) #define MMIO_74XX_BIT_CNT(x) ((x) & GENMASK(7, 0)) struct mmio_74xx_gpio_priv { From c4f0d16daa6d1c5d862d063379c03310387095d5 Mon Sep 17 00:00:00 2001 From: Jesse Taube Date: Sat, 23 Jul 2022 12:05:04 -0400 Subject: [PATCH 1333/1436] dt-bindings: gpio: fsl-imx-gpio: Add i.MXRT compatibles Both the i.MXRT1170 and 1050 have the same gpio controller as "fsl,imx35-gpio". Add i.MXRT to the compatible list. Signed-off-by: Jesse Taube Acked-by: Rob Herring Acked-by: Linus Walleij Signed-off-by: Bartosz Golaszewski --- Documentation/devicetree/bindings/gpio/fsl-imx-gpio.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.yaml b/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.yaml index f57d22d1ebd6..ae18603697d7 100644 --- a/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.yaml +++ b/Documentation/devicetree/bindings/gpio/fsl-imx-gpio.yaml @@ -37,6 +37,8 @@ properties: - fsl,imx8mp-gpio - fsl,imx8mq-gpio - fsl,imx8qxp-gpio + - fsl,imxrt1050-gpio + - fsl,imxrt1170-gpio - const: fsl,imx35-gpio reg: From 565cbaad83d83e288927b96565211109bc984007 Mon Sep 17 00:00:00 2001 From: Lecopzer Chen Date: Wed, 27 Apr 2022 15:29:01 +0100 Subject: [PATCH 1334/1436] ARM: 9202/1: kasan: support CONFIG_KASAN_VMALLOC Simply make shadow of vmalloc area mapped on demand. Since the virtual address of vmalloc for Arm is also between MODULE_VADDR and 0x100000000 (ZONE_HIGHMEM), which means the shadow address has already included between KASAN_SHADOW_START and KASAN_SHADOW_END. Thus we need to change nothing for memory map of Arm. This can fix ARM_MODULE_PLTS with KASan, support KASan for higmem and support CONFIG_VMAP_STACK with KASan. Signed-off-by: Lecopzer Chen Tested-by: Linus Walleij Reviewed-by: Linus Walleij Signed-off-by: Russell King (Oracle) --- arch/arm/Kconfig | 1 + arch/arm/mm/kasan_init.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 7630ba9cb6cc..545d2d4a492b 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -75,6 +75,7 @@ config ARM select HAVE_ARCH_KFENCE if MMU && !XIP_KERNEL select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU select HAVE_ARCH_KASAN if MMU && !XIP_KERNEL + select HAVE_ARCH_KASAN_VMALLOC if HAVE_ARCH_KASAN select HAVE_ARCH_MMAP_RND_BITS if MMU select HAVE_ARCH_PFN_VALID select HAVE_ARCH_SECCOMP diff --git a/arch/arm/mm/kasan_init.c b/arch/arm/mm/kasan_init.c index 5ad0d6c56d56..29caee9c79ce 100644 --- a/arch/arm/mm/kasan_init.c +++ b/arch/arm/mm/kasan_init.c @@ -236,7 +236,11 @@ void __init kasan_init(void) clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END); - kasan_populate_early_shadow(kasan_mem_to_shadow((void *)VMALLOC_START), + if (!IS_ENABLED(CONFIG_KASAN_VMALLOC)) + kasan_populate_early_shadow(kasan_mem_to_shadow((void *)VMALLOC_START), + kasan_mem_to_shadow((void *)VMALLOC_END)); + + kasan_populate_early_shadow(kasan_mem_to_shadow((void *)VMALLOC_END), kasan_mem_to_shadow((void *)-1UL) + 1); for_each_mem_range(i, &pa_start, &pa_end) { From 8fa7ea40bf56945c3ff5af00c0dca1fd9e26f129 Mon Sep 17 00:00:00 2001 From: Lecopzer Chen Date: Wed, 27 Apr 2022 15:30:00 +0100 Subject: [PATCH 1335/1436] ARM: 9203/1: kconfig: fix MODULE_PLTS for KASAN with KASAN_VMALLOC When we run out of module space address with ko insertion, and with MODULE_PLTS, module would turn to try to find memory from VMALLOC address space. Unfortunately, with KASAN enabled, VMALLOC doesn't work without KASAN_VMALLOC, thus select KASAN_VMALLOC by default. 8<--- cut here --- Unable to handle kernel paging request at virtual address bd300860 [bd300860] *pgd=41cf1811, *pte=41cf26df, *ppte=41cf265f Internal error: Oops: 80f [#1] PREEMPT SMP ARM Modules linked in: hello(O+) CPU: 0 PID: 89 Comm: insmod Tainted: G O 5.16.0-rc6+ #19 Hardware name: Generic DT based system PC is at mmioset+0x30/0xa8 LR is at 0x0 pc : [] lr : [<00000000>] psr: 20000013 sp : c451fc18 ip : bd300860 fp : c451fc2c r10: f18042cc r9 : f18042d0 r8 : 00000000 r7 : 00000001 r6 : 00000003 r5 : 01312d00 r4 : f1804300 r3 : 00000000 r2 : 00262560 r1 : 00000000 r0 : bd300860 Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 10c5387d Table: 43e9406a DAC: 00000051 Register r0 information: non-paged memory Register r1 information: NULL pointer Register r2 information: non-paged memory Register r3 information: NULL pointer Register r4 information: 4887-page vmalloc region starting at 0xf1802000 allocated at load_module+0x14f4/0x32a8 Register r5 information: non-paged memory Register r6 information: non-paged memory Register r7 information: non-paged memory Register r8 information: NULL pointer Register r9 information: 4887-page vmalloc region starting at 0xf1802000 allocated at load_module+0x14f4/0x32a8 Register r10 information: 4887-page vmalloc region starting at 0xf1802000 allocated at load_module+0x14f4/0x32a8 Register r11 information: non-slab/vmalloc memory Register r12 information: non-paged memory Process insmod (pid: 89, stack limit = 0xc451c000) Stack: (0xc451fc18 to 0xc4520000) fc00: f18041f0 c04803a4 fc20: c451fc44 c451fc30 c048053c c0480358 f1804030 01312cff c451fc64 c451fc48 fc40: c047f330 c0480500 f18040c0 c1b52ccc 00000001 c5be7700 c451fc74 c451fc68 fc60: f1802098 c047f300 c451fcb4 c451fc78 c026106c f180208c c4880004 00000000 fc80: c451fcb4 bf001000 c044ff48 c451fec0 f18040c0 00000000 c1b54cc4 00000000 fca0: c451fdf0 f1804268 c451fe64 c451fcb8 c0264e88 c0260d48 ffff8000 00007fff fcc0: f18040c0 c025cd00 c451fd14 00000003 0157f008 f1804258 f180425c f1804174 fce0: f1804154 f180424c f18041f0 f180414c f1804178 f18041c0 bf0025d4 188a3fa8 fd00: 0000009e f1804170 f2b18000 c451ff10 c0d92e40 f180416c c451feec 00000001 fd20: 00000000 c451fec8 c451fe20 c451fed0 f18040cc 00000000 f17ea000 c451fdc0 fd40: 41b58ab3 c1387729 c0261c28 c047fb5c c451fe2c c451fd60 c0525308 c048033c fd60: 188a3fb4 c3ccb090 c451fe00 c3ccb080 00000000 00000000 00016920 00000000 fd80: c02d0388 c047f55c c02d0388 00000000 c451fddc c451fda0 c02d0388 00000000 fda0: 41b58ab3 c13a72d0 c0524ff0 c1705f48 c451fdfc c451fdc0 c02d0388 c047f55c fdc0: 00016920 00000000 00000003 c1bb2384 c451fdfc c3ccb080 c1bb2384 00000000 fde0: 00000000 00000000 00000000 00000000 c451fe1c c451fe00 c04e9d70 c1705f48 fe00: c1b54cc4 c1bbc71c c3ccb080 00000000 c3ccb080 00000000 00000003 c451fec0 fe20: c451fe64 c451fe30 c0525918 c0524ffc c451feb0 c1705f48 00000000 c1b54cc4 fe40: b78a3fd0 c451ff60 00000000 0157f008 00000003 c451fec0 c451ffa4 c451fe68 fe60: c0265480 c0261c34 c451feb0 7fffffff 00000000 00000002 00000000 c4880000 fe80: 41b58ab3 c138777b c02652cc c04803ec 000a0000 c451ff00 ffffff9c b6ac9f60 fea0: c451fed4 c1705f48 c04a4a90 b78a3fdc f17ea000 ffffff9c b6ac9f60 c0100244 fec0: f17ea21a f17ea300 f17ea000 00016920 f1800240 f18000ac f17fb7dc 01316000 fee0: 013161b0 00002590 01316250 00000000 00000000 00000000 00002580 00000029 ff00: 0000002a 00000013 00000000 0000000c 00000000 00000000 0157f004 c451ffb0 ff20: c1719be0 aed6f410 c451ff74 c451ff38 c0c4103c c0c407d0 c451ff84 c451ff48 ff40: 00000805 c02c8658 c1604230 c1719c30 00000805 0157f004 00000005 c451ffb0 ff60: c1719be0 aed6f410 c451ffac c451ff78 c0122130 c1705f48 c451ffac 0157f008 ff80: 00000006 0000005f 0000017b c0100244 c4880000 0000017b 00000000 c451ffa8 ffa0: c0100060 c02652d8 0157f008 00000006 00000003 0157f008 00000000 b6ac9f60 ffc0: 0157f008 00000006 0000005f 0000017b 00000000 00000000 aed85f74 00000000 ffe0: b6ac9cd8 b6ac9cc8 00030200 aecf2d60 a0000010 00000003 00000000 00000000 Backtrace: [] (kasan_poison) from [] (kasan_unpoison+0x48/0x5c) [] (kasan_unpoison) from [] (__asan_register_globals+0x3c/0x64) r5:01312cff r4:f1804030 [] (__asan_register_globals) from [] (_sub_I_65535_1+0x18/0xf80 [hello]) r7:c5be7700 r6:00000001 r5:c1b52ccc r4:f18040c0 [] (_sub_I_65535_1 [hello]) from [] (do_init_module+0x330/0x72c) [] (do_init_module) from [] (load_module+0x3260/0x32a8) r10:f1804268 r9:c451fdf0 r8:00000000 r7:c1b54cc4 r6:00000000 r5:f18040c0 r4:c451fec0 [] (load_module) from [] (sys_finit_module+0x1b4/0x1e8) r10:c451fec0 r9:00000003 r8:0157f008 r7:00000000 r6:c451ff60 r5:b78a3fd0 r4:c1b54cc4 [] (sys_finit_module) from [] (ret_fast_syscall+0x0/0x1c) Exception stack(0xc451ffa8 to 0xc451fff0) ffa0: 0157f008 00000006 00000003 0157f008 00000000 b6ac9f60 ffc0: 0157f008 00000006 0000005f 0000017b 00000000 00000000 aed85f74 00000000 ffe0: b6ac9cd8 b6ac9cc8 00030200 aecf2d60 r10:0000017b r9:c4880000 r8:c0100244 r7:0000017b r6:0000005f r5:00000006 r4:0157f008 Code: e92d4100 e1a08001 e1a0e003 e2522040 (a8ac410a) ---[ end trace df6e12843197b6f5 ]--- Signed-off-by: Lecopzer Chen Tested-by: Linus Walleij Reviewed-by: Linus Walleij Signed-off-by: Russell King (Oracle) --- arch/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 545d2d4a492b..8a4954bc1652 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1415,6 +1415,7 @@ config HW_PERF_EVENTS config ARM_MODULE_PLTS bool "Use PLTs to allow module memory to spill over into vmalloc area" depends on MODULES + select KASAN_VMALLOC if KASAN default y help Allocate PLTs when loading modules so that jumps and calls whose From b97abb4d0e23766650619a6a57a52c91deb89b8a Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 24 Jul 2022 23:39:20 +0100 Subject: [PATCH 1336/1436] ARM: 9217/1: add definition of arch_irq_work_raise() The arm does not define arch_irq_work_raise() so is triggering the following sparse warning. Add a definiton to fix this: kernel/irq_work.c:70:13: warning: symbol 'arch_irq_work_raise' was not declared. Should it be static? arch/arm/kernel/smp.c:582:6: warning: symbol 'arch_irq_work_raise' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Russell King (Oracle) --- arch/arm/include/asm/irq_work.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/include/asm/irq_work.h b/arch/arm/include/asm/irq_work.h index 8895999834cc..3149e4dc1b54 100644 --- a/arch/arm/include/asm/irq_work.h +++ b/arch/arm/include/asm/irq_work.h @@ -9,4 +9,6 @@ static inline bool arch_irq_work_has_interrupt(void) return is_smp(); } +extern void arch_irq_work_raise(void); + #endif /* _ASM_ARM_IRQ_WORK_H */ From 3437021484dd8f71685012d47c2d2de6f020e943 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 24 Jul 2022 23:39:21 +0100 Subject: [PATCH 1337/1436] ARM: 9218/1: dma-mapping: fix pointer/integer warning Fix the use of a pointer assignment from integer where false is being used instead of NULL. Fix the following warning by usign NULL: arch/arm/mm/dma-mapping.c:712:52: warning: Using plain integer as NULL pointer Signed-off-by: Ben Dooks Signed-off-by: Russell King (Oracle) --- arch/arm/mm/dma-mapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 059cce018570..1483b6a4319d 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -709,7 +709,7 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, *handle = DMA_MAPPING_ERROR; allowblock = gfpflags_allow_blocking(gfp); - cma = allowblock ? dev_get_cma_area(dev) : false; + cma = allowblock ? dev_get_cma_area(dev) : NULL; if (cma) buf->allocator = &cma_allocator; From fe520635ddc4377e84f78c6cf1c54393f1dfa33b Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sun, 24 Jul 2022 23:39:22 +0100 Subject: [PATCH 1338/1436] ARM: 9219/1: fix undeclared soft_restart The soft_restart() is declared in so include that to fix the following sparse warning: arch/arm/kernel/reboot.c:78:6: warning: symbol 'soft_restart' was not declared. Should it be static? Signed-off-by: Ben Dooks Signed-off-by: Russell King (Oracle) --- arch/arm/kernel/reboot.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c index 2cb943422554..3f0d5c3dae11 100644 --- a/arch/arm/kernel/reboot.c +++ b/arch/arm/kernel/reboot.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "reboot.h" From f2d3b9a46e0ed4742abaa00506b18bb2ca9179d8 Mon Sep 17 00:00:00 2001 From: Saravana Kannan Date: Wed, 27 Jul 2022 19:19:35 +0100 Subject: [PATCH 1339/1436] ARM: 9220/1: amba: Remove deferred device addition The uevents generated for an amba device need PID and CID information that's available only when the amba device is powered on, clocked and out of reset. So, if those resources aren't available, the information can't be read to generate the uevents. To workaround this requirement, if the resources weren't available, the device addition was deferred and retried periodically. However, this deferred addition retry isn't based on resources becoming available. Instead, it's retried every 5 seconds and causes arbitrary probe delays for amba devices and their consumers. Also, maintaining a separate deferred-probe like mechanism is maintenance headache. With this commit, instead of deferring the device addition, we simply defer the generation of uevents for the device and probing of the device (because drivers needs PID and CID to match) until the PID and CID information can be read. This allows us to delete all the amba specific deferring code and also avoid the arbitrary probing delays. Cc: Rob Herring Cc: Ulf Hansson Cc: Saravana Kannan Cc: Linus Walleij Cc: Sudeep Holla Cc: Nicolas Saenz Julienne Cc: Geert Uytterhoeven Cc: Marek Szyprowski Cc: Kefeng Wang Cc: Greg Kroah-Hartman Cc: patches@armlinux.org.uk Signed-off-by: Saravana Kannan Tested-by: Marek Szyprowski Tested-by: Kefeng Wang Tested-by: Sudeep Holla Signed-off-by: Russell King (Oracle) --- drivers/amba/bus.c | 315 +++++++++++++++++++++------------------------ 1 file changed, 146 insertions(+), 169 deletions(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 0cb20324da16..32b0e0b930c1 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -130,11 +130,100 @@ static struct attribute *amba_dev_attrs[] = { }; ATTRIBUTE_GROUPS(amba_dev); +static int amba_read_periphid(struct amba_device *dev) +{ + struct reset_control *rstc; + u32 size, pid, cid; + void __iomem *tmp; + int i, ret; + + ret = dev_pm_domain_attach(&dev->dev, true); + if (ret) { + dev_dbg(&dev->dev, "can't get PM domain: %d\n", ret); + goto err_out; + } + + ret = amba_get_enable_pclk(dev); + if (ret) { + dev_dbg(&dev->dev, "can't get pclk: %d\n", ret); + goto err_pm; + } + + /* + * Find reset control(s) of the amba bus and de-assert them. + */ + rstc = of_reset_control_array_get_optional_shared(dev->dev.of_node); + if (IS_ERR(rstc)) { + ret = PTR_ERR(rstc); + if (ret != -EPROBE_DEFER) + dev_err(&dev->dev, "can't get reset: %d\n", ret); + goto err_clk; + } + reset_control_deassert(rstc); + reset_control_put(rstc); + + size = resource_size(&dev->res); + tmp = ioremap(dev->res.start, size); + if (!tmp) { + ret = -ENOMEM; + goto err_clk; + } + + /* + * Read pid and cid based on size of resource + * they are located at end of region + */ + for (pid = 0, i = 0; i < 4; i++) + pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8); + for (cid = 0, i = 0; i < 4; i++) + cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8); + + if (cid == CORESIGHT_CID) { + /* set the base to the start of the last 4k block */ + void __iomem *csbase = tmp + size - 4096; + + dev->uci.devarch = readl(csbase + UCI_REG_DEVARCH_OFFSET); + dev->uci.devtype = readl(csbase + UCI_REG_DEVTYPE_OFFSET) & 0xff; + } + + if (cid == AMBA_CID || cid == CORESIGHT_CID) { + dev->periphid = pid; + dev->cid = cid; + } + + if (!dev->periphid) + ret = -ENODEV; + + iounmap(tmp); + +err_clk: + amba_put_disable_pclk(dev); +err_pm: + dev_pm_domain_detach(&dev->dev, true); +err_out: + return ret; +} + static int amba_match(struct device *dev, struct device_driver *drv) { struct amba_device *pcdev = to_amba_device(dev); struct amba_driver *pcdrv = to_amba_driver(drv); + if (!pcdev->periphid) { + int ret = amba_read_periphid(pcdev); + + /* + * Returning any error other than -EPROBE_DEFER from bus match + * can cause driver registration failure. So, if there's a + * permanent failure in reading pid and cid, simply map it to + * -EPROBE_DEFER. + */ + if (ret) + return -EPROBE_DEFER; + dev_set_uevent_suppress(dev, false); + kobject_uevent(&dev->kobj, KOBJ_ADD); + } + /* When driver_override is set, only bind to the matching driver */ if (pcdev->driver_override) return !strcmp(pcdev->driver_override, drv->name); @@ -368,6 +457,42 @@ static int __init amba_init(void) postcore_initcall(amba_init); +static int amba_proxy_probe(struct amba_device *adev, + const struct amba_id *id) +{ + WARN(1, "Stub driver should never match any device.\n"); + return -ENODEV; +} + +static const struct amba_id amba_stub_drv_ids[] = { + { 0, 0 }, +}; + +static struct amba_driver amba_proxy_drv = { + .drv = { + .name = "amba-proxy", + }, + .probe = amba_proxy_probe, + .id_table = amba_stub_drv_ids, +}; + +static int __init amba_stub_drv_init(void) +{ + if (!IS_ENABLED(CONFIG_MODULES)) + return 0; + + /* + * The amba_match() function will get called only if there is at least + * one amba driver registered. If all amba drivers are modules and are + * only loaded based on uevents, then we'll hit a chicken-and-egg + * situation where amba_match() is waiting on drivers and drivers are + * waiting on amba_match(). So, register a stub driver to make sure + * amba_match() is called even if no amba driver has been registered. + */ + return amba_driver_register(&amba_proxy_drv); +} +late_initcall_sync(amba_stub_drv_init); + /** * amba_driver_register - register an AMBA device driver * @drv: amba device driver structure @@ -410,156 +535,6 @@ static void amba_device_release(struct device *dev) kfree(d); } -static int amba_read_periphid(struct amba_device *dev) -{ - struct reset_control *rstc; - u32 size, pid, cid; - void __iomem *tmp; - int i, ret; - - ret = dev_pm_domain_attach(&dev->dev, true); - if (ret) - goto err_out; - - ret = amba_get_enable_pclk(dev); - if (ret) - goto err_pm; - - /* - * Find reset control(s) of the amba bus and de-assert them. - */ - rstc = of_reset_control_array_get_optional_shared(dev->dev.of_node); - if (IS_ERR(rstc)) { - ret = PTR_ERR(rstc); - if (ret != -EPROBE_DEFER) - dev_err(&dev->dev, "can't get reset: %d\n", ret); - goto err_clk; - } - reset_control_deassert(rstc); - reset_control_put(rstc); - - size = resource_size(&dev->res); - tmp = ioremap(dev->res.start, size); - if (!tmp) { - ret = -ENOMEM; - goto err_clk; - } - - /* - * Read pid and cid based on size of resource - * they are located at end of region - */ - for (pid = 0, i = 0; i < 4; i++) - pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) << (i * 8); - for (cid = 0, i = 0; i < 4; i++) - cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) << (i * 8); - - if (cid == CORESIGHT_CID) { - /* set the base to the start of the last 4k block */ - void __iomem *csbase = tmp + size - 4096; - - dev->uci.devarch = readl(csbase + UCI_REG_DEVARCH_OFFSET); - dev->uci.devtype = readl(csbase + UCI_REG_DEVTYPE_OFFSET) & 0xff; - } - - if (cid == AMBA_CID || cid == CORESIGHT_CID) { - dev->periphid = pid; - dev->cid = cid; - } - - if (!dev->periphid) - ret = -ENODEV; - - iounmap(tmp); - -err_clk: - amba_put_disable_pclk(dev); -err_pm: - dev_pm_domain_detach(&dev->dev, true); -err_out: - return ret; -} - -static int amba_device_try_add(struct amba_device *dev, struct resource *parent) -{ - int ret; - - ret = request_resource(parent, &dev->res); - if (ret) - goto err_out; - - /* Hard-coded primecell ID instead of plug-n-play */ - if (dev->periphid != 0) - goto skip_probe; - - ret = amba_read_periphid(dev); - if (ret) - goto err_release; - -skip_probe: - ret = device_add(&dev->dev); -err_release: - if (ret) - release_resource(&dev->res); -err_out: - return ret; -} - -/* - * Registration of AMBA device require reading its pid and cid registers. - * To do this, the device must be turned on (if it is a part of power domain) - * and have clocks enabled. However in some cases those resources might not be - * yet available. Returning EPROBE_DEFER is not a solution in such case, - * because callers don't handle this special error code. Instead such devices - * are added to the special list and their registration is retried from - * periodic worker, until all resources are available and registration succeeds. - */ -struct deferred_device { - struct amba_device *dev; - struct resource *parent; - struct list_head node; -}; - -static LIST_HEAD(deferred_devices); -static DEFINE_MUTEX(deferred_devices_lock); - -static void amba_deferred_retry_func(struct work_struct *dummy); -static DECLARE_DELAYED_WORK(deferred_retry_work, amba_deferred_retry_func); - -#define DEFERRED_DEVICE_TIMEOUT (msecs_to_jiffies(5 * 1000)) - -static int amba_deferred_retry(void) -{ - struct deferred_device *ddev, *tmp; - - mutex_lock(&deferred_devices_lock); - - list_for_each_entry_safe(ddev, tmp, &deferred_devices, node) { - int ret = amba_device_try_add(ddev->dev, ddev->parent); - - if (ret == -EPROBE_DEFER) - continue; - - list_del_init(&ddev->node); - amba_device_put(ddev->dev); - kfree(ddev); - } - - mutex_unlock(&deferred_devices_lock); - - return 0; -} -late_initcall(amba_deferred_retry); - -static void amba_deferred_retry_func(struct work_struct *dummy) -{ - amba_deferred_retry(); - - if (!list_empty(&deferred_devices)) - schedule_delayed_work(&deferred_retry_work, - DEFERRED_DEVICE_TIMEOUT); -} - /** * amba_device_add - add a previously allocated AMBA device structure * @dev: AMBA device allocated by amba_device_alloc @@ -571,28 +546,30 @@ static void amba_deferred_retry_func(struct work_struct *dummy) */ int amba_device_add(struct amba_device *dev, struct resource *parent) { - int ret = amba_device_try_add(dev, parent); + int ret; - if (ret == -EPROBE_DEFER) { - struct deferred_device *ddev; + ret = request_resource(parent, &dev->res); + if (ret) + return ret; - ddev = kmalloc(sizeof(*ddev), GFP_KERNEL); - if (!ddev) - return -ENOMEM; - - ddev->dev = dev; - ddev->parent = parent; - ret = 0; - - mutex_lock(&deferred_devices_lock); - - if (list_empty(&deferred_devices)) - schedule_delayed_work(&deferred_retry_work, - DEFERRED_DEVICE_TIMEOUT); - list_add_tail(&ddev->node, &deferred_devices); - - mutex_unlock(&deferred_devices_lock); + /* If primecell ID isn't hard-coded, figure it out */ + if (!dev->periphid) { + /* + * AMBA device uevents require reading its pid and cid + * registers. To do this, the device must be on, clocked and + * out of reset. However in some cases those resources might + * not yet be available. If that's the case, we suppress the + * generation of uevents until we can read the pid and cid + * registers. See also amba_match(). + */ + if (amba_read_periphid(dev)) + dev_set_uevent_suppress(&dev->dev, true); } + + ret = device_add(&dev->dev); + if (ret) + release_resource(&dev->res); + return ret; } EXPORT_SYMBOL_GPL(amba_device_add); From b6c694740ea21620c2b86ad37be2c0dc7051a48c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 14 Jul 2022 18:59:59 -0700 Subject: [PATCH 1340/1436] kobject: fix Kconfig.debug "its" grammar Use the possessive "its" instead of the contraction "it's" where appropriate. Cc: Russell King Cc: Greg Kroah-Hartman Signed-off-by: Randy Dunlap Link: https://lore.kernel.org/r/20220715015959.12657-1-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- lib/Kconfig.debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2e24db4bff19..abb1b287b8f1 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1560,7 +1560,7 @@ config DEBUG_KOBJECT_RELEASE help kobjects are reference counted objects. This means that their last reference count put is not predictable, and the kobject can - live on past the point at which a driver decides to drop it's + live on past the point at which a driver decides to drop its initial reference to the kobject gained on allocation. An example of this would be a struct device which has just been unregistered. From b18ee4a44e3ff21936d35a9b215cfd6cd5f3af9a Mon Sep 17 00:00:00 2001 From: Slark Xiao Date: Thu, 21 Jul 2022 10:06:23 +0800 Subject: [PATCH 1341/1436] sysfs docs: ABI: Fix typo in comment Fix typo in the comment Signed-off-by: Slark Xiao Link: https://lore.kernel.org/r/20220721020623.20974-1-slark_xiao@163.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/stable/sysfs-module | 2 +- Documentation/ABI/testing/sysfs-class-rtrs-client | 2 +- Documentation/ABI/testing/sysfs-class-rtrs-server | 2 +- Documentation/ABI/testing/sysfs-devices-platform-ACPI-TAD | 2 +- Documentation/ABI/testing/sysfs-devices-power | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/ABI/stable/sysfs-module b/Documentation/ABI/stable/sysfs-module index 560b4a3278df..41b1f16e8795 100644 --- a/Documentation/ABI/stable/sysfs-module +++ b/Documentation/ABI/stable/sysfs-module @@ -38,7 +38,7 @@ What: /sys/module//srcversion Date: Jun 2005 Description: If the module source has MODULE_VERSION, this file will contain - the checksum of the the source code. + the checksum of the source code. What: /sys/module//version Date: Jun 2005 diff --git a/Documentation/ABI/testing/sysfs-class-rtrs-client b/Documentation/ABI/testing/sysfs-class-rtrs-client index 49a4157c7bf1..fecc59d1b96f 100644 --- a/Documentation/ABI/testing/sysfs-class-rtrs-client +++ b/Documentation/ABI/testing/sysfs-class-rtrs-client @@ -78,7 +78,7 @@ What: /sys/class/rtrs-client//paths//hca_name Date: Feb 2020 KernelVersion: 5.7 Contact: Jack Wang Danil Kipnis -Description: RO, Contains the the name of HCA the connection established on. +Description: RO, Contains the name of HCA the connection established on. What: /sys/class/rtrs-client//paths//hca_port Date: Feb 2020 diff --git a/Documentation/ABI/testing/sysfs-class-rtrs-server b/Documentation/ABI/testing/sysfs-class-rtrs-server index 3b6d5b067df0..b08601d80409 100644 --- a/Documentation/ABI/testing/sysfs-class-rtrs-server +++ b/Documentation/ABI/testing/sysfs-class-rtrs-server @@ -24,7 +24,7 @@ What: /sys/class/rtrs-server//paths//hca_name Date: Feb 2020 KernelVersion: 5.7 Contact: Jack Wang Danil Kipnis -Description: RO, Contains the the name of HCA the connection established on. +Description: RO, Contains the name of HCA the connection established on. What: /sys/class/rtrs-server//paths//hca_port Date: Feb 2020 diff --git a/Documentation/ABI/testing/sysfs-devices-platform-ACPI-TAD b/Documentation/ABI/testing/sysfs-devices-platform-ACPI-TAD index f7b360a61b21..bc44bc903bc8 100644 --- a/Documentation/ABI/testing/sysfs-devices-platform-ACPI-TAD +++ b/Documentation/ABI/testing/sysfs-devices-platform-ACPI-TAD @@ -74,7 +74,7 @@ Description: Reads also cause the AC alarm timer status to be reset. - Another way to reset the the status of the AC alarm timer is to + Another way to reset the status of the AC alarm timer is to write (the number) 0 to this file. If the status return value indicates that the timer has expired, diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power index 1b2a2d41ff80..54195530e97a 100644 --- a/Documentation/ABI/testing/sysfs-devices-power +++ b/Documentation/ABI/testing/sysfs-devices-power @@ -303,5 +303,5 @@ Date: Apr 2010 Contact: Dominik Brodowski Description: Reports the runtime PM children usage count of a device, or - 0 if the the children will be ignored. + 0 if the children will be ignored. From f2d57765b79857264fb0ddc52679d661b60ecc21 Mon Sep 17 00:00:00 2001 From: "Fabio M. De Francesco" Date: Fri, 15 Jul 2022 01:50:30 +0200 Subject: [PATCH 1342/1436] firmware_loader: Replace kmap() with kmap_local_page() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The use of kmap() is being deprecated in favor of kmap_local_page(). Two main problems with kmap(): (1) It comes with an overhead as mapping space is restricted and protected by a global lock for synchronization and (2) kmap() also requires global TLB invalidation when the kmap’s pool wraps and it might block when the mapping space is fully utilized until a slot becomes available. kmap_local_page() is preferred over kmap() and kmap_atomic(). Where it cannot mechanically replace the latters, code refactor should be considered (special care must be taken if kernel virtual addresses are aliases in different contexts). With kmap_local_page() the mappings are per thread, CPU local, can take page faults, and can be called from any context (including interrupts). Call kmap_local_page() in firmware_loader wherever kmap() is currently used. In firmware_rw() use the helpers copy_{from,to}_page() instead of open coding the local mappings + memcpy(). Successfully tested with "firmware" selftests on a QEMU/KVM 32-bits VM with 4GB RAM, booting a kernel with HIGHMEM64GB enabled. Cc: Greg Kroah-Hartman Cc: Luis Chamberlain Suggested-by: Ira Weiny Reviewed-by: Takashi Iwai Signed-off-by: Fabio M. De Francesco Link: https://lore.kernel.org/r/20220714235030.12732-1-fmdefrancesco@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_loader/main.c | 4 ++-- drivers/base/firmware_loader/sysfs.c | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index ac3f34e80194..7c3590fd97c2 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -435,11 +435,11 @@ static int fw_decompress_xz_pages(struct device *dev, struct fw_priv *fw_priv, /* decompress onto the new allocated page */ page = fw_priv->pages[fw_priv->nr_pages - 1]; - xz_buf.out = kmap(page); + xz_buf.out = kmap_local_page(page); xz_buf.out_pos = 0; xz_buf.out_size = PAGE_SIZE; xz_ret = xz_dec_run(xz_dec, &xz_buf); - kunmap(page); + kunmap_local(xz_buf.out); fw_priv->size += xz_buf.out_pos; /* partial decompression means either end or error */ if (xz_buf.out_pos != PAGE_SIZE) diff --git a/drivers/base/firmware_loader/sysfs.c b/drivers/base/firmware_loader/sysfs.c index 5b0b85b70b6f..77bad32c481a 100644 --- a/drivers/base/firmware_loader/sysfs.c +++ b/drivers/base/firmware_loader/sysfs.c @@ -242,19 +242,17 @@ static void firmware_rw(struct fw_priv *fw_priv, char *buffer, loff_t offset, size_t count, bool read) { while (count) { - void *page_data; int page_nr = offset >> PAGE_SHIFT; int page_ofs = offset & (PAGE_SIZE - 1); int page_cnt = min_t(size_t, PAGE_SIZE - page_ofs, count); - page_data = kmap(fw_priv->pages[page_nr]); - if (read) - memcpy(buffer, page_data + page_ofs, page_cnt); + memcpy_from_page(buffer, fw_priv->pages[page_nr], + page_ofs, page_cnt); else - memcpy(page_data + page_ofs, buffer, page_cnt); + memcpy_to_page(fw_priv->pages[page_nr], page_ofs, + buffer, page_cnt); - kunmap(fw_priv->pages[page_nr]); buffer += page_cnt; offset += page_cnt; count -= page_cnt; From da0b93d65e5bba6d4381f9dc99c547b60582e7a7 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 18 Jul 2022 17:47:13 +0200 Subject: [PATCH 1343/1436] KVM: nSVM: Pull CS.Base from actual VMCB12 for soft int/ex re-injection enter_svm_guest_mode() first calls nested_vmcb02_prepare_control() to copy control fields from VMCB12 to the current VMCB, then nested_vmcb02_prepare_save() to perform a similar copy of the save area. This means that nested_vmcb02_prepare_control() still runs with the previous save area values in the current VMCB so it shouldn't take the L2 guest CS.Base from this area. Explicitly pull CS.Base from the actual VMCB12 instead in enter_svm_guest_mode(). Granted, having a non-zero CS.Base is a very rare thing (and even impossible in 64-bit mode), having it change between nested VMRUNs is probably even rarer, but if it happens it would create a really subtle bug so it's better to fix it upfront. Fixes: 6ef88d6e36c2 ("KVM: SVM: Re-inject INT3/INTO instead of retrying the instruction") Signed-off-by: Maciej S. Szmigiero Message-Id: <4caa0f67589ae3c22c311ee0e6139496902f2edc.1658159083.git.maciej.szmigiero@oracle.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/nested.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index adf4120b05d9..23252ab82194 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -639,7 +639,8 @@ static bool is_evtinj_nmi(u32 evtinj) } static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, - unsigned long vmcb12_rip) + unsigned long vmcb12_rip, + unsigned long vmcb12_csbase) { u32 int_ctl_vmcb01_bits = V_INTR_MASKING_MASK; u32 int_ctl_vmcb12_bits = V_TPR_MASK | V_IRQ_INJECTION_BITS_MASK; @@ -711,7 +712,7 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm, svm->nmi_l1_to_l2 = is_evtinj_nmi(vmcb02->control.event_inj); if (is_evtinj_soft(vmcb02->control.event_inj)) { svm->soft_int_injected = true; - svm->soft_int_csbase = svm->vmcb->save.cs.base; + svm->soft_int_csbase = vmcb12_csbase; svm->soft_int_old_rip = vmcb12_rip; if (svm->nrips_enabled) svm->soft_int_next_rip = svm->nested.ctl.next_rip; @@ -800,7 +801,7 @@ int enter_svm_guest_mode(struct kvm_vcpu *vcpu, u64 vmcb12_gpa, nested_svm_copy_common_state(svm->vmcb01.ptr, svm->nested.vmcb02.ptr); svm_switch_vmcb(svm, &svm->nested.vmcb02); - nested_vmcb02_prepare_control(svm, vmcb12->save.rip); + nested_vmcb02_prepare_control(svm, vmcb12->save.rip, vmcb12->save.cs.base); nested_vmcb02_prepare_save(svm, vmcb12); ret = nested_svm_load_cr3(&svm->vcpu, svm->nested.save.cr3, @@ -1663,7 +1664,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu, nested_copy_vmcb_control_to_cache(svm, ctl); svm_switch_vmcb(svm, &svm->nested.vmcb02); - nested_vmcb02_prepare_control(svm, svm->vmcb->save.rip); + nested_vmcb02_prepare_control(svm, svm->vmcb->save.rip, svm->vmcb->save.cs.base); /* * While the nested guest CR3 is already checked and set by From 35d539c3e44f2021ff47a91cf4e6a35c550b6fbc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 22:42:20 +0000 Subject: [PATCH 1344/1436] KVM: x86/mmu: Return a u64 (the old SPTE) from mmu_spte_clear_track_bits() Return a u64, not an int, from mmu_spte_clear_track_bits(). The return value is the old SPTE value, which is very much a 64-bit value. The sole caller that consumes the return value, drop_spte(), already uses a u64. The only reason that truncating the SPTE value is not problematic is because drop_spte() only queries the shadow-present bit, which is in the lower 32 bits. Signed-off-by: Sean Christopherson Message-Id: <20220715224226.3749507-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 52664c3caaab..b2379ede2ed6 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -529,7 +529,7 @@ static bool mmu_spte_update(u64 *sptep, u64 new_spte) * state bits, it is used to clear the last level sptep. * Returns the old PTE. */ -static int mmu_spte_clear_track_bits(struct kvm *kvm, u64 *sptep) +static u64 mmu_spte_clear_track_bits(struct kvm *kvm, u64 *sptep) { kvm_pfn_t pfn; u64 old_spte = *sptep; From a42989e7fbb0186d9fee05b29e0ea9cb639d0bd3 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 22:42:21 +0000 Subject: [PATCH 1345/1436] KVM: x86/mmu: Directly "destroy" PTE list when recycling rmaps Use pte_list_destroy() directly when recycling rmaps instead of bouncing through kvm_unmap_rmapp() and kvm_zap_rmapp(). Calling kvm_unmap_rmapp() is unnecessary and odd as it requires passing dummy parameters; passing NULL for @slot when __rmap_add() already has a valid slot is especially weird and confusing. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220715224226.3749507-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index b2379ede2ed6..92fcffec0227 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1596,7 +1596,7 @@ static void __rmap_add(struct kvm *kvm, rmap_count = pte_list_add(cache, spte, rmap_head); if (rmap_count > RMAP_RECYCLE_THRESHOLD) { - kvm_unmap_rmapp(kvm, rmap_head, NULL, gfn, sp->role.level, __pte(0)); + pte_list_destroy(kvm, rmap_head); kvm_flush_remote_tlbs_with_address( kvm, sp->gfn, KVM_PAGES_PER_HPAGE(sp->role.level)); } From aed02fe3cae41c4f9a5f31390b198025bfc9cf88 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 22:42:22 +0000 Subject: [PATCH 1346/1436] KVM: x86/mmu: Drop the "p is for pointer" from rmap helpers Drop the trailing "p" from rmap helpers, i.e. rename functions to simply be kvm__rmap(). Declaring that a function takes a pointer is completely unnecessary and goes against kernel style. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220715224226.3749507-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 43 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 92fcffec0227..fec999d2fc13 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -403,7 +403,7 @@ static u64 __update_clear_spte_slow(u64 *sptep, u64 spte) * The idea using the light way get the spte on x86_32 guest is from * gup_get_pte (mm/gup.c). * - * An spte tlb flush may be pending, because kvm_set_pte_rmapp + * An spte tlb flush may be pending, because kvm_set_pte_rmap * coalesces them and we are running out of the MMU lock. Therefore * we need to protect against in-progress updates of the spte. * @@ -1383,22 +1383,22 @@ static bool kvm_vcpu_write_protect_gfn(struct kvm_vcpu *vcpu, u64 gfn) return kvm_mmu_slot_gfn_write_protect(vcpu->kvm, slot, gfn, PG_LEVEL_4K); } -static bool kvm_zap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, - const struct kvm_memory_slot *slot) +static bool kvm_zap_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, + const struct kvm_memory_slot *slot) { return pte_list_destroy(kvm, rmap_head); } -static bool kvm_unmap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, - struct kvm_memory_slot *slot, gfn_t gfn, int level, - pte_t unused) +static bool kvm_unmap_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, + struct kvm_memory_slot *slot, gfn_t gfn, int level, + pte_t unused) { - return kvm_zap_rmapp(kvm, rmap_head, slot); + return kvm_zap_rmap(kvm, rmap_head, slot); } -static bool kvm_set_pte_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, - struct kvm_memory_slot *slot, gfn_t gfn, int level, - pte_t pte) +static bool kvm_set_pte_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, + struct kvm_memory_slot *slot, gfn_t gfn, int level, + pte_t pte) { u64 *sptep; struct rmap_iterator iter; @@ -1529,7 +1529,7 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range) bool flush = false; if (kvm_memslots_have_rmaps(kvm)) - flush = kvm_handle_gfn_range(kvm, range, kvm_unmap_rmapp); + flush = kvm_handle_gfn_range(kvm, range, kvm_unmap_rmap); if (is_tdp_mmu_enabled(kvm)) flush = kvm_tdp_mmu_unmap_gfn_range(kvm, range, flush); @@ -1542,7 +1542,7 @@ bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range) bool flush = false; if (kvm_memslots_have_rmaps(kvm)) - flush = kvm_handle_gfn_range(kvm, range, kvm_set_pte_rmapp); + flush = kvm_handle_gfn_range(kvm, range, kvm_set_pte_rmap); if (is_tdp_mmu_enabled(kvm)) flush |= kvm_tdp_mmu_set_spte_gfn(kvm, range); @@ -1550,9 +1550,9 @@ bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range) return flush; } -static bool kvm_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, - struct kvm_memory_slot *slot, gfn_t gfn, int level, - pte_t unused) +static bool kvm_age_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, + struct kvm_memory_slot *slot, gfn_t gfn, int level, + pte_t unused) { u64 *sptep; struct rmap_iterator iter; @@ -1564,9 +1564,9 @@ static bool kvm_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, return young; } -static bool kvm_test_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head, - struct kvm_memory_slot *slot, gfn_t gfn, - int level, pte_t unused) +static bool kvm_test_age_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, + struct kvm_memory_slot *slot, gfn_t gfn, + int level, pte_t unused) { u64 *sptep; struct rmap_iterator iter; @@ -1615,7 +1615,7 @@ bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) bool young = false; if (kvm_memslots_have_rmaps(kvm)) - young = kvm_handle_gfn_range(kvm, range, kvm_age_rmapp); + young = kvm_handle_gfn_range(kvm, range, kvm_age_rmap); if (is_tdp_mmu_enabled(kvm)) young |= kvm_tdp_mmu_age_gfn_range(kvm, range); @@ -1628,7 +1628,7 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range) bool young = false; if (kvm_memslots_have_rmaps(kvm)) - young = kvm_handle_gfn_range(kvm, range, kvm_test_age_rmapp); + young = kvm_handle_gfn_range(kvm, range, kvm_test_age_rmap); if (is_tdp_mmu_enabled(kvm)) young |= kvm_tdp_mmu_test_age_gfn(kvm, range); @@ -6004,8 +6004,7 @@ static bool __kvm_zap_rmaps(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) if (WARN_ON_ONCE(start >= end)) continue; - flush = slot_handle_level_range(kvm, memslot, kvm_zap_rmapp, - + flush = slot_handle_level_range(kvm, memslot, kvm_zap_rmap, PG_LEVEL_4K, KVM_MAX_HUGEPAGE_LEVEL, start, end - 1, true, flush); } From 2833eda0e296ba3c410e9d57636de14d2589ad4e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 22:42:23 +0000 Subject: [PATCH 1347/1436] KVM: x86/mmu: Rename __kvm_zap_rmaps() to align with other nomenclature Rename __kvm_zap_rmaps() to kvm_rmap_zap_gfn_range() to avoid future confusion with a soon-to-be-introduced __kvm_zap_rmap(). Using a plural "rmaps" is somewhat ambiguous without additional context, as it's not obvious whether it's referring to multiple rmap lists, versus multiple rmap entries within a single list. Use kvm_rmap_zap_gfn_range() to align with the pattern established by kvm_rmap_zap_collapsible_sptes(), without losing the information that it zaps only rmap-based MMUs, i.e. don't rename it to __kvm_zap_gfn_range(). No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220715224226.3749507-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index fec999d2fc13..61c32d8d1f6d 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -5982,7 +5982,7 @@ void kvm_mmu_uninit_vm(struct kvm *kvm) mmu_free_vm_memory_caches(kvm); } -static bool __kvm_zap_rmaps(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) +static bool kvm_rmap_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) { const struct kvm_memory_slot *memslot; struct kvm_memslots *slots; @@ -6029,7 +6029,7 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end) kvm_inc_notifier_count(kvm, gfn_start, gfn_end); - flush = __kvm_zap_rmaps(kvm, gfn_start, gfn_end); + flush = kvm_rmap_zap_gfn_range(kvm, gfn_start, gfn_end); if (is_tdp_mmu_enabled(kvm)) { for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) From f8480721a74b82c6e88fff09286aa452d5ed6d71 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 22:42:24 +0000 Subject: [PATCH 1348/1436] KVM: x86/mmu: Rename rmap zap helpers to eliminate "unmap" wrapper Rename kvm_unmap_rmap() and kvm_zap_rmap() to kvm_zap_rmap() and __kvm_zap_rmap() respectively to show that what was the "unmap" helper is just a wrapper for the "zap" helper, i.e. that they do the exact same thing, one just exists to deal with its caller passing in more params. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220715224226.3749507-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 61c32d8d1f6d..00be88e0a5f7 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -1383,17 +1383,17 @@ static bool kvm_vcpu_write_protect_gfn(struct kvm_vcpu *vcpu, u64 gfn) return kvm_mmu_slot_gfn_write_protect(vcpu->kvm, slot, gfn, PG_LEVEL_4K); } -static bool kvm_zap_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, - const struct kvm_memory_slot *slot) +static bool __kvm_zap_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, + const struct kvm_memory_slot *slot) { return pte_list_destroy(kvm, rmap_head); } -static bool kvm_unmap_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, - struct kvm_memory_slot *slot, gfn_t gfn, int level, - pte_t unused) +static bool kvm_zap_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, + struct kvm_memory_slot *slot, gfn_t gfn, int level, + pte_t unused) { - return kvm_zap_rmap(kvm, rmap_head, slot); + return __kvm_zap_rmap(kvm, rmap_head, slot); } static bool kvm_set_pte_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, @@ -1529,7 +1529,7 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range) bool flush = false; if (kvm_memslots_have_rmaps(kvm)) - flush = kvm_handle_gfn_range(kvm, range, kvm_unmap_rmap); + flush = kvm_handle_gfn_range(kvm, range, kvm_zap_rmap); if (is_tdp_mmu_enabled(kvm)) flush = kvm_tdp_mmu_unmap_gfn_range(kvm, range, flush); @@ -6004,7 +6004,7 @@ static bool kvm_rmap_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_e if (WARN_ON_ONCE(start >= end)) continue; - flush = slot_handle_level_range(kvm, memslot, kvm_zap_rmap, + flush = slot_handle_level_range(kvm, memslot, __kvm_zap_rmap, PG_LEVEL_4K, KVM_MAX_HUGEPAGE_LEVEL, start, end - 1, true, flush); } From 9202aee816c84d69179f94193c5dd321bb0e8530 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 22:42:25 +0000 Subject: [PATCH 1349/1436] KVM: x86/mmu: Rename pte_list_{destroy,remove}() to show they zap SPTEs Rename pte_list_remove() and pte_list_destroy() to kvm_zap_one_rmap_spte() and kvm_zap_all_rmap_sptes() respectively to document that (a) they zap SPTEs and (b) to better document how they differ (remove vs. destroy does not exactly scream "one vs. all"). No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220715224226.3749507-7-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 00be88e0a5f7..282e7e2ab446 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -957,15 +957,16 @@ static void __pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head) } } -static void pte_list_remove(struct kvm *kvm, struct kvm_rmap_head *rmap_head, - u64 *sptep) +static void kvm_zap_one_rmap_spte(struct kvm *kvm, + struct kvm_rmap_head *rmap_head, u64 *sptep) { mmu_spte_clear_track_bits(kvm, sptep); __pte_list_remove(sptep, rmap_head); } -/* Return true if rmap existed, false otherwise */ -static bool pte_list_destroy(struct kvm *kvm, struct kvm_rmap_head *rmap_head) +/* Return true if at least one SPTE was zapped, false otherwise */ +static bool kvm_zap_all_rmap_sptes(struct kvm *kvm, + struct kvm_rmap_head *rmap_head) { struct pte_list_desc *desc, *next; int i; @@ -1386,7 +1387,7 @@ static bool kvm_vcpu_write_protect_gfn(struct kvm_vcpu *vcpu, u64 gfn) static bool __kvm_zap_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, const struct kvm_memory_slot *slot) { - return pte_list_destroy(kvm, rmap_head); + return kvm_zap_all_rmap_sptes(kvm, rmap_head); } static bool kvm_zap_rmap(struct kvm *kvm, struct kvm_rmap_head *rmap_head, @@ -1417,7 +1418,7 @@ restart: need_flush = true; if (pte_write(pte)) { - pte_list_remove(kvm, rmap_head, sptep); + kvm_zap_one_rmap_spte(kvm, rmap_head, sptep); goto restart; } else { new_spte = kvm_mmu_changed_pte_notifier_make_spte( @@ -1596,7 +1597,7 @@ static void __rmap_add(struct kvm *kvm, rmap_count = pte_list_add(cache, spte, rmap_head); if (rmap_count > RMAP_RECYCLE_THRESHOLD) { - pte_list_destroy(kvm, rmap_head); + kvm_zap_all_rmap_sptes(kvm, rmap_head); kvm_flush_remote_tlbs_with_address( kvm, sp->gfn, KVM_PAGES_PER_HPAGE(sp->role.level)); } @@ -6406,7 +6407,7 @@ restart: if (sp->role.direct && sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn, pfn, PG_LEVEL_NUM)) { - pte_list_remove(kvm, rmap_head, sptep); + kvm_zap_one_rmap_spte(kvm, rmap_head, sptep); if (kvm_available_flush_tlb_with_range()) kvm_flush_remote_tlbs_with_address(kvm, sp->gfn, From 3c2e10373ec73cdd78411a28a14a9abb9da1bef6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 22:42:26 +0000 Subject: [PATCH 1350/1436] KVM: x86/mmu: Remove underscores from __pte_list_remove() Remove the underscores from __pte_list_remove(), the function formerly known as pte_list_remove() is now named kvm_zap_one_rmap_spte() to show that it zaps rmaps/PTEs, i.e. doesn't just remove an entry from a list. No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220715224226.3749507-8-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 282e7e2ab446..5957c3e66b77 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -921,7 +921,7 @@ pte_list_desc_remove_entry(struct kvm_rmap_head *rmap_head, mmu_free_pte_list_desc(desc); } -static void __pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head) +static void pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head) { struct pte_list_desc *desc; struct pte_list_desc *prev_desc; @@ -961,7 +961,7 @@ static void kvm_zap_one_rmap_spte(struct kvm *kvm, struct kvm_rmap_head *rmap_head, u64 *sptep) { mmu_spte_clear_track_bits(kvm, sptep); - __pte_list_remove(sptep, rmap_head); + pte_list_remove(sptep, rmap_head); } /* Return true if at least one SPTE was zapped, false otherwise */ @@ -1051,7 +1051,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte) slot = __gfn_to_memslot(slots, gfn); rmap_head = gfn_to_rmap(gfn, sp->role.level, slot); - __pte_list_remove(spte, rmap_head); + pte_list_remove(spte, rmap_head); } /* @@ -1693,7 +1693,7 @@ static void mmu_page_add_parent_pte(struct kvm_mmu_memory_cache *cache, static void mmu_page_remove_parent_pte(struct kvm_mmu_page *sp, u64 *parent_pte) { - __pte_list_remove(parent_pte, &sp->parent_ptes); + pte_list_remove(parent_pte, &sp->parent_ptes); } static void drop_parent_pte(struct kvm_mmu_page *sp, From 01e69cef63f88d809181f62f03a01d7295f2d5a4 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Mon, 18 Jul 2022 03:38:33 -0500 Subject: [PATCH 1351/1436] KVM: SVM: Fix x2APIC MSRs interception The index for svm_direct_access_msrs was incorrectly initialized with the APIC MMIO register macros. Fix by introducing a macro for calculating x2APIC MSRs. Fixes: 5c127c85472c ("KVM: SVM: Adding support for configuring x2APIC MSRs interception") Cc: Maxim Levitsky Signed-off-by: Suravee Suthikulpanit Message-Id: <20220718083833.222117-1-suravee.suthikulpanit@amd.com> Reviewed-by: Maxim Levitsky Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/svm.c | 52 ++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index ba81a7e58f75..aef63aae922d 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -74,6 +74,8 @@ static uint64_t osvw_len = 4, osvw_status; static DEFINE_PER_CPU(u64, current_tsc_ratio); +#define X2APIC_MSR(x) (APIC_BASE_MSR + (x >> 4)) + static const struct svm_direct_access_msrs { u32 index; /* Index of the MSR */ bool always; /* True if intercept is initially cleared */ @@ -100,31 +102,31 @@ static const struct svm_direct_access_msrs { { .index = MSR_IA32_CR_PAT, .always = false }, { .index = MSR_AMD64_SEV_ES_GHCB, .always = true }, { .index = MSR_TSC_AUX, .always = false }, - { .index = (APIC_BASE_MSR + APIC_ID), .always = false }, - { .index = (APIC_BASE_MSR + APIC_LVR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_TASKPRI), .always = false }, - { .index = (APIC_BASE_MSR + APIC_ARBPRI), .always = false }, - { .index = (APIC_BASE_MSR + APIC_PROCPRI), .always = false }, - { .index = (APIC_BASE_MSR + APIC_EOI), .always = false }, - { .index = (APIC_BASE_MSR + APIC_RRR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_LDR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_DFR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_SPIV), .always = false }, - { .index = (APIC_BASE_MSR + APIC_ISR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_TMR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_IRR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_ESR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_ICR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_ICR2), .always = false }, - { .index = (APIC_BASE_MSR + APIC_LVTT), .always = false }, - { .index = (APIC_BASE_MSR + APIC_LVTTHMR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_LVTPC), .always = false }, - { .index = (APIC_BASE_MSR + APIC_LVT0), .always = false }, - { .index = (APIC_BASE_MSR + APIC_LVT1), .always = false }, - { .index = (APIC_BASE_MSR + APIC_LVTERR), .always = false }, - { .index = (APIC_BASE_MSR + APIC_TMICT), .always = false }, - { .index = (APIC_BASE_MSR + APIC_TMCCT), .always = false }, - { .index = (APIC_BASE_MSR + APIC_TDCR), .always = false }, + { .index = X2APIC_MSR(APIC_ID), .always = false }, + { .index = X2APIC_MSR(APIC_LVR), .always = false }, + { .index = X2APIC_MSR(APIC_TASKPRI), .always = false }, + { .index = X2APIC_MSR(APIC_ARBPRI), .always = false }, + { .index = X2APIC_MSR(APIC_PROCPRI), .always = false }, + { .index = X2APIC_MSR(APIC_EOI), .always = false }, + { .index = X2APIC_MSR(APIC_RRR), .always = false }, + { .index = X2APIC_MSR(APIC_LDR), .always = false }, + { .index = X2APIC_MSR(APIC_DFR), .always = false }, + { .index = X2APIC_MSR(APIC_SPIV), .always = false }, + { .index = X2APIC_MSR(APIC_ISR), .always = false }, + { .index = X2APIC_MSR(APIC_TMR), .always = false }, + { .index = X2APIC_MSR(APIC_IRR), .always = false }, + { .index = X2APIC_MSR(APIC_ESR), .always = false }, + { .index = X2APIC_MSR(APIC_ICR), .always = false }, + { .index = X2APIC_MSR(APIC_ICR2), .always = false }, + { .index = X2APIC_MSR(APIC_LVTT), .always = false }, + { .index = X2APIC_MSR(APIC_LVTTHMR), .always = false }, + { .index = X2APIC_MSR(APIC_LVTPC), .always = false }, + { .index = X2APIC_MSR(APIC_LVT0), .always = false }, + { .index = X2APIC_MSR(APIC_LVT1), .always = false }, + { .index = X2APIC_MSR(APIC_LVTERR), .always = false }, + { .index = X2APIC_MSR(APIC_TMICT), .always = false }, + { .index = X2APIC_MSR(APIC_TMCCT), .always = false }, + { .index = X2APIC_MSR(APIC_TDCR), .always = false }, { .index = MSR_INVALID, .always = false }, }; From 94bda2f4cd868046094351b06b87d7d1053e990d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 23:00:13 +0000 Subject: [PATCH 1352/1436] KVM: x86: Reject loading KVM if host.PAT[0] != WB Reject KVM if entry '0' in the host's IA32_PAT MSR is not programmed to writeback (WB) memtype. KVM subtly relies on IA32_PAT entry '0' to be programmed to WB by leaving the PAT bits in shadow paging and NPT SPTEs as '0'. If something other than WB is in PAT[0], at _best_ guests will suffer very poor performance, and at worst KVM will crash the system by breaking cache-coherency expecations (e.g. using WC for guest memory). Signed-off-by: Sean Christopherson Reviewed-by: Maxim Levitsky Message-Id: <20220715230016.3762909-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f389691d8c04..12199c40f2bc 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9141,6 +9141,7 @@ static struct notifier_block pvclock_gtod_notifier = { int kvm_arch_init(void *opaque) { struct kvm_x86_init_ops *ops = opaque; + u64 host_pat; int r; if (kvm_x86_ops.hardware_enable) { @@ -9179,6 +9180,20 @@ int kvm_arch_init(void *opaque) goto out; } + /* + * KVM assumes that PAT entry '0' encodes WB memtype and simply zeroes + * the PAT bits in SPTEs. Bail if PAT[0] is programmed to something + * other than WB. Note, EPT doesn't utilize the PAT, but don't bother + * with an exception. PAT[0] is set to WB on RESET and also by the + * kernel, i.e. failure indicates a kernel bug or broken firmware. + */ + if (rdmsrl_safe(MSR_IA32_CR_PAT, &host_pat) || + (host_pat & GENMASK(2, 0)) != 6) { + pr_err("kvm: host PAT[0] is not WB\n"); + r = -EIO; + goto out; + } + r = -ENOMEM; x86_emulator_cache = kvm_alloc_emulator_cache(); From 82ffad2ddf5d7b5b9c14c705fed4a7d5f2ec4c38 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 23:00:14 +0000 Subject: [PATCH 1353/1436] KVM: x86: Drop unnecessary goto+label in kvm_arch_init() Return directly if kvm_arch_init() detects an error before doing any real work, jumping through a label obfuscates what's happening and carries the unnecessary risk of leaving 'r' uninitialized. No functional change intended. Signed-off-by: Sean Christopherson Reviewed-by: Maxim Levitsky Message-Id: <20220715230016.3762909-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 12199c40f2bc..41aa3137665c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9146,21 +9146,18 @@ int kvm_arch_init(void *opaque) if (kvm_x86_ops.hardware_enable) { pr_err("kvm: already loaded vendor module '%s'\n", kvm_x86_ops.name); - r = -EEXIST; - goto out; + return -EEXIST; } if (!ops->cpu_has_kvm_support()) { pr_err_ratelimited("kvm: no hardware support for '%s'\n", ops->runtime_ops->name); - r = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; } if (ops->disabled_by_bios()) { pr_err_ratelimited("kvm: support for '%s' disabled by bios\n", ops->runtime_ops->name); - r = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; } /* @@ -9170,14 +9167,12 @@ int kvm_arch_init(void *opaque) */ if (!boot_cpu_has(X86_FEATURE_FPU) || !boot_cpu_has(X86_FEATURE_FXSR)) { printk(KERN_ERR "kvm: inadequate fpu\n"); - r = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; } if (IS_ENABLED(CONFIG_PREEMPT_RT) && !boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) { pr_err("RT requires X86_FEATURE_CONSTANT_TSC\n"); - r = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; } /* @@ -9190,21 +9185,19 @@ int kvm_arch_init(void *opaque) if (rdmsrl_safe(MSR_IA32_CR_PAT, &host_pat) || (host_pat & GENMASK(2, 0)) != 6) { pr_err("kvm: host PAT[0] is not WB\n"); - r = -EIO; - goto out; + return -EIO; } - r = -ENOMEM; - x86_emulator_cache = kvm_alloc_emulator_cache(); if (!x86_emulator_cache) { pr_err("kvm: failed to allocate cache for x86 emulator\n"); - goto out; + return -ENOMEM; } user_return_msrs = alloc_percpu(struct kvm_user_return_msrs); if (!user_return_msrs) { printk(KERN_ERR "kvm: failed to allocate percpu kvm_user_return_msrs\n"); + r = -ENOMEM; goto out_free_x86_emulator_cache; } kvm_nr_uret_msrs = 0; @@ -9235,7 +9228,6 @@ out_free_percpu: free_percpu(user_return_msrs); out_free_x86_emulator_cache: kmem_cache_destroy(x86_emulator_cache); -out: return r; } From 38bf9d7bf277bb40c4dceedd2b5eb87d02c36d5b Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 23:00:15 +0000 Subject: [PATCH 1354/1436] KVM: x86/mmu: Add shadow mask for effective host MTRR memtype Add shadow_memtype_mask to capture that EPT needs a non-zero memtype mask instead of relying on TDP being enabled, as NPT doesn't need a non-zero mask. This is a glorified nop as kvm_x86_ops.get_mt_mask() returns zero for NPT anyways. No functional change intended. Signed-off-by: Sean Christopherson Reviewed-by: Maxim Levitsky Message-Id: <20220715230016.3762909-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/spte.c | 21 ++++++++++++++++++--- arch/x86/kvm/mmu/spte.h | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/mmu/spte.c b/arch/x86/kvm/mmu/spte.c index fb1f17504138..7314d27d57a4 100644 --- a/arch/x86/kvm/mmu/spte.c +++ b/arch/x86/kvm/mmu/spte.c @@ -33,6 +33,7 @@ u64 __read_mostly shadow_mmio_value; u64 __read_mostly shadow_mmio_mask; u64 __read_mostly shadow_mmio_access_mask; u64 __read_mostly shadow_present_mask; +u64 __read_mostly shadow_memtype_mask; u64 __read_mostly shadow_me_value; u64 __read_mostly shadow_me_mask; u64 __read_mostly shadow_acc_track_mask; @@ -161,10 +162,10 @@ bool make_spte(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp, if (level > PG_LEVEL_4K) spte |= PT_PAGE_SIZE_MASK; - if (tdp_enabled) - spte |= static_call(kvm_x86_get_mt_mask)(vcpu, gfn, - kvm_is_mmio_pfn(pfn)); + if (shadow_memtype_mask) + spte |= static_call(kvm_x86_get_mt_mask)(vcpu, gfn, + kvm_is_mmio_pfn(pfn)); if (host_writable) spte |= shadow_host_writable_mask; else @@ -391,6 +392,13 @@ void kvm_mmu_set_ept_masks(bool has_ad_bits, bool has_exec_only) shadow_nx_mask = 0ull; shadow_x_mask = VMX_EPT_EXECUTABLE_MASK; shadow_present_mask = has_exec_only ? 0ull : VMX_EPT_READABLE_MASK; + /* + * EPT overrides the host MTRRs, and so KVM must program the desired + * memtype directly into the SPTEs. Note, this mask is just the mask + * of all bits that factor into the memtype, the actual memtype must be + * dynamically calculated, e.g. to ensure host MMIO is mapped UC. + */ + shadow_memtype_mask = VMX_EPT_MT_MASK | VMX_EPT_IPAT_BIT; shadow_acc_track_mask = VMX_EPT_RWX_MASK; shadow_host_writable_mask = EPT_SPTE_HOST_WRITABLE; shadow_mmu_writable_mask = EPT_SPTE_MMU_WRITABLE; @@ -441,6 +449,13 @@ void kvm_mmu_reset_all_pte_masks(void) shadow_nx_mask = PT64_NX_MASK; shadow_x_mask = 0; shadow_present_mask = PT_PRESENT_MASK; + + /* + * For shadow paging and NPT, KVM uses PAT entry '0' to encode WB + * memtype in the SPTEs, i.e. relies on host MTRRs to provide the + * correct memtype (WB is the "weakest" memtype). + */ + shadow_memtype_mask = 0; shadow_acc_track_mask = 0; shadow_me_mask = 0; shadow_me_value = 0; diff --git a/arch/x86/kvm/mmu/spte.h b/arch/x86/kvm/mmu/spte.h index ba3dccb202bc..cabe3fbb4f39 100644 --- a/arch/x86/kvm/mmu/spte.h +++ b/arch/x86/kvm/mmu/spte.h @@ -147,6 +147,7 @@ extern u64 __read_mostly shadow_mmio_value; extern u64 __read_mostly shadow_mmio_mask; extern u64 __read_mostly shadow_mmio_access_mask; extern u64 __read_mostly shadow_present_mask; +extern u64 __read_mostly shadow_memtype_mask; extern u64 __read_mostly shadow_me_value; extern u64 __read_mostly shadow_me_mask; From d5e90a699875ce552d0058d05b9b4b458b46fa6a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 23:00:16 +0000 Subject: [PATCH 1355/1436] KVM: x86/mmu: Restrict mapping level based on guest MTRR iff they're used Restrict the mapping level for SPTEs based on the guest MTRRs if and only if KVM may actually use the guest MTRRs to compute the "real" memtype. For all forms of paging, guest MTRRs are purely virtual in the sense that they are completely ignored by hardware, i.e. they affect the memtype only if software manually consumes them. The only scenario where KVM consumes the guest MTRRs is when shadow_memtype_mask is non-zero and the guest has non-coherent DMA, in all other cases KVM simply leaves the PAT field in SPTEs as '0' to encode WB memtype. Note, KVM may still ultimately ignore guest MTRRs, e.g. if the backing pfn is host MMIO, but false positives are ok as they only cause a slight performance blip (unless the guest is doing weird things with its MTRRs, which is extremely unlikely). Signed-off-by: Sean Christopherson Reviewed-by: Maxim Levitsky Message-Id: <20220715230016.3762909-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 5957c3e66b77..7c0b10aac3ed 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4296,14 +4296,26 @@ EXPORT_SYMBOL_GPL(kvm_handle_page_fault); int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault) { - while (fault->max_level > PG_LEVEL_4K) { - int page_num = KVM_PAGES_PER_HPAGE(fault->max_level); - gfn_t base = (fault->addr >> PAGE_SHIFT) & ~(page_num - 1); + /* + * If the guest's MTRRs may be used to compute the "real" memtype, + * restrict the mapping level to ensure KVM uses a consistent memtype + * across the entire mapping. If the host MTRRs are ignored by TDP + * (shadow_memtype_mask is non-zero), and the VM has non-coherent DMA + * (DMA doesn't snoop CPU caches), KVM's ABI is to honor the memtype + * from the guest's MTRRs so that guest accesses to memory that is + * DMA'd aren't cached against the guest's wishes. + * + * Note, KVM may still ultimately ignore guest MTRRs for certain PFNs, + * e.g. KVM will force UC memtype for host MMIO. + */ + if (shadow_memtype_mask && kvm_arch_has_noncoherent_dma(vcpu->kvm)) { + for ( ; fault->max_level > PG_LEVEL_4K; --fault->max_level) { + int page_num = KVM_PAGES_PER_HPAGE(fault->max_level); + gfn_t base = (fault->addr >> PAGE_SHIFT) & ~(page_num - 1); - if (kvm_mtrr_check_gfn_range_consistency(vcpu, base, page_num)) - break; - - --fault->max_level; + if (kvm_mtrr_check_gfn_range_consistency(vcpu, base, page_num)) + break; + } } return direct_page_fault(vcpu, fault); From a8ac499bb6abbd55fe60f1dc2d053f4b5b13aa73 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 23:21:04 +0000 Subject: [PATCH 1356/1436] KVM: x86/mmu: Don't require refcounted "struct page" to create huge SPTEs Drop the requirement that a pfn be backed by a refcounted, compound or or ZONE_DEVICE, struct page, and instead rely solely on the host page tables to identify huge pages. The PageCompound() check is a remnant of an old implementation that identified (well, attempt to identify) huge pages without walking the host page tables. The ZONE_DEVICE check was added as an exception to the PageCompound() requirement. In other words, neither check is actually a hard requirement, if the primary has a pfn backed with a huge page, then KVM can back the pfn with a huge page regardless of the backing store. Dropping the @pfn parameter will also allow KVM to query the max host mapping level without having to first get the pfn, which is advantageous for use outside of the page fault path where KVM wants to take action if and only if a page can be mapped huge, i.e. avoids the pfn lookup for gfns that can't be backed with a huge page. Cc: Mingwei Zhang Signed-off-by: Sean Christopherson Reviewed-by: Mingwei Zhang Message-Id: <20220715232107.3775620-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 23 +++++------------------ arch/x86/kvm/mmu/mmu_internal.h | 2 +- arch/x86/kvm/mmu/tdp_mmu.c | 8 +------- 3 files changed, 7 insertions(+), 26 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 7c0b10aac3ed..091278a8bd56 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2920,11 +2920,10 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep) __direct_pte_prefetch(vcpu, sp, sptep); } -static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, +static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, const struct kvm_memory_slot *slot) { int level = PG_LEVEL_4K; - struct page *page; unsigned long hva; unsigned long flags; pgd_t pgd; @@ -2932,17 +2931,6 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, kvm_pfn_t pfn, pud_t pud; pmd_t pmd; - /* - * Note, @slot must be non-NULL, i.e. the caller is responsible for - * ensuring @pfn isn't garbage and is backed by a memslot. - */ - page = kvm_pfn_to_refcounted_page(pfn); - if (!page) - return PG_LEVEL_4K; - - if (!PageCompound(page) && !kvm_is_zone_device_page(page)) - return PG_LEVEL_4K; - /* * Note, using the already-retrieved memslot and __gfn_to_hva_memslot() * is not solely for performance, it's also necessary to avoid the @@ -2995,7 +2983,7 @@ out: int kvm_mmu_max_mapping_level(struct kvm *kvm, const struct kvm_memory_slot *slot, gfn_t gfn, - kvm_pfn_t pfn, int max_level) + int max_level) { struct kvm_lpage_info *linfo; int host_level; @@ -3010,7 +2998,7 @@ int kvm_mmu_max_mapping_level(struct kvm *kvm, if (max_level == PG_LEVEL_4K) return PG_LEVEL_4K; - host_level = host_pfn_mapping_level(kvm, gfn, pfn, slot); + host_level = host_pfn_mapping_level(kvm, gfn, slot); return min(host_level, max_level); } @@ -3035,8 +3023,7 @@ void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault * level, which will be used to do precise, accurate accounting. */ fault->req_level = kvm_mmu_max_mapping_level(vcpu->kvm, slot, - fault->gfn, fault->pfn, - fault->max_level); + fault->gfn, fault->max_level); if (fault->req_level == PG_LEVEL_4K || fault->huge_page_disallowed) return; @@ -6418,7 +6405,7 @@ restart: */ if (sp->role.direct && sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn, - pfn, PG_LEVEL_NUM)) { + PG_LEVEL_NUM)) { kvm_zap_one_rmap_spte(kvm, rmap_head, sptep); if (kvm_available_flush_tlb_with_range()) diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index ae2d660e2dab..582def531d4d 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -309,7 +309,7 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa, int kvm_mmu_max_mapping_level(struct kvm *kvm, const struct kvm_memory_slot *slot, gfn_t gfn, - kvm_pfn_t pfn, int max_level); + int max_level); void kvm_mmu_hugepage_adjust(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault); void disallowed_hugepage_adjust(struct kvm_page_fault *fault, u64 spte, int cur_level); diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index f3a430d64975..d75d93edc40a 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -1733,7 +1733,6 @@ static void zap_collapsible_spte_range(struct kvm *kvm, gfn_t end = start + slot->npages; struct tdp_iter iter; int max_mapping_level; - kvm_pfn_t pfn; rcu_read_lock(); @@ -1745,13 +1744,8 @@ static void zap_collapsible_spte_range(struct kvm *kvm, !is_last_spte(iter.old_spte, iter.level)) continue; - /* - * This is a leaf SPTE. Check if the PFN it maps can - * be mapped at a higher level. - */ - pfn = spte_to_pfn(iter.old_spte); max_mapping_level = kvm_mmu_max_mapping_level(kvm, slot, - iter.gfn, pfn, PG_LEVEL_NUM); + iter.gfn, PG_LEVEL_NUM); WARN_ON(max_mapping_level < iter.level); From 65e3b446bcceaac7448cb25a2a5bf4adbcf25fe6 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 23:21:05 +0000 Subject: [PATCH 1357/1436] KVM: x86/mmu: Document the "rules" for using host_pfn_mapping_level() Add a comment to document how host_pfn_mapping_level() can be used safely, as the line between safe and dangerous is quite thin. E.g. if KVM were to ever support in-place promotion to create huge pages, consuming the level is safe if the caller holds mmu_lock and checks that there's an existing _leaf_ SPTE, but unsafe if the caller only checks that there's a non-leaf SPTE. Opportunistically tweak the existing comments to explicitly document why KVM needs to use READ_ONCE(). No functional change intended. Signed-off-by: Sean Christopherson Message-Id: <20220715232107.3775620-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 091278a8bd56..8e477333a263 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -2920,6 +2920,31 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep) __direct_pte_prefetch(vcpu, sp, sptep); } +/* + * Lookup the mapping level for @gfn in the current mm. + * + * WARNING! Use of host_pfn_mapping_level() requires the caller and the end + * consumer to be tied into KVM's handlers for MMU notifier events! + * + * There are several ways to safely use this helper: + * + * - Check mmu_notifier_retry_hva() after grabbing the mapping level, before + * consuming it. In this case, mmu_lock doesn't need to be held during the + * lookup, but it does need to be held while checking the MMU notifier. + * + * - Hold mmu_lock AND ensure there is no in-progress MMU notifier invalidation + * event for the hva. This can be done by explicit checking the MMU notifier + * or by ensuring that KVM already has a valid mapping that covers the hva. + * + * - Do not use the result to install new mappings, e.g. use the host mapping + * level only to decide whether or not to zap an entry. In this case, it's + * not required to hold mmu_lock (though it's highly likely the caller will + * want to hold mmu_lock anyways, e.g. to modify SPTEs). + * + * Note! The lookup can still race with modifications to host page tables, but + * the above "rules" ensure KVM will not _consume_ the result of the walk if a + * race with the primary MMU occurs. + */ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, const struct kvm_memory_slot *slot) { @@ -2942,16 +2967,19 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn, hva = __gfn_to_hva_memslot(slot, gfn); /* - * Lookup the mapping level in the current mm. The information - * may become stale soon, but it is safe to use as long as - * 1) mmu_notifier_retry was checked after taking mmu_lock, and - * 2) mmu_lock is taken now. - * - * We still need to disable IRQs to prevent concurrent tear down - * of page tables. + * Disable IRQs to prevent concurrent tear down of host page tables, + * e.g. if the primary MMU promotes a P*D to a huge page and then frees + * the original page table. */ local_irq_save(flags); + /* + * Read each entry once. As above, a non-leaf entry can be promoted to + * a huge page _during_ this walk. Re-reading the entry could send the + * walk into the weeks, e.g. p*d_large() returns false (sees the old + * value) and then p*d_offset() walks into the target huge page instead + * of the old page table (sees the new value). + */ pgd = READ_ONCE(*pgd_offset(kvm->mm, hva)); if (pgd_none(pgd)) goto out; From 85f44f8cc07b5f61bef30fe5343d629fd4263230 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 23:21:06 +0000 Subject: [PATCH 1358/1436] KVM: x86/mmu: Don't bottom out on leafs when zapping collapsible SPTEs When zapping collapsible SPTEs in the TDP MMU, don't bottom out on a leaf SPTE now that KVM doesn't require a PFN to compute the host mapping level, i.e. now that there's no need to first find a leaf SPTE and then step back up. Drop the now unused tdp_iter_step_up(), as it is not the safest of helpers (using any of the low level iterators requires some understanding of the various side effects). Signed-off-by: Sean Christopherson Message-Id: <20220715232107.3775620-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/tdp_iter.c | 9 ------ arch/x86/kvm/mmu/tdp_iter.h | 1 - arch/x86/kvm/mmu/tdp_mmu.c | 57 ++++++++++++++++++------------------- 3 files changed, 27 insertions(+), 40 deletions(-) diff --git a/arch/x86/kvm/mmu/tdp_iter.c b/arch/x86/kvm/mmu/tdp_iter.c index 9c65a64a56d9..39b48e7d7d1a 100644 --- a/arch/x86/kvm/mmu/tdp_iter.c +++ b/arch/x86/kvm/mmu/tdp_iter.c @@ -145,15 +145,6 @@ static bool try_step_up(struct tdp_iter *iter) return true; } -/* - * Step the iterator back up a level in the paging structure. Should only be - * used when the iterator is below the root level. - */ -void tdp_iter_step_up(struct tdp_iter *iter) -{ - WARN_ON(!try_step_up(iter)); -} - /* * Step to the next SPTE in a pre-order traversal of the paging structure. * To get to the next SPTE, the iterator either steps down towards the goal diff --git a/arch/x86/kvm/mmu/tdp_iter.h b/arch/x86/kvm/mmu/tdp_iter.h index adfca0cf94d3..f0af385c56e0 100644 --- a/arch/x86/kvm/mmu/tdp_iter.h +++ b/arch/x86/kvm/mmu/tdp_iter.h @@ -114,6 +114,5 @@ void tdp_iter_start(struct tdp_iter *iter, struct kvm_mmu_page *root, int min_level, gfn_t next_last_level_gfn); void tdp_iter_next(struct tdp_iter *iter); void tdp_iter_restart(struct tdp_iter *iter); -void tdp_iter_step_up(struct tdp_iter *iter); #endif /* __KVM_X86_MMU_TDP_ITER_H */ diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index d75d93edc40a..40ccb5fba870 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -1721,10 +1721,6 @@ void kvm_tdp_mmu_clear_dirty_pt_masked(struct kvm *kvm, clear_dirty_pt_masked(kvm, root, gfn, mask, wrprot); } -/* - * Clear leaf entries which could be replaced by large mappings, for - * GFNs within the slot. - */ static void zap_collapsible_spte_range(struct kvm *kvm, struct kvm_mmu_page *root, const struct kvm_memory_slot *slot) @@ -1736,48 +1732,49 @@ static void zap_collapsible_spte_range(struct kvm *kvm, rcu_read_lock(); - tdp_root_for_each_pte(iter, root, start, end) { + for_each_tdp_pte_min_level(iter, root, PG_LEVEL_2M, start, end) { +retry: if (tdp_mmu_iter_cond_resched(kvm, &iter, false, true)) continue; - if (!is_shadow_present_pte(iter.old_spte) || - !is_last_spte(iter.old_spte, iter.level)) + if (iter.level > KVM_MAX_HUGEPAGE_LEVEL || + !is_shadow_present_pte(iter.old_spte)) + continue; + + /* + * Don't zap leaf SPTEs, if a leaf SPTE could be replaced with + * a large page size, then its parent would have been zapped + * instead of stepping down. + */ + if (is_last_spte(iter.old_spte, iter.level)) + continue; + + /* + * If iter.gfn resides outside of the slot, i.e. the page for + * the current level overlaps but is not contained by the slot, + * then the SPTE can't be made huge. More importantly, trying + * to query that info from slot->arch.lpage_info will cause an + * out-of-bounds access. + */ + if (iter.gfn < start || iter.gfn >= end) continue; max_mapping_level = kvm_mmu_max_mapping_level(kvm, slot, iter.gfn, PG_LEVEL_NUM); - - WARN_ON(max_mapping_level < iter.level); - - /* - * If this page is already mapped at the highest - * viable level, there's nothing more to do. - */ - if (max_mapping_level == iter.level) + if (max_mapping_level < iter.level) continue; - /* - * The page can be remapped at a higher level, so step - * up to zap the parent SPTE. - */ - while (max_mapping_level > iter.level) - tdp_iter_step_up(&iter); - /* Note, a successful atomic zap also does a remote TLB flush. */ - tdp_mmu_zap_spte_atomic(kvm, &iter); - - /* - * If the atomic zap fails, the iter will recurse back into - * the same subtree to retry. - */ + if (tdp_mmu_zap_spte_atomic(kvm, &iter)) + goto retry; } rcu_read_unlock(); } /* - * Clear non-leaf entries (and free associated page tables) which could - * be replaced by large mappings, for GFNs within the slot. + * Zap non-leaf SPTEs (and free their associated page tables) which could + * be replaced by huge pages, for GFNs within the slot. */ void kvm_tdp_mmu_zap_collapsible_sptes(struct kvm *kvm, const struct kvm_memory_slot *slot) From cfe12e64b0657142824819d939fcfe62f14104a1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 15 Jul 2022 23:21:07 +0000 Subject: [PATCH 1359/1436] KVM: selftests: Add an option to run vCPUs while disabling dirty logging Add a command line option to dirty_log_perf_test to run vCPUs for the entire duration of disabling dirty logging. By default, the test stops running runs vCPUs before disabling dirty logging, which is faster but less interesting as it doesn't stress KVM's handling of contention between page faults and the zapping of collapsible SPTEs. Enabling the flag also lets the user verify that KVM is indeed rebuilding zapped SPTEs as huge pages by checking KVM's pages_{1g,2m,4k} stats. Without vCPUs to fault in the zapped SPTEs, the stats will show that KVM is zapping pages, but they never show whether or not KVM actually allows huge pages to be recreated. Note! Enabling the flag can _significantly_ increase runtime, especially if the thread that's disabling dirty logging doesn't have a dedicated pCPU, e.g. if all pCPUs are used to run vCPUs. Signed-off-by: Sean Christopherson Message-Id: <20220715232107.3775620-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/dirty_log_perf_test.c | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/dirty_log_perf_test.c b/tools/testing/selftests/kvm/dirty_log_perf_test.c index 808a36dbf0c0..f99e39a672d3 100644 --- a/tools/testing/selftests/kvm/dirty_log_perf_test.c +++ b/tools/testing/selftests/kvm/dirty_log_perf_test.c @@ -59,6 +59,7 @@ static void arch_cleanup_vm(struct kvm_vm *vm) static int nr_vcpus = 1; static uint64_t guest_percpu_mem_size = DEFAULT_PER_VCPU_MEM_SIZE; +static bool run_vcpus_while_disabling_dirty_logging; /* Host variables */ static u64 dirty_log_manual_caps; @@ -109,8 +110,13 @@ static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) ts_diff.tv_nsec); } + /* + * Keep running the guest while dirty logging is being disabled + * (iteration is negative) so that vCPUs are accessing memory + * for the entire duration of zapping collapsible SPTEs. + */ while (current_iteration == READ_ONCE(iteration) && - !READ_ONCE(host_quit)) {} + READ_ONCE(iteration) >= 0 && !READ_ONCE(host_quit)) {} } avg = timespec_div(total, vcpu_last_completed_iteration[vcpu_idx]); @@ -302,6 +308,14 @@ static void run_test(enum vm_guest_mode mode, void *arg) } } + /* + * Run vCPUs while dirty logging is being disabled to stress disabling + * in terms of both performance and correctness. Opt-in via command + * line as this significantly increases time to disable dirty logging. + */ + if (run_vcpus_while_disabling_dirty_logging) + WRITE_ONCE(iteration, -1); + /* Disable dirty logging */ clock_gettime(CLOCK_MONOTONIC, &start); disable_dirty_logging(vm, p->slots); @@ -309,7 +323,11 @@ static void run_test(enum vm_guest_mode mode, void *arg) pr_info("Disabling dirty logging time: %ld.%.9lds\n", ts_diff.tv_sec, ts_diff.tv_nsec); - /* Tell the vcpu thread to quit */ + /* + * Tell the vCPU threads to quit. No need to manually check that vCPUs + * have stopped running after disabling dirty logging, the join will + * wait for them to exit. + */ host_quit = true; perf_test_join_vcpu_threads(nr_vcpus); @@ -349,6 +367,9 @@ static void help(char *name) " Warning: a low offset can conflict with the loaded test code.\n"); guest_modes_help(); printf(" -n: Run the vCPUs in nested mode (L2)\n"); + printf(" -e: Run vCPUs while dirty logging is being disabled. This\n" + " can significantly increase runtime, especially if there\n" + " isn't a dedicated pCPU for the main thread.\n"); printf(" -b: specify the size of the memory region which should be\n" " dirtied by each vCPU. e.g. 10M or 3G.\n" " (default: 1G)\n"); @@ -385,8 +406,11 @@ int main(int argc, char *argv[]) guest_modes_append_default(); - while ((opt = getopt(argc, argv, "ghi:p:m:nb:f:v:os:x:")) != -1) { + while ((opt = getopt(argc, argv, "eghi:p:m:nb:f:v:os:x:")) != -1) { switch (opt) { + case 'e': + /* 'e' is for evil. */ + run_vcpus_while_disabling_dirty_logging = true; case 'g': dirty_log_manual_caps = 0; break; From c33f6f2228fe8517e38941a508e9f905f99ecba9 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 7 Jun 2022 21:35:50 +0000 Subject: [PATCH 1360/1436] KVM: x86: Split kvm_is_valid_cr4() and export only the non-vendor bits Split the common x86 parts of kvm_is_valid_cr4(), i.e. the reserved bits checks, into a separate helper, __kvm_is_valid_cr4(), and export only the inner helper to vendor code in order to prevent nested VMX from calling back into vmx_is_valid_cr4() via kvm_is_valid_cr4(). On SVM, this is a nop as SVM doesn't place any additional restrictions on CR4. On VMX, this is also currently a nop, but only because nested VMX is missing checks on reserved CR4 bits for nested VM-Enter. That bug will be fixed in a future patch, and could simply use kvm_is_valid_cr4() as-is, but nVMX has _another_ bug where VMXON emulation doesn't enforce VMX's restrictions on CR0/CR4. The cleanest and most intuitive way to fix the VMXON bug is to use nested_host_cr{0,4}_valid(). If the CR4 variant routes through kvm_is_valid_cr4(), using nested_host_cr4_valid() won't do the right thing for the VMXON case as vmx_is_valid_cr4() enforces VMX's restrictions if and only if the vCPU is post-VMXON. Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Message-Id: <20220607213604.3346000-2-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/nested.c | 3 ++- arch/x86/kvm/vmx/vmx.c | 4 ++-- arch/x86/kvm/x86.c | 12 +++++++++--- arch/x86/kvm/x86.h | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 23252ab82194..76dcc8a3e849 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -325,7 +325,8 @@ static bool __nested_vmcb_check_save(struct kvm_vcpu *vcpu, return false; } - if (CC(!kvm_is_valid_cr4(vcpu, save->cr4))) + /* Note, SVM doesn't have any additional restrictions on CR4. */ + if (CC(!__kvm_is_valid_cr4(vcpu, save->cr4))) return false; if (CC(!kvm_valid_efer(vcpu, save->efer))) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index b0cc911a8f6f..75ee509f0b7b 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -3238,8 +3238,8 @@ static bool vmx_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { /* * We operate under the default treatment of SMM, so VMX cannot be - * enabled under SMM. Note, whether or not VMXE is allowed at all is - * handled by kvm_is_valid_cr4(). + * enabled under SMM. Note, whether or not VMXE is allowed at all, + * i.e. is a reserved bit, is handled by common x86 code. */ if ((cr4 & X86_CR4_VMXE) && is_smm(vcpu)) return false; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 41aa3137665c..5366f884e9a7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1081,7 +1081,7 @@ int kvm_emulate_xsetbv(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_emulate_xsetbv); -bool kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) +bool __kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) { if (cr4 & cr4_reserved_bits) return false; @@ -1089,9 +1089,15 @@ bool kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) if (cr4 & vcpu->arch.cr4_guest_rsvd_bits) return false; - return static_call(kvm_x86_is_valid_cr4)(vcpu, cr4); + return true; +} +EXPORT_SYMBOL_GPL(__kvm_is_valid_cr4); + +static bool kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) +{ + return __kvm_is_valid_cr4(vcpu, cr4) && + static_call(kvm_x86_is_valid_cr4)(vcpu, cr4); } -EXPORT_SYMBOL_GPL(kvm_is_valid_cr4); void kvm_post_set_cr4(struct kvm_vcpu *vcpu, unsigned long old_cr4, unsigned long cr4) { diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 501b884b8cc4..1926d2cb8e79 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -434,7 +434,7 @@ static inline void kvm_machine_check(void) void kvm_load_guest_xsave_state(struct kvm_vcpu *vcpu); void kvm_load_host_xsave_state(struct kvm_vcpu *vcpu); int kvm_spec_ctrl_test_value(u64 value); -bool kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4); +bool __kvm_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4); int kvm_handle_memory_failure(struct kvm_vcpu *vcpu, int r, struct x86_exception *e); int kvm_handle_invpcid(struct kvm_vcpu *vcpu, unsigned long type, gva_t gva); From ca58f3aa53d165afe4ab74c755bc2f6d168617ac Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 7 Jun 2022 21:35:51 +0000 Subject: [PATCH 1361/1436] KVM: nVMX: Account for KVM reserved CR4 bits in consistency checks Check that the guest (L2) and host (L1) CR4 values that would be loaded by nested VM-Enter and VM-Exit respectively are valid with respect to KVM's (L0 host) allowed CR4 bits. Failure to check KVM reserved bits would allow L1 to load an illegal CR4 (or trigger hardware VM-Fail or failed VM-Entry) by massaging guest CPUID to allow features that are not supported by KVM. Amusingly, KVM itself is an accomplice in its doom, as KVM adjusts L1's MSR_IA32_VMX_CR4_FIXED1 to allow L1 to enable bits for L2 based on L1's CPUID model. Note, although nested_{guest,host}_cr4_valid() are _currently_ used if and only if the vCPU is post-VMXON (nested.vmxon == true), that may not be true in the future, e.g. emulating VMXON has a bug where it doesn't check the allowed/required CR0/CR4 bits. Cc: stable@vger.kernel.org Fixes: 3899152ccbf4 ("KVM: nVMX: fix checks on CR{0,4} during virtual VMX operation") Signed-off-by: Sean Christopherson Message-Id: <20220607213604.3346000-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index c92cea0b8ccc..129ae4e01f7c 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -281,7 +281,8 @@ static inline bool nested_cr4_valid(struct kvm_vcpu *vcpu, unsigned long val) u64 fixed0 = to_vmx(vcpu)->nested.msrs.cr4_fixed0; u64 fixed1 = to_vmx(vcpu)->nested.msrs.cr4_fixed1; - return fixed_bits_valid(val, fixed0, fixed1); + return fixed_bits_valid(val, fixed0, fixed1) && + __kvm_is_valid_cr4(vcpu, val); } /* No difference in the restrictions on guest and host CR4 in VMX operation. */ From c7d855c2aff2d511fd60ee2e356134c4fb394799 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 7 Jun 2022 21:35:52 +0000 Subject: [PATCH 1362/1436] KVM: nVMX: Inject #UD if VMXON is attempted with incompatible CR0/CR4 Inject a #UD if L1 attempts VMXON with a CR0 or CR4 that is disallowed per the associated nested VMX MSRs' fixed0/1 settings. KVM cannot rely on hardware to perform the checks, even for the few checks that have higher priority than VM-Exit, as (a) KVM may have forced CR0/CR4 bits in hardware while running the guest, (b) there may incompatible CR0/CR4 bits that have lower priority than VM-Exit, e.g. CR0.NE, and (c) userspace may have further restricted the allowed CR0/CR4 values by manipulating the guest's nested VMX MSRs. Note, despite a very strong desire to throw shade at Jim, commit 70f3aac964ae ("kvm: nVMX: Remove superfluous VMX instruction fault checks") is not to blame for the buggy behavior (though the comment...). That commit only removed the CR0.PE, EFLAGS.VM, and COMPATIBILITY mode checks (though it did erroneously drop the CPL check, but that has already been remedied). KVM may force CR0.PE=1, but will do so only when also forcing EFLAGS.VM=1 to emulate Real Mode, i.e. hardware will still #UD. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216033 Fixes: ec378aeef9df ("KVM: nVMX: Implement VMXON and VMXOFF") Reported-by: Eric Li Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Message-Id: <20220607213604.3346000-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index bfa366938c49..9c3350545b09 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4952,20 +4952,25 @@ static int handle_vmon(struct kvm_vcpu *vcpu) | FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX; /* - * The Intel VMX Instruction Reference lists a bunch of bits that are - * prerequisite to running VMXON, most notably cr4.VMXE must be set to - * 1 (see vmx_is_valid_cr4() for when we allow the guest to set this). - * Otherwise, we should fail with #UD. But most faulting conditions - * have already been checked by hardware, prior to the VM-exit for - * VMXON. We do test guest cr4.VMXE because processor CR4 always has - * that bit set to 1 in non-root mode. + * Note, KVM cannot rely on hardware to perform the CR0/CR4 #UD checks + * that have higher priority than VM-Exit (see Intel SDM's pseudocode + * for VMXON), as KVM must load valid CR0/CR4 values into hardware while + * running the guest, i.e. KVM needs to check the _guest_ values. + * + * Rely on hardware for the other two pre-VM-Exit checks, !VM86 and + * !COMPATIBILITY modes. KVM may run the guest in VM86 to emulate Real + * Mode, but KVM will never take the guest out of those modes. */ - if (!kvm_read_cr4_bits(vcpu, X86_CR4_VMXE)) { + if (!nested_host_cr0_valid(vcpu, kvm_read_cr0(vcpu)) || + !nested_host_cr4_valid(vcpu, kvm_read_cr4(vcpu))) { kvm_queue_exception(vcpu, UD_VECTOR); return 1; } - /* CPL=0 must be checked manually. */ + /* + * CPL=0 and all other checks that are lower priority than VM-Exit must + * be checked manually. + */ if (vmx_get_cpl(vcpu)) { kvm_inject_gp(vcpu, 0); return 1; From a645c2b506fbca06f671b22f0991bd99064d7e69 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 7 Jun 2022 21:35:53 +0000 Subject: [PATCH 1363/1436] KVM: nVMX: Rename handle_vm{on,off}() to handle_vmx{on,off}() Rename the exit handlers for VMXON and VMXOFF to match the instruction names, the terms "vmon" and "vmoff" are not used anywhere in Intel's documentation, nor are they used elsehwere in KVM. Sadly, the exit reasons are exposed to userspace and so cannot be renamed without breaking userspace. :-( Fixes: ec378aeef9df ("KVM: nVMX: Implement VMXON and VMXOFF") Signed-off-by: Sean Christopherson Message-Id: <20220607213604.3346000-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 9c3350545b09..1e760994d207 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4942,7 +4942,7 @@ out_vmcs02: } /* Emulate the VMXON instruction. */ -static int handle_vmon(struct kvm_vcpu *vcpu) +static int handle_vmxon(struct kvm_vcpu *vcpu) { int ret; gpa_t vmptr; @@ -5039,7 +5039,7 @@ static inline void nested_release_vmcs12(struct kvm_vcpu *vcpu) } /* Emulate the VMXOFF instruction */ -static int handle_vmoff(struct kvm_vcpu *vcpu) +static int handle_vmxoff(struct kvm_vcpu *vcpu) { if (!nested_vmx_check_permission(vcpu)) return 1; @@ -6816,8 +6816,8 @@ __init int nested_vmx_hardware_setup(int (*exit_handlers[])(struct kvm_vcpu *)) exit_handlers[EXIT_REASON_VMREAD] = handle_vmread; exit_handlers[EXIT_REASON_VMRESUME] = handle_vmresume; exit_handlers[EXIT_REASON_VMWRITE] = handle_vmwrite; - exit_handlers[EXIT_REASON_VMOFF] = handle_vmoff; - exit_handlers[EXIT_REASON_VMON] = handle_vmon; + exit_handlers[EXIT_REASON_VMOFF] = handle_vmxoff; + exit_handlers[EXIT_REASON_VMON] = handle_vmxon; exit_handlers[EXIT_REASON_INVEPT] = handle_invept; exit_handlers[EXIT_REASON_INVVPID] = handle_invvpid; exit_handlers[EXIT_REASON_VMFUNC] = handle_vmfunc; From f8ae08f9789ad59d318ea75b570caa454aceda81 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 7 Jun 2022 21:35:54 +0000 Subject: [PATCH 1364/1436] KVM: nVMX: Let userspace set nVMX MSR to any _host_ supported value Restrict the nVMX MSRs based on KVM's config, not based on the guest's current config. Using the guest's config to audit the new config prevents userspace from restoring the original config (KVM's config) if at any point in the past the guest's config was restricted in any way. Fixes: 62cc6b9dc61e ("KVM: nVMX: support restore of VMX capability MSRs") Cc: stable@vger.kernel.org Cc: David Matlack Signed-off-by: Sean Christopherson Message-Id: <20220607213604.3346000-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 70 +++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 1e760994d207..c1c85fd75d42 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -1224,7 +1224,7 @@ static int vmx_restore_vmx_basic(struct vcpu_vmx *vmx, u64 data) BIT_ULL(49) | BIT_ULL(54) | BIT_ULL(55) | /* reserved */ BIT_ULL(31) | GENMASK_ULL(47, 45) | GENMASK_ULL(63, 56); - u64 vmx_basic = vmx->nested.msrs.basic; + u64 vmx_basic = vmcs_config.nested.basic; if (!is_bitwise_subset(vmx_basic, data, feature_and_reserved)) return -EINVAL; @@ -1247,36 +1247,42 @@ static int vmx_restore_vmx_basic(struct vcpu_vmx *vmx, u64 data) return 0; } -static int -vmx_restore_control_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data) +static void vmx_get_control_msr(struct nested_vmx_msrs *msrs, u32 msr_index, + u32 **low, u32 **high) { - u64 supported; - u32 *lowp, *highp; - switch (msr_index) { case MSR_IA32_VMX_TRUE_PINBASED_CTLS: - lowp = &vmx->nested.msrs.pinbased_ctls_low; - highp = &vmx->nested.msrs.pinbased_ctls_high; + *low = &msrs->pinbased_ctls_low; + *high = &msrs->pinbased_ctls_high; break; case MSR_IA32_VMX_TRUE_PROCBASED_CTLS: - lowp = &vmx->nested.msrs.procbased_ctls_low; - highp = &vmx->nested.msrs.procbased_ctls_high; + *low = &msrs->procbased_ctls_low; + *high = &msrs->procbased_ctls_high; break; case MSR_IA32_VMX_TRUE_EXIT_CTLS: - lowp = &vmx->nested.msrs.exit_ctls_low; - highp = &vmx->nested.msrs.exit_ctls_high; + *low = &msrs->exit_ctls_low; + *high = &msrs->exit_ctls_high; break; case MSR_IA32_VMX_TRUE_ENTRY_CTLS: - lowp = &vmx->nested.msrs.entry_ctls_low; - highp = &vmx->nested.msrs.entry_ctls_high; + *low = &msrs->entry_ctls_low; + *high = &msrs->entry_ctls_high; break; case MSR_IA32_VMX_PROCBASED_CTLS2: - lowp = &vmx->nested.msrs.secondary_ctls_low; - highp = &vmx->nested.msrs.secondary_ctls_high; + *low = &msrs->secondary_ctls_low; + *high = &msrs->secondary_ctls_high; break; default: BUG(); } +} + +static int +vmx_restore_control_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data) +{ + u32 *lowp, *highp; + u64 supported; + + vmx_get_control_msr(&vmcs_config.nested, msr_index, &lowp, &highp); supported = vmx_control_msr(*lowp, *highp); @@ -1288,6 +1294,7 @@ vmx_restore_control_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data) if (!is_bitwise_subset(supported, data, GENMASK_ULL(63, 32))) return -EINVAL; + vmx_get_control_msr(&vmx->nested.msrs, msr_index, &lowp, &highp); *lowp = data; *highp = data >> 32; return 0; @@ -1301,10 +1308,8 @@ static int vmx_restore_vmx_misc(struct vcpu_vmx *vmx, u64 data) BIT_ULL(28) | BIT_ULL(29) | BIT_ULL(30) | /* reserved */ GENMASK_ULL(13, 9) | BIT_ULL(31); - u64 vmx_misc; - - vmx_misc = vmx_control_msr(vmx->nested.msrs.misc_low, - vmx->nested.msrs.misc_high); + u64 vmx_misc = vmx_control_msr(vmcs_config.nested.misc_low, + vmcs_config.nested.misc_high); if (!is_bitwise_subset(vmx_misc, data, feature_and_reserved_bits)) return -EINVAL; @@ -1332,10 +1337,8 @@ static int vmx_restore_vmx_misc(struct vcpu_vmx *vmx, u64 data) static int vmx_restore_vmx_ept_vpid_cap(struct vcpu_vmx *vmx, u64 data) { - u64 vmx_ept_vpid_cap; - - vmx_ept_vpid_cap = vmx_control_msr(vmx->nested.msrs.ept_caps, - vmx->nested.msrs.vpid_caps); + u64 vmx_ept_vpid_cap = vmx_control_msr(vmcs_config.nested.ept_caps, + vmcs_config.nested.vpid_caps); /* Every bit is either reserved or a feature bit. */ if (!is_bitwise_subset(vmx_ept_vpid_cap, data, -1ULL)) @@ -1346,20 +1349,21 @@ static int vmx_restore_vmx_ept_vpid_cap(struct vcpu_vmx *vmx, u64 data) return 0; } -static int vmx_restore_fixed0_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data) +static u64 *vmx_get_fixed0_msr(struct nested_vmx_msrs *msrs, u32 msr_index) { - u64 *msr; - switch (msr_index) { case MSR_IA32_VMX_CR0_FIXED0: - msr = &vmx->nested.msrs.cr0_fixed0; - break; + return &msrs->cr0_fixed0; case MSR_IA32_VMX_CR4_FIXED0: - msr = &vmx->nested.msrs.cr4_fixed0; - break; + return &msrs->cr4_fixed0; default: BUG(); } +} + +static int vmx_restore_fixed0_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data) +{ + const u64 *msr = vmx_get_fixed0_msr(&vmcs_config.nested, msr_index); /* * 1 bits (which indicates bits which "must-be-1" during VMX operation) @@ -1368,7 +1372,7 @@ static int vmx_restore_fixed0_msr(struct vcpu_vmx *vmx, u32 msr_index, u64 data) if (!is_bitwise_subset(data, *msr, -1ULL)) return -EINVAL; - *msr = data; + *vmx_get_fixed0_msr(&vmx->nested.msrs, msr_index) = data; return 0; } @@ -1429,7 +1433,7 @@ int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data) vmx->nested.msrs.vmcs_enum = data; return 0; case MSR_IA32_VMX_VMFUNC: - if (data & ~vmx->nested.msrs.vmfunc_controls) + if (data & ~vmcs_config.nested.vmfunc_controls) return -EINVAL; vmx->nested.msrs.vmfunc_controls = data; return 0; From 8805875aa4732340af49aa601f59a60e482f635f Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Jul 2022 05:07:39 -0400 Subject: [PATCH 1365/1436] Revert "KVM: nVMX: Do not expose MPX VMX controls when guest MPX disabled" Since commit 5f76f6f5ff96 ("KVM: nVMX: Do not expose MPX VMX controls when guest MPX disabled"), KVM has taken ownership of the "load IA32_BNDCFGS" and "clear IA32_BNDCFGS" VMX entry/exit controls, trying to set these bits in the IA32_VMX_TRUE_{ENTRY,EXIT}_CTLS MSRs if the guest's CPUID supports MPX, and clear otherwise. The intent of the patch was to apply it to L0 in order to work around L1 kernels that lack the fix in commit 691bd4340bef ("kvm: vmx: allow host to access guest MSR_IA32_BNDCFGS", 2017-07-04): by hiding the control bits from L0, L1 hides BNDCFGS from KVM_GET_MSR_INDEX_LIST, and the L1 bug is neutralized even in the lack of commit 691bd4340bef. This was perhaps a sensible kludge at the time, but a horrible idea in the long term and in fact it has not been extended to other CPUID bits like these: X86_FEATURE_LM => VM_EXIT_HOST_ADDR_SPACE_SIZE, VM_ENTRY_IA32E_MODE, VMX_MISC_SAVE_EFER_LMA X86_FEATURE_TSC => CPU_BASED_RDTSC_EXITING, CPU_BASED_USE_TSC_OFFSETTING, SECONDARY_EXEC_TSC_SCALING X86_FEATURE_INVPCID_SINGLE => SECONDARY_EXEC_ENABLE_INVPCID X86_FEATURE_MWAIT => CPU_BASED_MONITOR_EXITING, CPU_BASED_MWAIT_EXITING X86_FEATURE_INTEL_PT => SECONDARY_EXEC_PT_CONCEAL_VMX, SECONDARY_EXEC_PT_USE_GPA, VM_EXIT_CLEAR_IA32_RTIT_CTL, VM_ENTRY_LOAD_IA32_RTIT_CTL X86_FEATURE_XSAVES => SECONDARY_EXEC_XSAVES These days it's sort of common knowledge that any MSR in KVM_GET_MSR_INDEX_LIST must allow *at least* setting it with KVM_SET_MSR to a default value, so it is unlikely that something like commit 5f76f6f5ff96 will be needed again. So revert it, at the potential cost of breaking L1s with a 6 year old kernel. While in principle the L0 owner doesn't control what runs on L1, such an old hypervisor would probably have many other bugs. Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/vmx.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 75ee509f0b7b..4fd25e1d6ec9 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -7457,23 +7457,6 @@ static void nested_vmx_cr_fixed1_bits_update(struct kvm_vcpu *vcpu) #undef cr4_fixed1_update } -static void nested_vmx_entry_exit_ctls_update(struct kvm_vcpu *vcpu) -{ - struct vcpu_vmx *vmx = to_vmx(vcpu); - - if (kvm_mpx_supported()) { - bool mpx_enabled = guest_cpuid_has(vcpu, X86_FEATURE_MPX); - - if (mpx_enabled) { - vmx->nested.msrs.entry_ctls_high |= VM_ENTRY_LOAD_BNDCFGS; - vmx->nested.msrs.exit_ctls_high |= VM_EXIT_CLEAR_BNDCFGS; - } else { - vmx->nested.msrs.entry_ctls_high &= ~VM_ENTRY_LOAD_BNDCFGS; - vmx->nested.msrs.exit_ctls_high &= ~VM_EXIT_CLEAR_BNDCFGS; - } - } -} - static void update_intel_pt_cfg(struct kvm_vcpu *vcpu) { struct vcpu_vmx *vmx = to_vmx(vcpu); @@ -7565,10 +7548,8 @@ static void vmx_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) ~(FEAT_CTL_VMX_ENABLED_INSIDE_SMX | FEAT_CTL_VMX_ENABLED_OUTSIDE_SMX); - if (nested_vmx_allowed(vcpu)) { + if (nested_vmx_allowed(vcpu)) nested_vmx_cr_fixed1_bits_update(vcpu); - nested_vmx_entry_exit_ctls_update(vcpu); - } if (boot_cpu_has(X86_FEATURE_INTEL_PT) && guest_cpuid_has(vcpu, X86_FEATURE_INTEL_PT)) From 93255bf92939d948bc86d81c6bb70bb0fecc5db1 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 22 Jul 2022 22:44:06 +0000 Subject: [PATCH 1366/1436] KVM: VMX: Mark all PERF_GLOBAL_(OVF)_CTRL bits reserved if there's no vPMU Mark all MSR_CORE_PERF_GLOBAL_CTRL and MSR_CORE_PERF_GLOBAL_OVF_CTRL bits as reserved if there is no guest vPMU. The nVMX VM-Entry consistency checks do not check for a valid vPMU prior to consuming the masks via kvm_valid_perf_global_ctrl(), i.e. may incorrectly allow a non-zero mask to be loaded via VM-Enter or VM-Exit (well, attempted to be loaded, the actual MSR load will be rejected by intel_is_valid_msr()). Fixes: f5132b01386b ("KVM: Expose a version 2 architectural PMU to a guests") Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Message-Id: <20220722224409.1336532-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/pmu_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 4bc098fbec31..6e355c5d2f40 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -527,6 +527,8 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) pmu->version = 0; pmu->reserved_bits = 0xffffffff00200000ull; pmu->raw_event_mask = X86_RAW_EVENT_MASK; + pmu->global_ctrl_mask = ~0ull; + pmu->global_ovf_ctrl_mask = ~0ull; pmu->fixed_ctr_ctrl_mask = ~0ull; pmu->pebs_enable_mask = ~0ull; pmu->pebs_data_cfg_mask = ~0ull; From b663f0b5f3d665c261256d1f76e98f077c6e56af Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 22 Jul 2022 22:44:07 +0000 Subject: [PATCH 1367/1436] KVM: VMX: Add helper to check if the guest PMU has PERF_GLOBAL_CTRL Add a helper to check of the guest PMU has PERF_GLOBAL_CTRL, which is unintuitive _and_ diverges from Intel's architecturally defined behavior. Even worse, KVM currently implements the check using two different (but equivalent) checks, _and_ there has been at least one attempt to add a _third_ flavor. Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Message-Id: <20220722224409.1336532-4-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/pmu_intel.c | 4 ++-- arch/x86/kvm/vmx/vmx.h | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 6e355c5d2f40..78f2800fd850 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -111,7 +111,7 @@ static bool intel_pmc_is_enabled(struct kvm_pmc *pmc) { struct kvm_pmu *pmu = pmc_to_pmu(pmc); - if (pmu->version < 2) + if (!intel_pmu_has_perf_global_ctrl(pmu)) return true; return test_bit(pmc->idx, (unsigned long *)&pmu->global_ctrl); @@ -207,7 +207,7 @@ static bool intel_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr) case MSR_CORE_PERF_GLOBAL_STATUS: case MSR_CORE_PERF_GLOBAL_CTRL: case MSR_CORE_PERF_GLOBAL_OVF_CTRL: - ret = pmu->version > 1; + return intel_pmu_has_perf_global_ctrl(pmu); break; case MSR_IA32_PEBS_ENABLE: ret = vcpu_get_perf_capabilities(vcpu) & PERF_CAP_PEBS_FORMAT; diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index 286c88e285ea..2a0b94e0fda7 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -91,6 +91,18 @@ union vmx_exit_reason { u32 full; }; +static inline bool intel_pmu_has_perf_global_ctrl(struct kvm_pmu *pmu) +{ + /* + * Architecturally, Intel's SDM states that IA32_PERF_GLOBAL_CTRL is + * supported if "CPUID.0AH: EAX[7:0] > 0", i.e. if the PMU version is + * greater than zero. However, KVM only exposes and emulates the MSR + * to/for the guest if the guest PMU supports at least "Architectural + * Performance Monitoring Version 2". + */ + return pmu->version > 1; +} + #define vcpu_to_lbr_desc(vcpu) (&to_vmx(vcpu)->lbr_desc) #define vcpu_to_lbr_records(vcpu) (&to_vmx(vcpu)->lbr_desc.records) From 4496a6f9b45e8cd83343ad86a3984d614e22cf54 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Fri, 22 Jul 2022 22:44:08 +0000 Subject: [PATCH 1368/1436] KVM: nVMX: Attempt to load PERF_GLOBAL_CTRL on nVMX xfer iff it exists Attempt to load PERF_GLOBAL_CTRL during nested VM-Enter/VM-Exit if and only if the MSR exists (according to the guest vCPU model). KVM has very misguided handling of VM_{ENTRY,EXIT}_LOAD_IA32_PERF_GLOBAL_CTRL and attempts to force the nVMX MSR settings to match the vPMU model, i.e. to hide/expose the control based on whether or not the MSR exists from the guest's perspective. KVM's modifications fail to handle the scenario where the vPMU is hidden from the guest _after_ being exposed to the guest, e.g. by userspace doing multiple KVM_SET_CPUID2 calls, which is allowed if done before any KVM_RUN. nested_vmx_pmu_refresh() is called if and only if there's a recognized vPMU, i.e. KVM will leave the bits in the allow state and then ultimately reject the MSR load and WARN. KVM should not force the VMX MSRs in the first place. KVM taking control of the MSRs was a misguided attempt at mimicking what commit 5f76f6f5ff96 ("KVM: nVMX: Do not expose MPX VMX controls when guest MPX disabled", 2018-10-01) did for MPX. However, the MPX commit was a workaround for another KVM bug and not something that should be imitated (and it should never been done in the first place). In other words, KVM's ABI _should_ be that userspace has full control over the MSRs, at which point triggering the WARN that loading the MSR must not fail is trivial. The intent of the WARN is still valid; KVM has consistency checks to ensure that vmcs12->{guest,host}_ia32_perf_global_ctrl is valid. The problem is that '0' must be considered a valid value at all times, and so the simple/obvious solution is to just not actually load the MSR when it does not exist. It is userspace's responsibility to provide a sane vCPU model, i.e. KVM is well within its ABI and Intel's VMX architecture to skip the loads if the MSR does not exist. Fixes: 03a8871add95 ("KVM: nVMX: Expose load IA32_PERF_GLOBAL_CTRL VM-{Entry,Exit} control") Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Message-Id: <20220722224409.1336532-5-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index c1c85fd75d42..819cfd926954 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -2623,6 +2623,7 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, } if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL) && + intel_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu)) && WARN_ON_ONCE(kvm_set_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL, vmcs12->guest_ia32_perf_global_ctrl))) { *entry_failure_code = ENTRY_FAIL_DEFAULT; @@ -4333,7 +4334,8 @@ static void load_vmcs12_host_state(struct kvm_vcpu *vcpu, vmcs_write64(GUEST_IA32_PAT, vmcs12->host_ia32_pat); vcpu->arch.pat = vmcs12->host_ia32_pat; } - if (vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) + if ((vmcs12->vm_exit_controls & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL) && + intel_pmu_has_perf_global_ctrl(vcpu_to_pmu(vcpu))) WARN_ON_ONCE(kvm_set_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL, vmcs12->host_ia32_perf_global_ctrl)); From 9389d5774aca444b6343d3b5f9b05f0820fe705e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 22 Jul 2022 22:44:09 +0000 Subject: [PATCH 1369/1436] Revert "KVM: nVMX: Expose load IA32_PERF_GLOBAL_CTRL VM-{Entry,Exit} control" This reverts commit 03a8871add95213827e2bea84c12133ae5df952e. Since commit 03a8871add95 ("KVM: nVMX: Expose load IA32_PERF_GLOBAL_CTRL VM-{Entry,Exit} control"), KVM has taken ownership of the "load IA32_PERF_GLOBAL_CTRL" VMX entry/exit control bits, trying to set these bits in the IA32_VMX_TRUE_{ENTRY,EXIT}_CTLS MSRs if the guest's CPUID supports the architectural PMU (CPUID[EAX=0Ah].EAX[7:0]=1), and clear otherwise. This was a misguided attempt at mimicking what commit 5f76f6f5ff96 ("KVM: nVMX: Do not expose MPX VMX controls when guest MPX disabled", 2018-10-01) did for MPX. However, that commit was a workaround for another KVM bug and not something that should be imitated. Mucking with the VMX MSRs creates a subtle, difficult to maintain ABI as KVM must ensure that any internal changes, e.g. to how KVM handles _any_ guest CPUID changes, yield the same functional result. Therefore, KVM's policy is to let userspace have full control of the guest vCPU model so long as the host kernel is not at risk. Now that KVM really truly ensures kvm_set_msr() will succeed by loading PERF_GLOBAL_CTRL if and only if it exists, revert KVM's misguided and roundabout behavior. Signed-off-by: Paolo Bonzini [sean: make it a pure revert] Signed-off-by: Sean Christopherson Message-Id: <20220722224409.1336532-6-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 22 ---------------------- arch/x86/kvm/vmx/nested.h | 2 -- arch/x86/kvm/vmx/pmu_intel.c | 3 --- 3 files changed, 27 deletions(-) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 819cfd926954..ebeeddb6aeb1 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4824,28 +4824,6 @@ int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification, return 0; } -void nested_vmx_pmu_refresh(struct kvm_vcpu *vcpu, - bool vcpu_has_perf_global_ctrl) -{ - struct vcpu_vmx *vmx; - - if (!nested_vmx_allowed(vcpu)) - return; - - vmx = to_vmx(vcpu); - if (vcpu_has_perf_global_ctrl) { - vmx->nested.msrs.entry_ctls_high |= - VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; - vmx->nested.msrs.exit_ctls_high |= - VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL; - } else { - vmx->nested.msrs.entry_ctls_high &= - ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; - vmx->nested.msrs.exit_ctls_high &= - ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL; - } -} - static int nested_vmx_get_vmptr(struct kvm_vcpu *vcpu, gpa_t *vmpointer, int *ret) { diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index 129ae4e01f7c..88b00a7359e4 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -32,8 +32,6 @@ int vmx_set_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); int vmx_get_vmx_msr(struct nested_vmx_msrs *msrs, u32 msr_index, u64 *pdata); int get_vmx_mem_address(struct kvm_vcpu *vcpu, unsigned long exit_qualification, u32 vmx_instruction_info, bool wr, int len, gva_t *ret); -void nested_vmx_pmu_refresh(struct kvm_vcpu *vcpu, - bool vcpu_has_perf_global_ctrl); void nested_mark_vmcs12_pages_dirty(struct kvm_vcpu *vcpu); bool nested_vmx_check_io_bitmaps(struct kvm_vcpu *vcpu, unsigned int port, int size); diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 78f2800fd850..862c1a4d971b 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -592,9 +592,6 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu) bitmap_set(pmu->all_valid_pmc_idx, INTEL_PMC_MAX_GENERIC, pmu->nr_arch_fixed_counters); - nested_vmx_pmu_refresh(vcpu, - intel_is_valid_msr(vcpu, MSR_CORE_PERF_GLOBAL_CTRL)); - if (cpuid_model_is_consistent(vcpu)) x86_perf_get_lbr(&lbr_desc->records); else From a910b5ab6b250a88fff1866bf708642d83317466 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 7 Jun 2022 21:36:00 +0000 Subject: [PATCH 1370/1436] KVM: nVMX: Set UMIP bit CR4_FIXED1 MSR when emulating UMIP Make UMIP an "allowed-1" bit CR4_FIXED1 MSR when KVM is emulating UMIP. KVM emulates UMIP for both L1 and L2, and so should enumerate that L2 is allowed to have CR4.UMIP=1. Not setting the bit doesn't immediately break nVMX, as KVM does set/clear the bit in CR4_FIXED1 in response to a guest CPUID update, i.e. KVM will correctly (dis)allow nested VM-Entry based on whether or not UMIP is exposed to L1. That said, KVM should enumerate the bit as being allowed from time zero, e.g. userspace will see the wrong value if the MSR is read before CPUID is written. Fixes: 0367f205a3b7 ("KVM: vmx: add support for emulating UMIP") Signed-off-by: Sean Christopherson Message-Id: <20220607213604.3346000-12-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/vmx/nested.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index ebeeddb6aeb1..ed247a121325 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -6757,6 +6757,9 @@ void nested_vmx_setup_ctls_msrs(struct nested_vmx_msrs *msrs, u32 ept_caps) rdmsrl(MSR_IA32_VMX_CR0_FIXED1, msrs->cr0_fixed1); rdmsrl(MSR_IA32_VMX_CR4_FIXED1, msrs->cr4_fixed1); + if (vmx_umip_emulated()) + msrs->cr4_fixed1 |= X86_CR4_UMIP; + msrs->vmcs_enum = nested_vmx_calc_vmcs_enum_msr(); } From ce30d8b976b46b697cfcbc0aa5dab03edb0301dc Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 7 Jun 2022 21:36:04 +0000 Subject: [PATCH 1371/1436] KVM: selftests: Verify VMX MSRs can be restored to KVM-supported values Verify that KVM allows toggling VMX MSR bits to be "more" restrictive, and also allows restoring each MSR to KVM's original, less restrictive value. Signed-off-by: Sean Christopherson Message-Id: <20220607213604.3346000-16-seanjc@google.com> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/include/x86_64/processor.h | 1 + .../selftests/kvm/x86_64/vmx_msrs_test.c | 84 +++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/vmx_msrs_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 91429330faea..d625a3f83780 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -50,6 +50,7 @@ /x86_64/vmx_dirty_log_test /x86_64/vmx_exception_with_invalid_guest_state /x86_64/vmx_invalid_nested_guest_state +/x86_64/vmx_msrs_test /x86_64/vmx_preemption_timer_test /x86_64/vmx_set_nested_state_test /x86_64/vmx_tsc_adjust_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 6b22fb1ce2b9..690b499c3471 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -107,6 +107,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_apic_access_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_dirty_log_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_exception_with_invalid_guest_state +TEST_GEN_PROGS_x86_64 += x86_64/vmx_msrs_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_invalid_nested_guest_state TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h index 4060fe954d53..45edf45821d0 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -100,6 +100,7 @@ struct kvm_x86_cpu_feature { #define X86_FEATURE_SMEP KVM_X86_CPU_FEATURE(0x7, 0, EBX, 7) #define X86_FEATURE_INVPCID KVM_X86_CPU_FEATURE(0x7, 0, EBX, 10) #define X86_FEATURE_RTM KVM_X86_CPU_FEATURE(0x7, 0, EBX, 11) +#define X86_FEATURE_MPX KVM_X86_CPU_FEATURE(0x7, 0, EBX, 14) #define X86_FEATURE_SMAP KVM_X86_CPU_FEATURE(0x7, 0, EBX, 20) #define X86_FEATURE_PCOMMIT KVM_X86_CPU_FEATURE(0x7, 0, EBX, 22) #define X86_FEATURE_CLFLUSHOPT KVM_X86_CPU_FEATURE(0x7, 0, EBX, 23) diff --git a/tools/testing/selftests/kvm/x86_64/vmx_msrs_test.c b/tools/testing/selftests/kvm/x86_64/vmx_msrs_test.c new file mode 100644 index 000000000000..322d561b4260 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/vmx_msrs_test.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * VMX control MSR test + * + * Copyright (C) 2022 Google LLC. + * + * Tests for KVM ownership of bits in the VMX entry/exit control MSRs. Checks + * that KVM will set owned bits where appropriate, and will not if + * KVM_X86_QUIRK_TWEAK_VMX_CTRL_MSRS is disabled. + */ +#include +#include "kvm_util.h" +#include "vmx.h" + +static void vmx_fixed1_msr_test(struct kvm_vcpu *vcpu, uint32_t msr_index, + uint64_t mask) +{ + uint64_t val = vcpu_get_msr(vcpu, msr_index); + uint64_t bit; + + mask &= val; + + for_each_set_bit(bit, &mask, 64) { + vcpu_set_msr(vcpu, msr_index, val & ~BIT_ULL(bit)); + vcpu_set_msr(vcpu, msr_index, val); + } +} + +static void vmx_fixed0_msr_test(struct kvm_vcpu *vcpu, uint32_t msr_index, + uint64_t mask) +{ + uint64_t val = vcpu_get_msr(vcpu, msr_index); + uint64_t bit; + + mask = ~mask | val; + + for_each_clear_bit(bit, &mask, 64) { + vcpu_set_msr(vcpu, msr_index, val | BIT_ULL(bit)); + vcpu_set_msr(vcpu, msr_index, val); + } +} + +static void vmx_fixed0and1_msr_test(struct kvm_vcpu *vcpu, uint32_t msr_index) +{ + vmx_fixed0_msr_test(vcpu, msr_index, GENMASK_ULL(31, 0)); + vmx_fixed1_msr_test(vcpu, msr_index, GENMASK_ULL(63, 32)); +} + +static void vmx_save_restore_msrs_test(struct kvm_vcpu *vcpu) +{ + vcpu_set_msr(vcpu, MSR_IA32_VMX_VMCS_ENUM, 0); + vcpu_set_msr(vcpu, MSR_IA32_VMX_VMCS_ENUM, -1ull); + + vmx_fixed1_msr_test(vcpu, MSR_IA32_VMX_BASIC, + BIT_ULL(49) | BIT_ULL(54) | BIT_ULL(55)); + + vmx_fixed1_msr_test(vcpu, MSR_IA32_VMX_MISC, + BIT_ULL(5) | GENMASK_ULL(8, 6) | BIT_ULL(14) | + BIT_ULL(15) | BIT_ULL(28) | BIT_ULL(29) | BIT_ULL(30)); + + vmx_fixed0and1_msr_test(vcpu, MSR_IA32_VMX_PROCBASED_CTLS2); + vmx_fixed1_msr_test(vcpu, MSR_IA32_VMX_EPT_VPID_CAP, -1ull); + vmx_fixed0and1_msr_test(vcpu, MSR_IA32_VMX_TRUE_PINBASED_CTLS); + vmx_fixed0and1_msr_test(vcpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS); + vmx_fixed0and1_msr_test(vcpu, MSR_IA32_VMX_TRUE_EXIT_CTLS); + vmx_fixed0and1_msr_test(vcpu, MSR_IA32_VMX_TRUE_ENTRY_CTLS); + vmx_fixed1_msr_test(vcpu, MSR_IA32_VMX_VMFUNC, -1ull); +} + +int main(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + + /* No need to actually do KVM_RUN, thus no guest code. */ + vm = vm_create_with_one_vcpu(&vcpu, NULL); + + vmx_save_restore_msrs_test(vcpu); + + kvm_vm_free(vm); +} From d9f74d98bbec978edbf860f729b531281ba0d8ff Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 18 Jul 2022 16:17:17 +0300 Subject: [PATCH 1372/1436] tools/power/x86/intel-speed-select: Fix off by one check Change > MAX_DIE_PER_PACKAGE to >= MAX_DIE_PER_PACKAGE to prevent accessing one element beyond the end of the array. Fixes: 7fd786dfbd2c ("tools/power/x86/intel-speed-select: OOB daemon mode") Signed-off-by: Dan Carpenter Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- tools/power/x86/intel-speed-select/isst-daemon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/intel-speed-select/isst-daemon.c b/tools/power/x86/intel-speed-select/isst-daemon.c index dd372924bc82..d0400c6684ba 100644 --- a/tools/power/x86/intel-speed-select/isst-daemon.c +++ b/tools/power/x86/intel-speed-select/isst-daemon.c @@ -41,7 +41,7 @@ void process_level_change(int cpu) time_t tm; int ret; - if (pkg_id >= MAX_PACKAGE_COUNT || die_id > MAX_DIE_PER_PACKAGE) { + if (pkg_id >= MAX_PACKAGE_COUNT || die_id >= MAX_DIE_PER_PACKAGE) { debug_printf("Invalid package/die info for cpu:%d\n", cpu); return; } From c55ae10230a719020d8ad5a221cbe347d5225157 Mon Sep 17 00:00:00 2001 From: Xin Gao Date: Mon, 18 Jul 2022 20:49:07 +0800 Subject: [PATCH 1373/1436] tools/power/x86/intel-speed-select: Remove unneeded semicolon Remove an unneeded semicolon. Signed-off-by: Xin Gao Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- tools/power/x86/intel-speed-select/hfi-events.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/intel-speed-select/hfi-events.c b/tools/power/x86/intel-speed-select/hfi-events.c index 761375062505..f0ed69721308 100644 --- a/tools/power/x86/intel-speed-select/hfi-events.c +++ b/tools/power/x86/intel-speed-select/hfi-events.c @@ -144,7 +144,7 @@ static int family_handler(struct nl_msg *msg, void *arg) continue; res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]); break; - }; + } return 0; } From 7842efa5e194122ba2d2795102c70db00906024e Mon Sep 17 00:00:00 2001 From: Andrey Strachuk Date: Tue, 19 Jul 2022 14:03:41 +0300 Subject: [PATCH 1374/1436] platform/x86: sony-laptop: Remove useless comparisons in sony_pic_read_possible_resource() Local variable 'p' is initialized by an address of field of acpi_resource structure, so it does not make sense to compare 'p' with NULL. Local variable 'io' is initialized by an address of field of acpi_resource structure, so it does not make sense to compare 'io' with NULL. Found by Linux Verification Center (linuxtesting.org) with SVACE. Signed-off-by: Andrey Strachuk Link: https://lore.kernel.org/r/20220719110341.7239-1-strochuk@ispras.ru Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/sony-laptop.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index d8d0c0bed5e9..07ef05f727a2 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -4341,7 +4341,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) { struct acpi_resource_irq *p = &resource->data.irq; struct sony_pic_irq *interrupt = NULL; - if (!p || !p->interrupt_count) { + if (!p->interrupt_count) { /* * IRQ descriptors may have no IRQ# bits set, * particularly those those w/ _STA disabled @@ -4374,11 +4374,6 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) struct acpi_resource_io *io = &resource->data.io; struct sony_pic_ioport *ioport = list_first_entry(&dev->ioports, struct sony_pic_ioport, list); - if (!io) { - dprintk("Blank IO resource\n"); - return AE_OK; - } - if (!ioport->io1.minimum) { memcpy(&ioport->io1, io, sizeof(*io)); dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum, From 0a8735a6acf36ac35499563dc44f3e3d5034a2ce Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Sun, 24 Jul 2022 22:34:28 -0500 Subject: [PATCH 1375/1436] KVM: SVM: Do not virtualize MSR accesses for APIC LVTT register AMD does not support APIC TSC-deadline timer mode. AVIC hardware will generate GP fault when guest kernel writes 1 to bits [18] of the APIC LVTT register (offset 0x32) to set the timer mode. (Note: bit 18 is reserved on AMD system). Therefore, always intercept and let KVM emulate the MSR accesses. Fixes: f3d7c8aa6882 ("KVM: SVM: Fix x2APIC MSRs interception") Signed-off-by: Suravee Suthikulpanit Message-Id: <20220725033428.3699-1-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/svm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index aef63aae922d..3e0639a68385 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -118,7 +118,14 @@ static const struct svm_direct_access_msrs { { .index = X2APIC_MSR(APIC_ESR), .always = false }, { .index = X2APIC_MSR(APIC_ICR), .always = false }, { .index = X2APIC_MSR(APIC_ICR2), .always = false }, - { .index = X2APIC_MSR(APIC_LVTT), .always = false }, + + /* + * Note: + * AMD does not virtualize APIC TSC-deadline timer mode, but it is + * emulated by KVM. When setting APIC LVTT (0x832) register bit 18, + * the AVIC hardware would generate GP fault. Therefore, always + * intercept the MSR 0x832, and do not setup direct_access_msr. + */ { .index = X2APIC_MSR(APIC_LVTTHMR), .always = false }, { .index = X2APIC_MSR(APIC_LVTPC), .always = false }, { .index = X2APIC_MSR(APIC_LVT0), .always = false }, From 1bd9dfec9fd419920572b057e2c98d9877190b06 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Mon, 25 Jul 2022 00:33:56 -0500 Subject: [PATCH 1376/1436] KVM: x86: Do not block APIC write for non ICR registers The commit 5413bcba7ed5 ("KVM: x86: Add support for vICR APIC-write VM-Exits in x2APIC mode") introduces logic to prevent APIC write for offset other than ICR in kvm_apic_write_nodecode() function. This breaks x2AVIC support, which requires KVM to trap and emulate x2APIC MSR writes. Therefore, removes the warning and modify to logic to allow MSR write. Fixes: 5413bcba7ed5 ("KVM: x86: Add support for vICR APIC-write VM-Exits in x2APIC mode") Cc: Zeng Guang Suggested-by: Sean Christopherson Signed-off-by: Suravee Suthikulpanit Message-Id: <20220725053356.4275-1-suravee.suthikulpanit@amd.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/lapic.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 9d4f73c4dc02..e2ce3556915e 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -69,6 +69,7 @@ static bool lapic_timer_advance_dynamic __read_mostly; /* step-by-step approximation to mitigate fluctuation */ #define LAPIC_TIMER_ADVANCE_ADJUST_STEP 8 static int kvm_lapic_msr_read(struct kvm_lapic *apic, u32 reg, u64 *data); +static int kvm_lapic_msr_write(struct kvm_lapic *apic, u32 reg, u64 data); static inline void __kvm_lapic_set_reg(char *regs, int reg_off, u32 val) { @@ -2283,21 +2284,20 @@ void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset) struct kvm_lapic *apic = vcpu->arch.apic; u64 val; - if (apic_x2apic_mode(apic)) { - /* - * When guest APIC is in x2APIC mode and IPI virtualization - * is enabled, accessing APIC_ICR may cause trap-like VM-exit - * on Intel hardware. Other offsets are not possible. - */ - if (WARN_ON_ONCE(offset != APIC_ICR)) - return; - + if (apic_x2apic_mode(apic)) kvm_lapic_msr_read(apic, offset, &val); + else + val = kvm_lapic_get_reg(apic, offset); + + /* + * ICR is a single 64-bit register when x2APIC is enabled. For legacy + * xAPIC, ICR writes need to go down the common (slightly slower) path + * to get the upper half from ICR2. + */ + if (apic_x2apic_mode(apic) && offset == APIC_ICR) { kvm_apic_send_ipi(apic, (u32)val, (u32)(val >> 32)); trace_kvm_apic_write(APIC_ICR, val); } else { - val = kvm_lapic_get_reg(apic, offset); - /* TODO: optimize to just emulate side effect w/o one more write */ kvm_lapic_reg_write(apic, offset, (u32)val); } From 6c6ab524cfae0799e55c82b2c1d61f1af0156f8d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Sat, 23 Jul 2022 01:30:29 +0000 Subject: [PATCH 1377/1436] KVM: x86/mmu: Treat NX as a valid SPTE bit for NPT Treat the NX bit as valid when using NPT, as KVM will set the NX bit when the NX huge page mitigation is enabled (mindblowing) and trigger the WARN that fires on reserved SPTE bits being set. KVM has required NX support for SVM since commit b26a71a1a5b9 ("KVM: SVM: Refuse to load kvm_amd if NX support is not available") for exactly this reason, but apparently it never occurred to anyone to actually test NPT with the mitigation enabled. ------------[ cut here ]------------ spte = 0x800000018a600ee7, level = 2, rsvd bits = 0x800f0000001fe000 WARNING: CPU: 152 PID: 15966 at arch/x86/kvm/mmu/spte.c:215 make_spte+0x327/0x340 [kvm] Hardware name: Google, Inc. Arcadia_IT_80/Arcadia_IT_80, BIOS 10.48.0 01/27/2022 RIP: 0010:make_spte+0x327/0x340 [kvm] Call Trace: tdp_mmu_map_handle_target_level+0xc3/0x230 [kvm] kvm_tdp_mmu_map+0x343/0x3b0 [kvm] direct_page_fault+0x1ae/0x2a0 [kvm] kvm_tdp_page_fault+0x7d/0x90 [kvm] kvm_mmu_page_fault+0xfb/0x2e0 [kvm] npf_interception+0x55/0x90 [kvm_amd] svm_invoke_exit_handler+0x31/0xf0 [kvm_amd] svm_handle_exit+0xf6/0x1d0 [kvm_amd] vcpu_enter_guest+0xb6d/0xee0 [kvm] ? kvm_pmu_trigger_event+0x6d/0x230 [kvm] vcpu_run+0x65/0x2c0 [kvm] kvm_arch_vcpu_ioctl_run+0x355/0x610 [kvm] kvm_vcpu_ioctl+0x551/0x610 [kvm] __se_sys_ioctl+0x77/0xc0 __x64_sys_ioctl+0x1d/0x20 do_syscall_64+0x44/0xa0 entry_SYSCALL_64_after_hwframe+0x46/0xb0 ---[ end trace 0000000000000000 ]--- Cc: stable@vger.kernel.org Signed-off-by: Sean Christopherson Message-Id: <20220723013029.1753623-1-seanjc@google.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 8e477333a263..3e1317325e1f 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -4735,7 +4735,7 @@ reset_tdp_shadow_zero_bits_mask(struct kvm_mmu *context) if (boot_cpu_is_amd()) __reset_rsvds_bits_mask(shadow_zero_check, reserved_hpa_bits(), - context->root_role.level, false, + context->root_role.level, true, boot_cpu_has(X86_FEATURE_GBPAGES), false, true); else From 6fac42f127b8e8464b8c13036dfed825981881d9 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Thu, 28 Jul 2022 08:09:19 +0300 Subject: [PATCH 1378/1436] KVM: SVM: Dump Virtual Machine Save Area (VMSA) to klog As Virtual Machine Save Area (VMSA) is essential in troubleshooting attestation, dump it to the klog with the KERN_DEBUG level of priority. Cc: Jarkko Sakkinen Suggested-by: Harald Hoyer Signed-off-by: Jarkko Sakkinen Message-Id: <20220728050919.24113-1-jarkko@profian.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/svm/sev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 309bcdb2f929..1b70e6d68113 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -603,6 +603,9 @@ static int sev_es_sync_vmsa(struct vcpu_svm *svm) save->xss = svm->vcpu.arch.ia32_xss; save->dr6 = svm->vcpu.arch.dr6; + pr_debug("Virtual Machine Save Area (VMSA):\n"); + print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, save, sizeof(*save), false); + return 0; } From 7edc3a68038ab151a8791ddb6217755a5e4a5809 Mon Sep 17 00:00:00 2001 From: Kai Huang Date: Thu, 28 Jul 2022 15:04:52 +1200 Subject: [PATCH 1379/1436] KVM, x86/mmu: Fix the comment around kvm_tdp_mmu_zap_leafs() Now kvm_tdp_mmu_zap_leafs() only zaps leaf SPTEs but not any non-root pages within that GFN range anymore, so the comment around it isn't right. Fix it by shifting the comment from tdp_mmu_zap_leafs() instead of duplicating it, as tdp_mmu_zap_leafs() is static and is only called by kvm_tdp_mmu_zap_leafs(). Opportunistically tweak the blurb about SPTEs being cleared to (a) say "zapped" instead of "cleared" because "cleared" will be wrong if/when KVM allows a non-zero value for non-present SPTE (i.e. for Intel TDX), and (b) to clarify that a flush is needed if and only if a SPTE has been zapped since MMU lock was last acquired. Fixes: f47e5bbbc92f ("KVM: x86/mmu: Zap only TDP MMU leafs in zap range and mmu_notifier unmap") Suggested-by: Sean Christopherson Reviewed-by: Sean Christopherson Signed-off-by: Kai Huang Message-Id: <20220728030452.484261-1-kai.huang@intel.com> Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/tdp_mmu.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c index 40ccb5fba870..bf2ccf9debca 100644 --- a/arch/x86/kvm/mmu/tdp_mmu.c +++ b/arch/x86/kvm/mmu/tdp_mmu.c @@ -924,9 +924,6 @@ bool kvm_tdp_mmu_zap_sp(struct kvm *kvm, struct kvm_mmu_page *sp) } /* - * Zap leafs SPTEs for the range of gfns, [start, end). Returns true if SPTEs - * have been cleared and a TLB flush is needed before releasing the MMU lock. - * * If can_yield is true, will release the MMU lock and reschedule if the * scheduler needs the CPU or there is contention on the MMU lock. If this * function cannot yield, it will not release the MMU lock or reschedule and @@ -969,10 +966,9 @@ static bool tdp_mmu_zap_leafs(struct kvm *kvm, struct kvm_mmu_page *root, } /* - * Tears down the mappings for the range of gfns, [start, end), and frees the - * non-root pages mapping GFNs strictly within that range. Returns true if - * SPTEs have been cleared and a TLB flush is needed before releasing the - * MMU lock. + * Zap leaf SPTEs for the range of gfns, [start, end), for all roots. Returns + * true if a TLB flush is needed before releasing the MMU lock, i.e. if one or + * more SPTEs were zapped since the MMU lock was last acquired. */ bool kvm_tdp_mmu_zap_leafs(struct kvm *kvm, int as_id, gfn_t start, gfn_t end, bool can_yield, bool flush) From c9d959fc32a5f9312282817052d8986614f2dc08 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 28 Jul 2022 20:06:35 +0200 Subject: [PATCH 1380/1436] platform/x86: pmc_atom: Match all Lex BayTrail boards with critclk_systems DMI table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The critclk_systems[] DMI match table already contains 2 Lex BayTrail boards and patches were just submitted to add 3 more entries for the following models: 3I380NX, 3I380A, 3I380CW. Looking at: https://www.lex.com.tw/products/embedded-ipc-board/ we can see that Lex BayTrail makes many embedded boards with multiple ethernet boards and none of their products are battery powered so we don't need to worry (too much) about power consumption when suspended. Add a new DMI match which simply matches all Lex BayTrail boards and drop the 2 existing board specific quirks. Fixes: 648e921888ad ("clk: x86: Stop marking clocks as CLK_IS_CRITICAL") Reported-by: Michael Schöne Reported-by: Paul Spooren Reported-by: Matwey V. Kornilov Signed-off-by: Hans de Goede --- drivers/platform/x86/pmc_atom.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/pmc_atom.c b/drivers/platform/x86/pmc_atom.c index b8b1ed1406de..154317e9910d 100644 --- a/drivers/platform/x86/pmc_atom.c +++ b/drivers/platform/x86/pmc_atom.c @@ -389,21 +389,16 @@ static const struct dmi_system_id critclk_systems[] = { }, }, { - /* pmc_plt_clk0 - 3 are used for the 4 ethernet controllers */ - .ident = "Lex 3I380D", + /* + * Lex System / Lex Computech Co. makes a lot of Bay Trail + * based embedded boards which often come with multiple + * ethernet controllers using multiple pmc_plt_clks. See: + * https://www.lex.com.tw/products/embedded-ipc-board/ + */ + .ident = "Lex BayTrail", .callback = dmi_callback, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"), - DMI_MATCH(DMI_PRODUCT_NAME, "3I380D"), - }, - }, - { - /* pmc_plt_clk* - are used for ethernet controllers */ - .ident = "Lex 2I385SW", - .callback = dmi_callback, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"), - DMI_MATCH(DMI_PRODUCT_NAME, "2I385SW"), }, }, { From b4b830a34d8046633231b7fe87f6f2cb6240dc9f Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Tue, 19 Jul 2022 18:35:40 +0300 Subject: [PATCH 1381/1436] platform/mellanox: mlxreg-lc: Fix error flow and extend verbosity Fix error flow: - Clean-up client object in case of probing failure. - Prevent running remove routine in case of probing failure. Probing and removing are invoked by hotplug events raised upon line card insertion and removing. If probing procedure failed all data is cleared and there is nothing to do in remove routine. Fixes: 62f9529b8d5c ("platform/mellanox: mlxreg-lc: Add initial support for Nvidia line card devices") Signed-off-by: Vadim Pasternak Link: https://lore.kernel.org/r/20220719153540.61304-1-vadimp@nvidia.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/mellanox/mlxreg-lc.c | 82 ++++++++++++++++++++------- 1 file changed, 63 insertions(+), 19 deletions(-) diff --git a/drivers/platform/mellanox/mlxreg-lc.c b/drivers/platform/mellanox/mlxreg-lc.c index c897a2f15840..55834ccb4ac7 100644 --- a/drivers/platform/mellanox/mlxreg-lc.c +++ b/drivers/platform/mellanox/mlxreg-lc.c @@ -716,8 +716,12 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, switch (regval) { case MLXREG_LC_SN4800_C16: err = mlxreg_lc_sn4800_c16_config_init(mlxreg_lc, regmap, data); - if (err) + if (err) { + dev_err(dev, "Failed to config client %s at bus %d at addr 0x%02x\n", + data->hpdev.brdinfo->type, data->hpdev.nr, + data->hpdev.brdinfo->addr); return err; + } break; default: return -ENODEV; @@ -730,8 +734,11 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, mlxreg_lc->mux = platform_device_register_resndata(dev, "i2c-mux-mlxcpld", data->hpdev.nr, NULL, 0, mlxreg_lc->mux_data, sizeof(*mlxreg_lc->mux_data)); - if (IS_ERR(mlxreg_lc->mux)) + if (IS_ERR(mlxreg_lc->mux)) { + dev_err(dev, "Failed to create mux infra for client %s at bus %d at addr 0x%02x\n", + data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); return PTR_ERR(mlxreg_lc->mux); + } /* Register IO access driver. */ if (mlxreg_lc->io_data) { @@ -740,6 +747,9 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, platform_device_register_resndata(dev, "mlxreg-io", data->hpdev.nr, NULL, 0, mlxreg_lc->io_data, sizeof(*mlxreg_lc->io_data)); if (IS_ERR(mlxreg_lc->io_regs)) { + dev_err(dev, "Failed to create regio for client %s at bus %d at addr 0x%02x\n", + data->hpdev.brdinfo->type, data->hpdev.nr, + data->hpdev.brdinfo->addr); err = PTR_ERR(mlxreg_lc->io_regs); goto fail_register_io; } @@ -753,6 +763,9 @@ mlxreg_lc_config_init(struct mlxreg_lc *mlxreg_lc, void *regmap, mlxreg_lc->led_data, sizeof(*mlxreg_lc->led_data)); if (IS_ERR(mlxreg_lc->led)) { + dev_err(dev, "Failed to create LED objects for client %s at bus %d at addr 0x%02x\n", + data->hpdev.brdinfo->type, data->hpdev.nr, + data->hpdev.brdinfo->addr); err = PTR_ERR(mlxreg_lc->led); goto fail_register_led; } @@ -809,7 +822,8 @@ static int mlxreg_lc_probe(struct platform_device *pdev) if (!data->hpdev.adapter) { dev_err(&pdev->dev, "Failed to get adapter for bus %d\n", data->hpdev.nr); - return -EFAULT; + err = -EFAULT; + goto i2c_get_adapter_fail; } /* Create device at the top of line card I2C tree.*/ @@ -818,32 +832,40 @@ static int mlxreg_lc_probe(struct platform_device *pdev) if (IS_ERR(data->hpdev.client)) { dev_err(&pdev->dev, "Failed to create client %s at bus %d at addr 0x%02x\n", data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); - - i2c_put_adapter(data->hpdev.adapter); - data->hpdev.adapter = NULL; - return PTR_ERR(data->hpdev.client); + err = PTR_ERR(data->hpdev.client); + goto i2c_new_device_fail; } regmap = devm_regmap_init_i2c(data->hpdev.client, &mlxreg_lc_regmap_conf); if (IS_ERR(regmap)) { + dev_err(&pdev->dev, "Failed to create regmap for client %s at bus %d at addr 0x%02x\n", + data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); err = PTR_ERR(regmap); - goto mlxreg_lc_probe_fail; + goto devm_regmap_init_i2c_fail; } /* Set default registers. */ for (i = 0; i < mlxreg_lc_regmap_conf.num_reg_defaults; i++) { err = regmap_write(regmap, mlxreg_lc_regmap_default[i].reg, mlxreg_lc_regmap_default[i].def); - if (err) - goto mlxreg_lc_probe_fail; + if (err) { + dev_err(&pdev->dev, "Failed to set default regmap %d for client %s at bus %d at addr 0x%02x\n", + i, data->hpdev.brdinfo->type, data->hpdev.nr, + data->hpdev.brdinfo->addr); + goto regmap_write_fail; + } } /* Sync registers with hardware. */ regcache_mark_dirty(regmap); err = regcache_sync(regmap); - if (err) - goto mlxreg_lc_probe_fail; + if (err) { + dev_err(&pdev->dev, "Failed to sync regmap for client %s at bus %d at addr 0x%02x\n", + data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr); + err = PTR_ERR(regmap); + goto regcache_sync_fail; + } par_pdata = data->hpdev.brdinfo->platform_data; mlxreg_lc->par_regmap = par_pdata->regmap; @@ -854,12 +876,27 @@ static int mlxreg_lc_probe(struct platform_device *pdev) /* Configure line card. */ err = mlxreg_lc_config_init(mlxreg_lc, regmap, data); if (err) - goto mlxreg_lc_probe_fail; + goto mlxreg_lc_config_init_fail; return err; -mlxreg_lc_probe_fail: +mlxreg_lc_config_init_fail: +regcache_sync_fail: +regmap_write_fail: +devm_regmap_init_i2c_fail: + if (data->hpdev.client) { + i2c_unregister_device(data->hpdev.client); + data->hpdev.client = NULL; + } +i2c_new_device_fail: i2c_put_adapter(data->hpdev.adapter); + data->hpdev.adapter = NULL; +i2c_get_adapter_fail: + /* Clear event notification callback and handle. */ + if (data->notifier) { + data->notifier->user_handler = NULL; + data->notifier->handle = NULL; + } return err; } @@ -868,11 +905,18 @@ static int mlxreg_lc_remove(struct platform_device *pdev) struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev); struct mlxreg_lc *mlxreg_lc = platform_get_drvdata(pdev); - /* Clear event notification callback. */ - if (data->notifier) { - data->notifier->user_handler = NULL; - data->notifier->handle = NULL; - } + /* + * Probing and removing are invoked by hotplug events raised upon line card insertion and + * removing. If probing procedure fails all data is cleared. However, hotplug event still + * will be raised on line card removing and activate removing procedure. In this case there + * is nothing to remove. + */ + if (!data->notifier || !data->notifier->handle) + return 0; + + /* Clear event notification callback and handle. */ + data->notifier->user_handler = NULL; + data->notifier->handle = NULL; /* Destroy static I2C device feeding by main power. */ mlxreg_lc_destroy_static_devices(mlxreg_lc, mlxreg_lc->main_devs, From 40ec787e1adf302c11668d4cc69838f4d584187d Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 20 Jul 2022 21:23:38 +0300 Subject: [PATCH 1382/1436] platform/olpc: Fix uninitialized data in debugfs write The call to: size = simple_write_to_buffer(cmdbuf, sizeof(cmdbuf), ppos, buf, size); will succeed if at least one byte is written to the "cmdbuf" buffer. The "*ppos" value controls which byte is written. Another problem is that this code does not check for errors so it's possible for the entire buffer to be uninitialized. Inintialize the struct to zero to prevent reading uninitialized stack data. Debugfs is normally only writable by root so the impact of this bug is very minimal. Fixes: 6cca83d498bd ("Platform: OLPC: move debugfs support from x86 EC driver") Signed-off-by: Dan Carpenter Link: https://lore.kernel.org/r/YthIKn+TfZSZMEcM@kili Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/olpc/olpc-ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c index 4ff5c3a12991..921520475ff6 100644 --- a/drivers/platform/olpc/olpc-ec.c +++ b/drivers/platform/olpc/olpc-ec.c @@ -264,7 +264,7 @@ static ssize_t ec_dbgfs_cmd_write(struct file *file, const char __user *buf, int i, m; unsigned char ec_cmd[EC_MAX_CMD_ARGS]; unsigned int ec_cmd_int[EC_MAX_CMD_ARGS]; - char cmdbuf[64]; + char cmdbuf[64] = ""; int ec_cmd_bytes; mutex_lock(&ec_dbgfs_lock); From e6abe8ff8e0c4fa905567775f48e102005ae960b Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 21 Jul 2022 14:11:20 +0200 Subject: [PATCH 1383/1436] platform/surface: gpe: Add support for 13" Intel version of Surface Laptop 4 The 13" Intel version of the Surface Laptop 4 uses the same GPE as the Surface Laptop Studio for wakeups via the lid. Set it up accordingly. Signed-off-by: Maximilian Luz Link: https://lore.kernel.org/r/20220721121120.2002430-1-luzmaximilian@gmail.com Signed-off-by: Hans de Goede --- drivers/platform/surface/surface_gpe.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/platform/surface/surface_gpe.c b/drivers/platform/surface/surface_gpe.c index 27365cbe1ee9..c219b840d491 100644 --- a/drivers/platform/surface/surface_gpe.c +++ b/drivers/platform/surface/surface_gpe.c @@ -171,6 +171,18 @@ static const struct dmi_system_id dmi_lid_device_table[] = { }, .driver_data = (void *)lid_device_props_l4D, }, + { + .ident = "Surface Laptop 4 (Intel 13\")", + .matches = { + /* + * We match for SKU here due to different variants: The + * AMD (15") version does not rely on GPEs. + */ + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_4_1950:1951"), + }, + .driver_data = (void *)lid_device_props_l4B, + }, { .ident = "Surface Laptop Studio", .matches = { From 6dd71251b9aeedd540fd7003bc5f73d59dd6dcb2 Mon Sep 17 00:00:00 2001 From: Xin Gao Date: Fri, 22 Jul 2022 10:23:37 +0800 Subject: [PATCH 1384/1436] platform/x86: pmc_atom: Fix comment typo The double `of' is duplicated in line 50, remove one. Signed-off-by: Xin Gao Link: https://lore.kernel.org/r/20220722022337.15903-1-gaoxin@cdjrlc.com Signed-off-by: Hans de Goede --- include/linux/platform_data/x86/pmc_atom.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/platform_data/x86/pmc_atom.h b/include/linux/platform_data/x86/pmc_atom.h index 6807839c718b..3edfb6d4e67a 100644 --- a/include/linux/platform_data/x86/pmc_atom.h +++ b/include/linux/platform_data/x86/pmc_atom.h @@ -47,7 +47,7 @@ #define PMC_S0I2_TMR 0x88 #define PMC_S0I3_TMR 0x8C #define PMC_S0_TMR 0x90 -/* Sleep state counter is in units of of 32us */ +/* Sleep state counter is in units of 32us */ #define PMC_TMR_SHIFT 5 /* Power status of power islands */ From f3a76018dd55d8ddcd28cb47049f46ae5c0ce557 Mon Sep 17 00:00:00 2001 From: Phillip Potter Date: Fri, 29 Jul 2022 00:11:49 +0100 Subject: [PATCH 1385/1436] staging: r8188eu: remove initializer from ret in rtw_pwr_wakeup Remove the success initializer from the ret variable in rtw_pwr_wakeup, as we set it later anyway in the success path, and also set on failure. This makes the function appear cleaner and more consistent. Suggested-by: Dan Carpenter Tested-by: Philipp Hortmann Signed-off-by: Phillip Potter Link: https://lore.kernel.org/r/20220728231150.972-2-phil@philpotter.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_pwrctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/r8188eu/core/rtw_pwrctrl.c b/drivers/staging/r8188eu/core/rtw_pwrctrl.c index 8b1c50668dfe..75e655bae16a 100644 --- a/drivers/staging/r8188eu/core/rtw_pwrctrl.c +++ b/drivers/staging/r8188eu/core/rtw_pwrctrl.c @@ -381,7 +381,7 @@ int rtw_pwr_wakeup(struct adapter *padapter) struct mlme_priv *pmlmepriv = &padapter->mlmepriv; unsigned long timeout = jiffies + msecs_to_jiffies(3000); unsigned long deny_time; - int ret = 0; + int ret; while (pwrpriv->ps_processing && time_before(jiffies, timeout)) msleep(10); From 9bfd900beeecaba009ccde8cf13716d3cac4d2e1 Mon Sep 17 00:00:00 2001 From: Atish Patra Date: Fri, 29 Jul 2022 17:14:11 +0530 Subject: [PATCH 1386/1436] RISC-V: KVM: Improve ISA extension by using a bitmap Currently, the every vcpu only stores the ISA extensions in a unsigned long which is not scalable as number of extensions will continue to grow. Using a bitmap allows the ISA extension to support any number of extensions. The CONFIG one reg interface implementation is modified to support the bitmap as well. But it is meant only for base extensions. Thus, the first element of the bitmap array is sufficient for that interface. In the future, all the new multi-letter extensions must use the ISA_EXT one reg interface that allows enabling/disabling any extension now. Signed-off-by: Atish Patra Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_host.h | 3 +- arch/riscv/include/asm/kvm_vcpu_fp.h | 8 +- arch/riscv/kvm/vcpu.c | 150 +++++++++++++++++---------- arch/riscv/kvm/vcpu_fp.c | 27 +++-- 4 files changed, 116 insertions(+), 72 deletions(-) diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index 319c8aeb42af..c749cdacbd63 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -170,7 +171,7 @@ struct kvm_vcpu_arch { int last_exit_cpu; /* ISA feature bits (similar to MISA) */ - unsigned long isa; + DECLARE_BITMAP(isa, RISCV_ISA_EXT_MAX); /* SSCRATCH, STVEC, and SCOUNTEREN of Host */ unsigned long host_sscratch; diff --git a/arch/riscv/include/asm/kvm_vcpu_fp.h b/arch/riscv/include/asm/kvm_vcpu_fp.h index 4da9b8e0f050..b5540147409f 100644 --- a/arch/riscv/include/asm/kvm_vcpu_fp.h +++ b/arch/riscv/include/asm/kvm_vcpu_fp.h @@ -22,9 +22,9 @@ void __kvm_riscv_fp_d_restore(struct kvm_cpu_context *context); void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx, - unsigned long isa); + const unsigned long *isa); void kvm_riscv_vcpu_guest_fp_restore(struct kvm_cpu_context *cntx, - unsigned long isa); + const unsigned long *isa); void kvm_riscv_vcpu_host_fp_save(struct kvm_cpu_context *cntx); void kvm_riscv_vcpu_host_fp_restore(struct kvm_cpu_context *cntx); #else @@ -32,12 +32,12 @@ static inline void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu) { } static inline void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx, - unsigned long isa) + const unsigned long *isa) { } static inline void kvm_riscv_vcpu_guest_fp_restore( struct kvm_cpu_context *cntx, - unsigned long isa) + const unsigned long *isa) { } static inline void kvm_riscv_vcpu_host_fp_save(struct kvm_cpu_context *cntx) diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index f3455dc013fa..5d42c50aedcb 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -38,16 +38,57 @@ const struct kvm_stats_header kvm_vcpu_stats_header = { sizeof(kvm_vcpu_stats_desc), }; -#define KVM_RISCV_ISA_DISABLE_ALLOWED (riscv_isa_extension_mask(d) | \ - riscv_isa_extension_mask(f)) +#define KVM_RISCV_BASE_ISA_MASK GENMASK(25, 0) -#define KVM_RISCV_ISA_DISABLE_NOT_ALLOWED (riscv_isa_extension_mask(a) | \ - riscv_isa_extension_mask(c) | \ - riscv_isa_extension_mask(i) | \ - riscv_isa_extension_mask(m)) +/* Mapping between KVM ISA Extension ID & Host ISA extension ID */ +static const unsigned long kvm_isa_ext_arr[] = { + RISCV_ISA_EXT_a, + RISCV_ISA_EXT_c, + RISCV_ISA_EXT_d, + RISCV_ISA_EXT_f, + RISCV_ISA_EXT_h, + RISCV_ISA_EXT_i, + RISCV_ISA_EXT_m, +}; -#define KVM_RISCV_ISA_ALLOWED (KVM_RISCV_ISA_DISABLE_ALLOWED | \ - KVM_RISCV_ISA_DISABLE_NOT_ALLOWED) +static unsigned long kvm_riscv_vcpu_base2isa_ext(unsigned long base_ext) +{ + unsigned long i; + + for (i = 0; i < KVM_RISCV_ISA_EXT_MAX; i++) { + if (kvm_isa_ext_arr[i] == base_ext) + return i; + } + + return KVM_RISCV_ISA_EXT_MAX; +} + +static bool kvm_riscv_vcpu_isa_enable_allowed(unsigned long ext) +{ + switch (ext) { + case KVM_RISCV_ISA_EXT_H: + return false; + default: + break; + } + + return true; +} + +static bool kvm_riscv_vcpu_isa_disable_allowed(unsigned long ext) +{ + switch (ext) { + case KVM_RISCV_ISA_EXT_A: + case KVM_RISCV_ISA_EXT_C: + case KVM_RISCV_ISA_EXT_I: + case KVM_RISCV_ISA_EXT_M: + return false; + default: + break; + } + + return true; +} static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu) { @@ -99,13 +140,20 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) { struct kvm_cpu_context *cntx; struct kvm_vcpu_csr *reset_csr = &vcpu->arch.guest_reset_csr; + unsigned long host_isa, i; /* Mark this VCPU never ran */ vcpu->arch.ran_atleast_once = false; vcpu->arch.mmu_page_cache.gfp_zero = __GFP_ZERO; + bitmap_zero(vcpu->arch.isa, RISCV_ISA_EXT_MAX); /* Setup ISA features available to VCPU */ - vcpu->arch.isa = riscv_isa_extension_base(NULL) & KVM_RISCV_ISA_ALLOWED; + for (i = 0; i < ARRAY_SIZE(kvm_isa_ext_arr); i++) { + host_isa = kvm_isa_ext_arr[i]; + if (__riscv_isa_extension_available(NULL, host_isa) && + kvm_riscv_vcpu_isa_enable_allowed(i)) + set_bit(host_isa, vcpu->arch.isa); + } /* Setup VCPU hfence queue */ spin_lock_init(&vcpu->arch.hfence_lock); @@ -199,7 +247,7 @@ static int kvm_riscv_vcpu_get_reg_config(struct kvm_vcpu *vcpu, switch (reg_num) { case KVM_REG_RISCV_CONFIG_REG(isa): - reg_val = vcpu->arch.isa; + reg_val = vcpu->arch.isa[0] & KVM_RISCV_BASE_ISA_MASK; break; default: return -EINVAL; @@ -219,7 +267,7 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_RISCV_CONFIG); - unsigned long reg_val; + unsigned long i, isa_ext, reg_val; if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) return -EINVAL; @@ -227,13 +275,32 @@ static int kvm_riscv_vcpu_set_reg_config(struct kvm_vcpu *vcpu, if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) return -EFAULT; + /* This ONE REG interface is only defined for single letter extensions */ + if (fls(reg_val) >= RISCV_ISA_EXT_BASE) + return -EINVAL; + switch (reg_num) { case KVM_REG_RISCV_CONFIG_REG(isa): if (!vcpu->arch.ran_atleast_once) { - /* Ignore the disable request for these extensions */ - vcpu->arch.isa = reg_val | KVM_RISCV_ISA_DISABLE_NOT_ALLOWED; - vcpu->arch.isa &= riscv_isa_extension_base(NULL); - vcpu->arch.isa &= KVM_RISCV_ISA_ALLOWED; + /* Ignore the enable/disable request for certain extensions */ + for (i = 0; i < RISCV_ISA_EXT_BASE; i++) { + isa_ext = kvm_riscv_vcpu_base2isa_ext(i); + if (isa_ext >= KVM_RISCV_ISA_EXT_MAX) { + reg_val &= ~BIT(i); + continue; + } + if (!kvm_riscv_vcpu_isa_enable_allowed(isa_ext)) + if (reg_val & BIT(i)) + reg_val &= ~BIT(i); + if (!kvm_riscv_vcpu_isa_disable_allowed(isa_ext)) + if (!(reg_val & BIT(i))) + reg_val |= BIT(i); + } + reg_val &= riscv_isa_extension_base(NULL); + /* Do not modify anything beyond single letter extensions */ + reg_val = (vcpu->arch.isa[0] & ~KVM_RISCV_BASE_ISA_MASK) | + (reg_val & KVM_RISCV_BASE_ISA_MASK); + vcpu->arch.isa[0] = reg_val; kvm_riscv_vcpu_fp_reset(vcpu); } else { return -EOPNOTSUPP; @@ -374,17 +441,6 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu, return 0; } -/* Mapping between KVM ISA Extension ID & Host ISA extension ID */ -static unsigned long kvm_isa_ext_arr[] = { - RISCV_ISA_EXT_a, - RISCV_ISA_EXT_c, - RISCV_ISA_EXT_d, - RISCV_ISA_EXT_f, - RISCV_ISA_EXT_h, - RISCV_ISA_EXT_i, - RISCV_ISA_EXT_m, -}; - static int kvm_riscv_vcpu_get_reg_isa_ext(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) { @@ -399,11 +455,12 @@ static int kvm_riscv_vcpu_get_reg_isa_ext(struct kvm_vcpu *vcpu, if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) return -EINVAL; - if (reg_num >= KVM_RISCV_ISA_EXT_MAX || reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) + if (reg_num >= KVM_RISCV_ISA_EXT_MAX || + reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) return -EINVAL; host_isa_ext = kvm_isa_ext_arr[reg_num]; - if (__riscv_isa_extension_available(&vcpu->arch.isa, host_isa_ext)) + if (__riscv_isa_extension_available(vcpu->arch.isa, host_isa_ext)) reg_val = 1; /* Mark the given extension as available */ if (copy_to_user(uaddr, ®_val, KVM_REG_SIZE(reg->id))) @@ -422,12 +479,12 @@ static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu, KVM_REG_RISCV_ISA_EXT); unsigned long reg_val; unsigned long host_isa_ext; - unsigned long host_isa_ext_mask; if (KVM_REG_SIZE(reg->id) != sizeof(unsigned long)) return -EINVAL; - if (reg_num >= KVM_RISCV_ISA_EXT_MAX || reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) + if (reg_num >= KVM_RISCV_ISA_EXT_MAX || + reg_num >= ARRAY_SIZE(kvm_isa_ext_arr)) return -EINVAL; if (copy_from_user(®_val, uaddr, KVM_REG_SIZE(reg->id))) @@ -437,30 +494,19 @@ static int kvm_riscv_vcpu_set_reg_isa_ext(struct kvm_vcpu *vcpu, if (!__riscv_isa_extension_available(NULL, host_isa_ext)) return -EOPNOTSUPP; - if (host_isa_ext >= RISCV_ISA_EXT_BASE && - host_isa_ext < RISCV_ISA_EXT_MAX) { - /* - * Multi-letter ISA extension. Currently there is no provision - * to enable/disable the multi-letter ISA extensions for guests. - * Return success if the request is to enable any ISA extension - * that is available in the hardware. - * Return -EOPNOTSUPP otherwise. - */ - if (!reg_val) - return -EOPNOTSUPP; - else - return 0; - } - - /* Single letter base ISA extension */ if (!vcpu->arch.ran_atleast_once) { - host_isa_ext_mask = BIT_MASK(host_isa_ext); - if (!reg_val && (host_isa_ext_mask & KVM_RISCV_ISA_DISABLE_ALLOWED)) - vcpu->arch.isa &= ~host_isa_ext_mask; + /* + * All multi-letter extension and a few single letter + * extension can be disabled + */ + if (reg_val == 1 && + kvm_riscv_vcpu_isa_enable_allowed(reg_num)) + set_bit(host_isa_ext, vcpu->arch.isa); + else if (!reg_val && + kvm_riscv_vcpu_isa_disable_allowed(reg_num)) + clear_bit(host_isa_ext, vcpu->arch.isa); else - vcpu->arch.isa |= host_isa_ext_mask; - vcpu->arch.isa &= riscv_isa_extension_base(NULL); - vcpu->arch.isa &= KVM_RISCV_ISA_ALLOWED; + return -EINVAL; kvm_riscv_vcpu_fp_reset(vcpu); } else { return -EOPNOTSUPP; diff --git a/arch/riscv/kvm/vcpu_fp.c b/arch/riscv/kvm/vcpu_fp.c index d4308c512007..9d8cbc42057a 100644 --- a/arch/riscv/kvm/vcpu_fp.c +++ b/arch/riscv/kvm/vcpu_fp.c @@ -16,12 +16,11 @@ #ifdef CONFIG_FPU void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu) { - unsigned long isa = vcpu->arch.isa; struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; cntx->sstatus &= ~SR_FS; - if (riscv_isa_extension_available(&isa, f) || - riscv_isa_extension_available(&isa, d)) + if (riscv_isa_extension_available(vcpu->arch.isa, f) || + riscv_isa_extension_available(vcpu->arch.isa, d)) cntx->sstatus |= SR_FS_INITIAL; else cntx->sstatus |= SR_FS_OFF; @@ -34,24 +33,24 @@ static void kvm_riscv_vcpu_fp_clean(struct kvm_cpu_context *cntx) } void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx, - unsigned long isa) + const unsigned long *isa) { if ((cntx->sstatus & SR_FS) == SR_FS_DIRTY) { - if (riscv_isa_extension_available(&isa, d)) + if (riscv_isa_extension_available(isa, d)) __kvm_riscv_fp_d_save(cntx); - else if (riscv_isa_extension_available(&isa, f)) + else if (riscv_isa_extension_available(isa, f)) __kvm_riscv_fp_f_save(cntx); kvm_riscv_vcpu_fp_clean(cntx); } } void kvm_riscv_vcpu_guest_fp_restore(struct kvm_cpu_context *cntx, - unsigned long isa) + const unsigned long *isa) { if ((cntx->sstatus & SR_FS) != SR_FS_OFF) { - if (riscv_isa_extension_available(&isa, d)) + if (riscv_isa_extension_available(isa, d)) __kvm_riscv_fp_d_restore(cntx); - else if (riscv_isa_extension_available(&isa, f)) + else if (riscv_isa_extension_available(isa, f)) __kvm_riscv_fp_f_restore(cntx); kvm_riscv_vcpu_fp_clean(cntx); } @@ -80,7 +79,6 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu, unsigned long rtype) { struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; - unsigned long isa = vcpu->arch.isa; unsigned long __user *uaddr = (unsigned long __user *)(unsigned long)reg->addr; unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | @@ -89,7 +87,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu, void *reg_val; if ((rtype == KVM_REG_RISCV_FP_F) && - riscv_isa_extension_available(&isa, f)) { + riscv_isa_extension_available(vcpu->arch.isa, f)) { if (KVM_REG_SIZE(reg->id) != sizeof(u32)) return -EINVAL; if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr)) @@ -100,7 +98,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu, else return -EINVAL; } else if ((rtype == KVM_REG_RISCV_FP_D) && - riscv_isa_extension_available(&isa, d)) { + riscv_isa_extension_available(vcpu->arch.isa, d)) { if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) { if (KVM_REG_SIZE(reg->id) != sizeof(u32)) return -EINVAL; @@ -126,7 +124,6 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu, unsigned long rtype) { struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; - unsigned long isa = vcpu->arch.isa; unsigned long __user *uaddr = (unsigned long __user *)(unsigned long)reg->addr; unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | @@ -135,7 +132,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu, void *reg_val; if ((rtype == KVM_REG_RISCV_FP_F) && - riscv_isa_extension_available(&isa, f)) { + riscv_isa_extension_available(vcpu->arch.isa, f)) { if (KVM_REG_SIZE(reg->id) != sizeof(u32)) return -EINVAL; if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr)) @@ -146,7 +143,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu, else return -EINVAL; } else if ((rtype == KVM_REG_RISCV_FP_D) && - riscv_isa_extension_available(&isa, d)) { + riscv_isa_extension_available(vcpu->arch.isa, d)) { if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) { if (KVM_REG_SIZE(reg->id) != sizeof(u32)) return -EINVAL; From 6259d2f834f2834e32254e0c02a4c4996d34495a Mon Sep 17 00:00:00 2001 From: Zhang Jiaming Date: Fri, 29 Jul 2022 17:14:17 +0530 Subject: [PATCH 1387/1436] RISC-V: KVM: Fix variable spelling mistake There is a spelling mistake in mmu.c and vcpu_exit.c. Fix it. Signed-off-by: Zhang Jiaming Signed-off-by: Anup Patel --- arch/riscv/kvm/mmu.c | 8 ++++---- arch/riscv/kvm/vcpu_exit.c | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c index 9826073fbc67..b75d4e200064 100644 --- a/arch/riscv/kvm/mmu.c +++ b/arch/riscv/kvm/mmu.c @@ -611,7 +611,7 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, { int ret; kvm_pfn_t hfn; - bool writeable; + bool writable; short vma_pageshift; gfn_t gfn = gpa >> PAGE_SHIFT; struct vm_area_struct *vma; @@ -659,7 +659,7 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, mmu_seq = kvm->mmu_notifier_seq; - hfn = gfn_to_pfn_prot(kvm, gfn, is_write, &writeable); + hfn = gfn_to_pfn_prot(kvm, gfn, is_write, &writable); if (hfn == KVM_PFN_ERR_HWPOISON) { send_sig_mceerr(BUS_MCEERR_AR, (void __user *)hva, vma_pageshift, current); @@ -673,14 +673,14 @@ int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, * for write faults. */ if (logging && !is_write) - writeable = false; + writable = false; spin_lock(&kvm->mmu_lock); if (mmu_notifier_retry(kvm, mmu_seq)) goto out_unlock; - if (writeable) { + if (writable) { kvm_set_pfn_dirty(hfn); mark_page_dirty(kvm, gfn); ret = gstage_map_page(kvm, pcache, gpa, hfn << PAGE_SHIFT, diff --git a/arch/riscv/kvm/vcpu_exit.c b/arch/riscv/kvm/vcpu_exit.c index dbb09afd7546..f4e569688619 100644 --- a/arch/riscv/kvm/vcpu_exit.c +++ b/arch/riscv/kvm/vcpu_exit.c @@ -417,17 +417,17 @@ static int gstage_page_fault(struct kvm_vcpu *vcpu, struct kvm_run *run, { struct kvm_memory_slot *memslot; unsigned long hva, fault_addr; - bool writeable; + bool writable; gfn_t gfn; int ret; fault_addr = (trap->htval << 2) | (trap->stval & 0x3); gfn = fault_addr >> PAGE_SHIFT; memslot = gfn_to_memslot(vcpu->kvm, gfn); - hva = gfn_to_hva_memslot_prot(memslot, gfn, &writeable); + hva = gfn_to_hva_memslot_prot(memslot, gfn, &writable); if (kvm_is_error_hva(hva) || - (trap->scause == EXC_STORE_GUEST_PAGE_FAULT && !writeable)) { + (trap->scause == EXC_STORE_GUEST_PAGE_FAULT && !writable)) { switch (trap->scause) { case EXC_LOAD_GUEST_PAGE_FAULT: return emulate_load(vcpu, run, fault_addr, From cca986fab9e819319353bece789cb9d2890c1115 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 29 Jul 2022 17:14:26 +0530 Subject: [PATCH 1388/1436] RISC-V: KVM: Make kvm_riscv_guest_timer_init a void function It can never fail so convey that fact explicitly by making the function void. Also in kvm_arch_init_vm it makes it clear that there no need to do any cleanup after kvm_riscv_gstage_vmid_init has been called. Signed-off-by: Nikolay Borisov Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_vcpu_timer.h | 2 +- arch/riscv/kvm/vcpu_timer.c | 4 +--- arch/riscv/kvm/vm.c | 4 +++- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/riscv/include/asm/kvm_vcpu_timer.h b/arch/riscv/include/asm/kvm_vcpu_timer.h index 375281eb49e0..50138e2eb91b 100644 --- a/arch/riscv/include/asm/kvm_vcpu_timer.h +++ b/arch/riscv/include/asm/kvm_vcpu_timer.h @@ -39,6 +39,6 @@ int kvm_riscv_vcpu_timer_init(struct kvm_vcpu *vcpu); int kvm_riscv_vcpu_timer_deinit(struct kvm_vcpu *vcpu); int kvm_riscv_vcpu_timer_reset(struct kvm_vcpu *vcpu); void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu); -int kvm_riscv_guest_timer_init(struct kvm *kvm); +void kvm_riscv_guest_timer_init(struct kvm *kvm); #endif diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c index 5c4c37ff2d48..595043857049 100644 --- a/arch/riscv/kvm/vcpu_timer.c +++ b/arch/riscv/kvm/vcpu_timer.c @@ -214,12 +214,10 @@ void kvm_riscv_vcpu_timer_restore(struct kvm_vcpu *vcpu) #endif } -int kvm_riscv_guest_timer_init(struct kvm *kvm) +void kvm_riscv_guest_timer_init(struct kvm *kvm) { struct kvm_guest_timer *gt = &kvm->arch.timer; riscv_cs_get_mult_shift(>->nsec_mult, >->nsec_shift); gt->time_delta = -get_cycles64(); - - return 0; } diff --git a/arch/riscv/kvm/vm.c b/arch/riscv/kvm/vm.c index 945a2bf5e3f6..65a964d7e70d 100644 --- a/arch/riscv/kvm/vm.c +++ b/arch/riscv/kvm/vm.c @@ -41,7 +41,9 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) return r; } - return kvm_riscv_guest_timer_init(kvm); + kvm_riscv_guest_timer_init(kvm); + + return 0; } void kvm_arch_destroy_vm(struct kvm *kvm) From fe283e5fa1edc59f37265c91dc79bf119a5ccc79 Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Fri, 29 Jul 2022 17:14:34 +0530 Subject: [PATCH 1389/1436] RISC-V: KVM: move preempt_disable() call in kvm_arch_vcpu_ioctl_run local_irq_disable provides stronger guarantees than preempt_disable so calling the latter is redundant when interrupts are disabled. Instead, explicitly disable preemption right before interrupts are enabled/disabled to ensure that the time accounted in guest_timing_exit_irqoff includes time taken by the guest or interrupts. Signed-off-by: Nikolay Borisov Signed-off-by: Anup Patel --- arch/riscv/kvm/vcpu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 5d42c50aedcb..a3c051cb070c 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -936,8 +936,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) kvm_riscv_check_vcpu_requests(vcpu); - preempt_disable(); - local_irq_disable(); /* @@ -974,7 +972,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) kvm_request_pending(vcpu)) { vcpu->mode = OUTSIDE_GUEST_MODE; local_irq_enable(); - preempt_enable(); kvm_vcpu_srcu_read_lock(vcpu); continue; } @@ -1008,6 +1005,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) /* Syncup interrupts state with HW */ kvm_riscv_vcpu_sync_interrupts(vcpu); + preempt_disable(); + /* * We must ensure that any pending interrupts are taken before * we exit guest timing so that timer ticks are accounted as From b91f0e4cb8a3ce4f2716a13739ade0f7bea8eadb Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 29 Jul 2022 17:14:40 +0530 Subject: [PATCH 1390/1436] RISC-V: KVM: Factor-out instruction emulation into separate sources The instruction and CSR emulation for VCPU is going to grow over time due to upcoming AIA, PMU, Nested and other virtualization features. Let us factor-out VCPU instruction emulation from vcpu_exit.c to a separate source dedicated for this purpose. Signed-off-by: Anup Patel Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_host.h | 11 +- arch/riscv/include/asm/kvm_vcpu_insn.h | 33 ++ arch/riscv/kvm/Makefile | 1 + arch/riscv/kvm/vcpu_exit.c | 490 +---------------------- arch/riscv/kvm/vcpu_insn.c | 520 +++++++++++++++++++++++++ 5 files changed, 562 insertions(+), 493 deletions(-) create mode 100644 arch/riscv/include/asm/kvm_vcpu_insn.h create mode 100644 arch/riscv/kvm/vcpu_insn.c diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index c749cdacbd63..d482d771eba4 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #define KVM_MAX_VCPUS 1024 @@ -91,14 +92,6 @@ struct kvm_arch { struct kvm_guest_timer timer; }; -struct kvm_mmio_decode { - unsigned long insn; - int insn_len; - int len; - int shift; - int return_handled; -}; - struct kvm_sbi_context { int return_handled; }; @@ -304,14 +297,12 @@ void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu); void __kvm_riscv_unpriv_trap(void); -void kvm_riscv_vcpu_wfi(struct kvm_vcpu *vcpu); unsigned long kvm_riscv_vcpu_unpriv_read(struct kvm_vcpu *vcpu, bool read_insn, unsigned long guest_addr, struct kvm_cpu_trap *trap); void kvm_riscv_vcpu_trap_redirect(struct kvm_vcpu *vcpu, struct kvm_cpu_trap *trap); -int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, struct kvm_cpu_trap *trap); diff --git a/arch/riscv/include/asm/kvm_vcpu_insn.h b/arch/riscv/include/asm/kvm_vcpu_insn.h new file mode 100644 index 000000000000..4e3ba4e84d0f --- /dev/null +++ b/arch/riscv/include/asm/kvm_vcpu_insn.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 Ventana Micro Systems Inc. + */ + +#ifndef __KVM_VCPU_RISCV_INSN_H +#define __KVM_VCPU_RISCV_INSN_H + +struct kvm_vcpu; +struct kvm_run; +struct kvm_cpu_trap; + +struct kvm_mmio_decode { + unsigned long insn; + int insn_len; + int len; + int shift; + int return_handled; +}; + +void kvm_riscv_vcpu_wfi(struct kvm_vcpu *vcpu); +int kvm_riscv_vcpu_virtual_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_cpu_trap *trap); + +int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run, + unsigned long fault_addr, + unsigned long htinst); +int kvm_riscv_vcpu_mmio_store(struct kvm_vcpu *vcpu, struct kvm_run *run, + unsigned long fault_addr, + unsigned long htinst); +int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run); + +#endif diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile index e5c56182f48f..019df9208bdd 100644 --- a/arch/riscv/kvm/Makefile +++ b/arch/riscv/kvm/Makefile @@ -17,6 +17,7 @@ kvm-y += mmu.o kvm-y += vcpu.o kvm-y += vcpu_exit.o kvm-y += vcpu_fp.o +kvm-y += vcpu_insn.o kvm-y += vcpu_switch.o kvm-y += vcpu_sbi.o kvm-$(CONFIG_RISCV_SBI_V01) += vcpu_sbi_v01.o diff --git a/arch/riscv/kvm/vcpu_exit.c b/arch/riscv/kvm/vcpu_exit.c index f4e569688619..d5c36386878a 100644 --- a/arch/riscv/kvm/vcpu_exit.c +++ b/arch/riscv/kvm/vcpu_exit.c @@ -6,412 +6,9 @@ * Anup Patel */ -#include -#include -#include #include #include -#define INSN_OPCODE_MASK 0x007c -#define INSN_OPCODE_SHIFT 2 -#define INSN_OPCODE_SYSTEM 28 - -#define INSN_MASK_WFI 0xffffffff -#define INSN_MATCH_WFI 0x10500073 - -#define INSN_MATCH_LB 0x3 -#define INSN_MASK_LB 0x707f -#define INSN_MATCH_LH 0x1003 -#define INSN_MASK_LH 0x707f -#define INSN_MATCH_LW 0x2003 -#define INSN_MASK_LW 0x707f -#define INSN_MATCH_LD 0x3003 -#define INSN_MASK_LD 0x707f -#define INSN_MATCH_LBU 0x4003 -#define INSN_MASK_LBU 0x707f -#define INSN_MATCH_LHU 0x5003 -#define INSN_MASK_LHU 0x707f -#define INSN_MATCH_LWU 0x6003 -#define INSN_MASK_LWU 0x707f -#define INSN_MATCH_SB 0x23 -#define INSN_MASK_SB 0x707f -#define INSN_MATCH_SH 0x1023 -#define INSN_MASK_SH 0x707f -#define INSN_MATCH_SW 0x2023 -#define INSN_MASK_SW 0x707f -#define INSN_MATCH_SD 0x3023 -#define INSN_MASK_SD 0x707f - -#define INSN_MATCH_C_LD 0x6000 -#define INSN_MASK_C_LD 0xe003 -#define INSN_MATCH_C_SD 0xe000 -#define INSN_MASK_C_SD 0xe003 -#define INSN_MATCH_C_LW 0x4000 -#define INSN_MASK_C_LW 0xe003 -#define INSN_MATCH_C_SW 0xc000 -#define INSN_MASK_C_SW 0xe003 -#define INSN_MATCH_C_LDSP 0x6002 -#define INSN_MASK_C_LDSP 0xe003 -#define INSN_MATCH_C_SDSP 0xe002 -#define INSN_MASK_C_SDSP 0xe003 -#define INSN_MATCH_C_LWSP 0x4002 -#define INSN_MASK_C_LWSP 0xe003 -#define INSN_MATCH_C_SWSP 0xc002 -#define INSN_MASK_C_SWSP 0xe003 - -#define INSN_16BIT_MASK 0x3 - -#define INSN_IS_16BIT(insn) (((insn) & INSN_16BIT_MASK) != INSN_16BIT_MASK) - -#define INSN_LEN(insn) (INSN_IS_16BIT(insn) ? 2 : 4) - -#ifdef CONFIG_64BIT -#define LOG_REGBYTES 3 -#else -#define LOG_REGBYTES 2 -#endif -#define REGBYTES (1 << LOG_REGBYTES) - -#define SH_RD 7 -#define SH_RS1 15 -#define SH_RS2 20 -#define SH_RS2C 2 - -#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) -#define RVC_LW_IMM(x) ((RV_X(x, 6, 1) << 2) | \ - (RV_X(x, 10, 3) << 3) | \ - (RV_X(x, 5, 1) << 6)) -#define RVC_LD_IMM(x) ((RV_X(x, 10, 3) << 3) | \ - (RV_X(x, 5, 2) << 6)) -#define RVC_LWSP_IMM(x) ((RV_X(x, 4, 3) << 2) | \ - (RV_X(x, 12, 1) << 5) | \ - (RV_X(x, 2, 2) << 6)) -#define RVC_LDSP_IMM(x) ((RV_X(x, 5, 2) << 3) | \ - (RV_X(x, 12, 1) << 5) | \ - (RV_X(x, 2, 3) << 6)) -#define RVC_SWSP_IMM(x) ((RV_X(x, 9, 4) << 2) | \ - (RV_X(x, 7, 2) << 6)) -#define RVC_SDSP_IMM(x) ((RV_X(x, 10, 3) << 3) | \ - (RV_X(x, 7, 3) << 6)) -#define RVC_RS1S(insn) (8 + RV_X(insn, SH_RD, 3)) -#define RVC_RS2S(insn) (8 + RV_X(insn, SH_RS2C, 3)) -#define RVC_RS2(insn) RV_X(insn, SH_RS2C, 5) - -#define SHIFT_RIGHT(x, y) \ - ((y) < 0 ? ((x) << -(y)) : ((x) >> (y))) - -#define REG_MASK \ - ((1 << (5 + LOG_REGBYTES)) - (1 << LOG_REGBYTES)) - -#define REG_OFFSET(insn, pos) \ - (SHIFT_RIGHT((insn), (pos) - LOG_REGBYTES) & REG_MASK) - -#define REG_PTR(insn, pos, regs) \ - ((ulong *)((ulong)(regs) + REG_OFFSET(insn, pos))) - -#define GET_RM(insn) (((insn) >> 12) & 7) - -#define GET_RS1(insn, regs) (*REG_PTR(insn, SH_RS1, regs)) -#define GET_RS2(insn, regs) (*REG_PTR(insn, SH_RS2, regs)) -#define GET_RS1S(insn, regs) (*REG_PTR(RVC_RS1S(insn), 0, regs)) -#define GET_RS2S(insn, regs) (*REG_PTR(RVC_RS2S(insn), 0, regs)) -#define GET_RS2C(insn, regs) (*REG_PTR(insn, SH_RS2C, regs)) -#define GET_SP(regs) (*REG_PTR(2, 0, regs)) -#define SET_RD(insn, regs, val) (*REG_PTR(insn, SH_RD, regs) = (val)) -#define IMM_I(insn) ((s32)(insn) >> 20) -#define IMM_S(insn) (((s32)(insn) >> 25 << 5) | \ - (s32)(((insn) >> 7) & 0x1f)) -#define MASK_FUNCT3 0x7000 - -static int truly_illegal_insn(struct kvm_vcpu *vcpu, - struct kvm_run *run, - ulong insn) -{ - struct kvm_cpu_trap utrap = { 0 }; - - /* Redirect trap to Guest VCPU */ - utrap.sepc = vcpu->arch.guest_context.sepc; - utrap.scause = EXC_INST_ILLEGAL; - utrap.stval = insn; - kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); - - return 1; -} - -static int system_opcode_insn(struct kvm_vcpu *vcpu, - struct kvm_run *run, - ulong insn) -{ - if ((insn & INSN_MASK_WFI) == INSN_MATCH_WFI) { - vcpu->stat.wfi_exit_stat++; - kvm_riscv_vcpu_wfi(vcpu); - vcpu->arch.guest_context.sepc += INSN_LEN(insn); - return 1; - } - - return truly_illegal_insn(vcpu, run, insn); -} - -static int virtual_inst_fault(struct kvm_vcpu *vcpu, struct kvm_run *run, - struct kvm_cpu_trap *trap) -{ - unsigned long insn = trap->stval; - struct kvm_cpu_trap utrap = { 0 }; - struct kvm_cpu_context *ct; - - if (unlikely(INSN_IS_16BIT(insn))) { - if (insn == 0) { - ct = &vcpu->arch.guest_context; - insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, - ct->sepc, - &utrap); - if (utrap.scause) { - utrap.sepc = ct->sepc; - kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); - return 1; - } - } - if (INSN_IS_16BIT(insn)) - return truly_illegal_insn(vcpu, run, insn); - } - - switch ((insn & INSN_OPCODE_MASK) >> INSN_OPCODE_SHIFT) { - case INSN_OPCODE_SYSTEM: - return system_opcode_insn(vcpu, run, insn); - default: - return truly_illegal_insn(vcpu, run, insn); - } -} - -static int emulate_load(struct kvm_vcpu *vcpu, struct kvm_run *run, - unsigned long fault_addr, unsigned long htinst) -{ - u8 data_buf[8]; - unsigned long insn; - int shift = 0, len = 0, insn_len = 0; - struct kvm_cpu_trap utrap = { 0 }; - struct kvm_cpu_context *ct = &vcpu->arch.guest_context; - - /* Determine trapped instruction */ - if (htinst & 0x1) { - /* - * Bit[0] == 1 implies trapped instruction value is - * transformed instruction or custom instruction. - */ - insn = htinst | INSN_16BIT_MASK; - insn_len = (htinst & BIT(1)) ? INSN_LEN(insn) : 2; - } else { - /* - * Bit[0] == 0 implies trapped instruction value is - * zero or special value. - */ - insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, ct->sepc, - &utrap); - if (utrap.scause) { - /* Redirect trap if we failed to read instruction */ - utrap.sepc = ct->sepc; - kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); - return 1; - } - insn_len = INSN_LEN(insn); - } - - /* Decode length of MMIO and shift */ - if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) { - len = 4; - shift = 8 * (sizeof(ulong) - len); - } else if ((insn & INSN_MASK_LB) == INSN_MATCH_LB) { - len = 1; - shift = 8 * (sizeof(ulong) - len); - } else if ((insn & INSN_MASK_LBU) == INSN_MATCH_LBU) { - len = 1; - shift = 8 * (sizeof(ulong) - len); -#ifdef CONFIG_64BIT - } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) { - len = 8; - shift = 8 * (sizeof(ulong) - len); - } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) { - len = 4; -#endif - } else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) { - len = 2; - shift = 8 * (sizeof(ulong) - len); - } else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) { - len = 2; -#ifdef CONFIG_64BIT - } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) { - len = 8; - shift = 8 * (sizeof(ulong) - len); - insn = RVC_RS2S(insn) << SH_RD; - } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP && - ((insn >> SH_RD) & 0x1f)) { - len = 8; - shift = 8 * (sizeof(ulong) - len); -#endif - } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) { - len = 4; - shift = 8 * (sizeof(ulong) - len); - insn = RVC_RS2S(insn) << SH_RD; - } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP && - ((insn >> SH_RD) & 0x1f)) { - len = 4; - shift = 8 * (sizeof(ulong) - len); - } else { - return -EOPNOTSUPP; - } - - /* Fault address should be aligned to length of MMIO */ - if (fault_addr & (len - 1)) - return -EIO; - - /* Save instruction decode info */ - vcpu->arch.mmio_decode.insn = insn; - vcpu->arch.mmio_decode.insn_len = insn_len; - vcpu->arch.mmio_decode.shift = shift; - vcpu->arch.mmio_decode.len = len; - vcpu->arch.mmio_decode.return_handled = 0; - - /* Update MMIO details in kvm_run struct */ - run->mmio.is_write = false; - run->mmio.phys_addr = fault_addr; - run->mmio.len = len; - - /* Try to handle MMIO access in the kernel */ - if (!kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_addr, len, data_buf)) { - /* Successfully handled MMIO access in the kernel so resume */ - memcpy(run->mmio.data, data_buf, len); - vcpu->stat.mmio_exit_kernel++; - kvm_riscv_vcpu_mmio_return(vcpu, run); - return 1; - } - - /* Exit to userspace for MMIO emulation */ - vcpu->stat.mmio_exit_user++; - run->exit_reason = KVM_EXIT_MMIO; - - return 0; -} - -static int emulate_store(struct kvm_vcpu *vcpu, struct kvm_run *run, - unsigned long fault_addr, unsigned long htinst) -{ - u8 data8; - u16 data16; - u32 data32; - u64 data64; - ulong data; - unsigned long insn; - int len = 0, insn_len = 0; - struct kvm_cpu_trap utrap = { 0 }; - struct kvm_cpu_context *ct = &vcpu->arch.guest_context; - - /* Determine trapped instruction */ - if (htinst & 0x1) { - /* - * Bit[0] == 1 implies trapped instruction value is - * transformed instruction or custom instruction. - */ - insn = htinst | INSN_16BIT_MASK; - insn_len = (htinst & BIT(1)) ? INSN_LEN(insn) : 2; - } else { - /* - * Bit[0] == 0 implies trapped instruction value is - * zero or special value. - */ - insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, ct->sepc, - &utrap); - if (utrap.scause) { - /* Redirect trap if we failed to read instruction */ - utrap.sepc = ct->sepc; - kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); - return 1; - } - insn_len = INSN_LEN(insn); - } - - data = GET_RS2(insn, &vcpu->arch.guest_context); - data8 = data16 = data32 = data64 = data; - - if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) { - len = 4; - } else if ((insn & INSN_MASK_SB) == INSN_MATCH_SB) { - len = 1; -#ifdef CONFIG_64BIT - } else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) { - len = 8; -#endif - } else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) { - len = 2; -#ifdef CONFIG_64BIT - } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) { - len = 8; - data64 = GET_RS2S(insn, &vcpu->arch.guest_context); - } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP && - ((insn >> SH_RD) & 0x1f)) { - len = 8; - data64 = GET_RS2C(insn, &vcpu->arch.guest_context); -#endif - } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) { - len = 4; - data32 = GET_RS2S(insn, &vcpu->arch.guest_context); - } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP && - ((insn >> SH_RD) & 0x1f)) { - len = 4; - data32 = GET_RS2C(insn, &vcpu->arch.guest_context); - } else { - return -EOPNOTSUPP; - } - - /* Fault address should be aligned to length of MMIO */ - if (fault_addr & (len - 1)) - return -EIO; - - /* Save instruction decode info */ - vcpu->arch.mmio_decode.insn = insn; - vcpu->arch.mmio_decode.insn_len = insn_len; - vcpu->arch.mmio_decode.shift = 0; - vcpu->arch.mmio_decode.len = len; - vcpu->arch.mmio_decode.return_handled = 0; - - /* Copy data to kvm_run instance */ - switch (len) { - case 1: - *((u8 *)run->mmio.data) = data8; - break; - case 2: - *((u16 *)run->mmio.data) = data16; - break; - case 4: - *((u32 *)run->mmio.data) = data32; - break; - case 8: - *((u64 *)run->mmio.data) = data64; - break; - default: - return -EOPNOTSUPP; - } - - /* Update MMIO details in kvm_run struct */ - run->mmio.is_write = true; - run->mmio.phys_addr = fault_addr; - run->mmio.len = len; - - /* Try to handle MMIO access in the kernel */ - if (!kvm_io_bus_write(vcpu, KVM_MMIO_BUS, - fault_addr, len, run->mmio.data)) { - /* Successfully handled MMIO access in the kernel so resume */ - vcpu->stat.mmio_exit_kernel++; - kvm_riscv_vcpu_mmio_return(vcpu, run); - return 1; - } - - /* Exit to userspace for MMIO emulation */ - vcpu->stat.mmio_exit_user++; - run->exit_reason = KVM_EXIT_MMIO; - - return 0; -} - static int gstage_page_fault(struct kvm_vcpu *vcpu, struct kvm_run *run, struct kvm_cpu_trap *trap) { @@ -430,11 +27,13 @@ static int gstage_page_fault(struct kvm_vcpu *vcpu, struct kvm_run *run, (trap->scause == EXC_STORE_GUEST_PAGE_FAULT && !writable)) { switch (trap->scause) { case EXC_LOAD_GUEST_PAGE_FAULT: - return emulate_load(vcpu, run, fault_addr, - trap->htinst); + return kvm_riscv_vcpu_mmio_load(vcpu, run, + fault_addr, + trap->htinst); case EXC_STORE_GUEST_PAGE_FAULT: - return emulate_store(vcpu, run, fault_addr, - trap->htinst); + return kvm_riscv_vcpu_mmio_store(vcpu, run, + fault_addr, + trap->htinst); default: return -EOPNOTSUPP; }; @@ -448,21 +47,6 @@ static int gstage_page_fault(struct kvm_vcpu *vcpu, struct kvm_run *run, return 1; } -/** - * kvm_riscv_vcpu_wfi -- Emulate wait for interrupt (WFI) behaviour - * - * @vcpu: The VCPU pointer - */ -void kvm_riscv_vcpu_wfi(struct kvm_vcpu *vcpu) -{ - if (!kvm_arch_vcpu_runnable(vcpu)) { - kvm_vcpu_srcu_read_unlock(vcpu); - kvm_vcpu_halt(vcpu); - kvm_vcpu_srcu_read_lock(vcpu); - kvm_clear_request(KVM_REQ_UNHALT, vcpu); - } -} - /** * kvm_riscv_vcpu_unpriv_read -- Read machine word from Guest memory * @@ -601,66 +185,6 @@ void kvm_riscv_vcpu_trap_redirect(struct kvm_vcpu *vcpu, vcpu->arch.guest_context.sepc = csr_read(CSR_VSTVEC); } -/** - * kvm_riscv_vcpu_mmio_return -- Handle MMIO loads after user space emulation - * or in-kernel IO emulation - * - * @vcpu: The VCPU pointer - * @run: The VCPU run struct containing the mmio data - */ -int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) -{ - u8 data8; - u16 data16; - u32 data32; - u64 data64; - ulong insn; - int len, shift; - - if (vcpu->arch.mmio_decode.return_handled) - return 0; - - vcpu->arch.mmio_decode.return_handled = 1; - insn = vcpu->arch.mmio_decode.insn; - - if (run->mmio.is_write) - goto done; - - len = vcpu->arch.mmio_decode.len; - shift = vcpu->arch.mmio_decode.shift; - - switch (len) { - case 1: - data8 = *((u8 *)run->mmio.data); - SET_RD(insn, &vcpu->arch.guest_context, - (ulong)data8 << shift >> shift); - break; - case 2: - data16 = *((u16 *)run->mmio.data); - SET_RD(insn, &vcpu->arch.guest_context, - (ulong)data16 << shift >> shift); - break; - case 4: - data32 = *((u32 *)run->mmio.data); - SET_RD(insn, &vcpu->arch.guest_context, - (ulong)data32 << shift >> shift); - break; - case 8: - data64 = *((u64 *)run->mmio.data); - SET_RD(insn, &vcpu->arch.guest_context, - (ulong)data64 << shift >> shift); - break; - default: - return -EOPNOTSUPP; - } - -done: - /* Move to next instruction */ - vcpu->arch.guest_context.sepc += vcpu->arch.mmio_decode.insn_len; - - return 0; -} - /* * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on * proper exit to userspace. @@ -680,7 +204,7 @@ int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, switch (trap->scause) { case EXC_VIRTUAL_INST_FAULT: if (vcpu->arch.guest_context.hstatus & HSTATUS_SPV) - ret = virtual_inst_fault(vcpu, run, trap); + ret = kvm_riscv_vcpu_virtual_insn(vcpu, run, trap); break; case EXC_INST_GUEST_PAGE_FAULT: case EXC_LOAD_GUEST_PAGE_FAULT: diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c new file mode 100644 index 000000000000..be756879c2ee --- /dev/null +++ b/arch/riscv/kvm/vcpu_insn.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Western Digital Corporation or its affiliates. + * Copyright (c) 2022 Ventana Micro Systems Inc. + */ + +#include +#include + +#define INSN_OPCODE_MASK 0x007c +#define INSN_OPCODE_SHIFT 2 +#define INSN_OPCODE_SYSTEM 28 + +#define INSN_MASK_WFI 0xffffffff +#define INSN_MATCH_WFI 0x10500073 + +#define INSN_MATCH_LB 0x3 +#define INSN_MASK_LB 0x707f +#define INSN_MATCH_LH 0x1003 +#define INSN_MASK_LH 0x707f +#define INSN_MATCH_LW 0x2003 +#define INSN_MASK_LW 0x707f +#define INSN_MATCH_LD 0x3003 +#define INSN_MASK_LD 0x707f +#define INSN_MATCH_LBU 0x4003 +#define INSN_MASK_LBU 0x707f +#define INSN_MATCH_LHU 0x5003 +#define INSN_MASK_LHU 0x707f +#define INSN_MATCH_LWU 0x6003 +#define INSN_MASK_LWU 0x707f +#define INSN_MATCH_SB 0x23 +#define INSN_MASK_SB 0x707f +#define INSN_MATCH_SH 0x1023 +#define INSN_MASK_SH 0x707f +#define INSN_MATCH_SW 0x2023 +#define INSN_MASK_SW 0x707f +#define INSN_MATCH_SD 0x3023 +#define INSN_MASK_SD 0x707f + +#define INSN_MATCH_C_LD 0x6000 +#define INSN_MASK_C_LD 0xe003 +#define INSN_MATCH_C_SD 0xe000 +#define INSN_MASK_C_SD 0xe003 +#define INSN_MATCH_C_LW 0x4000 +#define INSN_MASK_C_LW 0xe003 +#define INSN_MATCH_C_SW 0xc000 +#define INSN_MASK_C_SW 0xe003 +#define INSN_MATCH_C_LDSP 0x6002 +#define INSN_MASK_C_LDSP 0xe003 +#define INSN_MATCH_C_SDSP 0xe002 +#define INSN_MASK_C_SDSP 0xe003 +#define INSN_MATCH_C_LWSP 0x4002 +#define INSN_MASK_C_LWSP 0xe003 +#define INSN_MATCH_C_SWSP 0xc002 +#define INSN_MASK_C_SWSP 0xe003 + +#define INSN_16BIT_MASK 0x3 + +#define INSN_IS_16BIT(insn) (((insn) & INSN_16BIT_MASK) != INSN_16BIT_MASK) + +#define INSN_LEN(insn) (INSN_IS_16BIT(insn) ? 2 : 4) + +#ifdef CONFIG_64BIT +#define LOG_REGBYTES 3 +#else +#define LOG_REGBYTES 2 +#endif +#define REGBYTES (1 << LOG_REGBYTES) + +#define SH_RD 7 +#define SH_RS1 15 +#define SH_RS2 20 +#define SH_RS2C 2 + +#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) +#define RVC_LW_IMM(x) ((RV_X(x, 6, 1) << 2) | \ + (RV_X(x, 10, 3) << 3) | \ + (RV_X(x, 5, 1) << 6)) +#define RVC_LD_IMM(x) ((RV_X(x, 10, 3) << 3) | \ + (RV_X(x, 5, 2) << 6)) +#define RVC_LWSP_IMM(x) ((RV_X(x, 4, 3) << 2) | \ + (RV_X(x, 12, 1) << 5) | \ + (RV_X(x, 2, 2) << 6)) +#define RVC_LDSP_IMM(x) ((RV_X(x, 5, 2) << 3) | \ + (RV_X(x, 12, 1) << 5) | \ + (RV_X(x, 2, 3) << 6)) +#define RVC_SWSP_IMM(x) ((RV_X(x, 9, 4) << 2) | \ + (RV_X(x, 7, 2) << 6)) +#define RVC_SDSP_IMM(x) ((RV_X(x, 10, 3) << 3) | \ + (RV_X(x, 7, 3) << 6)) +#define RVC_RS1S(insn) (8 + RV_X(insn, SH_RD, 3)) +#define RVC_RS2S(insn) (8 + RV_X(insn, SH_RS2C, 3)) +#define RVC_RS2(insn) RV_X(insn, SH_RS2C, 5) + +#define SHIFT_RIGHT(x, y) \ + ((y) < 0 ? ((x) << -(y)) : ((x) >> (y))) + +#define REG_MASK \ + ((1 << (5 + LOG_REGBYTES)) - (1 << LOG_REGBYTES)) + +#define REG_OFFSET(insn, pos) \ + (SHIFT_RIGHT((insn), (pos) - LOG_REGBYTES) & REG_MASK) + +#define REG_PTR(insn, pos, regs) \ + ((ulong *)((ulong)(regs) + REG_OFFSET(insn, pos))) + +#define GET_RM(insn) (((insn) >> 12) & 7) + +#define GET_RS1(insn, regs) (*REG_PTR(insn, SH_RS1, regs)) +#define GET_RS2(insn, regs) (*REG_PTR(insn, SH_RS2, regs)) +#define GET_RS1S(insn, regs) (*REG_PTR(RVC_RS1S(insn), 0, regs)) +#define GET_RS2S(insn, regs) (*REG_PTR(RVC_RS2S(insn), 0, regs)) +#define GET_RS2C(insn, regs) (*REG_PTR(insn, SH_RS2C, regs)) +#define GET_SP(regs) (*REG_PTR(2, 0, regs)) +#define SET_RD(insn, regs, val) (*REG_PTR(insn, SH_RD, regs) = (val)) +#define IMM_I(insn) ((s32)(insn) >> 20) +#define IMM_S(insn) (((s32)(insn) >> 25 << 5) | \ + (s32)(((insn) >> 7) & 0x1f)) +#define MASK_FUNCT3 0x7000 + +static int truly_illegal_insn(struct kvm_vcpu *vcpu, + struct kvm_run *run, + ulong insn) +{ + struct kvm_cpu_trap utrap = { 0 }; + + /* Redirect trap to Guest VCPU */ + utrap.sepc = vcpu->arch.guest_context.sepc; + utrap.scause = EXC_INST_ILLEGAL; + utrap.stval = insn; + kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); + + return 1; +} + +/** + * kvm_riscv_vcpu_wfi -- Emulate wait for interrupt (WFI) behaviour + * + * @vcpu: The VCPU pointer + */ +void kvm_riscv_vcpu_wfi(struct kvm_vcpu *vcpu) +{ + if (!kvm_arch_vcpu_runnable(vcpu)) { + kvm_vcpu_srcu_read_unlock(vcpu); + kvm_vcpu_halt(vcpu); + kvm_vcpu_srcu_read_lock(vcpu); + kvm_clear_request(KVM_REQ_UNHALT, vcpu); + } +} + +static int system_opcode_insn(struct kvm_vcpu *vcpu, + struct kvm_run *run, + ulong insn) +{ + if ((insn & INSN_MASK_WFI) == INSN_MATCH_WFI) { + vcpu->stat.wfi_exit_stat++; + kvm_riscv_vcpu_wfi(vcpu); + vcpu->arch.guest_context.sepc += INSN_LEN(insn); + return 1; + } + + return truly_illegal_insn(vcpu, run, insn); +} + +/** + * kvm_riscv_vcpu_virtual_insn -- Handle virtual instruction trap + * + * @vcpu: The VCPU pointer + * @run: The VCPU run struct containing the mmio data + * @trap: Trap details + * + * Returns > 0 to continue run-loop + * Returns 0 to exit run-loop and handle in user-space. + * Returns < 0 to report failure and exit run-loop + */ +int kvm_riscv_vcpu_virtual_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_cpu_trap *trap) +{ + unsigned long insn = trap->stval; + struct kvm_cpu_trap utrap = { 0 }; + struct kvm_cpu_context *ct; + + if (unlikely(INSN_IS_16BIT(insn))) { + if (insn == 0) { + ct = &vcpu->arch.guest_context; + insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, + ct->sepc, + &utrap); + if (utrap.scause) { + utrap.sepc = ct->sepc; + kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); + return 1; + } + } + if (INSN_IS_16BIT(insn)) + return truly_illegal_insn(vcpu, run, insn); + } + + switch ((insn & INSN_OPCODE_MASK) >> INSN_OPCODE_SHIFT) { + case INSN_OPCODE_SYSTEM: + return system_opcode_insn(vcpu, run, insn); + default: + return truly_illegal_insn(vcpu, run, insn); + } +} + +/** + * kvm_riscv_vcpu_mmio_load -- Emulate MMIO load instruction + * + * @vcpu: The VCPU pointer + * @run: The VCPU run struct containing the mmio data + * @fault_addr: Guest physical address to load + * @htinst: Transformed encoding of the load instruction + * + * Returns > 0 to continue run-loop + * Returns 0 to exit run-loop and handle in user-space. + * Returns < 0 to report failure and exit run-loop + */ +int kvm_riscv_vcpu_mmio_load(struct kvm_vcpu *vcpu, struct kvm_run *run, + unsigned long fault_addr, + unsigned long htinst) +{ + u8 data_buf[8]; + unsigned long insn; + int shift = 0, len = 0, insn_len = 0; + struct kvm_cpu_trap utrap = { 0 }; + struct kvm_cpu_context *ct = &vcpu->arch.guest_context; + + /* Determine trapped instruction */ + if (htinst & 0x1) { + /* + * Bit[0] == 1 implies trapped instruction value is + * transformed instruction or custom instruction. + */ + insn = htinst | INSN_16BIT_MASK; + insn_len = (htinst & BIT(1)) ? INSN_LEN(insn) : 2; + } else { + /* + * Bit[0] == 0 implies trapped instruction value is + * zero or special value. + */ + insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, ct->sepc, + &utrap); + if (utrap.scause) { + /* Redirect trap if we failed to read instruction */ + utrap.sepc = ct->sepc; + kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); + return 1; + } + insn_len = INSN_LEN(insn); + } + + /* Decode length of MMIO and shift */ + if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) { + len = 4; + shift = 8 * (sizeof(ulong) - len); + } else if ((insn & INSN_MASK_LB) == INSN_MATCH_LB) { + len = 1; + shift = 8 * (sizeof(ulong) - len); + } else if ((insn & INSN_MASK_LBU) == INSN_MATCH_LBU) { + len = 1; + shift = 8 * (sizeof(ulong) - len); +#ifdef CONFIG_64BIT + } else if ((insn & INSN_MASK_LD) == INSN_MATCH_LD) { + len = 8; + shift = 8 * (sizeof(ulong) - len); + } else if ((insn & INSN_MASK_LWU) == INSN_MATCH_LWU) { + len = 4; +#endif + } else if ((insn & INSN_MASK_LH) == INSN_MATCH_LH) { + len = 2; + shift = 8 * (sizeof(ulong) - len); + } else if ((insn & INSN_MASK_LHU) == INSN_MATCH_LHU) { + len = 2; +#ifdef CONFIG_64BIT + } else if ((insn & INSN_MASK_C_LD) == INSN_MATCH_C_LD) { + len = 8; + shift = 8 * (sizeof(ulong) - len); + insn = RVC_RS2S(insn) << SH_RD; + } else if ((insn & INSN_MASK_C_LDSP) == INSN_MATCH_C_LDSP && + ((insn >> SH_RD) & 0x1f)) { + len = 8; + shift = 8 * (sizeof(ulong) - len); +#endif + } else if ((insn & INSN_MASK_C_LW) == INSN_MATCH_C_LW) { + len = 4; + shift = 8 * (sizeof(ulong) - len); + insn = RVC_RS2S(insn) << SH_RD; + } else if ((insn & INSN_MASK_C_LWSP) == INSN_MATCH_C_LWSP && + ((insn >> SH_RD) & 0x1f)) { + len = 4; + shift = 8 * (sizeof(ulong) - len); + } else { + return -EOPNOTSUPP; + } + + /* Fault address should be aligned to length of MMIO */ + if (fault_addr & (len - 1)) + return -EIO; + + /* Save instruction decode info */ + vcpu->arch.mmio_decode.insn = insn; + vcpu->arch.mmio_decode.insn_len = insn_len; + vcpu->arch.mmio_decode.shift = shift; + vcpu->arch.mmio_decode.len = len; + vcpu->arch.mmio_decode.return_handled = 0; + + /* Update MMIO details in kvm_run struct */ + run->mmio.is_write = false; + run->mmio.phys_addr = fault_addr; + run->mmio.len = len; + + /* Try to handle MMIO access in the kernel */ + if (!kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_addr, len, data_buf)) { + /* Successfully handled MMIO access in the kernel so resume */ + memcpy(run->mmio.data, data_buf, len); + vcpu->stat.mmio_exit_kernel++; + kvm_riscv_vcpu_mmio_return(vcpu, run); + return 1; + } + + /* Exit to userspace for MMIO emulation */ + vcpu->stat.mmio_exit_user++; + run->exit_reason = KVM_EXIT_MMIO; + + return 0; +} + +/** + * kvm_riscv_vcpu_mmio_store -- Emulate MMIO store instruction + * + * @vcpu: The VCPU pointer + * @run: The VCPU run struct containing the mmio data + * @fault_addr: Guest physical address to store + * @htinst: Transformed encoding of the store instruction + * + * Returns > 0 to continue run-loop + * Returns 0 to exit run-loop and handle in user-space. + * Returns < 0 to report failure and exit run-loop + */ +int kvm_riscv_vcpu_mmio_store(struct kvm_vcpu *vcpu, struct kvm_run *run, + unsigned long fault_addr, + unsigned long htinst) +{ + u8 data8; + u16 data16; + u32 data32; + u64 data64; + ulong data; + unsigned long insn; + int len = 0, insn_len = 0; + struct kvm_cpu_trap utrap = { 0 }; + struct kvm_cpu_context *ct = &vcpu->arch.guest_context; + + /* Determine trapped instruction */ + if (htinst & 0x1) { + /* + * Bit[0] == 1 implies trapped instruction value is + * transformed instruction or custom instruction. + */ + insn = htinst | INSN_16BIT_MASK; + insn_len = (htinst & BIT(1)) ? INSN_LEN(insn) : 2; + } else { + /* + * Bit[0] == 0 implies trapped instruction value is + * zero or special value. + */ + insn = kvm_riscv_vcpu_unpriv_read(vcpu, true, ct->sepc, + &utrap); + if (utrap.scause) { + /* Redirect trap if we failed to read instruction */ + utrap.sepc = ct->sepc; + kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); + return 1; + } + insn_len = INSN_LEN(insn); + } + + data = GET_RS2(insn, &vcpu->arch.guest_context); + data8 = data16 = data32 = data64 = data; + + if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) { + len = 4; + } else if ((insn & INSN_MASK_SB) == INSN_MATCH_SB) { + len = 1; +#ifdef CONFIG_64BIT + } else if ((insn & INSN_MASK_SD) == INSN_MATCH_SD) { + len = 8; +#endif + } else if ((insn & INSN_MASK_SH) == INSN_MATCH_SH) { + len = 2; +#ifdef CONFIG_64BIT + } else if ((insn & INSN_MASK_C_SD) == INSN_MATCH_C_SD) { + len = 8; + data64 = GET_RS2S(insn, &vcpu->arch.guest_context); + } else if ((insn & INSN_MASK_C_SDSP) == INSN_MATCH_C_SDSP && + ((insn >> SH_RD) & 0x1f)) { + len = 8; + data64 = GET_RS2C(insn, &vcpu->arch.guest_context); +#endif + } else if ((insn & INSN_MASK_C_SW) == INSN_MATCH_C_SW) { + len = 4; + data32 = GET_RS2S(insn, &vcpu->arch.guest_context); + } else if ((insn & INSN_MASK_C_SWSP) == INSN_MATCH_C_SWSP && + ((insn >> SH_RD) & 0x1f)) { + len = 4; + data32 = GET_RS2C(insn, &vcpu->arch.guest_context); + } else { + return -EOPNOTSUPP; + } + + /* Fault address should be aligned to length of MMIO */ + if (fault_addr & (len - 1)) + return -EIO; + + /* Save instruction decode info */ + vcpu->arch.mmio_decode.insn = insn; + vcpu->arch.mmio_decode.insn_len = insn_len; + vcpu->arch.mmio_decode.shift = 0; + vcpu->arch.mmio_decode.len = len; + vcpu->arch.mmio_decode.return_handled = 0; + + /* Copy data to kvm_run instance */ + switch (len) { + case 1: + *((u8 *)run->mmio.data) = data8; + break; + case 2: + *((u16 *)run->mmio.data) = data16; + break; + case 4: + *((u32 *)run->mmio.data) = data32; + break; + case 8: + *((u64 *)run->mmio.data) = data64; + break; + default: + return -EOPNOTSUPP; + } + + /* Update MMIO details in kvm_run struct */ + run->mmio.is_write = true; + run->mmio.phys_addr = fault_addr; + run->mmio.len = len; + + /* Try to handle MMIO access in the kernel */ + if (!kvm_io_bus_write(vcpu, KVM_MMIO_BUS, + fault_addr, len, run->mmio.data)) { + /* Successfully handled MMIO access in the kernel so resume */ + vcpu->stat.mmio_exit_kernel++; + kvm_riscv_vcpu_mmio_return(vcpu, run); + return 1; + } + + /* Exit to userspace for MMIO emulation */ + vcpu->stat.mmio_exit_user++; + run->exit_reason = KVM_EXIT_MMIO; + + return 0; +} + +/** + * kvm_riscv_vcpu_mmio_return -- Handle MMIO loads after user space emulation + * or in-kernel IO emulation + * + * @vcpu: The VCPU pointer + * @run: The VCPU run struct containing the mmio data + */ +int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + u8 data8; + u16 data16; + u32 data32; + u64 data64; + ulong insn; + int len, shift; + + if (vcpu->arch.mmio_decode.return_handled) + return 0; + + vcpu->arch.mmio_decode.return_handled = 1; + insn = vcpu->arch.mmio_decode.insn; + + if (run->mmio.is_write) + goto done; + + len = vcpu->arch.mmio_decode.len; + shift = vcpu->arch.mmio_decode.shift; + + switch (len) { + case 1: + data8 = *((u8 *)run->mmio.data); + SET_RD(insn, &vcpu->arch.guest_context, + (ulong)data8 << shift >> shift); + break; + case 2: + data16 = *((u16 *)run->mmio.data); + SET_RD(insn, &vcpu->arch.guest_context, + (ulong)data16 << shift >> shift); + break; + case 4: + data32 = *((u32 *)run->mmio.data); + SET_RD(insn, &vcpu->arch.guest_context, + (ulong)data32 << shift >> shift); + break; + case 8: + data64 = *((u64 *)run->mmio.data); + SET_RD(insn, &vcpu->arch.guest_context, + (ulong)data64 << shift >> shift); + break; + default: + return -EOPNOTSUPP; + } + +done: + /* Move to next instruction */ + vcpu->arch.guest_context.sepc += vcpu->arch.mmio_decode.insn_len; + + return 0; +} From 1222b55cee2396a1a286e924d9f6abb6d7a04f55 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 29 Jul 2022 17:14:46 +0530 Subject: [PATCH 1391/1436] RISC-V: KVM: Add extensible system instruction emulation framework We will be emulating more system instructions in near future with upcoming AIA, PMU, Nested and other virtualization features. To accommodate above, we add an extensible system instruction emulation framework in vcpu_insn.c. Signed-off-by: Anup Patel Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_vcpu_insn.h | 9 +++ arch/riscv/kvm/vcpu_insn.c | 84 +++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/arch/riscv/include/asm/kvm_vcpu_insn.h b/arch/riscv/include/asm/kvm_vcpu_insn.h index 4e3ba4e84d0f..3351eb61a251 100644 --- a/arch/riscv/include/asm/kvm_vcpu_insn.h +++ b/arch/riscv/include/asm/kvm_vcpu_insn.h @@ -18,6 +18,15 @@ struct kvm_mmio_decode { int return_handled; }; +/* Return values used by function emulating a particular instruction */ +enum kvm_insn_return { + KVM_INSN_EXIT_TO_USER_SPACE = 0, + KVM_INSN_CONTINUE_NEXT_SEPC, + KVM_INSN_CONTINUE_SAME_SEPC, + KVM_INSN_ILLEGAL_TRAP, + KVM_INSN_VIRTUAL_TRAP +}; + void kvm_riscv_vcpu_wfi(struct kvm_vcpu *vcpu); int kvm_riscv_vcpu_virtual_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, struct kvm_cpu_trap *trap); diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c index be756879c2ee..75ca62a7fba5 100644 --- a/arch/riscv/kvm/vcpu_insn.c +++ b/arch/riscv/kvm/vcpu_insn.c @@ -118,8 +118,24 @@ (s32)(((insn) >> 7) & 0x1f)) #define MASK_FUNCT3 0x7000 -static int truly_illegal_insn(struct kvm_vcpu *vcpu, - struct kvm_run *run, +struct insn_func { + unsigned long mask; + unsigned long match; + /* + * Possible return values are as follows: + * 1) Returns < 0 for error case + * 2) Returns 0 for exit to user-space + * 3) Returns 1 to continue with next sepc + * 4) Returns 2 to continue with same sepc + * 5) Returns 3 to inject illegal instruction trap and continue + * 6) Returns 4 to inject virtual instruction trap and continue + * + * Use enum kvm_insn_return for return values + */ + int (*func)(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn); +}; + +static int truly_illegal_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn) { struct kvm_cpu_trap utrap = { 0 }; @@ -128,6 +144,24 @@ static int truly_illegal_insn(struct kvm_vcpu *vcpu, utrap.sepc = vcpu->arch.guest_context.sepc; utrap.scause = EXC_INST_ILLEGAL; utrap.stval = insn; + utrap.htval = 0; + utrap.htinst = 0; + kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); + + return 1; +} + +static int truly_virtual_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, + ulong insn) +{ + struct kvm_cpu_trap utrap = { 0 }; + + /* Redirect trap to Guest VCPU */ + utrap.sepc = vcpu->arch.guest_context.sepc; + utrap.scause = EXC_VIRTUAL_INST_FAULT; + utrap.stval = insn; + utrap.htval = 0; + utrap.htinst = 0; kvm_riscv_vcpu_trap_redirect(vcpu, &utrap); return 1; @@ -148,18 +182,48 @@ void kvm_riscv_vcpu_wfi(struct kvm_vcpu *vcpu) } } -static int system_opcode_insn(struct kvm_vcpu *vcpu, - struct kvm_run *run, +static int wfi_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn) +{ + vcpu->stat.wfi_exit_stat++; + kvm_riscv_vcpu_wfi(vcpu); + return KVM_INSN_CONTINUE_NEXT_SEPC; +} + +static const struct insn_func system_opcode_funcs[] = { + { + .mask = INSN_MASK_WFI, + .match = INSN_MATCH_WFI, + .func = wfi_insn, + }, +}; + +static int system_opcode_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn) { - if ((insn & INSN_MASK_WFI) == INSN_MATCH_WFI) { - vcpu->stat.wfi_exit_stat++; - kvm_riscv_vcpu_wfi(vcpu); - vcpu->arch.guest_context.sepc += INSN_LEN(insn); - return 1; + int i, rc = KVM_INSN_ILLEGAL_TRAP; + const struct insn_func *ifn; + + for (i = 0; i < ARRAY_SIZE(system_opcode_funcs); i++) { + ifn = &system_opcode_funcs[i]; + if ((insn & ifn->mask) == ifn->match) { + rc = ifn->func(vcpu, run, insn); + break; + } } - return truly_illegal_insn(vcpu, run, insn); + switch (rc) { + case KVM_INSN_ILLEGAL_TRAP: + return truly_illegal_insn(vcpu, run, insn); + case KVM_INSN_VIRTUAL_TRAP: + return truly_virtual_insn(vcpu, run, insn); + case KVM_INSN_CONTINUE_NEXT_SEPC: + vcpu->arch.guest_context.sepc += INSN_LEN(insn); + break; + default: + break; + } + + return (rc <= 0) ? rc : 1; } /** From 8a061562e2f2b32bfb5bff5bf3afc64e37d95a27 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 29 Jul 2022 17:14:53 +0530 Subject: [PATCH 1392/1436] RISC-V: KVM: Add extensible CSR emulation framework We add an extensible CSR emulation framework which is based upon the existing system instruction emulation. This will be useful to upcoming AIA, PMU, Nested and other virtualization features. The CSR emulation framework also has provision to emulate CSR in user space but this will be used only in very specific cases such as AIA IMSIC CSR emulation in user space or vendor specific CSR emulation in user space. By default, all CSRs not handled by KVM RISC-V will be redirected back to Guest VCPU as illegal instruction trap. Signed-off-by: Anup Patel Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_host.h | 5 + arch/riscv/include/asm/kvm_vcpu_insn.h | 6 + arch/riscv/kvm/vcpu.c | 34 +++-- arch/riscv/kvm/vcpu_insn.c | 172 ++++++++++++++++++++++++- include/uapi/linux/kvm.h | 8 ++ 5 files changed, 209 insertions(+), 16 deletions(-) diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index d482d771eba4..59a0cf2ca7b9 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -65,6 +65,8 @@ struct kvm_vcpu_stat { u64 wfi_exit_stat; u64 mmio_exit_user; u64 mmio_exit_kernel; + u64 csr_exit_user; + u64 csr_exit_kernel; u64 exits; }; @@ -210,6 +212,9 @@ struct kvm_vcpu_arch { /* MMIO instruction details */ struct kvm_mmio_decode mmio_decode; + /* CSR instruction details */ + struct kvm_csr_decode csr_decode; + /* SBI context */ struct kvm_sbi_context sbi_context; diff --git a/arch/riscv/include/asm/kvm_vcpu_insn.h b/arch/riscv/include/asm/kvm_vcpu_insn.h index 3351eb61a251..350011c83581 100644 --- a/arch/riscv/include/asm/kvm_vcpu_insn.h +++ b/arch/riscv/include/asm/kvm_vcpu_insn.h @@ -18,6 +18,11 @@ struct kvm_mmio_decode { int return_handled; }; +struct kvm_csr_decode { + unsigned long insn; + int return_handled; +}; + /* Return values used by function emulating a particular instruction */ enum kvm_insn_return { KVM_INSN_EXIT_TO_USER_SPACE = 0, @@ -28,6 +33,7 @@ enum kvm_insn_return { }; void kvm_riscv_vcpu_wfi(struct kvm_vcpu *vcpu); +int kvm_riscv_vcpu_csr_return(struct kvm_vcpu *vcpu, struct kvm_run *run); int kvm_riscv_vcpu_virtual_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, struct kvm_cpu_trap *trap); diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index a3c051cb070c..3c95924d38c7 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -26,6 +26,8 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { STATS_DESC_COUNTER(VCPU, wfi_exit_stat), STATS_DESC_COUNTER(VCPU, mmio_exit_user), STATS_DESC_COUNTER(VCPU, mmio_exit_kernel), + STATS_DESC_COUNTER(VCPU, csr_exit_user), + STATS_DESC_COUNTER(VCPU, csr_exit_kernel), STATS_DESC_COUNTER(VCPU, exits) }; @@ -899,22 +901,26 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) kvm_vcpu_srcu_read_lock(vcpu); - /* Process MMIO value returned from user-space */ - if (run->exit_reason == KVM_EXIT_MMIO) { + switch (run->exit_reason) { + case KVM_EXIT_MMIO: + /* Process MMIO value returned from user-space */ ret = kvm_riscv_vcpu_mmio_return(vcpu, vcpu->run); - if (ret) { - kvm_vcpu_srcu_read_unlock(vcpu); - return ret; - } - } - - /* Process SBI value returned from user-space */ - if (run->exit_reason == KVM_EXIT_RISCV_SBI) { + break; + case KVM_EXIT_RISCV_SBI: + /* Process SBI value returned from user-space */ ret = kvm_riscv_vcpu_sbi_return(vcpu, vcpu->run); - if (ret) { - kvm_vcpu_srcu_read_unlock(vcpu); - return ret; - } + break; + case KVM_EXIT_RISCV_CSR: + /* Process CSR value returned from user-space */ + ret = kvm_riscv_vcpu_csr_return(vcpu, vcpu->run); + break; + default: + ret = 0; + break; + } + if (ret) { + kvm_vcpu_srcu_read_unlock(vcpu); + return ret; } if (run->immediate_exit) { diff --git a/arch/riscv/kvm/vcpu_insn.c b/arch/riscv/kvm/vcpu_insn.c index 75ca62a7fba5..7eb90a47b571 100644 --- a/arch/riscv/kvm/vcpu_insn.c +++ b/arch/riscv/kvm/vcpu_insn.c @@ -14,6 +14,19 @@ #define INSN_MASK_WFI 0xffffffff #define INSN_MATCH_WFI 0x10500073 +#define INSN_MATCH_CSRRW 0x1073 +#define INSN_MASK_CSRRW 0x707f +#define INSN_MATCH_CSRRS 0x2073 +#define INSN_MASK_CSRRS 0x707f +#define INSN_MATCH_CSRRC 0x3073 +#define INSN_MASK_CSRRC 0x707f +#define INSN_MATCH_CSRRWI 0x5073 +#define INSN_MASK_CSRRWI 0x707f +#define INSN_MATCH_CSRRSI 0x6073 +#define INSN_MASK_CSRRSI 0x707f +#define INSN_MATCH_CSRRCI 0x7073 +#define INSN_MASK_CSRRCI 0x707f + #define INSN_MATCH_LB 0x3 #define INSN_MASK_LB 0x707f #define INSN_MATCH_LH 0x1003 @@ -71,6 +84,7 @@ #define SH_RS1 15 #define SH_RS2 20 #define SH_RS2C 2 +#define MASK_RX 0x1f #define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1)) #define RVC_LW_IMM(x) ((RV_X(x, 6, 1) << 2) | \ @@ -104,7 +118,7 @@ #define REG_PTR(insn, pos, regs) \ ((ulong *)((ulong)(regs) + REG_OFFSET(insn, pos))) -#define GET_RM(insn) (((insn) >> 12) & 7) +#define GET_FUNCT3(insn) (((insn) >> 12) & 7) #define GET_RS1(insn, regs) (*REG_PTR(insn, SH_RS1, regs)) #define GET_RS2(insn, regs) (*REG_PTR(insn, SH_RS2, regs)) @@ -116,7 +130,6 @@ #define IMM_I(insn) ((s32)(insn) >> 20) #define IMM_S(insn) (((s32)(insn) >> 25 << 5) | \ (s32)(((insn) >> 7) & 0x1f)) -#define MASK_FUNCT3 0x7000 struct insn_func { unsigned long mask; @@ -189,7 +202,162 @@ static int wfi_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn) return KVM_INSN_CONTINUE_NEXT_SEPC; } +struct csr_func { + unsigned int base; + unsigned int count; + /* + * Possible return values are as same as "func" callback in + * "struct insn_func". + */ + int (*func)(struct kvm_vcpu *vcpu, unsigned int csr_num, + unsigned long *val, unsigned long new_val, + unsigned long wr_mask); +}; + +static const struct csr_func csr_funcs[] = { }; + +/** + * kvm_riscv_vcpu_csr_return -- Handle CSR read/write after user space + * emulation or in-kernel emulation + * + * @vcpu: The VCPU pointer + * @run: The VCPU run struct containing the CSR data + * + * Returns > 0 upon failure and 0 upon success + */ +int kvm_riscv_vcpu_csr_return(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + ulong insn; + + if (vcpu->arch.csr_decode.return_handled) + return 0; + vcpu->arch.csr_decode.return_handled = 1; + + /* Update destination register for CSR reads */ + insn = vcpu->arch.csr_decode.insn; + if ((insn >> SH_RD) & MASK_RX) + SET_RD(insn, &vcpu->arch.guest_context, + run->riscv_csr.ret_value); + + /* Move to next instruction */ + vcpu->arch.guest_context.sepc += INSN_LEN(insn); + + return 0; +} + +static int csr_insn(struct kvm_vcpu *vcpu, struct kvm_run *run, ulong insn) +{ + int i, rc = KVM_INSN_ILLEGAL_TRAP; + unsigned int csr_num = insn >> SH_RS2; + unsigned int rs1_num = (insn >> SH_RS1) & MASK_RX; + ulong rs1_val = GET_RS1(insn, &vcpu->arch.guest_context); + const struct csr_func *tcfn, *cfn = NULL; + ulong val = 0, wr_mask = 0, new_val = 0; + + /* Decode the CSR instruction */ + switch (GET_FUNCT3(insn)) { + case GET_FUNCT3(INSN_MATCH_CSRRW): + wr_mask = -1UL; + new_val = rs1_val; + break; + case GET_FUNCT3(INSN_MATCH_CSRRS): + wr_mask = rs1_val; + new_val = -1UL; + break; + case GET_FUNCT3(INSN_MATCH_CSRRC): + wr_mask = rs1_val; + new_val = 0; + break; + case GET_FUNCT3(INSN_MATCH_CSRRWI): + wr_mask = -1UL; + new_val = rs1_num; + break; + case GET_FUNCT3(INSN_MATCH_CSRRSI): + wr_mask = rs1_num; + new_val = -1UL; + break; + case GET_FUNCT3(INSN_MATCH_CSRRCI): + wr_mask = rs1_num; + new_val = 0; + break; + default: + return rc; + } + + /* Save instruction decode info */ + vcpu->arch.csr_decode.insn = insn; + vcpu->arch.csr_decode.return_handled = 0; + + /* Update CSR details in kvm_run struct */ + run->riscv_csr.csr_num = csr_num; + run->riscv_csr.new_value = new_val; + run->riscv_csr.write_mask = wr_mask; + run->riscv_csr.ret_value = 0; + + /* Find in-kernel CSR function */ + for (i = 0; i < ARRAY_SIZE(csr_funcs); i++) { + tcfn = &csr_funcs[i]; + if ((tcfn->base <= csr_num) && + (csr_num < (tcfn->base + tcfn->count))) { + cfn = tcfn; + break; + } + } + + /* First try in-kernel CSR emulation */ + if (cfn && cfn->func) { + rc = cfn->func(vcpu, csr_num, &val, new_val, wr_mask); + if (rc > KVM_INSN_EXIT_TO_USER_SPACE) { + if (rc == KVM_INSN_CONTINUE_NEXT_SEPC) { + run->riscv_csr.ret_value = val; + vcpu->stat.csr_exit_kernel++; + kvm_riscv_vcpu_csr_return(vcpu, run); + rc = KVM_INSN_CONTINUE_SAME_SEPC; + } + return rc; + } + } + + /* Exit to user-space for CSR emulation */ + if (rc <= KVM_INSN_EXIT_TO_USER_SPACE) { + vcpu->stat.csr_exit_user++; + run->exit_reason = KVM_EXIT_RISCV_CSR; + } + + return rc; +} + static const struct insn_func system_opcode_funcs[] = { + { + .mask = INSN_MASK_CSRRW, + .match = INSN_MATCH_CSRRW, + .func = csr_insn, + }, + { + .mask = INSN_MASK_CSRRS, + .match = INSN_MATCH_CSRRS, + .func = csr_insn, + }, + { + .mask = INSN_MASK_CSRRC, + .match = INSN_MATCH_CSRRC, + .func = csr_insn, + }, + { + .mask = INSN_MASK_CSRRWI, + .match = INSN_MATCH_CSRRWI, + .func = csr_insn, + }, + { + .mask = INSN_MASK_CSRRSI, + .match = INSN_MATCH_CSRRSI, + .func = csr_insn, + }, + { + .mask = INSN_MASK_CSRRCI, + .match = INSN_MATCH_CSRRCI, + .func = csr_insn, + }, { .mask = INSN_MASK_WFI, .match = INSN_MATCH_WFI, diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 860f867c50c0..0c1f42a40fd3 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -270,6 +270,7 @@ struct kvm_xen_exit { #define KVM_EXIT_X86_BUS_LOCK 33 #define KVM_EXIT_XEN 34 #define KVM_EXIT_RISCV_SBI 35 +#define KVM_EXIT_RISCV_CSR 36 /* For KVM_EXIT_INTERNAL_ERROR */ /* Emulate instruction failed. */ @@ -496,6 +497,13 @@ struct kvm_run { unsigned long args[6]; unsigned long ret[2]; } riscv_sbi; + /* KVM_EXIT_RISCV_CSR */ + struct { + unsigned long csr_num; + unsigned long new_value; + unsigned long write_mask; + unsigned long ret_value; + } riscv_csr; /* Fix the size of the union. */ char padding[256]; }; From 4ab0e470c06dc741f6583578da44961669331b78 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 29 Jul 2022 17:15:00 +0530 Subject: [PATCH 1393/1436] KVM: Add gfp_custom flag in struct kvm_mmu_memory_cache The kvm_mmu_topup_memory_cache() always uses GFP_KERNEL_ACCOUNT for memory allocation which prevents it's use in atomic context. To address this limitation of kvm_mmu_topup_memory_cache(), we add gfp_custom flag in struct kvm_mmu_memory_cache. When the gfp_custom flag is set to some GFP_xyz flags, the kvm_mmu_topup_memory_cache() will use that instead of GFP_KERNEL_ACCOUNT. Signed-off-by: Anup Patel Reviewed-by: Atish Patra Signed-off-by: Anup Patel --- include/linux/kvm_types.h | 1 + virt/kvm/kvm_main.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index ac1ebb37a0ff..1dcfba68076a 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h @@ -87,6 +87,7 @@ struct gfn_to_pfn_cache { struct kvm_mmu_memory_cache { int nobjs; gfp_t gfp_zero; + gfp_t gfp_custom; struct kmem_cache *kmem_cache; void *objects[KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE]; }; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index a49df8988cd6..e3a6f7647474 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -386,7 +386,9 @@ int kvm_mmu_topup_memory_cache(struct kvm_mmu_memory_cache *mc, int min) if (mc->nobjs >= min) return 0; while (mc->nobjs < ARRAY_SIZE(mc->objects)) { - obj = mmu_memory_cache_alloc_obj(mc, GFP_KERNEL_ACCOUNT); + obj = mmu_memory_cache_alloc_obj(mc, (mc->gfp_custom) ? + mc->gfp_custom : + GFP_KERNEL_ACCOUNT); if (!obj) return mc->nobjs >= min ? 0 : -ENOMEM; mc->objects[mc->nobjs++] = obj; From c9d57373fc87a3ad00d12cffd0bb4c8108c73ff9 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 29 Jul 2022 17:15:06 +0530 Subject: [PATCH 1394/1436] RISC-V: KVM: Add G-stage ioremap() and iounmap() functions The in-kernel AIA IMSIC support requires on-demand mapping / unmapping of Guest IMSIC address to Host IMSIC guest files. To help achieve this, we add kvm_riscv_stage2_ioremap() and kvm_riscv_stage2_iounmap() functions. These new functions for updating G-stage page table mappings will be called in atomic context so we have special "in_atomic" parameter for this purpose. Signed-off-by: Anup Patel Reviewed-by: Atish Patra Signed-off-by: Anup Patel --- arch/riscv/include/asm/kvm_host.h | 5 +++++ arch/riscv/kvm/mmu.c | 18 ++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h index 59a0cf2ca7b9..60c517e4d576 100644 --- a/arch/riscv/include/asm/kvm_host.h +++ b/arch/riscv/include/asm/kvm_host.h @@ -284,6 +284,11 @@ void kvm_riscv_hfence_vvma_gva(struct kvm *kvm, void kvm_riscv_hfence_vvma_all(struct kvm *kvm, unsigned long hbase, unsigned long hmask); +int kvm_riscv_gstage_ioremap(struct kvm *kvm, gpa_t gpa, + phys_addr_t hpa, unsigned long size, + bool writable, bool in_atomic); +void kvm_riscv_gstage_iounmap(struct kvm *kvm, gpa_t gpa, + unsigned long size); int kvm_riscv_gstage_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot, gpa_t gpa, unsigned long hva, bool is_write); diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c index b75d4e200064..f7862ca4c4c6 100644 --- a/arch/riscv/kvm/mmu.c +++ b/arch/riscv/kvm/mmu.c @@ -343,8 +343,9 @@ static void gstage_wp_memory_region(struct kvm *kvm, int slot) kvm_flush_remote_tlbs(kvm); } -static int gstage_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa, - unsigned long size, bool writable) +int kvm_riscv_gstage_ioremap(struct kvm *kvm, gpa_t gpa, + phys_addr_t hpa, unsigned long size, + bool writable, bool in_atomic) { pte_t pte; int ret = 0; @@ -353,6 +354,7 @@ static int gstage_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa, struct kvm_mmu_memory_cache pcache; memset(&pcache, 0, sizeof(pcache)); + pcache.gfp_custom = (in_atomic) ? GFP_ATOMIC | __GFP_ACCOUNT : 0; pcache.gfp_zero = __GFP_ZERO; end = (gpa + size + PAGE_SIZE - 1) & PAGE_MASK; @@ -382,6 +384,13 @@ out: return ret; } +void kvm_riscv_gstage_iounmap(struct kvm *kvm, gpa_t gpa, unsigned long size) +{ + spin_lock(&kvm->mmu_lock); + gstage_unmap_range(kvm, gpa, size, false); + spin_unlock(&kvm->mmu_lock); +} + void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm, struct kvm_memory_slot *slot, gfn_t gfn_offset, @@ -517,8 +526,9 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, goto out; } - ret = gstage_ioremap(kvm, gpa, pa, - vm_end - vm_start, writable); + ret = kvm_riscv_gstage_ioremap(kvm, gpa, pa, + vm_end - vm_start, + writable, false); if (ret) break; } From 659ad6d82c3121088daeaa38ba94d182b55bbb22 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 29 Jul 2022 17:15:12 +0530 Subject: [PATCH 1395/1436] RISC-V: KVM: Use PAGE_KERNEL_IO in kvm_riscv_gstage_ioremap() When the host has Svpbmt extension, we should use page based memory type 2 (i.e. IO) for IO mappings in the G-stage page table. To achieve this, we replace use of PAGE_KERNEL with PAGE_KERNEL_IO in the kvm_riscv_gstage_ioremap(). Signed-off-by: Anup Patel Reviewed-by: Atish Patra Signed-off-by: Anup Patel --- arch/riscv/kvm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c index f7862ca4c4c6..bc545aef6034 100644 --- a/arch/riscv/kvm/mmu.c +++ b/arch/riscv/kvm/mmu.c @@ -361,7 +361,7 @@ int kvm_riscv_gstage_ioremap(struct kvm *kvm, gpa_t gpa, pfn = __phys_to_pfn(hpa); for (addr = gpa; addr < end; addr += PAGE_SIZE) { - pte = pfn_pte(pfn, PAGE_KERNEL); + pte = pfn_pte(pfn, PAGE_KERNEL_IO); if (!writable) pte = pte_wrprotect(pte); From 6bb2e00ea304ffc0446f345c46fe22713ce43cbf Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 29 Jul 2022 17:15:18 +0530 Subject: [PATCH 1396/1436] RISC-V: KVM: Add support for Svpbmt inside Guest/VM The Guest/VM can use Svpbmt in VS-stage page tables when allowed by the Hypervisor using the henvcfg.PBMTE bit. We add Svpbmt support for the KVM Guest/VM which can be enabled/disabled by the KVM user-space (QEMU/KVMTOOL) using the ISA extension ONE_REG interface. Signed-off-by: Anup Patel Reviewed-by: Atish Patra Signed-off-by: Anup Patel --- arch/riscv/include/asm/csr.h | 16 ++++++++++++++++ arch/riscv/include/uapi/asm/kvm.h | 1 + arch/riscv/kvm/vcpu.c | 16 ++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 6d85655e7edf..17516afc389a 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -156,6 +156,18 @@ (_AC(1, UL) << IRQ_S_TIMER) | \ (_AC(1, UL) << IRQ_S_EXT)) +/* xENVCFG flags */ +#define ENVCFG_STCE (_AC(1, ULL) << 63) +#define ENVCFG_PBMTE (_AC(1, ULL) << 62) +#define ENVCFG_CBZE (_AC(1, UL) << 7) +#define ENVCFG_CBCFE (_AC(1, UL) << 6) +#define ENVCFG_CBIE_SHIFT 4 +#define ENVCFG_CBIE (_AC(0x3, UL) << ENVCFG_CBIE_SHIFT) +#define ENVCFG_CBIE_ILL _AC(0x0, UL) +#define ENVCFG_CBIE_FLUSH _AC(0x1, UL) +#define ENVCFG_CBIE_INV _AC(0x3, UL) +#define ENVCFG_FIOM _AC(0x1, UL) + /* symbolic CSR names: */ #define CSR_CYCLE 0xc00 #define CSR_TIME 0xc01 @@ -252,7 +264,9 @@ #define CSR_HTIMEDELTA 0x605 #define CSR_HCOUNTEREN 0x606 #define CSR_HGEIE 0x607 +#define CSR_HENVCFG 0x60a #define CSR_HTIMEDELTAH 0x615 +#define CSR_HENVCFGH 0x61a #define CSR_HTVAL 0x643 #define CSR_HIP 0x644 #define CSR_HVIP 0x645 @@ -264,6 +278,8 @@ #define CSR_MISA 0x301 #define CSR_MIE 0x304 #define CSR_MTVEC 0x305 +#define CSR_MENVCFG 0x30a +#define CSR_MENVCFGH 0x31a #define CSR_MSCRATCH 0x340 #define CSR_MEPC 0x341 #define CSR_MCAUSE 0x342 diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h index 6119368ba6d5..24b2a6e27698 100644 --- a/arch/riscv/include/uapi/asm/kvm.h +++ b/arch/riscv/include/uapi/asm/kvm.h @@ -96,6 +96,7 @@ enum KVM_RISCV_ISA_EXT_ID { KVM_RISCV_ISA_EXT_H, KVM_RISCV_ISA_EXT_I, KVM_RISCV_ISA_EXT_M, + KVM_RISCV_ISA_EXT_SVPBMT, KVM_RISCV_ISA_EXT_MAX, }; diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 3c95924d38c7..5d271b597613 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -51,6 +51,7 @@ static const unsigned long kvm_isa_ext_arr[] = { RISCV_ISA_EXT_h, RISCV_ISA_EXT_i, RISCV_ISA_EXT_m, + RISCV_ISA_EXT_SVPBMT, }; static unsigned long kvm_riscv_vcpu_base2isa_ext(unsigned long base_ext) @@ -777,6 +778,19 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, return -EINVAL; } +static void kvm_riscv_vcpu_update_config(const unsigned long *isa) +{ + u64 henvcfg = 0; + + if (__riscv_isa_extension_available(isa, RISCV_ISA_EXT_SVPBMT)) + henvcfg |= ENVCFG_PBMTE; + + csr_write(CSR_HENVCFG, henvcfg); +#ifdef CONFIG_32BIT + csr_write(CSR_HENVCFGH, henvcfg >> 32); +#endif +} + void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) { struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr; @@ -791,6 +805,8 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) csr_write(CSR_HVIP, csr->hvip); csr_write(CSR_VSATP, csr->vsatp); + kvm_riscv_vcpu_update_config(vcpu->arch.isa); + kvm_riscv_gstage_update_hgatp(vcpu); kvm_riscv_vcpu_timer_restore(vcpu); From 273aaa24369cb8d0f246bb16f7122b91a1ef5188 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 29 Jul 2022 15:45:17 +0200 Subject: [PATCH 1397/1436] docs: embargoed-hardware-issues: fix invalid AMD contact email The current AMD contact info email address is incorrect, so fix it up to use the correct one. Cc: Jonathan Corbet Cc: Alex Shi Cc: Yanteng Si Cc: Hu Haowen Cc: Tom Lendacky Acked-by: Tom Lendacky Link: https://lore.kernel.org/r/20220729134517.2284700-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman --- Documentation/process/embargoed-hardware-issues.rst | 2 +- .../translations/zh_CN/process/embargoed-hardware-issues.rst | 2 +- .../translations/zh_TW/process/embargoed-hardware-issues.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/process/embargoed-hardware-issues.rst b/Documentation/process/embargoed-hardware-issues.rst index 48bd249d96b9..b6b4481e2474 100644 --- a/Documentation/process/embargoed-hardware-issues.rst +++ b/Documentation/process/embargoed-hardware-issues.rst @@ -244,7 +244,7 @@ disclosure of a particular issue, unless requested by a response team or by an involved disclosed party. The current ambassadors list: ============= ======================================================== - AMD Tom Lendacky + AMD Tom Lendacky Ampere Darren Hart ARM Catalin Marinas IBM Power Anton Blanchard diff --git a/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst b/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst index 88273ebe7823..cf5f1fca3d92 100644 --- a/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst +++ b/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst @@ -174,7 +174,7 @@ CVE分配 ============= ======================================================== ARM - AMD Tom Lendacky + AMD Tom Lendacky IBM Intel Tony Luck Qualcomm Trilok Soni diff --git a/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst b/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst index 6c76fc96131a..fbde3e26eda5 100644 --- a/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst +++ b/Documentation/translations/zh_TW/process/embargoed-hardware-issues.rst @@ -177,7 +177,7 @@ CVE分配 ============= ======================================================== ARM - AMD Tom Lendacky + AMD Tom Lendacky IBM Intel Tony Luck Qualcomm Trilok Soni From 944ad762bb47529da644e19bad65b1ef24e57844 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Jul 2022 18:43:12 +0200 Subject: [PATCH 1398/1436] dt-bindings: display: use spi-peripheral-props.yaml Instead of listing directly properties typical for SPI peripherals, reference the spi-peripheral-props.yaml schema. This allows using all properties typical for SPI-connected devices, even these which device bindings author did not tried yet. Remove the spi-* properties which now come via spi-peripheral-props.yaml schema, except for the cases when device schema adds some constraints like maximum frequency. While changing additionalProperties->unevaluatedProperties, put it in typical place, just before example DTS. The sitronix,st7735r references also panel-common.yaml and lists explicitly allowed properties, thus here reference only spi-peripheral-props.yaml for purpose of documenting the SPI slave device and bringing spi-max-frequency type validation. Signed-off-by: Krzysztof Kozlowski Acked-by: Sam Ravnborg Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220727164312.385836-1-krzysztof.kozlowski@linaro.org --- .../devicetree/bindings/display/panel/lg,lg4573.yaml | 2 +- .../devicetree/bindings/display/sitronix,st7735r.yaml | 1 + .../devicetree/bindings/display/solomon,ssd1307fb.yaml | 7 +++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/display/panel/lg,lg4573.yaml b/Documentation/devicetree/bindings/display/panel/lg,lg4573.yaml index b4314ce7b411..ee357e139ac0 100644 --- a/Documentation/devicetree/bindings/display/panel/lg,lg4573.yaml +++ b/Documentation/devicetree/bindings/display/panel/lg,lg4573.yaml @@ -15,13 +15,13 @@ maintainers: allOf: - $ref: panel-common.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# properties: compatible: const: lg,lg4573 reg: true - spi-max-frequency: true required: - compatible diff --git a/Documentation/devicetree/bindings/display/sitronix,st7735r.yaml b/Documentation/devicetree/bindings/display/sitronix,st7735r.yaml index 157b1a7b18f9..53f181ef3670 100644 --- a/Documentation/devicetree/bindings/display/sitronix,st7735r.yaml +++ b/Documentation/devicetree/bindings/display/sitronix,st7735r.yaml @@ -15,6 +15,7 @@ description: allOf: - $ref: panel/panel-common.yaml# + - $ref: /schemas/spi/spi-peripheral-props.yaml# properties: compatible: diff --git a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml index 3fbd87c2c120..669f70b1b4c4 100644 --- a/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml +++ b/Documentation/devicetree/bindings/display/solomon,ssd1307fb.yaml @@ -49,9 +49,6 @@ properties: vbat-supply: description: The supply for VBAT - # Only required for SPI - spi-max-frequency: true - solomon,height: $ref: /schemas/types.yaml#/definitions/uint32 default: 16 @@ -153,6 +150,8 @@ required: - reg allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + - if: properties: compatible: @@ -223,7 +222,7 @@ allOf: solomon,dclk-frq: default: 10 -additionalProperties: false +unevaluatedProperties: false examples: - | From 532b04d846ddf3c90c37547baeb1c54de7b36ea6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Jul 2022 18:44:23 +0200 Subject: [PATCH 1399/1436] dt-bindings: eeprom: at25: use spi-peripheral-props.yaml Instead of listing directly properties typical for SPI peripherals, reference the spi-peripheral-props.yaml schema. This allows using all properties typical for SPI-connected devices, even these which device bindings author did not tried yet. Remove the spi-* properties which now come via spi-peripheral-props.yaml schema, except for the cases when device schema adds some constraints like maximum frequency. While changing additionalProperties->unevaluatedProperties, put it in typical place, just before example DTS. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220727164424.386499-1-krzysztof.kozlowski@linaro.org --- Documentation/devicetree/bindings/eeprom/at25.yaml | 5 ++--- .../devicetree/bindings/misc/eeprom-93xx46.yaml | 9 ++++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/eeprom/at25.yaml b/Documentation/devicetree/bindings/eeprom/at25.yaml index fbf99e346966..8b1c997caac1 100644 --- a/Documentation/devicetree/bindings/eeprom/at25.yaml +++ b/Documentation/devicetree/bindings/eeprom/at25.yaml @@ -44,8 +44,6 @@ properties: reg: maxItems: 1 - spi-max-frequency: true - pagesize: $ref: /schemas/types.yaml#/definitions/uint32 enum: [1, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072] @@ -105,6 +103,7 @@ required: - spi-max-frequency allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# - if: properties: compatible: @@ -117,7 +116,7 @@ allOf: - size - address-width -additionalProperties: false +unevaluatedProperties: false examples: - | diff --git a/Documentation/devicetree/bindings/misc/eeprom-93xx46.yaml b/Documentation/devicetree/bindings/misc/eeprom-93xx46.yaml index 44fd2f6f0d8a..43ac2376a453 100644 --- a/Documentation/devicetree/bindings/misc/eeprom-93xx46.yaml +++ b/Documentation/devicetree/bindings/misc/eeprom-93xx46.yaml @@ -28,9 +28,6 @@ properties: description: chip select of EEPROM maxItems: 1 - spi-max-frequency: true - spi-cs-high: true - read-only: description: parameter-less property which disables writes to the EEPROM @@ -42,14 +39,16 @@ properties: of EEPROM (e.g. for SPI bus multiplexing) maxItems: 1 - required: - compatible - reg - data-size - spi-max-frequency -additionalProperties: false +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false examples: - | From b600d6a6c55eac2c4af6f3bf8cf7a2deacecd83b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Jul 2022 18:44:24 +0200 Subject: [PATCH 1400/1436] dt-bindings: eeprom: microchip,93lc46b: move to eeprom directory Move the Atmel/Microchip 93xx46 SPI compatible EEPROM family bindings from misc to eeprom directory to properly match subsystem. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220727164424.386499-2-krzysztof.kozlowski@linaro.org --- .../{misc/eeprom-93xx46.yaml => eeprom/microchip,93lc46b.yaml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Documentation/devicetree/bindings/{misc/eeprom-93xx46.yaml => eeprom/microchip,93lc46b.yaml} (95%) diff --git a/Documentation/devicetree/bindings/misc/eeprom-93xx46.yaml b/Documentation/devicetree/bindings/eeprom/microchip,93lc46b.yaml similarity index 95% rename from Documentation/devicetree/bindings/misc/eeprom-93xx46.yaml rename to Documentation/devicetree/bindings/eeprom/microchip,93lc46b.yaml index 43ac2376a453..0c2f5ddb79c5 100644 --- a/Documentation/devicetree/bindings/misc/eeprom-93xx46.yaml +++ b/Documentation/devicetree/bindings/eeprom/microchip,93lc46b.yaml @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: http://devicetree.org/schemas/misc/eeprom-93xx46.yaml# +$id: http://devicetree.org/schemas/eeprom/microchip,93lc46b.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# title: Microchip 93xx46 SPI compatible EEPROM family dt bindings From 4e8bb4ba5a558159ffbfa7e60322a1c151c3903c Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Mon, 18 Apr 2022 21:01:54 +0800 Subject: [PATCH 1401/1436] csky: Add jump-label implementation Add jump-label implementation for static branch Signed-off-by: Guo Ren Signed-off-by: Guo Ren --- arch/csky/Kconfig | 2 ++ arch/csky/include/asm/jump_label.h | 47 ++++++++++++++++++++++++++ arch/csky/kernel/Makefile | 1 + arch/csky/kernel/jump_label.c | 54 ++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 arch/csky/include/asm/jump_label.h create mode 100644 arch/csky/kernel/jump_label.c diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index 21d72b078eef..41d7d614f7a2 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig @@ -40,6 +40,8 @@ config CSKY select GX6605S_TIMER if CPU_CK610 select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_AUDITSYSCALL + select HAVE_ARCH_JUMP_LABEL if !CPU_CK610 + select HAVE_ARCH_JUMP_LABEL_RELATIVE select HAVE_ARCH_MMAP_RND_BITS select HAVE_ARCH_SECCOMP_FILTER select HAVE_CONTEXT_TRACKING diff --git a/arch/csky/include/asm/jump_label.h b/arch/csky/include/asm/jump_label.h new file mode 100644 index 000000000000..d488ba6084bc --- /dev/null +++ b/arch/csky/include/asm/jump_label.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ASM_CSKY_JUMP_LABEL_H +#define __ASM_CSKY_JUMP_LABEL_H + +#ifndef __ASSEMBLY__ + +#include + +#define JUMP_LABEL_NOP_SIZE 4 + +static __always_inline bool arch_static_branch(struct static_key *key, + bool branch) +{ + asm_volatile_goto( + "1: nop32 \n" + " .pushsection __jump_table, \"aw\" \n" + " .align 2 \n" + " .long 1b - ., %l[label] - . \n" + " .long %0 - . \n" + " .popsection \n" + : : "i"(&((char *)key)[branch]) : : label); + + return false; +label: + return true; +} + +static __always_inline bool arch_static_branch_jump(struct static_key *key, + bool branch) +{ + asm_volatile_goto( + "1: bsr32 %l[label] \n" + " .pushsection __jump_table, \"aw\" \n" + " .align 2 \n" + " .long 1b - ., %l[label] - . \n" + " .long %0 - . \n" + " .popsection \n" + : : "i"(&((char *)key)[branch]) : : label); + + return false; +label: + return true; +} + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_CSKY_JUMP_LABEL_H */ diff --git a/arch/csky/kernel/Makefile b/arch/csky/kernel/Makefile index 4eb41421ca5b..6f14c924b20d 100644 --- a/arch/csky/kernel/Makefile +++ b/arch/csky/kernel/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_CSKY_PMU_V1) += perf_event.o obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o +obj-$(CONFIG_JUMP_LABEL) += jump_label.o ifdef CONFIG_FUNCTION_TRACER CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) diff --git a/arch/csky/kernel/jump_label.c b/arch/csky/kernel/jump_label.c new file mode 100644 index 000000000000..d0e8b21447e1 --- /dev/null +++ b/arch/csky/kernel/jump_label.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include + +#define NOP32_HI 0xc400 +#define NOP32_LO 0x4820 +#define BSR_LINK 0xe000 + +void arch_jump_label_transform(struct jump_entry *entry, + enum jump_label_type type) +{ + unsigned long addr = jump_entry_code(entry); + u16 insn[2]; + int ret = 0; + + if (type == JUMP_LABEL_JMP) { + long offset = jump_entry_target(entry) - jump_entry_code(entry); + + if (WARN_ON(offset & 1 || offset < -67108864 || offset >= 67108864)) + return; + + offset = offset >> 1; + + insn[0] = BSR_LINK | + ((uint16_t)((unsigned long) offset >> 16) & 0x3ff); + insn[1] = (uint16_t)((unsigned long) offset & 0xffff); + } else { + insn[0] = NOP32_HI; + insn[1] = NOP32_LO; + } + + ret = copy_to_kernel_nofault((void *)addr, insn, 4); + WARN_ON(ret); + + flush_icache_range(addr, addr + 4); +} + +void arch_jump_label_transform_static(struct jump_entry *entry, + enum jump_label_type type) +{ + /* + * We use the same instructions in the arch_static_branch and + * arch_static_branch_jump inline functions, so there's no + * need to patch them up here. + * The core will call arch_jump_label_transform when those + * instructions need to be replaced. + */ + arch_jump_label_transform(entry, type); +} From 87f600af59e8cf6abb04bac15328bcb517e26485 Mon Sep 17 00:00:00 2001 From: Phillip Potter Date: Sun, 31 Jul 2022 00:59:10 +0100 Subject: [PATCH 1402/1436] staging: r8188eu: fix potential uninitialised variable use in rtw_pwrctrl.c Set ret to 0 (success) before entering first if statement, thereby assuring that even if the device is not associated and further checks pass, we do not then end up returning the uninitialized value of ret. This assignment is deliberately now directly before the if statement, in order to keep it clear what is happening as opposed to having it as an initialization at the start of the function like it was originally. Also add a comment to make it clear this first if block is currently a success path. As a side note, smatch does not trigger warnings for this change, for me at least. Within core/rtw_pwrctrl.c in the rtw_pwr_wakeup function, I previously dropped the initialization of 'ret' (int ret = 0;) in favour of its assignment which happens inside the first if block directly before its corresponding goto. This was the cause of this bug, and was introduced by: commit f3a76018dd55 ("staging: r8188eu: remove initializer from ret in rtw_pwr_wakeup"). Fixes: f3a76018dd55 ("staging: r8188eu: remove initializer from ret in rtw_pwr_wakeup") Reported-by: kernel test robot Signed-off-by: Phillip Potter Link: https://lore.kernel.org/r/20220730235910.1145-1-phil@philpotter.co.uk Signed-off-by: Greg Kroah-Hartman --- drivers/staging/r8188eu/core/rtw_pwrctrl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/r8188eu/core/rtw_pwrctrl.c b/drivers/staging/r8188eu/core/rtw_pwrctrl.c index 75e655bae16a..10550bd2c16d 100644 --- a/drivers/staging/r8188eu/core/rtw_pwrctrl.c +++ b/drivers/staging/r8188eu/core/rtw_pwrctrl.c @@ -387,10 +387,10 @@ int rtw_pwr_wakeup(struct adapter *padapter) msleep(10); /* I think this should be check in IPS, LPS, autosuspend functions... */ - if (check_fwstate(pmlmepriv, _FW_LINKED)) { - ret = 0; + /* Below goto is a success path taken for already linked devices */ + ret = 0; + if (check_fwstate(pmlmepriv, _FW_LINKED)) goto exit; - } if (pwrpriv->rf_pwrstate == rf_off && ips_leave(padapter) == _FAIL) { ret = -ENOMEM; From 45e15c1a375ea380d55880be2f8182cb737b60ed Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Sat, 23 Jul 2022 21:32:34 -0400 Subject: [PATCH 1403/1436] csky: Add qspinlock support Enable qspinlock by the requirements mentioned in a8ad07e5240c9 ("asm-generic: qspinlock: Indicate the use of mixed-size atomics"). C-SKY only has "ldex/stex" for all atomic operations. So csky give a strong forward guarantee for "ldex/stex." That means when ldex grabbed the cache line into $L1, it would block other cores from snooping the address with several cycles. The atomic_fetch_add & xchg16 has the same forward guarantee level in C-SKY. Qspinlock has better code size and performance in a fast path. Signed-off-by: Guo Ren Signed-off-by: Guo Ren --- arch/csky/Kconfig | 1 + arch/csky/include/asm/Kbuild | 4 ++-- arch/csky/include/asm/cmpxchg.h | 20 ++++++++++++++++++++ arch/csky/include/asm/spinlock.h | 12 ++++++++++++ arch/csky/include/asm/spinlock_types.h | 9 +++++++++ 5 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 arch/csky/include/asm/spinlock.h create mode 100644 arch/csky/include/asm/spinlock_types.h diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index 41d7d614f7a2..333def12faef 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig @@ -8,6 +8,7 @@ config CSKY select ARCH_HAS_SYNC_DMA_FOR_DEVICE select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_QUEUED_RWLOCKS + select ARCH_USE_QUEUED_SPINLOCKS select ARCH_WANT_FRAME_POINTERS if !CPU_CK610 && $(cc-option,-mbacktrace) select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT select COMMON_CLK diff --git a/arch/csky/include/asm/Kbuild b/arch/csky/include/asm/Kbuild index 103207a58f97..1117c28cb7e8 100644 --- a/arch/csky/include/asm/Kbuild +++ b/arch/csky/include/asm/Kbuild @@ -3,10 +3,10 @@ generic-y += asm-offsets.h generic-y += extable.h generic-y += gpio.h generic-y += kvm_para.h -generic-y += spinlock.h -generic-y += spinlock_types.h +generic-y += mcs_spinlock.h generic-y += qrwlock.h generic-y += qrwlock_types.h +generic-y += qspinlock.h generic-y += parport.h generic-y += user.h generic-y += vmlinux.lds.h diff --git a/arch/csky/include/asm/cmpxchg.h b/arch/csky/include/asm/cmpxchg.h index 5b8faccd65e4..5f693fadb56c 100644 --- a/arch/csky/include/asm/cmpxchg.h +++ b/arch/csky/include/asm/cmpxchg.h @@ -15,6 +15,26 @@ extern void __bad_xchg(void); __typeof__(*(ptr)) __ret; \ unsigned long tmp; \ switch (size) { \ + case 2: { \ + u32 ret; \ + u32 shif = ((ulong)__ptr & 2) ? 16 : 0; \ + u32 mask = 0xffff << shif; \ + __ptr = (__typeof__(ptr))((ulong)__ptr & ~2); \ + __asm__ __volatile__ ( \ + "1: ldex.w %0, (%4)\n" \ + " and %1, %0, %2\n" \ + " or %1, %1, %3\n" \ + " stex.w %1, (%4)\n" \ + " bez %1, 1b\n" \ + : "=&r" (ret), "=&r" (tmp) \ + : "r" (~mask), \ + "r" ((u32)__new << shif), \ + "r" (__ptr) \ + : "memory"); \ + __ret = (__typeof__(*(ptr))) \ + ((ret & mask) >> shif); \ + break; \ + } \ case 4: \ asm volatile ( \ "1: ldex.w %0, (%3) \n" \ diff --git a/arch/csky/include/asm/spinlock.h b/arch/csky/include/asm/spinlock.h new file mode 100644 index 000000000000..83a2005341f5 --- /dev/null +++ b/arch/csky/include/asm/spinlock.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __ASM_CSKY_SPINLOCK_H +#define __ASM_CSKY_SPINLOCK_H + +#include +#include + +/* See include/linux/spinlock.h */ +#define smp_mb__after_spinlock() smp_mb() + +#endif /* __ASM_CSKY_SPINLOCK_H */ diff --git a/arch/csky/include/asm/spinlock_types.h b/arch/csky/include/asm/spinlock_types.h new file mode 100644 index 000000000000..75bdf3af80ba --- /dev/null +++ b/arch/csky/include/asm/spinlock_types.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __ASM_CSKY_SPINLOCK_TYPES_H +#define __ASM_CSKY_SPINLOCK_TYPES_H + +#include +#include + +#endif /* __ASM_CSKY_SPINLOCK_TYPES_H */ From 7f8030cea33001d08cdaf2ee5a24385b2c3f723e Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Sat, 23 Jul 2022 22:52:17 -0400 Subject: [PATCH 1404/1436] csky: Enable ARCH_INLINE_READ*/WRITE*/SPIN* Enable ARCH_INLINE_READ*/WRITE*/SPIN* when !PREEMPTION, it is copied from arch/arm64. It could reduce procedure calls and improves performance. Signed-off-by: Guo Ren Signed-off-by: Guo Ren --- arch/csky/Kconfig | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/csky/Kconfig b/arch/csky/Kconfig index 333def12faef..b23458b5c74f 100644 --- a/arch/csky/Kconfig +++ b/arch/csky/Kconfig @@ -9,6 +9,32 @@ config CSKY select ARCH_USE_BUILTIN_BSWAP select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS + select ARCH_INLINE_READ_LOCK if !PREEMPTION + select ARCH_INLINE_READ_LOCK_BH if !PREEMPTION + select ARCH_INLINE_READ_LOCK_IRQ if !PREEMPTION + select ARCH_INLINE_READ_LOCK_IRQSAVE if !PREEMPTION + select ARCH_INLINE_READ_UNLOCK if !PREEMPTION + select ARCH_INLINE_READ_UNLOCK_BH if !PREEMPTION + select ARCH_INLINE_READ_UNLOCK_IRQ if !PREEMPTION + select ARCH_INLINE_READ_UNLOCK_IRQRESTORE if !PREEMPTION + select ARCH_INLINE_WRITE_LOCK if !PREEMPTION + select ARCH_INLINE_WRITE_LOCK_BH if !PREEMPTION + select ARCH_INLINE_WRITE_LOCK_IRQ if !PREEMPTION + select ARCH_INLINE_WRITE_LOCK_IRQSAVE if !PREEMPTION + select ARCH_INLINE_WRITE_UNLOCK if !PREEMPTION + select ARCH_INLINE_WRITE_UNLOCK_BH if !PREEMPTION + select ARCH_INLINE_WRITE_UNLOCK_IRQ if !PREEMPTION + select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE if !PREEMPTION + select ARCH_INLINE_SPIN_TRYLOCK if !PREEMPTION + select ARCH_INLINE_SPIN_TRYLOCK_BH if !PREEMPTION + select ARCH_INLINE_SPIN_LOCK if !PREEMPTION + select ARCH_INLINE_SPIN_LOCK_BH if !PREEMPTION + select ARCH_INLINE_SPIN_LOCK_IRQ if !PREEMPTION + select ARCH_INLINE_SPIN_LOCK_IRQSAVE if !PREEMPTION + select ARCH_INLINE_SPIN_UNLOCK if !PREEMPTION + select ARCH_INLINE_SPIN_UNLOCK_BH if !PREEMPTION + select ARCH_INLINE_SPIN_UNLOCK_IRQ if !PREEMPTION + select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE if !PREEMPTION select ARCH_WANT_FRAME_POINTERS if !CPU_CK610 && $(cc-option,-mbacktrace) select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT select COMMON_CLK From f940dc0f225183ccdba044e87daeeb93398819ad Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Sun, 31 Jul 2022 21:57:30 -0400 Subject: [PATCH 1405/1436] csky: cmpxchg: Coding convention for BUILD_BUG() Use BUILD_BUG() instead of the custom bad_xchg. Signed-off-by: Guo Ren Signed-off-by: Guo Ren --- arch/csky/include/asm/cmpxchg.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/arch/csky/include/asm/cmpxchg.h b/arch/csky/include/asm/cmpxchg.h index 5f693fadb56c..916043b845f1 100644 --- a/arch/csky/include/asm/cmpxchg.h +++ b/arch/csky/include/asm/cmpxchg.h @@ -4,10 +4,9 @@ #define __ASM_CSKY_CMPXCHG_H #ifdef CONFIG_SMP +#include #include -extern void __bad_xchg(void); - #define __xchg_relaxed(new, ptr, size) \ ({ \ __typeof__(ptr) __ptr = (ptr); \ @@ -46,7 +45,7 @@ extern void __bad_xchg(void); :); \ break; \ default: \ - __bad_xchg(); \ + BUILD_BUG(); \ } \ __ret; \ }) @@ -76,7 +75,7 @@ extern void __bad_xchg(void); :); \ break; \ default: \ - __bad_xchg(); \ + BUILD_BUG(); \ } \ __ret; \ }) @@ -107,7 +106,7 @@ extern void __bad_xchg(void); :); \ break; \ default: \ - __bad_xchg(); \ + BUILD_BUG(); \ } \ __ret; \ }) @@ -139,7 +138,7 @@ extern void __bad_xchg(void); :); \ break; \ default: \ - __bad_xchg(); \ + BUILD_BUG(); \ } \ __ret; \ }) From 45fef4c4b9c94e86d9c13f0b2e7e71bb32254509 Mon Sep 17 00:00:00 2001 From: Guo Ren Date: Sun, 31 Jul 2022 22:34:24 -0400 Subject: [PATCH 1406/1436] csky: abiv1: Fixup compile error LD vmlinux.o arch/csky/lib/string.o: In function `memmove': string.c:(.text+0x108): multiple definition of `memmove' lib/string.o:string.c:(.text+0x7e8): first defined here arch/csky/lib/string.o: In function `memset': string.c:(.text+0x148): multiple definition of `memset' lib/string.o:string.c:(.text+0x2ac): first defined here scripts/Makefile.vmlinux_o:68: recipe for target 'vmlinux.o' failed make[4]: *** [vmlinux.o] Error 1 Fixes: e4df2d5e852a ("csky: Add C based string functions") Signed-off-by: Guo Ren Signed-off-by: Guo Ren Cc: --- arch/csky/abiv1/inc/abi/string.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/csky/abiv1/inc/abi/string.h b/arch/csky/abiv1/inc/abi/string.h index 9d95594b0feb..de50117b904d 100644 --- a/arch/csky/abiv1/inc/abi/string.h +++ b/arch/csky/abiv1/inc/abi/string.h @@ -6,4 +6,10 @@ #define __HAVE_ARCH_MEMCPY extern void *memcpy(void *, const void *, __kernel_size_t); +#define __HAVE_ARCH_MEMMOVE +extern void *memmove(void *, const void *, __kernel_size_t); + +#define __HAVE_ARCH_MEMSET +extern void *memset(void *, int, __kernel_size_t); + #endif /* __ABI_CSKY_STRING_H */ From 67f43c9c6a47776493f790f5ee03d76974e1b39d Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Mon, 27 Jun 2022 15:28:22 +0100 Subject: [PATCH 1407/1436] xen/manage: Use orderly_reboot() to reboot Currently when the toolstack issues a reboot, it gets translated into a call to ctrl_alt_del(). But tying reboot to ctrl-alt-del means rebooting may fail if e.g. the user has masked the ctrl-alt-del.target under systemd. A previous attempt to fix this issue made a change that sets the kernel.ctrl-alt-del sysctl to 1 before ctrl_alt_del() is called. However, this doesn't give userspace the opportunity to block rebooting or even do any cleanup or syncing. Instead, call orderly_reboot() which will call the "reboot" command, giving userspace the opportunity to block it or perform the usual reboot process while being independent of the ctrl-alt-del behaviour. It also matches what happens in the shutdown case. Signed-off-by: Ross Lagerwall Reviewed-by: Juergen Gross Link: https://lore.kernel.org/r/20220627142822.3612106-1-ross.lagerwall@citrix.com Signed-off-by: Juergen Gross --- drivers/xen/manage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 3d5a384d65f7..c16df629907e 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -205,7 +205,7 @@ static void do_poweroff(void) static void do_reboot(void) { shutting_down = SHUTDOWN_POWEROFF; /* ? */ - ctrl_alt_del(); + orderly_reboot(); } static struct shutdown_handler shutdown_handlers[] = { From 8441dac05e7f346abc4f63a15d4af0adeabfaa9b Mon Sep 17 00:00:00 2001 From: Zhang Jiaming Date: Thu, 30 Jun 2022 15:50:27 +0800 Subject: [PATCH 1408/1436] xen: Fix spelling mistake Change 'maped' to 'mapped'. Change 'unmaped' to 'unmapped'. Signed-off-by: Zhang Jiaming Reviewed-by: Juergen Gross Link: https://lore.kernel.org/r/20220630075027.68833-1-jiaming@nfschina.com Signed-off-by: Juergen Gross --- drivers/xen/xen-front-pgdir-shbuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/xen/xen-front-pgdir-shbuf.c b/drivers/xen/xen-front-pgdir-shbuf.c index bef8d72a6ca6..5c0b5cb5b419 100644 --- a/drivers/xen/xen-front-pgdir-shbuf.c +++ b/drivers/xen/xen-front-pgdir-shbuf.c @@ -89,7 +89,7 @@ EXPORT_SYMBOL_GPL(xen_front_pgdir_shbuf_get_dir_start); * shared by the frontend itself) or map the provided granted * references onto the backing storage (buf->pages). * - * \param buf shared buffer which grants to be maped. + * \param buf shared buffer which grants to be mapped. * \return zero on success or a negative number on failure. */ int xen_front_pgdir_shbuf_map(struct xen_front_pgdir_shbuf *buf) @@ -110,7 +110,7 @@ EXPORT_SYMBOL_GPL(xen_front_pgdir_shbuf_map); * shared by the frontend itself) or unmap the provided granted * references. * - * \param buf shared buffer which grants to be unmaped. + * \param buf shared buffer which grants to be unmapped. * \return zero on success or a negative number on failure. */ int xen_front_pgdir_shbuf_unmap(struct xen_front_pgdir_shbuf *buf) From a603002eea8213eec5211be5a85db8340aea06d0 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 22 Jun 2022 08:38:36 +0200 Subject: [PATCH 1409/1436] virtio: replace restricted mem access flag with callback Instead of having a global flag to require restricted memory access for all virtio devices, introduce a callback which can select that requirement on a per-device basis. For convenience add a common function returning always true, which can be used for use cases like SEV. Per default use a callback always returning false. As the callback needs to be set in early init code already, add a virtio anchor which is builtin in case virtio is enabled. Signed-off-by: Juergen Gross Tested-by: Oleksandr Tyshchenko # Arm64 guest using Xen Reviewed-by: Stefano Stabellini Link: https://lore.kernel.org/r/20220622063838.8854-2-jgross@suse.com Signed-off-by: Juergen Gross --- arch/s390/mm/init.c | 4 ++-- arch/x86/mm/mem_encrypt_amd.c | 4 ++-- drivers/virtio/Kconfig | 4 ++++ drivers/virtio/Makefile | 1 + drivers/virtio/virtio.c | 4 ++-- drivers/virtio/virtio_anchor.c | 18 ++++++++++++++++++ include/linux/platform-feature.h | 6 +----- include/linux/virtio_anchor.h | 19 +++++++++++++++++++ include/xen/xen.h | 4 ++-- 9 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 drivers/virtio/virtio_anchor.c create mode 100644 include/linux/virtio_anchor.h diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 6a0ac00d5a42..4a154a084966 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -48,6 +47,7 @@ #include #include #include +#include #include pgd_t swapper_pg_dir[PTRS_PER_PGD] __section(".bss..swapper_pg_dir"); @@ -175,7 +175,7 @@ static void pv_init(void) if (!is_prot_virt_guest()) return; - platform_set(PLATFORM_VIRTIO_RESTRICTED_MEM_ACCESS); + virtio_set_mem_acc_cb(virtio_require_restricted_mem_acc); /* make sure bounce buffers are shared */ swiotlb_init(true, SWIOTLB_FORCE | SWIOTLB_VERBOSE); diff --git a/arch/x86/mm/mem_encrypt_amd.c b/arch/x86/mm/mem_encrypt_amd.c index f6d038e2cd8e..97452688f99f 100644 --- a/arch/x86/mm/mem_encrypt_amd.c +++ b/arch/x86/mm/mem_encrypt_amd.c @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include #include #include @@ -245,7 +245,7 @@ void __init sev_setup_arch(void) swiotlb_adjust_size(size); /* Set restricted memory access for virtio. */ - platform_set(PLATFORM_VIRTIO_RESTRICTED_MEM_ACCESS); + virtio_set_mem_acc_cb(virtio_require_restricted_mem_acc); } static unsigned long pg_level_to_pfn(int level, pte_t *kpte, pgprot_t *ret_prot) diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index e1556d2a355a..56c77f63cd22 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -1,6 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only +config VIRTIO_ANCHOR + bool + config VIRTIO tristate + select VIRTIO_ANCHOR help This option is selected by any driver which implements the virtio bus, such as CONFIG_VIRTIO_PCI, CONFIG_VIRTIO_MMIO, CONFIG_RPMSG diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 0a82d0873248..8e98d24917cc 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_VIRTIO) += virtio.o virtio_ring.o +obj-$(CONFIG_VIRTIO_ANCHOR) += virtio_anchor.o obj-$(CONFIG_VIRTIO_PCI_LIB) += virtio_pci_modern_dev.o obj-$(CONFIG_VIRTIO_PCI_LIB_LEGACY) += virtio_pci_legacy_dev.o obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 7deeed30d1f3..14c142d77fba 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -2,10 +2,10 @@ #include #include #include +#include #include #include #include -#include #include /* Unique numbering for virtio devices. */ @@ -174,7 +174,7 @@ static int virtio_features_ok(struct virtio_device *dev) might_sleep(); - if (platform_has(PLATFORM_VIRTIO_RESTRICTED_MEM_ACCESS)) { + if (virtio_check_mem_acc_cb(dev)) { if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) { dev_warn(&dev->dev, "device must provide VIRTIO_F_VERSION_1\n"); diff --git a/drivers/virtio/virtio_anchor.c b/drivers/virtio/virtio_anchor.c new file mode 100644 index 000000000000..4d6a5d269b55 --- /dev/null +++ b/drivers/virtio/virtio_anchor.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include + +bool virtio_require_restricted_mem_acc(struct virtio_device *dev) +{ + return true; +} +EXPORT_SYMBOL_GPL(virtio_require_restricted_mem_acc); + +static bool virtio_no_restricted_mem_acc(struct virtio_device *dev) +{ + return false; +} + +bool (*virtio_check_mem_acc_cb)(struct virtio_device *dev) = + virtio_no_restricted_mem_acc; +EXPORT_SYMBOL_GPL(virtio_check_mem_acc_cb); diff --git a/include/linux/platform-feature.h b/include/linux/platform-feature.h index b2f48be999fa..6ed859928b97 100644 --- a/include/linux/platform-feature.h +++ b/include/linux/platform-feature.h @@ -6,11 +6,7 @@ #include /* The platform features are starting with the architecture specific ones. */ - -/* Used to enable platform specific DMA handling for virtio devices. */ -#define PLATFORM_VIRTIO_RESTRICTED_MEM_ACCESS (0 + PLATFORM_ARCH_FEAT_N) - -#define PLATFORM_FEAT_N (1 + PLATFORM_ARCH_FEAT_N) +#define PLATFORM_FEAT_N (0 + PLATFORM_ARCH_FEAT_N) void platform_set(unsigned int feature); void platform_clear(unsigned int feature); diff --git a/include/linux/virtio_anchor.h b/include/linux/virtio_anchor.h new file mode 100644 index 000000000000..432e6c00b3ca --- /dev/null +++ b/include/linux/virtio_anchor.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_VIRTIO_ANCHOR_H +#define _LINUX_VIRTIO_ANCHOR_H + +#ifdef CONFIG_VIRTIO_ANCHOR +struct virtio_device; + +bool virtio_require_restricted_mem_acc(struct virtio_device *dev); +extern bool (*virtio_check_mem_acc_cb)(struct virtio_device *dev); + +static inline void virtio_set_mem_acc_cb(bool (*func)(struct virtio_device *)) +{ + virtio_check_mem_acc_cb = func; +} +#else +#define virtio_set_mem_acc_cb(func) do { } while (0) +#endif + +#endif /* _LINUX_VIRTIO_ANCHOR_H */ diff --git a/include/xen/xen.h b/include/xen/xen.h index 0780a81e140d..ac5a144c6a65 100644 --- a/include/xen/xen.h +++ b/include/xen/xen.h @@ -52,12 +52,12 @@ bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, extern u64 xen_saved_max_mem_size; #endif -#include +#include static inline void xen_set_restricted_virtio_memory_access(void) { if (IS_ENABLED(CONFIG_XEN_VIRTIO) && xen_domain()) - platform_set(PLATFORM_VIRTIO_RESTRICTED_MEM_ACCESS); + virtio_set_mem_acc_cb(virtio_require_restricted_mem_acc); } #ifdef CONFIG_XEN_UNPOPULATED_ALLOC From a870544ca9d215449e91ebc01e35d80b23151c78 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 22 Jun 2022 08:38:37 +0200 Subject: [PATCH 1410/1436] kernel: remove platform_has() infrastructure The only use case of the platform_has() infrastructure has been removed again, so remove the whole feature. Signed-off-by: Juergen Gross Tested-by: Oleksandr Tyshchenko # Arm64 guest using Xen Reviewed-by: Stefano Stabellini Link: https://lore.kernel.org/r/20220622063838.8854-3-jgross@suse.com Signed-off-by: Juergen Gross --- MAINTAINERS | 8 -------- include/asm-generic/Kbuild | 1 - include/asm-generic/platform-feature.h | 8 -------- include/linux/platform-feature.h | 15 -------------- kernel/Makefile | 2 +- kernel/platform-feature.c | 27 -------------------------- 6 files changed, 1 insertion(+), 60 deletions(-) delete mode 100644 include/asm-generic/platform-feature.h delete mode 100644 include/linux/platform-feature.h delete mode 100644 kernel/platform-feature.c diff --git a/MAINTAINERS b/MAINTAINERS index 64379c699903..c173a580ff77 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15953,14 +15953,6 @@ S: Maintained F: Documentation/devicetree/bindings/iio/chemical/plantower,pms7003.yaml F: drivers/iio/chemical/pms7003.c -PLATFORM FEATURE INFRASTRUCTURE -M: Juergen Gross -S: Maintained -F: arch/*/include/asm/platform-feature.h -F: include/asm-generic/platform-feature.h -F: include/linux/platform-feature.h -F: kernel/platform-feature.c - PLDMFW LIBRARY M: Jacob Keller S: Maintained diff --git a/include/asm-generic/Kbuild b/include/asm-generic/Kbuild index 8e47d483b524..302506bbc2a4 100644 --- a/include/asm-generic/Kbuild +++ b/include/asm-generic/Kbuild @@ -44,7 +44,6 @@ mandatory-y += msi.h mandatory-y += pci.h mandatory-y += percpu.h mandatory-y += pgalloc.h -mandatory-y += platform-feature.h mandatory-y += preempt.h mandatory-y += rwonce.h mandatory-y += sections.h diff --git a/include/asm-generic/platform-feature.h b/include/asm-generic/platform-feature.h deleted file mode 100644 index 4b0af3d51588..000000000000 --- a/include/asm-generic/platform-feature.h +++ /dev/null @@ -1,8 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_GENERIC_PLATFORM_FEATURE_H -#define _ASM_GENERIC_PLATFORM_FEATURE_H - -/* Number of arch specific feature flags. */ -#define PLATFORM_ARCH_FEAT_N 0 - -#endif /* _ASM_GENERIC_PLATFORM_FEATURE_H */ diff --git a/include/linux/platform-feature.h b/include/linux/platform-feature.h deleted file mode 100644 index 6ed859928b97..000000000000 --- a/include/linux/platform-feature.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _PLATFORM_FEATURE_H -#define _PLATFORM_FEATURE_H - -#include -#include - -/* The platform features are starting with the architecture specific ones. */ -#define PLATFORM_FEAT_N (0 + PLATFORM_ARCH_FEAT_N) - -void platform_set(unsigned int feature); -void platform_clear(unsigned int feature); -bool platform_has(unsigned int feature); - -#endif /* _PLATFORM_FEATURE_H */ diff --git a/kernel/Makefile b/kernel/Makefile index a7e1f49ab2b3..318789c728d3 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -7,7 +7,7 @@ obj-y = fork.o exec_domain.o panic.o \ cpu.o exit.o softirq.o resource.o \ sysctl.o capability.o ptrace.o user.o \ signal.o sys.o umh.o workqueue.o pid.o task_work.o \ - extable.o params.o platform-feature.o \ + extable.o params.o \ kthread.o sys_ni.o nsproxy.o \ notifier.o ksysfs.o cred.o reboot.o \ async.o range.o smpboot.o ucount.o regset.o diff --git a/kernel/platform-feature.c b/kernel/platform-feature.c deleted file mode 100644 index cb6a6c3e4fed..000000000000 --- a/kernel/platform-feature.c +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include -#include - -#define PLATFORM_FEAT_ARRAY_SZ BITS_TO_LONGS(PLATFORM_FEAT_N) -static unsigned long __read_mostly platform_features[PLATFORM_FEAT_ARRAY_SZ]; - -void platform_set(unsigned int feature) -{ - set_bit(feature, platform_features); -} -EXPORT_SYMBOL_GPL(platform_set); - -void platform_clear(unsigned int feature) -{ - clear_bit(feature, platform_features); -} -EXPORT_SYMBOL_GPL(platform_clear); - -bool platform_has(unsigned int feature) -{ - return test_bit(feature, platform_features); -} -EXPORT_SYMBOL_GPL(platform_has); From 251e90e7e346a23742b90e2c4db19d322e071d99 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 22 Jun 2022 08:38:38 +0200 Subject: [PATCH 1411/1436] xen: don't require virtio with grants for non-PV guests Commit fa1f57421e0b ("xen/virtio: Enable restricted memory access using Xen grant mappings") introduced a new requirement for using virtio devices: the backend now needs to support the VIRTIO_F_ACCESS_PLATFORM feature. This is an undue requirement for non-PV guests, as those can be operated with existing backends without any problem, as long as those backends are running in dom0. Per default allow virtio devices without grant support for non-PV guests. On Arm require VIRTIO_F_ACCESS_PLATFORM for devices having been listed in the device tree to use grants. Add a new config item to always force use of grants for virtio. Fixes: fa1f57421e0b ("xen/virtio: Enable restricted memory access using Xen grant mappings") Reported-by: Viresh Kumar Signed-off-by: Juergen Gross Reviewed-by: Oleksandr Tyshchenko Tested-by: Oleksandr Tyshchenko # Arm64 guest using Xen Reviewed-by: Stefano Stabellini Link: https://lore.kernel.org/r/20220622063838.8854-4-jgross@suse.com Signed-off-by: Juergen Gross --- arch/arm/xen/enlighten.c | 4 +++- arch/x86/xen/enlighten_hvm.c | 4 +++- arch/x86/xen/enlighten_pv.c | 5 ++++- drivers/xen/Kconfig | 9 +++++++++ drivers/xen/grant-dma-ops.c | 10 ++++++++++ include/xen/xen-ops.h | 9 +++++++++ include/xen/xen.h | 8 -------- 7 files changed, 38 insertions(+), 11 deletions(-) diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index 1f9c3ba32833..93c8ccbf2982 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -443,7 +444,8 @@ static int __init xen_guest_init(void) if (!xen_domain()) return 0; - xen_set_restricted_virtio_memory_access(); + if (IS_ENABLED(CONFIG_XEN_VIRTIO)) + virtio_set_mem_acc_cb(xen_virtio_mem_acc); if (!acpi_disabled) xen_acpi_guest_init(); diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c index 8b71b1dd7639..28762f800596 100644 --- a/arch/x86/xen/enlighten_hvm.c +++ b/arch/x86/xen/enlighten_hvm.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -195,7 +196,8 @@ static void __init xen_hvm_guest_init(void) if (xen_pv_domain()) return; - xen_set_restricted_virtio_memory_access(); + if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT)) + virtio_set_mem_acc_cb(virtio_require_restricted_mem_acc); init_hvm_pv_info(); diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c index 70fb2ea85e90..0ed2e487a693 100644 --- a/arch/x86/xen/enlighten_pv.c +++ b/arch/x86/xen/enlighten_pv.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -109,7 +110,9 @@ static DEFINE_PER_CPU(struct tls_descs, shadow_tls_desc); static void __init xen_pv_init_platform(void) { - xen_set_restricted_virtio_memory_access(); + /* PV guests can't operate virtio devices without grants. */ + if (IS_ENABLED(CONFIG_XEN_VIRTIO)) + virtio_set_mem_acc_cb(virtio_require_restricted_mem_acc); populate_extra_pte(fix_to_virt(FIX_PARAVIRT_BOOTMAP)); diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index bfd5f4f706bc..a65bd92121a5 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -355,4 +355,13 @@ config XEN_VIRTIO If in doubt, say n. +config XEN_VIRTIO_FORCE_GRANT + bool "Require Xen virtio support to use grants" + depends on XEN_VIRTIO + help + Require virtio for Xen guests to use grant mappings. + This will avoid the need to give the backend the right to map all + of the guest memory. This will need support on the backend side + (e.g. qemu or kernel, depending on the virtio device types used). + endmenu diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c index fc0142484001..8973fc1e9ccc 100644 --- a/drivers/xen/grant-dma-ops.c +++ b/drivers/xen/grant-dma-ops.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -287,6 +289,14 @@ bool xen_is_grant_dma_device(struct device *dev) return has_iommu; } +bool xen_virtio_mem_acc(struct virtio_device *dev) +{ + if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT)) + return true; + + return xen_is_grant_dma_device(dev->dev.parent); +} + void xen_grant_setup_dma_ops(struct device *dev) { struct xen_grant_dma_data *data; diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 80546960f8b7..dae0f350c678 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -217,6 +218,7 @@ static inline void xen_preemptible_hcall_end(void) { } #ifdef CONFIG_XEN_GRANT_DMA_OPS void xen_grant_setup_dma_ops(struct device *dev); bool xen_is_grant_dma_device(struct device *dev); +bool xen_virtio_mem_acc(struct virtio_device *dev); #else static inline void xen_grant_setup_dma_ops(struct device *dev) { @@ -225,6 +227,13 @@ static inline bool xen_is_grant_dma_device(struct device *dev) { return false; } + +struct virtio_device; + +static inline bool xen_virtio_mem_acc(struct virtio_device *dev) +{ + return false; +} #endif /* CONFIG_XEN_GRANT_DMA_OPS */ #endif /* INCLUDE_XEN_OPS_H */ diff --git a/include/xen/xen.h b/include/xen/xen.h index ac5a144c6a65..a99bab817523 100644 --- a/include/xen/xen.h +++ b/include/xen/xen.h @@ -52,14 +52,6 @@ bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, extern u64 xen_saved_max_mem_size; #endif -#include - -static inline void xen_set_restricted_virtio_memory_access(void) -{ - if (IS_ENABLED(CONFIG_XEN_VIRTIO) && xen_domain()) - virtio_set_mem_acc_cb(virtio_require_restricted_mem_acc); -} - #ifdef CONFIG_XEN_UNPOPULATED_ALLOC int xen_alloc_unpopulated_pages(unsigned int nr_pages, struct page **pages); void xen_free_unpopulated_pages(unsigned int nr_pages, struct page **pages); From 31f6e3832a0f1c366e54033335aed2375f6e447a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 1 Aug 2022 07:27:18 -0400 Subject: [PATCH 1412/1436] KVM: x86/mmu: remove unused variable The last use of 'pfn' went away with the same-named argument to host_pfn_mapping_level; now that the hugepage level is obtained exclusively from the host page tables, kvm_mmu_zap_collapsible_spte does not need to know host pfns at all. Fixes: a8ac499bb6ab ("KVM: x86/mmu: Don't require refcounted "struct page" to create huge SPTEs") Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu/mmu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c index 3e1317325e1f..4236a28b9be5 100644 --- a/arch/x86/kvm/mmu/mmu.c +++ b/arch/x86/kvm/mmu/mmu.c @@ -6416,13 +6416,11 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm, u64 *sptep; struct rmap_iterator iter; int need_tlb_flush = 0; - kvm_pfn_t pfn; struct kvm_mmu_page *sp; restart: for_each_rmap_spte(rmap_head, &iter, sptep) { sp = sptep_to_sp(sptep); - pfn = spte_to_pfn(*sptep); /* * We cannot do huge page mapping for indirect shadow pages, From ad5b072716e9ea7164b578a06c615966e9203c45 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Tue, 19 Jul 2022 14:31:32 +0000 Subject: [PATCH 1413/1436] selftests: KVM: Check stat name before other fields In order to provide more useful test assertions that describe the broken stats descriptor, perform sanity check on the stat name before any other descriptor field. While at it, avoid dereferencing the name field if the sanity check fails as it is more likely to contain garbage. Signed-off-by: Oliver Upton Reviewed-by: Andrew Jones Message-Id: <20220719143134.3246798-2-oliver.upton@linux.dev> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/kvm_binary_stats_test.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index b01e8b0851e7..40227ad9ba0c 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -73,6 +73,10 @@ static void stats_test(int stats_fd) for (i = 0; i < header.num_desc; ++i) { pdesc = get_stats_descriptor(stats_desc, i, &header); + /* Check name string */ + TEST_ASSERT(strlen(pdesc->name) < header.name_size, + "KVM stats name (index: %d) too long", i); + /* Check type,unit,base boundaries */ TEST_ASSERT((pdesc->flags & KVM_STATS_TYPE_MASK) <= KVM_STATS_TYPE_MAX, "Unknown KVM stats type"); @@ -99,9 +103,7 @@ static void stats_test(int stats_fd) TEST_ASSERT(pdesc->exponent <= 0, "Unsupported KVM stats unit"); break; } - /* Check name string */ - TEST_ASSERT(strlen(pdesc->name) < header.name_size, - "KVM stats name(%s) too long", pdesc->name); + /* Check size field, which should not be zero */ TEST_ASSERT(pdesc->size, "KVM descriptor(%s) with size of 0", pdesc->name); From 7eebae78bc9754564779927976f37d04c2c01b64 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Tue, 19 Jul 2022 14:31:33 +0000 Subject: [PATCH 1414/1436] selftests: KVM: Provide descriptive assertions in kvm_binary_stats_test As it turns out, tests sometimes fail. When that is the case, packing the test assertion with as much relevant information helps track down the problem more quickly. Sharpen up the stat descriptor assertions in kvm_binary_stats_test to more precisely describe the reason for the test assertion and which stat is to blame. Signed-off-by: Oliver Upton Reviewed-by: Andrew Jones Message-Id: <20220719143134.3246798-3-oliver.upton@linux.dev> Signed-off-by: Paolo Bonzini --- .../selftests/kvm/kvm_binary_stats_test.c | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 40227ad9ba0c..3237c7c94bf0 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -31,6 +31,7 @@ static void stats_test(int stats_fd) struct kvm_stats_desc *stats_desc; u64 *stats_data; struct kvm_stats_desc *pdesc; + u32 type, unit, base; /* Read kvm stats header */ read_stats_header(stats_fd, &header); @@ -72,18 +73,21 @@ static void stats_test(int stats_fd) /* Sanity check for fields in descriptors */ for (i = 0; i < header.num_desc; ++i) { pdesc = get_stats_descriptor(stats_desc, i, &header); + type = pdesc->flags & KVM_STATS_TYPE_MASK; + unit = pdesc->flags & KVM_STATS_UNIT_MASK; + base = pdesc->flags & KVM_STATS_BASE_MASK; /* Check name string */ TEST_ASSERT(strlen(pdesc->name) < header.name_size, "KVM stats name (index: %d) too long", i); /* Check type,unit,base boundaries */ - TEST_ASSERT((pdesc->flags & KVM_STATS_TYPE_MASK) <= KVM_STATS_TYPE_MAX, - "Unknown KVM stats type"); - TEST_ASSERT((pdesc->flags & KVM_STATS_UNIT_MASK) <= KVM_STATS_UNIT_MAX, - "Unknown KVM stats unit"); - TEST_ASSERT((pdesc->flags & KVM_STATS_BASE_MASK) <= KVM_STATS_BASE_MAX, - "Unknown KVM stats base"); + TEST_ASSERT(type <= KVM_STATS_TYPE_MAX, + "Unknown KVM stats (%s) type: %u", pdesc->name, type); + TEST_ASSERT(unit <= KVM_STATS_UNIT_MAX, + "Unknown KVM stats (%s) unit: %u", pdesc->name, unit); + TEST_ASSERT(base <= KVM_STATS_BASE_MAX, + "Unknown KVM stats (%s) base: %u", pdesc->name, base); /* * Check exponent for stats unit @@ -97,10 +101,14 @@ static void stats_test(int stats_fd) case KVM_STATS_UNIT_NONE: case KVM_STATS_UNIT_BYTES: case KVM_STATS_UNIT_CYCLES: - TEST_ASSERT(pdesc->exponent >= 0, "Unsupported KVM stats unit"); + TEST_ASSERT(pdesc->exponent >= 0, + "Unsupported KVM stats (%s) exponent: %i", + pdesc->name, pdesc->exponent); break; case KVM_STATS_UNIT_SECONDS: - TEST_ASSERT(pdesc->exponent <= 0, "Unsupported KVM stats unit"); + TEST_ASSERT(pdesc->exponent <= 0, + "Unsupported KVM stats (%s) exponent: %i", + pdesc->name, pdesc->exponent); break; } From dd4d1c3bb3f1cd91a7a67ed3d73299ecb273ff92 Mon Sep 17 00:00:00 2001 From: Oliver Upton Date: Tue, 19 Jul 2022 14:31:34 +0000 Subject: [PATCH 1415/1436] selftests: KVM: Add exponent check for boolean stats The only sensible exponent for a boolean stat is 0. Add a test assertion requiring all boolean statistics to have an exponent of 0. Signed-off-by: Oliver Upton Reviewed-by: Andrew Jones Message-Id: <20220719143134.3246798-4-oliver.upton@linux.dev> Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/kvm_binary_stats_test.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index 3237c7c94bf0..0b45ac593387 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -96,6 +96,7 @@ static void stats_test(int stats_fd) * Exponent for unit seconds should be less than or equal to 0 * Exponent for unit clock cycles should be greater than or * equal to 0 + * Exponent for unit boolean should be 0 */ switch (pdesc->flags & KVM_STATS_UNIT_MASK) { case KVM_STATS_UNIT_NONE: @@ -110,6 +111,11 @@ static void stats_test(int stats_fd) "Unsupported KVM stats (%s) exponent: %i", pdesc->name, pdesc->exponent); break; + case KVM_STATS_UNIT_BOOLEAN: + TEST_ASSERT(pdesc->exponent == 0, + "Unsupported KVM stats (%s) exponent: %d", + pdesc->name, pdesc->exponent); + break; } /* Check size field, which should not be zero */ From 281106f938d3daaea6f8b6723a8217a2a1ef6936 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Fri, 22 Jul 2022 16:02:40 -0700 Subject: [PATCH 1416/1436] selftests: kvm: set rax before vmcall kvm_hypercall has to place the hypercall number in rax. Trace events show that kvm_pv_test doesn't work properly: kvm_pv_test-53132: kvm_hypercall: nr 0x0 a0 0x0 a1 0x0 a2 0x0 a3 0x0 kvm_pv_test-53132: kvm_hypercall: nr 0x0 a0 0x0 a1 0x0 a2 0x0 a3 0x0 kvm_pv_test-53132: kvm_hypercall: nr 0x0 a0 0x0 a1 0x0 a2 0x0 a3 0x0 With this change, it starts working as expected: kvm_pv_test-54285: kvm_hypercall: nr 0x5 a0 0x0 a1 0x0 a2 0x0 a3 0x0 kvm_pv_test-54285: kvm_hypercall: nr 0xa a0 0x0 a1 0x0 a2 0x0 a3 0x0 kvm_pv_test-54285: kvm_hypercall: nr 0xb a0 0x0 a1 0x0 a2 0x0 a3 0x0 Signed-off-by: Andrei Vagin Message-Id: <20220722230241.1944655-5-avagin@google.com> Fixes: ac4a4d6de22e ("selftests: kvm: test enforcement of paravirtual cpuid features") Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/lib/x86_64/processor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c index f35626df1dea..2e6e61bbe81b 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1184,7 +1184,7 @@ uint64_t kvm_hypercall(uint64_t nr, uint64_t a0, uint64_t a1, uint64_t a2, asm volatile("vmcall" : "=a"(r) - : "b"(a0), "c"(a1), "d"(a2), "S"(a3)); + : "a"(nr), "b"(a0), "c"(a1), "d"(a2), "S"(a3)); return r; } From 42d0d4232ac1620c38a73bd133bf9927c9bc3ac4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 18 Jul 2022 17:53:28 +0300 Subject: [PATCH 1417/1436] platform/x86: p2sb: Move out of X86_PLATFORM_DEVICES dependency The P2SB library is used for various drivers, including server platforms. That's why the dependency on X86_PLATFORM_DEVICES seems superfluous. Reported-by: kernel test robot Signed-off-by: Andy Shevchenko Reviewed-by: Hans de Goede Link: https://lore.kernel.org/r/20220718145328.14374-1-andriy.shevchenko@linux.intel.com Signed-off-by: Hans de Goede --- drivers/platform/x86/Kconfig | 12 ++++++++++++ drivers/platform/x86/Makefile | 4 ++++ drivers/platform/x86/intel/Kconfig | 12 ------------ drivers/platform/x86/intel/Makefile | 2 -- drivers/platform/x86/{intel => }/p2sb.c | 0 5 files changed, 16 insertions(+), 14 deletions(-) rename drivers/platform/x86/{intel => }/p2sb.c (100%) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 6a33c862452b..f2f98e942cf2 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1138,3 +1138,15 @@ config WINMATE_FM07_KEYS that delivers key events when these buttons are pressed. endif # X86_PLATFORM_DEVICES + +config P2SB + bool "Primary to Sideband (P2SB) bridge access support" + depends on PCI && X86 + help + The Primary to Sideband (P2SB) bridge is an interface to some + PCI devices connected through it. In particular, SPI NOR controller + in Intel Apollo Lake SoC is one of such devices. + + The main purpose of this library is to unhide P2SB device in case + firmware kept it hidden on some platforms in order to access devices + behind it. diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index a0e417c34a9b..5a428caa654a 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -119,6 +119,10 @@ obj-$(CONFIG_X86_ANDROID_TABLETS) += x86-android-tablets.o # Intel uncore drivers obj-$(CONFIG_INTEL_IPS) += intel_ips.o +# Intel miscellaneous drivers +intel_p2sb-y := p2sb.o +obj-$(CONFIG_P2SB) += intel_p2sb.o + # Intel PMIC / PMC / P-Unit devices obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o obj-$(CONFIG_INTEL_SCU_PCI) += intel_scu_pcidrv.o diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index c9cfbaae436b..794968bda115 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -70,18 +70,6 @@ config INTEL_OAKTRAIL enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y here; it will only load on supported platforms. -config P2SB - bool "Primary to Sideband (P2SB) bridge access support" - depends on PCI - help - The Primary to Sideband (P2SB) bridge is an interface to some - PCI devices connected through it. In particular, SPI NOR controller - in Intel Apollo Lake SoC is one of such devices. - - The main purpose of this library is to unhide P2SB device in case - firmware kept it hidden on some platforms in order to access devices - behind it. - config INTEL_BXTWC_PMIC_TMU tristate "Intel Broxton Whiskey Cove TMU Driver" depends on INTEL_SOC_PMIC_BXTWC diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index 741a9404db98..717933dd0cfd 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -28,8 +28,6 @@ intel_int0002_vgpio-y := int0002_vgpio.o obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o intel_oaktrail-y := oaktrail.o obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o -intel_p2sb-y := p2sb.o -obj-$(CONFIG_P2SB) += intel_p2sb.o intel_sdsi-y := sdsi.o obj-$(CONFIG_INTEL_SDSI) += intel_sdsi.o intel_vsec-y := vsec.o diff --git a/drivers/platform/x86/intel/p2sb.c b/drivers/platform/x86/p2sb.c similarity index 100% rename from drivers/platform/x86/intel/p2sb.c rename to drivers/platform/x86/p2sb.c From 5ecd39d1bc4b10df6d640c54e04b4a1c70447d13 Mon Sep 17 00:00:00 2001 From: Johan Jonker Date: Fri, 3 Jun 2022 18:35:37 +0200 Subject: [PATCH 1418/1436] dt-bindings: net: convert emac_rockchip.txt to YAML Convert emac_rockchip.txt to YAML. Changes against original bindings: Add mdio sub node. Add extra clock for rk3036 Signed-off-by: Johan Jonker Reviewed-by: Rob Herring Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220603163539.537-1-jbx6244@gmail.com --- .../devicetree/bindings/net/emac_rockchip.txt | 52 -------- .../bindings/net/rockchip,emac.yaml | 115 ++++++++++++++++++ 2 files changed, 115 insertions(+), 52 deletions(-) delete mode 100644 Documentation/devicetree/bindings/net/emac_rockchip.txt create mode 100644 Documentation/devicetree/bindings/net/rockchip,emac.yaml diff --git a/Documentation/devicetree/bindings/net/emac_rockchip.txt b/Documentation/devicetree/bindings/net/emac_rockchip.txt deleted file mode 100644 index 05bd7dafce17..000000000000 --- a/Documentation/devicetree/bindings/net/emac_rockchip.txt +++ /dev/null @@ -1,52 +0,0 @@ -* ARC EMAC 10/100 Ethernet platform driver for Rockchip RK3036/RK3066/RK3188 SoCs - -Required properties: -- compatible: should be "rockchip,-emac" - "rockchip,rk3036-emac": found on RK3036 SoCs - "rockchip,rk3066-emac": found on RK3066 SoCs - "rockchip,rk3188-emac": found on RK3188 SoCs -- reg: Address and length of the register set for the device -- interrupts: Should contain the EMAC interrupts -- rockchip,grf: phandle to the syscon grf used to control speed and mode - for emac. -- phy: see ethernet.txt file in the same directory. -- phy-mode: see ethernet.txt file in the same directory. - -Optional properties: -- phy-supply: phandle to a regulator if the PHY needs one - -Clock handling: -- clocks: Must contain an entry for each entry in clock-names. -- clock-names: Shall be "hclk" for the host clock needed to calculate and set - polling period of EMAC and "macref" for the reference clock needed to transfer - data to and from the phy. - -Child nodes of the driver are the individual PHY devices connected to the -MDIO bus. They must have a "reg" property given the PHY address on the MDIO bus. - -Examples: - -ethernet@10204000 { - compatible = "rockchip,rk3188-emac"; - reg = <0xc0fc2000 0x3c>; - interrupts = <6>; - mac-address = [ 00 11 22 33 44 55 ]; - - clocks = <&cru HCLK_EMAC>, <&cru SCLK_MAC>; - clock-names = "hclk", "macref"; - - pinctrl-names = "default"; - pinctrl-0 = <&emac_xfer>, <&emac_mdio>, <&phy_int>; - - rockchip,grf = <&grf>; - - phy = <&phy0>; - phy-mode = "rmii"; - phy-supply = <&vcc_rmii>; - - #address-cells = <1>; - #size-cells = <0>; - phy0: ethernet-phy@0 { - reg = <1>; - }; -}; diff --git a/Documentation/devicetree/bindings/net/rockchip,emac.yaml b/Documentation/devicetree/bindings/net/rockchip,emac.yaml new file mode 100644 index 000000000000..a6d4f14df442 --- /dev/null +++ b/Documentation/devicetree/bindings/net/rockchip,emac.yaml @@ -0,0 +1,115 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/rockchip,emac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Rockchip RK3036/RK3066/RK3188 Ethernet Media Access Controller (EMAC) + +maintainers: + - Heiko Stuebner + +properties: + compatible: + enum: + - rockchip,rk3036-emac + - rockchip,rk3066-emac + - rockchip,rk3188-emac + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + minItems: 2 + items: + - description: host clock + - description: reference clock + - description: mac TX/RX clock + + clock-names: + minItems: 2 + items: + - const: hclk + - const: macref + - const: macclk + + rockchip,grf: + $ref: /schemas/types.yaml#/definitions/phandle + description: + Phandle to the syscon GRF used to control speed and mode for the EMAC. + + phy-supply: + description: + Phandle to a regulator if the PHY needs one. + + mdio: + $ref: mdio.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - rockchip,grf + - phy + - phy-mode + - mdio + +allOf: + - $ref: "ethernet-controller.yaml#" + - if: + properties: + compatible: + contains: + const: rockchip,rk3036-emac + + then: + properties: + clocks: + minItems: 3 + + clock-names: + minItems: 3 + + else: + properties: + clocks: + maxItems: 2 + + clock-names: + maxItems: 2 + +unevaluatedProperties: false + +examples: + - | + #include + #include + + ethernet@10204000 { + compatible = "rockchip,rk3188-emac"; + reg = <0xc0fc2000 0x3c>; + interrupts = ; + clocks = <&cru HCLK_EMAC>, <&cru SCLK_MAC>; + clock-names = "hclk", "macref"; + rockchip,grf = <&grf>; + pinctrl-0 = <&emac_xfer>, <&emac_mdio>, <&phy_int>; + pinctrl-names = "default"; + phy = <&phy0>; + phy-mode = "rmii"; + phy-supply = <&vcc_rmii>; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + phy0: ethernet-phy@0 { + reg = <1>; + }; + }; + }; From 3d46d78480757e6d403c3bc2b32d2b05ecbed543 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 1 Aug 2022 16:55:36 +0200 Subject: [PATCH 1419/1436] platform/x86/intel/vsec: Fix wrong type for local status variables The local status variables in intel_vsec_pci_error_detected() and intel_vsec_pci_slot_reset() should have pci_ers_result_t as type (and not pci_channel_state_t). Also fix a whitespace error as well as intel_vsec_pci_err_handlers not being marked static. This fixes the following sparse errors: drivers/platform/x86/intel/vsec.c:429:38: sparse: sparse: incorrect type in initializer (different base types) @@ expected restricted pci_channel_state_t [usertype] status @@ got restricted pci_ers_result_t @@ drivers/platform/x86/intel/vsec.c:429:38: sparse: expected restricted pci_channel_state_t [usertype] status drivers/platform/x86/intel/vsec.c:429:38: sparse: got restricted pci_ers_result_t drivers/platform/x86/intel/vsec.c:434:24: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted pci_channel_state_t [usertype] status @@ got restricted pci_ers_result_t @@ drivers/platform/x86/intel/vsec.c:434:24: sparse: expected restricted pci_channel_state_t [usertype] status drivers/platform/x86/intel/vsec.c:434:24: sparse: got restricted pci_ers_result_t drivers/platform/x86/intel/vsec.c:438:16: sparse: sparse: incorrect type in return expression (different base types) @@ expected restricted pci_ers_result_t @@ got restricted pci_channel_state_t [usertype] status @@ drivers/platform/x86/intel/vsec.c:438:16: sparse: expected restricted pci_ers_result_t drivers/platform/x86/intel/vsec.c:438:16: sparse: got restricted pci_channel_state_t [usertype] status drivers/platform/x86/intel/vsec.c:444:38: sparse: sparse: incorrect type in initializer (different base types) @@ expected restricted pci_channel_state_t [usertype] status @@ got restricted pci_ers_result_t @@ drivers/platform/x86/intel/vsec.c:444:38: sparse: expected restricted pci_channel_state_t [usertype] status drivers/platform/x86/intel/vsec.c:444:38: sparse: got restricted pci_ers_result_t drivers/platform/x86/intel/vsec.c:457:16: sparse: sparse: incorrect type in assignment (different base types) @@ expected restricted pci_channel_state_t [usertype] status @@ got restricted pci_ers_result_t @@ drivers/platform/x86/intel/vsec.c:457:16: sparse: expected restricted pci_channel_state_t [usertype] status drivers/platform/x86/intel/vsec.c:457:16: sparse: got restricted pci_ers_result_t drivers/platform/x86/intel/vsec.c:472:16: sparse: sparse: incorrect type in return expression (different base types) @@ expected restricted pci_ers_result_t @@ got restricted pci_channel_state_t [usertype] status @@ drivers/platform/x86/intel/vsec.c:472:16: sparse: expected restricted pci_ers_result_t drivers/platform/x86/intel/vsec.c:472:16: sparse: got restricted pci_channel_state_t [usertype] status drivers/platform/x86/intel/vsec.c:480:33: sparse: sparse: symbol 'intel_vsec_pci_err_handlers' was not declared. Should it be static? Reported-by: kernel test robot Cc: Srinivas Pandruvada Cc: David E Box Cc: Gayatri Kammela Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20220801145536.172410-1-hdegoede@redhat.com --- drivers/platform/x86/intel/vsec.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c index 70c76f54f544..bb81b8b1f7e9 100644 --- a/drivers/platform/x86/intel/vsec.c +++ b/drivers/platform/x86/intel/vsec.c @@ -426,7 +426,7 @@ MODULE_DEVICE_TABLE(pci, intel_vsec_pci_ids); static pci_ers_result_t intel_vsec_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { - pci_channel_state_t status = PCI_ERS_RESULT_NEED_RESET; + pci_ers_result_t status = PCI_ERS_RESULT_NEED_RESET; dev_info(&pdev->dev, "PCI error detected, state %d", state); @@ -441,7 +441,7 @@ static pci_ers_result_t intel_vsec_pci_error_detected(struct pci_dev *pdev, static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev) { struct intel_vsec_device *intel_vsec_dev; - pci_channel_state_t status = PCI_ERS_RESULT_DISCONNECT; + pci_ers_result_t status = PCI_ERS_RESULT_DISCONNECT; const struct pci_device_id *pci_dev_id; unsigned long index; @@ -454,7 +454,7 @@ static pci_ers_result_t intel_vsec_pci_slot_reset(struct pci_dev *pdev) goto out; } - status = PCI_ERS_RESULT_RECOVERED; + status = PCI_ERS_RESULT_RECOVERED; xa_for_each(&auxdev_array, index, intel_vsec_dev) { /* check if pdev doesn't match */ @@ -477,7 +477,7 @@ static void intel_vsec_pci_resume(struct pci_dev *pdev) dev_info(&pdev->dev, "Done resuming PCI device\n"); } -const struct pci_error_handlers intel_vsec_pci_err_handlers = { +static const struct pci_error_handlers intel_vsec_pci_err_handlers = { .error_detected = intel_vsec_pci_error_detected, .slot_reset = intel_vsec_pci_slot_reset, .resume = intel_vsec_pci_resume, From be55492e01ab8a2d259b3404ba24465a0ad27130 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 31 Jul 2022 19:52:21 -0700 Subject: [PATCH 1420/1436] devicetree/bindings: correct possessive "its" typos Correct all uses of "it's" that are meant to be possessive "its". Signed-off-by: Randy Dunlap Cc: Jonathan Corbet Cc: Rob Herring Cc: Krzysztof Kozlowski Cc: devicetree@vger.kernel.org Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220801025221.30563-1-rdunlap@infradead.org --- Documentation/devicetree/bindings/clock/st/st,flexgen.txt | 2 +- Documentation/devicetree/bindings/clock/ti/dra7-atl.txt | 2 +- Documentation/devicetree/bindings/hwmon/adt7475.yaml | 2 +- .../devicetree/bindings/input/touchscreen/ektf2127.txt | 2 +- Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml | 2 +- Documentation/devicetree/bindings/mips/lantiq/rcu.txt | 2 +- Documentation/devicetree/bindings/net/altera_tse.txt | 2 +- Documentation/devicetree/bindings/net/cpsw.txt | 2 +- Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt | 2 +- Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml | 2 +- Documentation/devicetree/bindings/sound/da9055.txt | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/st/st,flexgen.txt b/Documentation/devicetree/bindings/clock/st/st,flexgen.txt index 55a18939bddd..c918075405ba 100644 --- a/Documentation/devicetree/bindings/clock/st/st,flexgen.txt +++ b/Documentation/devicetree/bindings/clock/st/st,flexgen.txt @@ -78,7 +78,7 @@ Required properties: - #clock-cells : from common clock binding; shall be set to 1 (multiple clock outputs). -- clocks : must be set to the parent's phandle. it's could be output clocks of +- clocks : must be set to the parent's phandle. it could be output clocks of a quadsfs or/and a pll or/and clk_sysin (up to 7 clocks) - clock-output-names : List of strings used to name the clock outputs. diff --git a/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt b/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt index 21c002d28b9b..68504079f99f 100644 --- a/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt +++ b/Documentation/devicetree/bindings/clock/ti/dra7-atl.txt @@ -6,7 +6,7 @@ functional clock but can be configured to provide different clocks. ATL can maintain a clock averages to some desired frequency based on the bws/aws signals - can compensate the drift between the two ws signal. -In order to provide the support for ATL and it's output clocks (which can be used +In order to provide the support for ATL and its output clocks (which can be used internally within the SoC or external components) two sets of bindings is needed: Clock tree binding: diff --git a/Documentation/devicetree/bindings/hwmon/adt7475.yaml b/Documentation/devicetree/bindings/hwmon/adt7475.yaml index 56baf2e5c6d1..ea595102a86e 100644 --- a/Documentation/devicetree/bindings/hwmon/adt7475.yaml +++ b/Documentation/devicetree/bindings/hwmon/adt7475.yaml @@ -57,7 +57,7 @@ patternProperties: Configures bypassing the individual voltage input attenuator. If set to 1 the attenuator is bypassed if set to 0 the attenuator is not bypassed. If the property is absent then the attenuator - retains it's configuration from the bios/bootloader. + retains its configuration from the bios/bootloader. $ref: /schemas/types.yaml#/definitions/uint32 enum: [0, 1] diff --git a/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt b/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt index 5eef5e7d6aae..c9f2c9f578e3 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/ektf2127.txt @@ -6,7 +6,7 @@ Required properties: - interrupts : interrupt specification for the ektf2127 interrupt - power-gpios : GPIO specification for the pin connected to the ektf2127's wake input. This needs to be driven high - to take ektf2127 out of it's low power state + to take ektf2127 out of its low power state For additional optional properties see: touchscreen.txt diff --git a/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml index fe265bcab50d..fbface720678 100644 --- a/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml +++ b/Documentation/devicetree/bindings/mfd/rohm,bd71815-pmic.yaml @@ -74,7 +74,7 @@ properties: rohm,enable-hidden-gpo: description: | The BD71815 has undocumented GPO at pin E5. Pin is marked as GND at the - data-sheet as it's location in the middle of GND pins makes it hard to + data-sheet as its location in the middle of GND pins makes it hard to use on PCB. If your board has managed to use this pin you can enable the second GPO by defining this property. Dont enable this if you are unsure about how the E5 pin is connected on your board. diff --git a/Documentation/devicetree/bindings/mips/lantiq/rcu.txt b/Documentation/devicetree/bindings/mips/lantiq/rcu.txt index 58d51f480c9e..8ec6191c1712 100644 --- a/Documentation/devicetree/bindings/mips/lantiq/rcu.txt +++ b/Documentation/devicetree/bindings/mips/lantiq/rcu.txt @@ -2,7 +2,7 @@ Lantiq XWAY SoC RCU binding =========================== This binding describes the RCU (reset controller unit) multifunction device, -where each sub-device has it's own set of registers. +where each sub-device has its own set of registers. The RCU register range is used for multiple purposes. Mostly one device uses one or multiple register exclusively, but for some registers some diff --git a/Documentation/devicetree/bindings/net/altera_tse.txt b/Documentation/devicetree/bindings/net/altera_tse.txt index 0b7d4d3758ea..1d9148ff5130 100644 --- a/Documentation/devicetree/bindings/net/altera_tse.txt +++ b/Documentation/devicetree/bindings/net/altera_tse.txt @@ -15,7 +15,7 @@ Required properties: "rx_desc": MSGDMA Rx dispatcher descriptor space region "rx_resp": MSGDMA Rx dispatcher response space region "s1": SGDMA descriptor memory -- interrupts: Should contain the TSE interrupts and it's mode. +- interrupts: Should contain the TSE interrupts and its mode. - interrupt-names: Should contain the interrupt names "rx_irq": xDMA Rx dispatcher interrupt "tx_irq": xDMA Tx dispatcher interrupt diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt index 7c7ac5eb0313..ef655f386b2e 100644 --- a/Documentation/devicetree/bindings/net/cpsw.txt +++ b/Documentation/devicetree/bindings/net/cpsw.txt @@ -20,7 +20,7 @@ Required properties: - active_slave : Specifies the slave to use for time stamping, ethtool and SIOCGMIIPHY - cpsw-phy-sel : Specifies the phandle to the CPSW phy mode selection - device. See also cpsw-phy-sel.txt for it's binding. + device. See also cpsw-phy-sel.txt for its binding. Note that in legacy cases cpsw-phy-sel may be a child device instead of a phandle (DEPRECATED, use phys property instead). diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt index d096cf461d81..4571c857dbe5 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpc5200.txt @@ -172,7 +172,7 @@ Interrupt controller (fsl,mpc5200-pic) node The mpc5200 pic binding splits hardware IRQ numbers into two levels. The split reflects the layout of the PIC hardware itself, which groups interrupts into one of three groups; CRIT, MAIN or PERP. Also, the -Bestcomm dma engine has it's own set of interrupt sources which are +Bestcomm dma engine has its own set of interrupt sources which are cascaded off of peripheral interrupt 0, which the driver interprets as a fourth group, SDMA. diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index e2e173dfada7..ebe072f6aba9 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -13,7 +13,7 @@ description: This binding describes the hardware component responsible for side channel requests to the always-on subsystem (AOSS), used for certain power management requests that is not handled by the standard RPMh interface. Each client in the - SoC has it's own block of message RAM and IRQ for communication with the AOSS. + SoC has its own block of message RAM and IRQ for communication with the AOSS. The protocol used to communicate in the message RAM is known as Qualcomm Messaging Protocol (QMP) diff --git a/Documentation/devicetree/bindings/sound/da9055.txt b/Documentation/devicetree/bindings/sound/da9055.txt index ed1b7cc6f249..75c6338b6ae2 100644 --- a/Documentation/devicetree/bindings/sound/da9055.txt +++ b/Documentation/devicetree/bindings/sound/da9055.txt @@ -2,7 +2,7 @@ DA9055 provides Audio CODEC support (I2C only). -The Audio CODEC device in DA9055 has it's own I2C address which is configurable, +The Audio CODEC device in DA9055 has its own I2C address which is configurable, so the device is instantiated separately from the PMIC (MFD) device. For details on accompanying PMIC I2C device, see the following: From 7913145afa51bbed9eaf8e5b4ee55fa9884a71e5 Mon Sep 17 00:00:00 2001 From: Xu Qiang Date: Mon, 1 Aug 2022 12:05:06 +0000 Subject: [PATCH 1421/1436] of/fdt: declared return type does not match actual return type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit 649cab56de8e (“of: properly check for error returned by fdt_get_name()”) changed the return value type from bool to int, but forgot to change the return value simultaneously. populate_node was only called in unflatten_dt_nodes, and returns with values greater than or equal to 0 were discarded without further processing. Considering that return 0 usually indicates success, return 0 instead of return true. Fixes: 649cab56de8e (“of: properly check for error returned by fdt_get_name()”) Signed-off-by: Xu Qiang Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220801120506.11461-2-xuqiang36@huawei.com --- drivers/of/fdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 872b7b54e197..e02a30c92719 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -246,7 +246,7 @@ static int populate_node(const void *blob, } *pnp = np; - return true; + return 0; } static void reverse_nodes(struct device_node *parent) From 6312bb711e5c0bc5810a0966ff647a57b3236039 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Thu, 28 Jul 2022 11:51:37 -0600 Subject: [PATCH 1422/1436] dt-bindings: PCI: host-generic-pci: Allow IOMMU and MSI properties Allow 'iommu-map', 'iommu-map-mask', and 'msi-parent' properties for generic host. This fixes unevaluated property warnings on Arm Juno, AMD Seattle, and FSL LS1028a. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220728175137.1172841-1-robh@kernel.org --- Documentation/devicetree/bindings/pci/host-generic-pci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/pci/host-generic-pci.yaml b/Documentation/devicetree/bindings/pci/host-generic-pci.yaml index 6bcaa8f2c3cf..d25423aa7167 100644 --- a/Documentation/devicetree/bindings/pci/host-generic-pci.yaml +++ b/Documentation/devicetree/bindings/pci/host-generic-pci.yaml @@ -106,6 +106,9 @@ properties: maxItems: 3 dma-coherent: true + iommu-map: true + iommu-map-mask: true + msi-parent: true required: - compatible From 93215d9f46015099b932b6d463242540e841f696 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 26 Jul 2022 13:57:46 +0200 Subject: [PATCH 1423/1436] dt-bindings: power: drop quotes when not needed Id and schema fields do not need quotes. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Hector Martin Reviewed-by: Martin Blumenstingl Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220726115748.101015-1-krzysztof.kozlowski@linaro.org --- .../devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml | 4 ++-- .../devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml | 4 ++-- .../devicetree/bindings/power/apple,pmgr-pwrstate.yaml | 2 +- .../devicetree/bindings/power/brcm,bcm63xx-power.yaml | 4 ++-- Documentation/devicetree/bindings/power/renesas,apmu.yaml | 4 ++-- .../devicetree/bindings/power/renesas,rcar-sysc.yaml | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml b/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml index 4e52ef33a986..5390e988a934 100644 --- a/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml +++ b/Documentation/devicetree/bindings/power/amlogic,meson-ee-pwrc.yaml @@ -2,8 +2,8 @@ # Copyright 2019 BayLibre, SAS %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/amlogic,meson-ee-pwrc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/amlogic,meson-ee-pwrc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic Meson Everything-Else Power Domains diff --git a/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml b/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml index 86e5f6513bb3..eab21bb2050a 100644 --- a/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml +++ b/Documentation/devicetree/bindings/power/amlogic,meson-sec-pwrc.yaml @@ -3,8 +3,8 @@ # Author: Jianxin Pan %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/amlogic,meson-sec-pwrc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/amlogic,meson-sec-pwrc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Amlogic Meson Secure Power Domains diff --git a/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml b/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml index 19a194980142..94d369eb85de 100644 --- a/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml +++ b/Documentation/devicetree/bindings/power/apple,pmgr-pwrstate.yaml @@ -10,7 +10,7 @@ maintainers: - Hector Martin allOf: - - $ref: "power-domain.yaml#" + - $ref: power-domain.yaml# description: | Apple SoCs include PMGR blocks responsible for power management, diff --git a/Documentation/devicetree/bindings/power/brcm,bcm63xx-power.yaml b/Documentation/devicetree/bindings/power/brcm,bcm63xx-power.yaml index 63b15ac6dde4..d867bd6976d8 100644 --- a/Documentation/devicetree/bindings/power/brcm,bcm63xx-power.yaml +++ b/Documentation/devicetree/bindings/power/brcm,bcm63xx-power.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/brcm,bcm63xx-power.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/brcm,bcm63xx-power.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: BCM63xx power domain driver diff --git a/Documentation/devicetree/bindings/power/renesas,apmu.yaml b/Documentation/devicetree/bindings/power/renesas,apmu.yaml index d77fc88050c8..f2cc89e7f4e4 100644 --- a/Documentation/devicetree/bindings/power/renesas,apmu.yaml +++ b/Documentation/devicetree/bindings/power/renesas,apmu.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/renesas,apmu.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/renesas,apmu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas Advanced Power Management Unit diff --git a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.yaml b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.yaml index 8d56bedd3390..0720b54881c2 100644 --- a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.yaml +++ b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/renesas,rcar-sysc.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/renesas,rcar-sysc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Renesas R-Car and RZ/G System Controller From 7ae0d493a5af9dcd929b721d31a3cfad21f5fbda Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 26 Jul 2022 13:57:47 +0200 Subject: [PATCH 1424/1436] dt-bindings: power: reset: drop quotes when not needed string literals do not need quotes. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220726115748.101015-2-krzysztof.kozlowski@linaro.org --- .../devicetree/bindings/power/reset/regulator-poweroff.yaml | 2 +- .../devicetree/bindings/power/reset/xlnx,zynqmp-power.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/power/reset/regulator-poweroff.yaml b/Documentation/devicetree/bindings/power/reset/regulator-poweroff.yaml index 03bd1fa5a623..e9417557cd30 100644 --- a/Documentation/devicetree/bindings/power/reset/regulator-poweroff.yaml +++ b/Documentation/devicetree/bindings/power/reset/regulator-poweroff.yaml @@ -16,7 +16,7 @@ description: | properties: compatible: - const: "regulator-poweroff" + const: regulator-poweroff cpu-supply: description: diff --git a/Documentation/devicetree/bindings/power/reset/xlnx,zynqmp-power.yaml b/Documentation/devicetree/bindings/power/reset/xlnx,zynqmp-power.yaml index 68d7c14a7163..46de35861738 100644 --- a/Documentation/devicetree/bindings/power/reset/xlnx,zynqmp-power.yaml +++ b/Documentation/devicetree/bindings/power/reset/xlnx,zynqmp-power.yaml @@ -15,7 +15,7 @@ description: | properties: compatible: - const: "xlnx,zynqmp-power" + const: xlnx,zynqmp-power interrupts: maxItems: 1 From 1ea78ec5ba3143120c65be5f166fa61b528c4c2c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 26 Jul 2022 13:57:48 +0200 Subject: [PATCH 1425/1436] dt-bindings: power: supply: drop quotes when not needed Id and schema fields do not need quotes. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220726115748.101015-3-krzysztof.kozlowski@linaro.org --- .../bindings/power/supply/active-semi,act8945a-charger.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/bq2415x.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/bq24190.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/bq24257.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/bq24735.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/bq2515x.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/bq256xx.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/bq25890.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/bq25980.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/bq27xxx.yaml | 4 ++-- .../devicetree/bindings/power/supply/cpcap-battery.yaml | 4 ++-- .../devicetree/bindings/power/supply/cpcap-charger.yaml | 4 ++-- .../devicetree/bindings/power/supply/dlg,da9150-charger.yaml | 4 ++-- .../bindings/power/supply/dlg,da9150-fuel-gauge.yaml | 4 ++-- .../devicetree/bindings/power/supply/ingenic,battery.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/isp1704.yaml | 4 ++-- .../devicetree/bindings/power/supply/lego,ev3-battery.yaml | 4 ++-- .../devicetree/bindings/power/supply/lltc,lt3651-charger.yaml | 4 ++-- .../devicetree/bindings/power/supply/lltc,ltc294x.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml | 4 ++-- .../devicetree/bindings/power/supply/maxim,ds2760.yaml | 4 ++-- .../devicetree/bindings/power/supply/maxim,max14656.yaml | 4 ++-- .../devicetree/bindings/power/supply/maxim,max17040.yaml | 4 ++-- .../devicetree/bindings/power/supply/maxim,max17042.yaml | 4 ++-- .../devicetree/bindings/power/supply/maxim,max8903.yaml | 4 ++-- .../devicetree/bindings/power/supply/nokia,n900-battery.yaml | 4 ++-- .../devicetree/bindings/power/supply/olpc-battery.yaml | 4 ++-- .../devicetree/bindings/power/supply/power-supply.yaml | 4 ++-- .../bindings/power/supply/richtek,rt5033-battery.yaml | 4 ++-- .../devicetree/bindings/power/supply/richtek,rt9455.yaml | 4 ++-- .../devicetree/bindings/power/supply/sc2731-charger.yaml | 4 ++-- Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml | 4 ++-- .../bindings/power/supply/stericsson,ab8500-btemp.yaml | 4 ++-- .../bindings/power/supply/stericsson,ab8500-chargalg.yaml | 4 ++-- .../bindings/power/supply/stericsson,ab8500-charger.yaml | 4 ++-- .../bindings/power/supply/stericsson,ab8500-fg.yaml | 4 ++-- .../bindings/power/supply/summit,smb347-charger.yaml | 4 ++-- .../devicetree/bindings/power/supply/tps65090-charger.yaml | 4 ++-- .../devicetree/bindings/power/supply/tps65217-charger.yaml | 4 ++-- .../devicetree/bindings/power/supply/twl4030-charger.yaml | 4 ++-- .../power/supply/x-powers,axp20x-ac-power-supply.yaml | 4 ++-- .../power/supply/x-powers,axp20x-battery-power-supply.yaml | 4 ++-- .../power/supply/x-powers,axp20x-usb-power-supply.yaml | 4 ++-- 43 files changed, 86 insertions(+), 86 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/active-semi,act8945a-charger.yaml b/Documentation/devicetree/bindings/power/supply/active-semi,act8945a-charger.yaml index 3f74bc19415d..5220d9cb16d8 100644 --- a/Documentation/devicetree/bindings/power/supply/active-semi,act8945a-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/active-semi,act8945a-charger.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/active-semi,act8945a-charger.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/active-semi,act8945a-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Active-semi ACT8945A Charger Function diff --git a/Documentation/devicetree/bindings/power/supply/bq2415x.yaml b/Documentation/devicetree/bindings/power/supply/bq2415x.yaml index 118cf484cc69..a3c00e078918 100644 --- a/Documentation/devicetree/bindings/power/supply/bq2415x.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq2415x.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/bq2415x.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/bq2415x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Binding for TI bq2415x Li-Ion Charger diff --git a/Documentation/devicetree/bindings/power/supply/bq24190.yaml b/Documentation/devicetree/bindings/power/supply/bq24190.yaml index 0d7cbbdf808b..21a9dadc1c6a 100644 --- a/Documentation/devicetree/bindings/power/supply/bq24190.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq24190.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/bq24190.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/bq24190.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Binding for TI BQ2419x Li-Ion Battery Charger diff --git a/Documentation/devicetree/bindings/power/supply/bq24257.yaml b/Documentation/devicetree/bindings/power/supply/bq24257.yaml index 3a0f6cd9015a..c7406bef0fa8 100644 --- a/Documentation/devicetree/bindings/power/supply/bq24257.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq24257.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/bq24257.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/bq24257.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Binding for bq24250, bq24251 and bq24257 Li-Ion Charger diff --git a/Documentation/devicetree/bindings/power/supply/bq24735.yaml b/Documentation/devicetree/bindings/power/supply/bq24735.yaml index 131be6782c4b..dd9176ce71b3 100644 --- a/Documentation/devicetree/bindings/power/supply/bq24735.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq24735.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/bq24735.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/bq24735.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Binding for TI BQ24735 Li-Ion Battery Charger diff --git a/Documentation/devicetree/bindings/power/supply/bq2515x.yaml b/Documentation/devicetree/bindings/power/supply/bq2515x.yaml index 813d6afde606..27db38577822 100644 --- a/Documentation/devicetree/bindings/power/supply/bq2515x.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq2515x.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2020 Texas Instruments Incorporated %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/bq2515x.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/bq2515x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TI bq2515x 500-mA Linear charger family diff --git a/Documentation/devicetree/bindings/power/supply/bq256xx.yaml b/Documentation/devicetree/bindings/power/supply/bq256xx.yaml index 92ec7ed25668..91abe5733c41 100644 --- a/Documentation/devicetree/bindings/power/supply/bq256xx.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq256xx.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2020 Texas Instruments Incorporated %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/bq256xx.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/bq256xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TI bq256xx Switch Mode Buck Charger diff --git a/Documentation/devicetree/bindings/power/supply/bq25890.yaml b/Documentation/devicetree/bindings/power/supply/bq25890.yaml index bf823b615439..204c0147188f 100644 --- a/Documentation/devicetree/bindings/power/supply/bq25890.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq25890.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/bq25890.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/bq25890.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Binding for bq25890, bq25892, bq25895 and bq25896 Li-Ion Charger diff --git a/Documentation/devicetree/bindings/power/supply/bq25980.yaml b/Documentation/devicetree/bindings/power/supply/bq25980.yaml index 8367a1fd4057..4883527ab5c7 100644 --- a/Documentation/devicetree/bindings/power/supply/bq25980.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq25980.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2020 Texas Instruments Incorporated %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/bq25980.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/bq25980.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TI BQ25980 Flash Charger diff --git a/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml b/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml index 6af41da3e055..65fc6049efc1 100644 --- a/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml +++ b/Documentation/devicetree/bindings/power/supply/bq27xxx.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2020 Texas Instruments Incorporated %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/bq27xxx.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/bq27xxx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TI BQ27XXX fuel gauge family diff --git a/Documentation/devicetree/bindings/power/supply/cpcap-battery.yaml b/Documentation/devicetree/bindings/power/supply/cpcap-battery.yaml index 7153fd4ce55f..694bfdb5815c 100644 --- a/Documentation/devicetree/bindings/power/supply/cpcap-battery.yaml +++ b/Documentation/devicetree/bindings/power/supply/cpcap-battery.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/cpcap-battery.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/cpcap-battery.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Motorola CPCAP PMIC battery diff --git a/Documentation/devicetree/bindings/power/supply/cpcap-charger.yaml b/Documentation/devicetree/bindings/power/supply/cpcap-charger.yaml index cb6353683d7b..7e6bf30a0107 100644 --- a/Documentation/devicetree/bindings/power/supply/cpcap-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/cpcap-charger.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/cpcap-charger.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/cpcap-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Motorola CPCAP PMIC charger diff --git a/Documentation/devicetree/bindings/power/supply/dlg,da9150-charger.yaml b/Documentation/devicetree/bindings/power/supply/dlg,da9150-charger.yaml index 96336b05d76d..b289388952bf 100644 --- a/Documentation/devicetree/bindings/power/supply/dlg,da9150-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/dlg,da9150-charger.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/dlg,da9150-charger.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/dlg,da9150-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Dialog Semiconductor DA9150 Charger Power Supply bindings diff --git a/Documentation/devicetree/bindings/power/supply/dlg,da9150-fuel-gauge.yaml b/Documentation/devicetree/bindings/power/supply/dlg,da9150-fuel-gauge.yaml index 30c2fff7cf92..d47caf59d204 100644 --- a/Documentation/devicetree/bindings/power/supply/dlg,da9150-fuel-gauge.yaml +++ b/Documentation/devicetree/bindings/power/supply/dlg,da9150-fuel-gauge.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/dlg,da9150-fuel-gauge.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/dlg,da9150-fuel-gauge.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Dialog Semiconductor DA9150 Fuel-Gauge Power Supply bindings diff --git a/Documentation/devicetree/bindings/power/supply/ingenic,battery.yaml b/Documentation/devicetree/bindings/power/supply/ingenic,battery.yaml index 76c227a7cd5c..46527038bf22 100644 --- a/Documentation/devicetree/bindings/power/supply/ingenic,battery.yaml +++ b/Documentation/devicetree/bindings/power/supply/ingenic,battery.yaml @@ -2,8 +2,8 @@ # Copyright 2019-2020 Artur Rojek %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/ingenic,battery.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/ingenic,battery.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Ingenic JZ47xx battery bindings diff --git a/Documentation/devicetree/bindings/power/supply/isp1704.yaml b/Documentation/devicetree/bindings/power/supply/isp1704.yaml index 4c91da70011d..7e3449ed70d4 100644 --- a/Documentation/devicetree/bindings/power/supply/isp1704.yaml +++ b/Documentation/devicetree/bindings/power/supply/isp1704.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/isp1704.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/isp1704.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Binding for NXP ISP1704 USB Charger Detection diff --git a/Documentation/devicetree/bindings/power/supply/lego,ev3-battery.yaml b/Documentation/devicetree/bindings/power/supply/lego,ev3-battery.yaml index 518eabb63588..a99d989f1450 100644 --- a/Documentation/devicetree/bindings/power/supply/lego,ev3-battery.yaml +++ b/Documentation/devicetree/bindings/power/supply/lego,ev3-battery.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/lego,ev3-battery.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/lego,ev3-battery.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: LEGO MINDSTORMS EV3 Battery diff --git a/Documentation/devicetree/bindings/power/supply/lltc,lt3651-charger.yaml b/Documentation/devicetree/bindings/power/supply/lltc,lt3651-charger.yaml index e2d8d2aebb73..76cedf95a12c 100644 --- a/Documentation/devicetree/bindings/power/supply/lltc,lt3651-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/lltc,lt3651-charger.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/lltc,lt3651-charger.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/lltc,lt3651-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Analog Devices LT3651 Charger Power Supply bindings diff --git a/Documentation/devicetree/bindings/power/supply/lltc,ltc294x.yaml b/Documentation/devicetree/bindings/power/supply/lltc,ltc294x.yaml index 043bf378040f..109b41a0d56c 100644 --- a/Documentation/devicetree/bindings/power/supply/lltc,ltc294x.yaml +++ b/Documentation/devicetree/bindings/power/supply/lltc,ltc294x.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/lltc,ltc294x.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/lltc,ltc294x.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Binding for LTC2941, LTC2942, LTC2943 and LTC2944 battery fuel gauges diff --git a/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml index 6d7aa97a6475..cfffaeef8b09 100644 --- a/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml +++ b/Documentation/devicetree/bindings/power/supply/ltc4162-l.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2020 Topic Embedded Products %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/ltc4162-l.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/ltc4162-l.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Linear Technology (Analog Devices) LTC4162-L Charger diff --git a/Documentation/devicetree/bindings/power/supply/maxim,ds2760.yaml b/Documentation/devicetree/bindings/power/supply/maxim,ds2760.yaml index 818647edf63d..c838efcf7e16 100644 --- a/Documentation/devicetree/bindings/power/supply/maxim,ds2760.yaml +++ b/Documentation/devicetree/bindings/power/supply/maxim,ds2760.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/maxim,ds2760.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/maxim,ds2760.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Maxim DS2760 DT bindings diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max14656.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max14656.yaml index 0a41078ebd99..070ef6f96e60 100644 --- a/Documentation/devicetree/bindings/power/supply/maxim,max14656.yaml +++ b/Documentation/devicetree/bindings/power/supply/maxim,max14656.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/maxim,max14656.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/maxim,max14656.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Maxim MAX14656 DT bindings diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml index 6b4588a3253b..3a529326ecbd 100644 --- a/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml +++ b/Documentation/devicetree/bindings/power/supply/maxim,max17040.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/maxim,max17040.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/maxim,max17040.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Maxim 17040 fuel gauge series diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml index 971b53c58cc6..aff5d0792e0f 100644 --- a/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml +++ b/Documentation/devicetree/bindings/power/supply/maxim,max17042.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/maxim,max17042.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/maxim,max17042.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Maxim 17042 fuel gauge series diff --git a/Documentation/devicetree/bindings/power/supply/maxim,max8903.yaml b/Documentation/devicetree/bindings/power/supply/maxim,max8903.yaml index 4828ca0842ae..a8d625f285f1 100644 --- a/Documentation/devicetree/bindings/power/supply/maxim,max8903.yaml +++ b/Documentation/devicetree/bindings/power/supply/maxim,max8903.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/maxim,max8903.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/maxim,max8903.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Maxim Semiconductor MAX8903 Battery Charger diff --git a/Documentation/devicetree/bindings/power/supply/nokia,n900-battery.yaml b/Documentation/devicetree/bindings/power/supply/nokia,n900-battery.yaml index 4a1489f2b28d..5178e6207271 100644 --- a/Documentation/devicetree/bindings/power/supply/nokia,n900-battery.yaml +++ b/Documentation/devicetree/bindings/power/supply/nokia,n900-battery.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/nokia,n900-battery.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/nokia,n900-battery.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Nokia N900 battery diff --git a/Documentation/devicetree/bindings/power/supply/olpc-battery.yaml b/Documentation/devicetree/bindings/power/supply/olpc-battery.yaml index 0bd7bf3b8e1b..dd89e2532a07 100644 --- a/Documentation/devicetree/bindings/power/supply/olpc-battery.yaml +++ b/Documentation/devicetree/bindings/power/supply/olpc-battery.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/olpc-battery.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/olpc-battery.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: OLPC Battery diff --git a/Documentation/devicetree/bindings/power/supply/power-supply.yaml b/Documentation/devicetree/bindings/power/supply/power-supply.yaml index 9a490fbd32e1..2f672e6e8d72 100644 --- a/Documentation/devicetree/bindings/power/supply/power-supply.yaml +++ b/Documentation/devicetree/bindings/power/supply/power-supply.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/power-supply.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/power-supply.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Power Supply Core Support diff --git a/Documentation/devicetree/bindings/power/supply/richtek,rt5033-battery.yaml b/Documentation/devicetree/bindings/power/supply/richtek,rt5033-battery.yaml index ae647d3355a2..756c16d1727d 100644 --- a/Documentation/devicetree/bindings/power/supply/richtek,rt5033-battery.yaml +++ b/Documentation/devicetree/bindings/power/supply/richtek,rt5033-battery.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/richtek,rt5033-battery.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/richtek,rt5033-battery.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Richtek RT5033 PMIC Fuel Gauge diff --git a/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml b/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml index e1c233462f29..bce15101318e 100644 --- a/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml +++ b/Documentation/devicetree/bindings/power/supply/richtek,rt9455.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/richtek,rt9455.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/richtek,rt9455.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Binding for Richtek rt9455 battery charger diff --git a/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml b/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml index b62c2431f94e..eeb043f9bb4f 100644 --- a/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/sc2731-charger.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/sc2731-charger.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/sc2731-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Spreadtrum SC2731 PMICs battery charger binding diff --git a/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml b/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml index e019cffd1f38..d90a838a1744 100644 --- a/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml +++ b/Documentation/devicetree/bindings/power/supply/sc27xx-fg.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/sc27xx-fg.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/sc27xx-fg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Spreadtrum SC27XX PMICs Fuel Gauge Unit Power Supply Bindings diff --git a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-btemp.yaml b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-btemp.yaml index 4b8a00cec39c..525abdfb3e2d 100644 --- a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-btemp.yaml +++ b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-btemp.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/stericsson,ab8500-btemp.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/stericsson,ab8500-btemp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: AB8500 Battery Temperature Monitor diff --git a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-chargalg.yaml b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-chargalg.yaml index 6799224f7fb4..10bbdcfc87b6 100644 --- a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-chargalg.yaml +++ b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-chargalg.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/stericsson,ab8500-chargalg.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/stericsson,ab8500-chargalg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: AB8500 Charging Algorithm diff --git a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-charger.yaml b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-charger.yaml index 9518eb7289d0..e33329b3af61 100644 --- a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-charger.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/stericsson,ab8500-charger.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/stericsson,ab8500-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: AB8500 Charger diff --git a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-fg.yaml b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-fg.yaml index 2ce408a7c0ae..6a724ca90e99 100644 --- a/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-fg.yaml +++ b/Documentation/devicetree/bindings/power/supply/stericsson,ab8500-fg.yaml @@ -2,8 +2,8 @@ # Copyright (C) 2021 Sebastian Reichel %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/stericsson,ab8500-fg.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/stericsson,ab8500-fg.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: AB8500 Fuel Gauge diff --git a/Documentation/devicetree/bindings/power/supply/summit,smb347-charger.yaml b/Documentation/devicetree/bindings/power/supply/summit,smb347-charger.yaml index 20862cdfc116..0581497448ce 100644 --- a/Documentation/devicetree/bindings/power/supply/summit,smb347-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/summit,smb347-charger.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/summit,smb347-charger.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/summit,smb347-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Battery charger driver for SMB345, SMB347 and SMB358 diff --git a/Documentation/devicetree/bindings/power/supply/tps65090-charger.yaml b/Documentation/devicetree/bindings/power/supply/tps65090-charger.yaml index f2dd38bf078c..586745426341 100644 --- a/Documentation/devicetree/bindings/power/supply/tps65090-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/tps65090-charger.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/tps65090-charger.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/tps65090-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TPS65090 Frontend PMU with Switchmode Charger diff --git a/Documentation/devicetree/bindings/power/supply/tps65217-charger.yaml b/Documentation/devicetree/bindings/power/supply/tps65217-charger.yaml index 2c2fe883bb48..7ccf0cdffd3e 100644 --- a/Documentation/devicetree/bindings/power/supply/tps65217-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/tps65217-charger.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/tps65217-charger.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/tps65217-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TPS65217 Charger diff --git a/Documentation/devicetree/bindings/power/supply/twl4030-charger.yaml b/Documentation/devicetree/bindings/power/supply/twl4030-charger.yaml index fe3f32a0ea79..d8d3154f9cb1 100644 --- a/Documentation/devicetree/bindings/power/supply/twl4030-charger.yaml +++ b/Documentation/devicetree/bindings/power/supply/twl4030-charger.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/twl4030-charger.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/twl4030-charger.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: TWL4030 BCI (Battery Charger Interface) diff --git a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-ac-power-supply.yaml b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-ac-power-supply.yaml index de6a23aee977..5c8369fd3ef7 100644 --- a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-ac-power-supply.yaml +++ b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-ac-power-supply.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/x-powers,axp20x-ac-power-supply.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/x-powers,axp20x-ac-power-supply.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: AXP20x AC power-supply diff --git a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml index d055428ae39f..e0b95ecbbebd 100644 --- a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml +++ b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-battery-power-supply.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/x-powers,axp20x-battery-power-supply.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/x-powers,axp20x-battery-power-supply.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: AXP20x Battery power-supply diff --git a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml index 0c371b55c9e1..3ce648dd91bd 100644 --- a/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml +++ b/Documentation/devicetree/bindings/power/supply/x-powers,axp20x-usb-power-supply.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/power/supply/x-powers,axp20x-usb-power-supply.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/power/supply/x-powers,axp20x-usb-power-supply.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: AXP20x USB power-supply From 7e7a24c3c6c98abc4425abd1dbf2a71b42dfafcf Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 27 Jul 2022 18:41:48 +0200 Subject: [PATCH 1426/1436] dt-bindings: mtd: microchip,mchp48l640: use spi-peripheral-props.yaml Instead of listing directly properties typical for SPI peripherals, reference the spi-peripheral-props.yaml schema. This allows using all properties typical for SPI-connected devices, even these which device bindings author did not tried yet. Remove the spi-* properties which now come via spi-peripheral-props.yaml schema, except for the cases when device schema adds some constraints like maximum frequency. While changing additionalProperties->unevaluatedProperties, put it in typical place, just before example DTS. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Tudor Ambarus Reviewed-by: Heiko Schocher Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20220727164148.385476-1-krzysztof.kozlowski@linaro.org --- .../devicetree/bindings/mtd/microchip,mchp48l640.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml b/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml index 2cdf6bf3dc4a..8cc2a7ceb5fb 100644 --- a/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml +++ b/Documentation/devicetree/bindings/mtd/microchip,mchp48l640.yaml @@ -22,13 +22,14 @@ properties: reg: maxItems: 1 - spi-max-frequency: true - required: - compatible - reg -additionalProperties: false +allOf: + - $ref: /schemas/spi/spi-peripheral-props.yaml# + +unevaluatedProperties: false examples: - | From 300a596590e4a201cdbbb42af5701d448cceab3a Mon Sep 17 00:00:00 2001 From: Hans-Christian Noren Egtvedt Date: Sat, 20 Oct 2018 12:30:17 +0200 Subject: [PATCH 1427/1436] dma:dw: remove reference to AVR32 architecture in core.c The AVR32 architecture does no longer exist in the Linux kernel, hence remove a reference to it in comments to avoid confusion. Signed-off-by: Hans-Christian Noren Egtvedt --- drivers/dma/dw/core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 7ab83fe601ed..97ba3bfc10b1 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -29,9 +29,6 @@ * (DW_ahb_dmac) which is used with various AMBA 2.0 systems (not all * of which use ARM any more). See the "Databook" from Synopsys for * information beyond what licensees probably provide. - * - * The driver has been tested with the Atmel AT32AP7000, which does not - * support descriptor writeback. */ /* The set of bus widths supported by the DMA controller */ From 53291cb23c919c5407a5054a5cfdcba79690720b Mon Sep 17 00:00:00 2001 From: Hans-Christian Noren Egtvedt Date: Sat, 20 Oct 2018 12:30:17 +0200 Subject: [PATCH 1428/1436] mfd: remove reference to AVR32 architecture in atmel-smc.c The AVR32 architecture does no longer exist in the Linux kernel, hence remove a reference to it in comments to avoid confusion. Signed-off-by: Hans-Christian Noren Egtvedt --- drivers/mfd/atmel-smc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index d96f1d689e7f..f3bad2b52f17 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -240,7 +240,7 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle); * @conf: the SMC CS conf to apply * * Applies an SMC CS configuration. - * Only valid on at91sam9/avr32 SoCs. + * Only valid on at91sam9 SoCs. */ void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs, const struct atmel_smc_cs_conf *conf) @@ -281,7 +281,7 @@ EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply); * @conf: the SMC CS conf object to store the current conf * * Retrieve the SMC CS configuration. - * Only valid on at91sam9/avr32 SoCs. + * Only valid on at91sam9 SoCs. */ void atmel_smc_cs_conf_get(struct regmap *regmap, int cs, struct atmel_smc_cs_conf *conf) From 62bf2fa70b683e287bf8005345ba7861c7be63dc Mon Sep 17 00:00:00 2001 From: Hans-Christian Noren Egtvedt Date: Sat, 20 Oct 2018 12:33:59 +0200 Subject: [PATCH 1429/1436] misc: update maintainer email address and description for atmel-ssc I have changed my overall maintainer email address to the samfundet.no domain, hence update the atmel-ssc module to reflect that. Also remove the AVR32 reference, since the AVR32 architecture no longer exist in the Linux kernel. Signed-off-by: Hans-Christian Noren Egtvedt --- drivers/misc/atmel-ssc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 69f9b0336410..7f9f562d6433 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c @@ -276,7 +276,7 @@ static struct platform_driver ssc_driver = { }; module_platform_driver(ssc_driver); -MODULE_AUTHOR("Hans-Christian Egtvedt "); -MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91"); +MODULE_AUTHOR("Hans-Christian Noren Egtvedt "); +MODULE_DESCRIPTION("SSC driver for Atmel AT91"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:ssc"); From 8bfdfbb258913047b5d5384ec2a6b049af1bf437 Mon Sep 17 00:00:00 2001 From: Hans-Christian Noren Egtvedt Date: Sun, 5 Nov 2017 11:19:53 +0100 Subject: [PATCH 1430/1436] net: remove cdns,at32ap7000-macb device tree entry The AVR32 architecture has been removed from the kernel in commit 26202873bb51fafdaa51be3e8de7aab9beb49f70, hence clean out the cdns,at32ap7000-macb compatible entry in Cadence macb Ethernet driver. AVR32 architecture never supported device tree, hence this code was not used by anybody. Updated documentation to match the default entry, no users of cdns,at32ap7000-macb in the kernel tree. Signed-off-by: Hans-Christian Noren Egtvedt --- Documentation/devicetree/bindings/net/cdns,macb.yaml | 3 +-- drivers/net/ethernet/cadence/macb_main.c | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/net/cdns,macb.yaml b/Documentation/devicetree/bindings/net/cdns,macb.yaml index 86fc31c2d91b..86f2e2ac59d9 100644 --- a/Documentation/devicetree/bindings/net/cdns,macb.yaml +++ b/Documentation/devicetree/bindings/net/cdns,macb.yaml @@ -42,7 +42,6 @@ properties: - atmel,sama5d2-gem # GEM IP (10/100) on Atmel sama5d2 SoCs - atmel,sama5d3-gem # Gigabit IP on Atmel sama5d3 SoCs - atmel,sama5d4-gem # GEM IP (10/100) on Atmel sama5d4 SoCs - - cdns,at32ap7000-macb # Other 10/100 usage or use the generic form - cdns,np4-macb # NP4 SoC devices - microchip,sama7g5-emac # Microchip SAMA7G5 ethernet interface - microchip,sama7g5-gem # Microchip SAMA7G5 gigabit ethernet interface @@ -155,7 +154,7 @@ unevaluatedProperties: false examples: - | macb0: ethernet@fffc4000 { - compatible = "cdns,at32ap7000-macb"; + compatible = "cdns,macb"; reg = <0xfffc4000 0x4000>; interrupts = <21>; phy-mode = "rmii"; diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index d89098f4ede8..9dff6db16279 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -4770,7 +4770,6 @@ static const struct macb_config sama7g5_emac_config = { }; static const struct of_device_id macb_dt_ids[] = { - { .compatible = "cdns,at32ap7000-macb" }, { .compatible = "cdns,at91sam9260-macb", .data = &at91sam9260_config }, { .compatible = "cdns,macb" }, { .compatible = "cdns,np4-macb", .data = &np4_config }, From 0a2fd172b4ba5628eefa88fbfb8599c76f6ac021 Mon Sep 17 00:00:00 2001 From: Hans-Christian Noren Egtvedt Date: Sat, 20 Oct 2018 12:48:57 +0200 Subject: [PATCH 1431/1436] sound:spi: remove reference to AVR32 in Atmel AT73C213 DAC driver The AVR32 architecture does no longer exist in the Linux kernel, hence remove a reference to it in Kconfig help text to avoid confusion. Signed-off-by: Hans-Christian Noren Egtvedt --- sound/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/spi/Kconfig b/sound/spi/Kconfig index 44d39fa635ae..f407c37c37fa 100644 --- a/sound/spi/Kconfig +++ b/sound/spi/Kconfig @@ -19,7 +19,7 @@ config SND_AT73C213 DAC can be found on Atmel development boards. This driver requires the Atmel SSC driver for sound sink, a - peripheral found on most AT91 and AVR32 microprocessors. + peripheral found on most AT91 microprocessors. To compile this driver as a module, choose M here: the module will be called snd-at73c213. From 93dd2f713ad23f0e8ba0fedf94fabc215bbb8418 Mon Sep 17 00:00:00 2001 From: Hans-Christian Noren Egtvedt Date: Sat, 20 Oct 2018 12:39:09 +0200 Subject: [PATCH 1432/1436] usb:udc: remove reference to AVR32 architecture in Atmel USBA Kconfig The AVR32 architecture does no longer exist in the Linux kernel, hence remove a reference to it in Kconfig help text to avoid confusion. Signed-off-by: Hans-Christian Noren Egtvedt --- drivers/usb/gadget/udc/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 69394dc1cdfb..53cd4654e055 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -59,8 +59,8 @@ config USB_ATMEL_USBA tristate "Atmel USBA" depends on ARCH_AT91 help - USBA is the integrated high-speed USB Device controller on - the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. + USBA is the integrated high-speed USB Device controller on some + AT91SAM9 and AT91CAP9 processors from Atmel. The fifo_mode parameter is used to select endpoint allocation mode. fifo_mode = 0 is used to let the driver autoconfigure the endpoints. From 4492b0c0897055c110777ea6ece6c08c63e8a140 Mon Sep 17 00:00:00 2001 From: Hans-Christian Noren Egtvedt Date: Sun, 5 Nov 2017 10:43:11 +0100 Subject: [PATCH 1433/1436] video: remove support for non-existing atmel,at32ap-lcdc in atmel_lcdfb The AVR32 architecture has been removed from the kernel in commit 26202873bb51fafdaa51be3e8de7aab9beb49f70, hence clean out the atmel,at32ap-lcdc parts in the atmel_lcdfb.c video driver. AVR32 architecture never supported device tree, hence this code was not used by anybody. Signed-off-by: Hans-Christian Noren Egtvedt --- Documentation/devicetree/bindings/display/atmel,lcdc.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/display/atmel,lcdc.txt b/Documentation/devicetree/bindings/display/atmel,lcdc.txt index acb5a0132127..b5e355ada2fa 100644 --- a/Documentation/devicetree/bindings/display/atmel,lcdc.txt +++ b/Documentation/devicetree/bindings/display/atmel,lcdc.txt @@ -9,7 +9,6 @@ Required properties: "atmel,at91sam9g45-lcdc" , "atmel,at91sam9g45es-lcdc" , "atmel,at91sam9rl-lcdc" , - "atmel,at32ap-lcdc" - reg : Should contain 1 register ranges(address and length). Can contain an additional register range(address and length) for fixed framebuffer memory. Useful for dedicated memories. From 2fb0ec4ae5632ba288ab233849f85069d4c475a5 Mon Sep 17 00:00:00 2001 From: Hans-Christian Noren Egtvedt Date: Sat, 20 Oct 2018 12:40:16 +0200 Subject: [PATCH 1434/1436] video:backlight: remove reference to AVR32 architecture in ltv350qv The AVR32 architecture does no longer exist in the Linux kernel, hence remove a reference to also non-existing Linux BSP CD from Atmel. Signed-off-by: Hans-Christian Noren Egtvedt --- drivers/video/backlight/ltv350qv.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c index b6d373af6e3f..d54f501e4285 100644 --- a/drivers/video/backlight/ltv350qv.c +++ b/drivers/video/backlight/ltv350qv.c @@ -27,8 +27,7 @@ struct ltv350qv { /* * The power-on and power-off sequences are taken from the * LTV350QV-F04 data sheet from Samsung. The register definitions are - * taken from the S6F2002 command list also from Samsung. Both - * documents are distributed with the AVR32 Linux BSP CD from Atmel. + * taken from the S6F2002 command list also from Samsung. * * There's still some voodoo going on here, but it's a lot better than * in the first incarnation of the driver where all we had was the raw From 78acd4ca433425e6dd4032cfc2156c60e34931f2 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Wed, 3 Aug 2022 09:24:22 -0700 Subject: [PATCH 1435/1436] usb: cdns3: Don't use priv_dev uninitialized in cdns3_gadget_ep_enable() Clang warns: drivers/usb/cdns3/cdns3-gadget.c:2290:11: error: variable 'priv_dev' is uninitialized when used here [-Werror,-Wuninitialized] dev_dbg(priv_dev->dev, "usbss: invalid parameters\n"); ^~~~~~~~ include/linux/dev_printk.h:155:18: note: expanded from macro 'dev_dbg' dynamic_dev_dbg(dev, dev_fmt(fmt), ##__VA_ARGS__) ^~~ include/linux/dynamic_debug.h:167:7: note: expanded from macro 'dynamic_dev_dbg' dev, fmt, ##__VA_ARGS__) ^~~ include/linux/dynamic_debug.h:152:56: note: expanded from macro '_dynamic_func_call' __dynamic_func_call(__UNIQUE_ID(ddebug), fmt, func, ##__VA_ARGS__) ^~~~~~~~~~~ include/linux/dynamic_debug.h:134:15: note: expanded from macro '__dynamic_func_call' func(&id, ##__VA_ARGS__); \ ^~~~~~~~~~~ drivers/usb/cdns3/cdns3-gadget.c:2278:31: note: initialize the variable 'priv_dev' to silence this warning struct cdns3_device *priv_dev; ^ = NULL 1 error generated. The priv_dev assignment was moved below the if statement to avoid potentially dereferencing ep before it was checked but priv_dev is used in the dev_dbg() call. To fix this, move the priv_dev and comp_desc assignments back to their original spot and hoist the ep check above those assignments with a call to pr_debug() instead of dev_dbg(). Fixes: c3ffc9c4ca44 ("usb: cdns3: change place of 'priv_ep' assignment in cdns3_gadget_ep_dequeue(), cdns3_gadget_ep_enable()") Link: https://github.com/ClangBuiltLinux/linux/issues/1680 Signed-off-by: Nathan Chancellor Signed-off-by: Linus Torvalds --- drivers/usb/cdns3/cdns3-gadget.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index 9ac7d0a8c5da..d21b69997e75 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -2284,15 +2284,19 @@ static int cdns3_gadget_ep_enable(struct usb_ep *ep, int ret = 0; int val; - priv_ep = ep_to_cdns3_ep(ep); - - if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) { - dev_dbg(priv_dev->dev, "usbss: invalid parameters\n"); + if (!ep) { + pr_debug("usbss: ep not configured?\n"); return -EINVAL; } - comp_desc = priv_ep->endpoint.comp_desc; + priv_ep = ep_to_cdns3_ep(ep); priv_dev = priv_ep->cdns3_dev; + comp_desc = priv_ep->endpoint.comp_desc; + + if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT) { + dev_dbg(priv_dev->dev, "usbss: invalid parameters\n"); + return -EINVAL; + } if (!desc->wMaxPacketSize) { dev_err(priv_dev->dev, "usbss: missing wMaxPacketSize\n"); From f0a892f599c46af673e47418c47c15e69a7b67f4 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 4 Aug 2022 19:01:46 +0100 Subject: [PATCH 1436/1436] drm/amd/amdgpu: fix build failure due to implicit declaration The builds for alpha and mips allmodconfig fails with the error: drivers/gpu/drm/amd/amdgpu/psp_v13_0.c:534:23: error: implicit declaration of function 'vmalloc'; did you mean 'kvmalloc'? [-Werror=implicit-function-declaration] drivers/gpu/drm/amd/amdgpu/psp_v13_0.c:534:21: error: assignment to 'void *' from 'int' makes pointer from integer without a cast [-Werror=int-conversion] drivers/gpu/drm/amd/amdgpu/psp_v13_0.c:545:33: error: implicit declaration of function 'vfree'; did you mean 'kvfree'? [-Werror=implicit-function-declaration] Add the header file for vmalloc and vfree. Reported-by: Sudip Mukherjee Suggested-by: Linus Torvalds Signed-off-by: Sudip Mukherjee Signed-off-by: Linus Torvalds --- drivers/gpu/drm/amd/amdgpu/psp_v13_0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c index 63b2d32545cc..726a5bba40b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v13_0.c @@ -22,6 +22,7 @@ */ #include #include +#include #include "amdgpu.h" #include "amdgpu_psp.h" #include "amdgpu_ucode.h"

ZWk2^RfZ1?47Lmo3=E}aKAjH@FM*e# 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