From: Greg Kroah-Hartman Date: Fri, 22 Mar 2019 10:20:41 +0000 (+0100) Subject: 4.14-stable patches X-Git-Tag: v3.18.137~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=34cb5df84d735997bda6970d9409c04bc7aa1ad2;p=thirdparty%2Fkernel%2Fstable-queue.git 4.14-stable patches added patches: drm-radeon-evergreen_cs-fix-missing-break-in-switch-statement.patch kvm-call-kvm_arch_memslots_updated-before-updating-memslots.patch kvm-nvmx-apply-addr-size-mask-to-effective-address-for-vmx-instructions.patch kvm-nvmx-ignore-limit-checks-on-vmx-instructions-using-flat-segments.patch kvm-nvmx-sign-extend-displacements-of-vmx-instr-s-mem-operands.patch kvm-x86-mmu-detect-mmio-generation-wrap-in-any-address-space.patch kvm-x86-mmu-do-not-cache-mmio-accesses-while-memslots-are-in-flux.patch media-imx-csi-disable-csi-immediately-after-last-eof.patch media-imx-csi-stop-upstream-before-disabling-idma-channel.patch media-imx-prpencvf-stop-upstream-before-disabling-idma-channel.patch media-uvcvideo-avoid-null-pointer-dereference-at-the-end-of-streaming.patch media-vimc-add-vimc-streamer-for-stream-control.patch --- diff --git a/queue-4.14/drm-radeon-evergreen_cs-fix-missing-break-in-switch-statement.patch b/queue-4.14/drm-radeon-evergreen_cs-fix-missing-break-in-switch-statement.patch new file mode 100644 index 00000000000..438d78a13d6 --- /dev/null +++ b/queue-4.14/drm-radeon-evergreen_cs-fix-missing-break-in-switch-statement.patch @@ -0,0 +1,35 @@ +From cc5034a5d293dd620484d1d836aa16c6764a1c8c Mon Sep 17 00:00:00 2001 +From: "Gustavo A. R. Silva" +Date: Fri, 15 Feb 2019 14:29:26 -0600 +Subject: drm/radeon/evergreen_cs: fix missing break in switch statement + +From: Gustavo A. R. Silva + +commit cc5034a5d293dd620484d1d836aa16c6764a1c8c upstream. + +Add missing break statement in order to prevent the code from falling +through to case CB_TARGET_MASK. + +This bug was found thanks to the ongoing efforts to enable +-Wimplicit-fallthrough. + +Fixes: dd220a00e8bd ("drm/radeon/kms: add support for streamout v7") +Cc: stable@vger.kernel.org +Signed-off-by: Gustavo A. R. Silva +Signed-off-by: Alex Deucher +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/radeon/evergreen_cs.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/drivers/gpu/drm/radeon/evergreen_cs.c ++++ b/drivers/gpu/drm/radeon/evergreen_cs.c +@@ -1299,6 +1299,7 @@ static int evergreen_cs_handle_reg(struc + return -EINVAL; + } + ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff); ++ break; + case CB_TARGET_MASK: + track->cb_target_mask = radeon_get_ib_value(p, idx); + track->cb_dirty = true; diff --git a/queue-4.14/kvm-call-kvm_arch_memslots_updated-before-updating-memslots.patch b/queue-4.14/kvm-call-kvm_arch_memslots_updated-before-updating-memslots.patch new file mode 100644 index 00000000000..456cc4b41f6 --- /dev/null +++ b/queue-4.14/kvm-call-kvm_arch_memslots_updated-before-updating-memslots.patch @@ -0,0 +1,170 @@ +From 152482580a1b0accb60676063a1ac57b2d12daf6 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Tue, 5 Feb 2019 12:54:17 -0800 +Subject: KVM: Call kvm_arch_memslots_updated() before updating memslots + +From: Sean Christopherson + +commit 152482580a1b0accb60676063a1ac57b2d12daf6 upstream. + +kvm_arch_memslots_updated() is at this point in time an x86-specific +hook for handling MMIO generation wraparound. x86 stashes 19 bits of +the memslots generation number in its MMIO sptes in order to avoid +full page fault walks for repeat faults on emulated MMIO addresses. +Because only 19 bits are used, wrapping the MMIO generation number is +possible, if unlikely. kvm_arch_memslots_updated() alerts x86 that +the generation has changed so that it can invalidate all MMIO sptes in +case the effective MMIO generation has wrapped so as to avoid using a +stale spte, e.g. a (very) old spte that was created with generation==0. + +Given that the purpose of kvm_arch_memslots_updated() is to prevent +consuming stale entries, it needs to be called before the new generation +is propagated to memslots. Invalidating the MMIO sptes after updating +memslots means that there is a window where a vCPU could dereference +the new memslots generation, e.g. 0, and incorrectly reuse an old MMIO +spte that was created with (pre-wrap) generation==0. + +Fixes: e59dbe09f8e6 ("KVM: Introduce kvm_arch_memslots_updated()") +Cc: +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +--- + arch/mips/include/asm/kvm_host.h | 2 +- + arch/powerpc/include/asm/kvm_host.h | 2 +- + arch/s390/include/asm/kvm_host.h | 2 +- + arch/x86/include/asm/kvm_host.h | 2 +- + arch/x86/kvm/mmu.c | 4 ++-- + arch/x86/kvm/x86.c | 4 ++-- + include/linux/kvm_host.h | 2 +- + virt/kvm/arm/mmu.c | 2 +- + virt/kvm/kvm_main.c | 7 +++++-- + 9 files changed, 15 insertions(+), 12 deletions(-) + +--- a/arch/mips/include/asm/kvm_host.h ++++ b/arch/mips/include/asm/kvm_host.h +@@ -1132,7 +1132,7 @@ static inline void kvm_arch_hardware_uns + static inline void kvm_arch_sync_events(struct kvm *kvm) {} + static inline void kvm_arch_free_memslot(struct kvm *kvm, + struct kvm_memory_slot *free, struct kvm_memory_slot *dont) {} +-static inline void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots) {} ++static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} + static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} + static inline void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) {} + static inline void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) {} +--- a/arch/powerpc/include/asm/kvm_host.h ++++ b/arch/powerpc/include/asm/kvm_host.h +@@ -809,7 +809,7 @@ struct kvm_vcpu_arch { + static inline void kvm_arch_hardware_disable(void) {} + static inline void kvm_arch_hardware_unsetup(void) {} + static inline void kvm_arch_sync_events(struct kvm *kvm) {} +-static inline void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots) {} ++static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} + static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {} + static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} + static inline void kvm_arch_exit(void) {} +--- a/arch/s390/include/asm/kvm_host.h ++++ b/arch/s390/include/asm/kvm_host.h +@@ -784,7 +784,7 @@ static inline void kvm_arch_vcpu_uninit( + static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} + static inline void kvm_arch_free_memslot(struct kvm *kvm, + struct kvm_memory_slot *free, struct kvm_memory_slot *dont) {} +-static inline void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots) {} ++static inline void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) {} + static inline void kvm_arch_flush_shadow_all(struct kvm *kvm) {} + static inline void kvm_arch_flush_shadow_memslot(struct kvm *kvm, + struct kvm_memory_slot *slot) {} +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -1121,7 +1121,7 @@ void kvm_mmu_clear_dirty_pt_masked(struc + struct kvm_memory_slot *slot, + gfn_t gfn_offset, unsigned long mask); + void kvm_mmu_zap_all(struct kvm *kvm); +-void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, struct kvm_memslots *slots); ++void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen); + unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm); + void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages); + +--- a/arch/x86/kvm/mmu.c ++++ b/arch/x86/kvm/mmu.c +@@ -5418,13 +5418,13 @@ static bool kvm_has_zapped_obsolete_page + return unlikely(!list_empty_careful(&kvm->arch.zapped_obsolete_pages)); + } + +-void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, struct kvm_memslots *slots) ++void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen) + { + /* + * The very rare case: if the generation-number is round, + * zap all shadow pages. + */ +- if (unlikely((slots->generation & MMIO_GEN_MASK) == 0)) { ++ if (unlikely((gen & MMIO_GEN_MASK) == 0)) { + kvm_debug_ratelimited("kvm: zapping shadow pages for mmio generation wraparound\n"); + kvm_mmu_invalidate_zap_all_pages(kvm); + } +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -8524,13 +8524,13 @@ out_free: + return -ENOMEM; + } + +-void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots) ++void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) + { + /* + * memslots->generation has been incremented. + * mmio generation may have reached its maximum value. + */ +- kvm_mmu_invalidate_mmio_sptes(kvm, slots); ++ kvm_mmu_invalidate_mmio_sptes(kvm, gen); + } + + int kvm_arch_prepare_memory_region(struct kvm *kvm, +--- a/include/linux/kvm_host.h ++++ b/include/linux/kvm_host.h +@@ -625,7 +625,7 @@ void kvm_arch_free_memslot(struct kvm *k + struct kvm_memory_slot *dont); + int kvm_arch_create_memslot(struct kvm *kvm, struct kvm_memory_slot *slot, + unsigned long npages); +-void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots); ++void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen); + int kvm_arch_prepare_memory_region(struct kvm *kvm, + struct kvm_memory_slot *memslot, + const struct kvm_userspace_memory_region *mem, +--- a/virt/kvm/arm/mmu.c ++++ b/virt/kvm/arm/mmu.c +@@ -1955,7 +1955,7 @@ int kvm_arch_create_memslot(struct kvm * + return 0; + } + +-void kvm_arch_memslots_updated(struct kvm *kvm, struct kvm_memslots *slots) ++void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) + { + } + +--- a/virt/kvm/kvm_main.c ++++ b/virt/kvm/kvm_main.c +@@ -856,6 +856,7 @@ static struct kvm_memslots *install_new_ + int as_id, struct kvm_memslots *slots) + { + struct kvm_memslots *old_memslots = __kvm_memslots(kvm, as_id); ++ u64 gen; + + /* + * Set the low bit in the generation, which disables SPTE caching +@@ -878,9 +879,11 @@ static struct kvm_memslots *install_new_ + * space 0 will use generations 0, 4, 8, ... while * address space 1 will + * use generations 2, 6, 10, 14, ... + */ +- slots->generation += KVM_ADDRESS_SPACE_NUM * 2 - 1; ++ gen = slots->generation + KVM_ADDRESS_SPACE_NUM * 2 - 1; + +- kvm_arch_memslots_updated(kvm, slots); ++ kvm_arch_memslots_updated(kvm, gen); ++ ++ slots->generation = gen; + + return old_memslots; + } diff --git a/queue-4.14/kvm-nvmx-apply-addr-size-mask-to-effective-address-for-vmx-instructions.patch b/queue-4.14/kvm-nvmx-apply-addr-size-mask-to-effective-address-for-vmx-instructions.patch new file mode 100644 index 00000000000..9a810b3a5ca --- /dev/null +++ b/queue-4.14/kvm-nvmx-apply-addr-size-mask-to-effective-address-for-vmx-instructions.patch @@ -0,0 +1,71 @@ +From 8570f9e881e3fde98801bb3a47eef84dd934d405 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Wed, 23 Jan 2019 14:39:24 -0800 +Subject: KVM: nVMX: Apply addr size mask to effective address for VMX instructions + +From: Sean Christopherson + +commit 8570f9e881e3fde98801bb3a47eef84dd934d405 upstream. + +The address size of an instruction affects the effective address, not +the virtual/linear address. The final address may still be truncated, +e.g. to 32-bits outside of long mode, but that happens irrespective of +the address size, e.g. a 32-bit address size can yield a 64-bit virtual +address when using FS/GS with a non-zero base. + +Fixes: 064aea774768 ("KVM: nVMX: Decoding memory operands of VMX instructions") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kvm/vmx.c | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -7455,20 +7455,41 @@ static int get_vmx_mem_address(struct kv + if (index_is_valid) + off += kvm_register_read(vcpu, index_reg)< +Date: Wed, 23 Jan 2019 14:39:25 -0800 +Subject: KVM: nVMX: Ignore limit checks on VMX instructions using flat segments + +From: Sean Christopherson + +commit 34333cc6c2cb021662fd32e24e618d1b86de95bf upstream. + +Regarding segments with a limit==0xffffffff, the SDM officially states: + + When the effective limit is FFFFFFFFH (4 GBytes), these accesses may + or may not cause the indicated exceptions. Behavior is + implementation-specific and may vary from one execution to another. + +In practice, all CPUs that support VMX ignore limit checks for "flat +segments", i.e. an expand-up data or code segment with base=0 and +limit=0xffffffff. This is subtly different than wrapping the effective +address calculation based on the address size, as the flat segment +behavior also applies to accesses that would wrap the 4g boundary, e.g. +a 4-byte access starting at 0xffffffff will access linear addresses +0xffffffff, 0x0, 0x1 and 0x2. + +Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kvm/vmx.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -7513,10 +7513,16 @@ static int get_vmx_mem_address(struct kv + /* Protected mode: #GP(0)/#SS(0) if the segment is unusable. + */ + exn = (s.unusable != 0); +- /* Protected mode: #GP(0)/#SS(0) if the memory +- * operand is outside the segment limit. ++ ++ /* ++ * Protected mode: #GP(0)/#SS(0) if the memory operand is ++ * outside the segment limit. All CPUs that support VMX ignore ++ * limit checks for flat segments, i.e. segments with base==0, ++ * limit==0xffffffff and of type expand-up data or code. + */ +- exn = exn || (off + sizeof(u64) > s.limit); ++ if (!(s.base == 0 && s.limit == 0xffffffff && ++ ((s.type & 8) || !(s.type & 4)))) ++ exn = exn || (off + sizeof(u64) > s.limit); + } + if (exn) { + kvm_queue_exception_e(vcpu, diff --git a/queue-4.14/kvm-nvmx-sign-extend-displacements-of-vmx-instr-s-mem-operands.patch b/queue-4.14/kvm-nvmx-sign-extend-displacements-of-vmx-instr-s-mem-operands.patch new file mode 100644 index 00000000000..6595688a497 --- /dev/null +++ b/queue-4.14/kvm-nvmx-sign-extend-displacements-of-vmx-instr-s-mem-operands.patch @@ -0,0 +1,71 @@ +From 946c522b603f281195af1df91837a1d4d1eb3bc9 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Wed, 23 Jan 2019 14:39:23 -0800 +Subject: KVM: nVMX: Sign extend displacements of VMX instr's mem operands +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Sean Christopherson + +commit 946c522b603f281195af1df91837a1d4d1eb3bc9 upstream. + +The VMCS.EXIT_QUALIFCATION field reports the displacements of memory +operands for various instructions, including VMX instructions, as a +naturally sized unsigned value, but masks the value by the addr size, +e.g. given a ModRM encoded as -0x28(%ebp), the -0x28 displacement is +reported as 0xffffffd8 for a 32-bit address size. Despite some weird +wording regarding sign extension, the SDM explicitly states that bits +beyond the instructions address size are undefined: + + In all cases, bits of this field beyond the instruction’s address + size are undefined. + +Failure to sign extend the displacement results in KVM incorrectly +treating a negative displacement as a large positive displacement when +the address size of the VMX instruction is smaller than KVM's native +size, e.g. a 32-bit address size on a 64-bit KVM. + +The very original decoding, added by commit 064aea774768 ("KVM: nVMX: +Decoding memory operands of VMX instructions"), sort of modeled sign +extension by truncating the final virtual/linear address for a 32-bit +address size. I.e. it messed up the effective address but made it work +by adjusting the final address. + +When segmentation checks were added, the truncation logic was kept +as-is and no sign extension logic was introduced. In other words, it +kept calculating the wrong effective address while mostly generating +the correct virtual/linear address. As the effective address is what's +used in the segment limit checks, this results in KVM incorreclty +injecting #GP/#SS faults due to non-existent segment violations when +a nested VMM uses negative displacements with an address size smaller +than KVM's native address size. + +Using the -0x28(%ebp) example, an EBP value of 0x1000 will result in +KVM using 0x100000fd8 as the effective address when checking for a +segment limit violation. This causes a 100% failure rate when running +a 32-bit KVM build as L1 on top of a 64-bit KVM L0. + +Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions") +Cc: stable@vger.kernel.org +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kvm/vmx.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -7446,6 +7446,10 @@ static int get_vmx_mem_address(struct kv + /* Addr = segment_base + offset */ + /* offset = base + [index * scale] + displacement */ + off = exit_qualification; /* holds the displacement */ ++ if (addr_size == 1) ++ off = (gva_t)sign_extend64(off, 31); ++ else if (addr_size == 0) ++ off = (gva_t)sign_extend64(off, 15); + if (base_is_valid) + off += kvm_register_read(vcpu, base_reg); + if (index_is_valid) diff --git a/queue-4.14/kvm-x86-mmu-detect-mmio-generation-wrap-in-any-address-space.patch b/queue-4.14/kvm-x86-mmu-detect-mmio-generation-wrap-in-any-address-space.patch new file mode 100644 index 00000000000..2383d6380f5 --- /dev/null +++ b/queue-4.14/kvm-x86-mmu-detect-mmio-generation-wrap-in-any-address-space.patch @@ -0,0 +1,60 @@ +From e1359e2beb8b0a1188abc997273acbaedc8ee791 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Tue, 5 Feb 2019 13:01:12 -0800 +Subject: KVM: x86/mmu: Detect MMIO generation wrap in any address space + +From: Sean Christopherson + +commit e1359e2beb8b0a1188abc997273acbaedc8ee791 upstream. + +The check to detect a wrap of the MMIO generation explicitly looks for a +generation number of zero. Now that unique memslots generation numbers +are assigned to each address space, only address space 0 will get a +generation number of exactly zero when wrapping. E.g. when address +space 1 goes from 0x7fffe to 0x80002, the MMIO generation number will +wrap to 0x2. Adjust the MMIO generation to strip the address space +modifier prior to checking for a wrap. + +Fixes: 4bd518f1598d ("KVM: use separate generations for each address space") +Cc: +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kvm/mmu.c | 21 +++++++++++++++++++-- + 1 file changed, 19 insertions(+), 2 deletions(-) + +--- a/arch/x86/kvm/mmu.c ++++ b/arch/x86/kvm/mmu.c +@@ -5420,11 +5420,28 @@ static bool kvm_has_zapped_obsolete_page + + void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm, u64 gen) + { ++ gen &= MMIO_GEN_MASK; ++ ++ /* ++ * Shift to eliminate the "update in-progress" flag, which isn't ++ * included in the spte's generation number. ++ */ ++ gen >>= 1; ++ ++ /* ++ * Generation numbers are incremented in multiples of the number of ++ * address spaces in order to provide unique generations across all ++ * address spaces. Strip what is effectively the address space ++ * modifier prior to checking for a wrap of the MMIO generation so ++ * that a wrap in any address space is detected. ++ */ ++ gen &= ~((u64)KVM_ADDRESS_SPACE_NUM - 1); ++ + /* +- * The very rare case: if the generation-number is round, ++ * The very rare case: if the MMIO generation number has wrapped, + * zap all shadow pages. + */ +- if (unlikely((gen & MMIO_GEN_MASK) == 0)) { ++ if (unlikely(gen == 0)) { + kvm_debug_ratelimited("kvm: zapping shadow pages for mmio generation wraparound\n"); + kvm_mmu_invalidate_zap_all_pages(kvm); + } diff --git a/queue-4.14/kvm-x86-mmu-do-not-cache-mmio-accesses-while-memslots-are-in-flux.patch b/queue-4.14/kvm-x86-mmu-do-not-cache-mmio-accesses-while-memslots-are-in-flux.patch new file mode 100644 index 00000000000..49b1e961233 --- /dev/null +++ b/queue-4.14/kvm-x86-mmu-do-not-cache-mmio-accesses-while-memslots-are-in-flux.patch @@ -0,0 +1,64 @@ +From ddfd1730fd829743e41213e32ccc8b4aa6dc8325 Mon Sep 17 00:00:00 2001 +From: Sean Christopherson +Date: Tue, 5 Feb 2019 13:01:13 -0800 +Subject: KVM: x86/mmu: Do not cache MMIO accesses while memslots are in flux + +From: Sean Christopherson + +commit ddfd1730fd829743e41213e32ccc8b4aa6dc8325 upstream. + +When installing new memslots, KVM sets bit 0 of the generation number to +indicate that an update is in-progress. Until the update is complete, +there are no guarantees as to whether a vCPU will see the old or the new +memslots. Explicity prevent caching MMIO accesses so as to avoid using +an access cached from the old memslots after the new memslots have been +installed. + +Note that it is unclear whether or not disabling caching during the +update window is strictly necessary as there is no definitive +documentation as to what ordering guarantees KVM provides with respect +to updating memslots. That being said, the MMIO spte code does not +allow reusing sptes created while an update is in-progress, and the +associated documentation explicitly states: + + We do not want to use an MMIO sptes created with an odd generation + number, ... If KVM is unlucky and creates an MMIO spte while the + low bit is 1, the next access to the spte will always be a cache miss. + +At the very least, disabling the per-vCPU MMIO cache during updates will +make its behavior consistent with the MMIO spte behavior and +documentation. + +Fixes: 56f17dd3fbc4 ("kvm: x86: fix stale mmio cache bug") +Cc: +Signed-off-by: Sean Christopherson +Signed-off-by: Paolo Bonzini +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kvm/x86.h | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +--- a/arch/x86/kvm/x86.h ++++ b/arch/x86/kvm/x86.h +@@ -136,6 +136,11 @@ static inline bool emul_is_noncanonical_ + static inline void vcpu_cache_mmio_info(struct kvm_vcpu *vcpu, + gva_t gva, gfn_t gfn, unsigned access) + { ++ u64 gen = kvm_memslots(vcpu->kvm)->generation; ++ ++ if (unlikely(gen & 1)) ++ return; ++ + /* + * If this is a shadow nested page table, the "GVA" is + * actually a nGPA. +@@ -143,7 +148,7 @@ static inline void vcpu_cache_mmio_info( + vcpu->arch.mmio_gva = mmu_is_nested(vcpu) ? 0 : gva & PAGE_MASK; + vcpu->arch.access = access; + vcpu->arch.mmio_gfn = gfn; +- vcpu->arch.mmio_gen = kvm_memslots(vcpu->kvm)->generation; ++ vcpu->arch.mmio_gen = gen; + } + + static inline bool vcpu_match_mmio_gen(struct kvm_vcpu *vcpu) diff --git a/queue-4.14/media-imx-csi-disable-csi-immediately-after-last-eof.patch b/queue-4.14/media-imx-csi-disable-csi-immediately-after-last-eof.patch new file mode 100644 index 00000000000..456d1a77647 --- /dev/null +++ b/queue-4.14/media-imx-csi-disable-csi-immediately-after-last-eof.patch @@ -0,0 +1,90 @@ +From 2e0fe66e0a136252f4d89dbbccdcb26deb867eb8 Mon Sep 17 00:00:00 2001 +From: Steve Longerbeam +Date: Mon, 21 Jan 2019 21:35:50 -0200 +Subject: media: imx: csi: Disable CSI immediately after last EOF +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Steve Longerbeam + +commit 2e0fe66e0a136252f4d89dbbccdcb26deb867eb8 upstream. + +Disable the CSI immediately after receiving the last EOF before stream +off (and thus before disabling the IDMA channel). Do this by moving the +wait for EOF completion into a new function csi_idmac_wait_last_eof(). + +This fixes a complete system hard lockup on the SabreAuto when streaming +from the ADV7180, by repeatedly sending a stream off immediately followed +by stream on: + +while true; do v4l2-ctl -d4 --stream-mmap --stream-count=3; done + +Eventually this either causes the system lockup or EOF timeouts at all +subsequent stream on, until a system reset. + +The lockup occurs when disabling the IDMA channel at stream off. Disabling +the CSI before disabling the IDMA channel appears to be a reliable fix for +the hard lockup. + +Fixes: 4a34ec8e470cb ("[media] media: imx: Add CSI subdev driver") + +Reported-by: Gaël PORTAY +Signed-off-by: Steve Longerbeam +Cc: stable@vger.kernel.org # for 4.13 and up +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/media/imx/imx-media-csi.c | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +--- a/drivers/staging/media/imx/imx-media-csi.c ++++ b/drivers/staging/media/imx/imx-media-csi.c +@@ -538,7 +538,7 @@ out_put_ipu: + return ret; + } + +-static void csi_idmac_stop(struct csi_priv *priv) ++static void csi_idmac_wait_last_eof(struct csi_priv *priv) + { + unsigned long flags; + int ret; +@@ -555,7 +555,10 @@ static void csi_idmac_stop(struct csi_pr + &priv->last_eof_comp, msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT)); + if (ret == 0) + v4l2_warn(&priv->sd, "wait last EOF timeout\n"); ++} + ++static void csi_idmac_stop(struct csi_priv *priv) ++{ + devm_free_irq(priv->dev, priv->eof_irq, priv); + devm_free_irq(priv->dev, priv->nfb4eof_irq, priv); + +@@ -681,6 +684,16 @@ idmac_stop: + + static void csi_stop(struct csi_priv *priv) + { ++ if (priv->dest == IPU_CSI_DEST_IDMAC) ++ csi_idmac_wait_last_eof(priv); ++ ++ /* ++ * Disable the CSI asap, after syncing with the last EOF. ++ * Doing so after the IDMA channel is disabled has shown to ++ * create hard system-wide hangs. ++ */ ++ ipu_csi_disable(priv->csi); ++ + if (priv->dest == IPU_CSI_DEST_IDMAC) { + csi_idmac_stop(priv); + +@@ -688,8 +701,6 @@ static void csi_stop(struct csi_priv *pr + if (priv->fim) + imx_media_fim_set_stream(priv->fim, NULL, false); + } +- +- ipu_csi_disable(priv->csi); + } + + static const struct csi_skip_desc csi_skip[12] = { diff --git a/queue-4.14/media-imx-csi-stop-upstream-before-disabling-idma-channel.patch b/queue-4.14/media-imx-csi-stop-upstream-before-disabling-idma-channel.patch new file mode 100644 index 00000000000..458d9ae1a50 --- /dev/null +++ b/queue-4.14/media-imx-csi-stop-upstream-before-disabling-idma-channel.patch @@ -0,0 +1,91 @@ +From 4bc1ab41eee9d02ad2483bf8f51a7b72e3504eba Mon Sep 17 00:00:00 2001 +From: Steve Longerbeam +Date: Mon, 21 Jan 2019 21:35:51 -0200 +Subject: media: imx: csi: Stop upstream before disabling IDMA channel + +From: Steve Longerbeam + +commit 4bc1ab41eee9d02ad2483bf8f51a7b72e3504eba upstream. + +Move upstream stream off to just after receiving the last EOF completion +and disabling the CSI (and thus before disabling the IDMA channel) in +csi_stop(). For symmetry also move upstream stream on to beginning of +csi_start(). + +Doing this makes csi_s_stream() more symmetric with prp_s_stream() which +will require the same change to fix a hard lockup. + +Signed-off-by: Steve Longerbeam +Cc: stable@vger.kernel.org # for 4.13 and up +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/media/imx/imx-media-csi.c | 25 +++++++++++++------------ + 1 file changed, 13 insertions(+), 12 deletions(-) + +--- a/drivers/staging/media/imx/imx-media-csi.c ++++ b/drivers/staging/media/imx/imx-media-csi.c +@@ -648,10 +648,16 @@ static int csi_start(struct csi_priv *pr + usleep_range(delay_usec, delay_usec + 1000); + } + ++ /* start upstream */ ++ ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 1); ++ ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0; ++ if (ret) ++ return ret; ++ + if (priv->dest == IPU_CSI_DEST_IDMAC) { + ret = csi_idmac_start(priv); + if (ret) +- return ret; ++ goto stop_upstream; + } + + ret = csi_setup(priv); +@@ -679,6 +685,8 @@ fim_off: + idmac_stop: + if (priv->dest == IPU_CSI_DEST_IDMAC) + csi_idmac_stop(priv); ++stop_upstream: ++ v4l2_subdev_call(priv->src_sd, video, s_stream, 0); + return ret; + } + +@@ -694,6 +702,9 @@ static void csi_stop(struct csi_priv *pr + */ + ipu_csi_disable(priv->csi); + ++ /* stop upstream */ ++ v4l2_subdev_call(priv->src_sd, video, s_stream, 0); ++ + if (priv->dest == IPU_CSI_DEST_IDMAC) { + csi_idmac_stop(priv); + +@@ -861,23 +872,13 @@ static int csi_s_stream(struct v4l2_subd + goto update_count; + + if (enable) { +- /* upstream must be started first, before starting CSI */ +- ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 1); +- ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0; +- if (ret) +- goto out; +- + dev_dbg(priv->dev, "stream ON\n"); + ret = csi_start(priv); +- if (ret) { +- v4l2_subdev_call(priv->src_sd, video, s_stream, 0); ++ if (ret) + goto out; +- } + } else { + dev_dbg(priv->dev, "stream OFF\n"); +- /* CSI must be stopped first, then stop upstream */ + csi_stop(priv); +- v4l2_subdev_call(priv->src_sd, video, s_stream, 0); + } + + update_count: diff --git a/queue-4.14/media-imx-prpencvf-stop-upstream-before-disabling-idma-channel.patch b/queue-4.14/media-imx-prpencvf-stop-upstream-before-disabling-idma-channel.patch new file mode 100644 index 00000000000..157ae9da42e --- /dev/null +++ b/queue-4.14/media-imx-prpencvf-stop-upstream-before-disabling-idma-channel.patch @@ -0,0 +1,100 @@ +From a19c22677377b87e4354f7306f46ad99bc982a9f Mon Sep 17 00:00:00 2001 +From: Steve Longerbeam +Date: Mon, 21 Jan 2019 21:35:52 -0200 +Subject: media: imx: prpencvf: Stop upstream before disabling IDMA channel +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Steve Longerbeam + +commit a19c22677377b87e4354f7306f46ad99bc982a9f upstream. + +Upstream must be stopped immediately after receiving the last EOF and +before disabling the IDMA channel. This can be accomplished by moving +upstream stream off to just after receiving the last EOF completion in +prp_stop(). For symmetry also move upstream stream on to end of +prp_start(). + +This fixes a complete system hard lockup on the SabreAuto when streaming +from the ADV7180, by repeatedly sending a stream off immediately followed +by stream on: + +while true; do v4l2-ctl -d1 --stream-mmap --stream-count=3; done + +Eventually this either causes the system lockup or EOF timeouts at all +subsequent stream on, until a system reset. + +The lockup occurs when disabling the IDMA channel at stream off. Stopping +the video data stream entering the IDMA channel before disabling the +channel itself appears to be a reliable fix for the hard lockup. + +Fixes: f0d9c8924e2c3 ("[media] media: imx: Add IC subdev drivers") + +Reported-by: Gaël PORTAY +Tested-by: Gaël PORTAY +Signed-off-by: Steve Longerbeam +Cc: stable@vger.kernel.org # for 4.13 and up +Signed-off-by: Hans Verkuil +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/staging/media/imx/imx-ic-prpencvf.c | 26 +++++++++++++++++--------- + 1 file changed, 17 insertions(+), 9 deletions(-) + +--- a/drivers/staging/media/imx/imx-ic-prpencvf.c ++++ b/drivers/staging/media/imx/imx-ic-prpencvf.c +@@ -676,12 +676,23 @@ static int prp_start(struct prp_priv *pr + goto out_free_nfb4eof_irq; + } + ++ /* start upstream */ ++ ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 1); ++ ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0; ++ if (ret) { ++ v4l2_err(&ic_priv->sd, ++ "upstream stream on failed: %d\n", ret); ++ goto out_free_eof_irq; ++ } ++ + /* start the EOF timeout timer */ + mod_timer(&priv->eof_timeout_timer, + jiffies + msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT)); + + return 0; + ++out_free_eof_irq: ++ devm_free_irq(ic_priv->dev, priv->eof_irq, priv); + out_free_nfb4eof_irq: + devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv); + out_unsetup: +@@ -713,6 +724,12 @@ static void prp_stop(struct prp_priv *pr + if (ret == 0) + v4l2_warn(&ic_priv->sd, "wait last EOF timeout\n"); + ++ /* stop upstream */ ++ ret = v4l2_subdev_call(priv->src_sd, video, s_stream, 0); ++ if (ret && ret != -ENOIOCTLCMD) ++ v4l2_warn(&ic_priv->sd, ++ "upstream stream off failed: %d\n", ret); ++ + devm_free_irq(ic_priv->dev, priv->eof_irq, priv); + devm_free_irq(ic_priv->dev, priv->nfb4eof_irq, priv); + +@@ -1144,15 +1161,6 @@ static int prp_s_stream(struct v4l2_subd + if (ret) + goto out; + +- /* start/stop upstream */ +- ret = v4l2_subdev_call(priv->src_sd, video, s_stream, enable); +- ret = (ret && ret != -ENOIOCTLCMD) ? ret : 0; +- if (ret) { +- if (enable) +- prp_stop(priv); +- goto out; +- } +- + update_count: + priv->stream_count += enable ? 1 : -1; + if (priv->stream_count < 0) diff --git a/queue-4.14/media-uvcvideo-avoid-null-pointer-dereference-at-the-end-of-streaming.patch b/queue-4.14/media-uvcvideo-avoid-null-pointer-dereference-at-the-end-of-streaming.patch new file mode 100644 index 00000000000..faa85a5fea5 --- /dev/null +++ b/queue-4.14/media-uvcvideo-avoid-null-pointer-dereference-at-the-end-of-streaming.patch @@ -0,0 +1,58 @@ +From 9dd0627d8d62a7ddb001a75f63942d92b5336561 Mon Sep 17 00:00:00 2001 +From: Sakari Ailus +Date: Wed, 30 Jan 2019 05:09:41 -0500 +Subject: media: uvcvideo: Avoid NULL pointer dereference at the end of streaming + +From: Sakari Ailus + +commit 9dd0627d8d62a7ddb001a75f63942d92b5336561 upstream. + +The UVC video driver converts the timestamp from hardware specific unit +to one known by the kernel at the time when the buffer is dequeued. This +is fine in general, but the streamoff operation consists of the +following steps (among other things): + +1. uvc_video_clock_cleanup --- the hardware clock sample array is + released and the pointer to the array is set to NULL, + +2. buffers in active state are returned to the user and + +3. buf_finish callback is called on buffers that are prepared. + buf_finish includes calling uvc_video_clock_update that accesses the + hardware clock sample array. + +The above is serialised by a queue specific mutex. Address the problem +by skipping the clock conversion if the hardware clock sample array is +already released. + +Fixes: 9c0863b1cc48 ("[media] vb2: call buf_finish from __queue_cancel") + +Reported-by: Chiranjeevi Rapolu +Tested-by: Chiranjeevi Rapolu +Signed-off-by: Sakari Ailus +Cc: stable@vger.kernel.org +Signed-off-by: Laurent Pinchart +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/media/usb/uvc/uvc_video.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/drivers/media/usb/uvc/uvc_video.c ++++ b/drivers/media/usb/uvc/uvc_video.c +@@ -638,6 +638,14 @@ void uvc_video_clock_update(struct uvc_s + if (!uvc_hw_timestamps_param) + return; + ++ /* ++ * We will get called from __vb2_queue_cancel() if there are buffers ++ * done but not dequeued by the user, but the sample array has already ++ * been released at that time. Just bail out in that case. ++ */ ++ if (!clock->samples) ++ return; ++ + spin_lock_irqsave(&clock->lock, flags); + + if (clock->count < clock->size) diff --git a/queue-4.14/media-vimc-add-vimc-streamer-for-stream-control.patch b/queue-4.14/media-vimc-add-vimc-streamer-for-stream-control.patch new file mode 100644 index 00000000000..84d1d0ef59f --- /dev/null +++ b/queue-4.14/media-vimc-add-vimc-streamer-for-stream-control.patch @@ -0,0 +1,659 @@ +From adc589d2a20808fb99d46a78175cd023f2040338 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lucas=20A=2E=20M=2E=20Magalh=C3=A3es?= +Date: Mon, 21 Jan 2019 20:05:01 -0500 +Subject: media: vimc: Add vimc-streamer for stream control +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Lucas A. M. Magalhães + +commit adc589d2a20808fb99d46a78175cd023f2040338 upstream. + +Add a linear pipeline logic for the stream control. It's created by +walking backwards on the entity graph. When the stream starts it will +simply loop through the pipeline calling the respective process_frame +function of each entity. + +Fixes: f2fe89061d797 ("vimc: Virtual Media Controller core, capture +and sensor") + +Cc: stable@vger.kernel.org # for v4.20 +Signed-off-by: Lucas A. M. Magalhães +Acked-by: Helen Koike +Signed-off-by: Hans Verkuil +[hverkuil-cisco@xs4all.nl: fixed small space-after-tab issue in the patch] +Signed-off-by: Mauro Carvalho Chehab +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/media/platform/vimc/Makefile | 3 + drivers/media/platform/vimc/vimc-capture.c | 18 +- + drivers/media/platform/vimc/vimc-common.c | 35 ----- + drivers/media/platform/vimc/vimc-common.h | 15 -- + drivers/media/platform/vimc/vimc-debayer.c | 26 --- + drivers/media/platform/vimc/vimc-scaler.c | 28 ---- + drivers/media/platform/vimc/vimc-sensor.c | 56 +------- + drivers/media/platform/vimc/vimc-streamer.c | 188 ++++++++++++++++++++++++++++ + drivers/media/platform/vimc/vimc-streamer.h | 38 +++++ + 9 files changed, 260 insertions(+), 147 deletions(-) + +--- a/drivers/media/platform/vimc/Makefile ++++ b/drivers/media/platform/vimc/Makefile +@@ -5,6 +5,7 @@ vimc_common-objs := vimc-common.o + vimc_debayer-objs := vimc-debayer.o + vimc_scaler-objs := vimc-scaler.o + vimc_sensor-objs := vimc-sensor.o ++vimc_streamer-objs := vimc-streamer.o + + obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc-debayer.o \ +- vimc_scaler.o vimc_sensor.o ++ vimc_scaler.o vimc_sensor.o vimc_streamer.o +--- a/drivers/media/platform/vimc/vimc-capture.c ++++ b/drivers/media/platform/vimc/vimc-capture.c +@@ -23,6 +23,7 @@ + #include + + #include "vimc-common.h" ++#include "vimc-streamer.h" + + #define VIMC_CAP_DRV_NAME "vimc-capture" + +@@ -43,7 +44,7 @@ struct vimc_cap_device { + spinlock_t qlock; + struct mutex lock; + u32 sequence; +- struct media_pipeline pipe; ++ struct vimc_stream stream; + }; + + static const struct v4l2_pix_format fmt_default = { +@@ -247,14 +248,13 @@ static int vimc_cap_start_streaming(stru + vcap->sequence = 0; + + /* Start the media pipeline */ +- ret = media_pipeline_start(entity, &vcap->pipe); ++ ret = media_pipeline_start(entity, &vcap->stream.pipe); + if (ret) { + vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); + return ret; + } + +- /* Enable streaming from the pipe */ +- ret = vimc_pipeline_s_stream(&vcap->vdev.entity, 1); ++ ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1); + if (ret) { + media_pipeline_stop(entity); + vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); +@@ -272,8 +272,7 @@ static void vimc_cap_stop_streaming(stru + { + struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); + +- /* Disable streaming from the pipe */ +- vimc_pipeline_s_stream(&vcap->vdev.entity, 0); ++ vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 0); + + /* Stop the media pipeline */ + media_pipeline_stop(&vcap->vdev.entity); +@@ -354,8 +353,8 @@ static void vimc_cap_comp_unbind(struct + kfree(vcap); + } + +-static void vimc_cap_process_frame(struct vimc_ent_device *ved, +- struct media_pad *sink, const void *frame) ++static void *vimc_cap_process_frame(struct vimc_ent_device *ved, ++ const void *frame) + { + struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + ved); +@@ -369,7 +368,7 @@ static void vimc_cap_process_frame(struc + typeof(*vimc_buf), list); + if (!vimc_buf) { + spin_unlock(&vcap->qlock); +- return; ++ return ERR_PTR(-EAGAIN); + } + + /* Remove this entry from the list */ +@@ -390,6 +389,7 @@ static void vimc_cap_process_frame(struc + vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0, + vcap->format.sizeimage); + vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); ++ return NULL; + } + + static int vimc_cap_comp_bind(struct device *comp, struct device *master, +--- a/drivers/media/platform/vimc/vimc-common.c ++++ b/drivers/media/platform/vimc/vimc-common.c +@@ -207,41 +207,6 @@ const struct vimc_pix_map *vimc_pix_map_ + } + EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat); + +-int vimc_propagate_frame(struct media_pad *src, const void *frame) +-{ +- struct media_link *link; +- +- if (!(src->flags & MEDIA_PAD_FL_SOURCE)) +- return -EINVAL; +- +- /* Send this frame to all sink pads that are direct linked */ +- list_for_each_entry(link, &src->entity->links, list) { +- if (link->source == src && +- (link->flags & MEDIA_LNK_FL_ENABLED)) { +- struct vimc_ent_device *ved = NULL; +- struct media_entity *entity = link->sink->entity; +- +- if (is_media_entity_v4l2_subdev(entity)) { +- struct v4l2_subdev *sd = +- container_of(entity, struct v4l2_subdev, +- entity); +- ved = v4l2_get_subdevdata(sd); +- } else if (is_media_entity_v4l2_video_device(entity)) { +- struct video_device *vdev = +- container_of(entity, +- struct video_device, +- entity); +- ved = video_get_drvdata(vdev); +- } +- if (ved && ved->process_frame) +- ved->process_frame(ved, link->sink, frame); +- } +- } +- +- return 0; +-} +-EXPORT_SYMBOL_GPL(vimc_propagate_frame); +- + /* Helper function to allocate and initialize pads */ + struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) + { +--- a/drivers/media/platform/vimc/vimc-common.h ++++ b/drivers/media/platform/vimc/vimc-common.h +@@ -108,24 +108,13 @@ struct vimc_pix_map { + struct vimc_ent_device { + struct media_entity *ent; + struct media_pad *pads; +- void (*process_frame)(struct vimc_ent_device *ved, +- struct media_pad *sink, const void *frame); ++ void * (*process_frame)(struct vimc_ent_device *ved, ++ const void *frame); + void (*vdev_get_format)(struct vimc_ent_device *ved, + struct v4l2_pix_format *fmt); + }; + + /** +- * vimc_propagate_frame - propagate a frame through the topology +- * +- * @src: the source pad where the frame is being originated +- * @frame: the frame to be propagated +- * +- * This function will call the process_frame callback from the vimc_ent_device +- * struct of the nodes directly connected to the @src pad +- */ +-int vimc_propagate_frame(struct media_pad *src, const void *frame); +- +-/** + * vimc_pads_init - initialize pads + * + * @num_pads: number of pads to initialize +--- a/drivers/media/platform/vimc/vimc-debayer.c ++++ b/drivers/media/platform/vimc/vimc-debayer.c +@@ -320,7 +320,6 @@ static void vimc_deb_set_rgb_mbus_fmt_rg + static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) + { + struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); +- int ret; + + if (enable) { + const struct vimc_pix_map *vpix; +@@ -350,22 +349,10 @@ static int vimc_deb_s_stream(struct v4l2 + if (!vdeb->src_frame) + return -ENOMEM; + +- /* Turn the stream on in the subdevices directly connected */ +- ret = vimc_pipeline_s_stream(&vdeb->sd.entity, 1); +- if (ret) { +- vfree(vdeb->src_frame); +- vdeb->src_frame = NULL; +- return ret; +- } + } else { + if (!vdeb->src_frame) + return 0; + +- /* Disable streaming from the pipe */ +- ret = vimc_pipeline_s_stream(&vdeb->sd.entity, 0); +- if (ret) +- return ret; +- + vfree(vdeb->src_frame); + vdeb->src_frame = NULL; + } +@@ -479,9 +466,8 @@ static void vimc_deb_calc_rgb_sink(struc + } + } + +-static void vimc_deb_process_frame(struct vimc_ent_device *ved, +- struct media_pad *sink, +- const void *sink_frame) ++static void *vimc_deb_process_frame(struct vimc_ent_device *ved, ++ const void *sink_frame) + { + struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device, + ved); +@@ -490,7 +476,7 @@ static void vimc_deb_process_frame(struc + + /* If the stream in this node is not active, just return */ + if (!vdeb->src_frame) +- return; ++ return ERR_PTR(-EINVAL); + + for (i = 0; i < vdeb->sink_fmt.height; i++) + for (j = 0; j < vdeb->sink_fmt.width; j++) { +@@ -498,12 +484,8 @@ static void vimc_deb_process_frame(struc + vdeb->set_rgb_src(vdeb, i, j, rgb); + } + +- /* Propagate the frame through all source pads */ +- for (i = 1; i < vdeb->sd.entity.num_pads; i++) { +- struct media_pad *pad = &vdeb->sd.entity.pads[i]; ++ return vdeb->src_frame; + +- vimc_propagate_frame(pad, vdeb->src_frame); +- } + } + + static void vimc_deb_comp_unbind(struct device *comp, struct device *master, +--- a/drivers/media/platform/vimc/vimc-scaler.c ++++ b/drivers/media/platform/vimc/vimc-scaler.c +@@ -216,7 +216,6 @@ static const struct v4l2_subdev_pad_ops + static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) + { + struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); +- int ret; + + if (enable) { + const struct vimc_pix_map *vpix; +@@ -244,22 +243,10 @@ static int vimc_sca_s_stream(struct v4l2 + if (!vsca->src_frame) + return -ENOMEM; + +- /* Turn the stream on in the subdevices directly connected */ +- ret = vimc_pipeline_s_stream(&vsca->sd.entity, 1); +- if (ret) { +- vfree(vsca->src_frame); +- vsca->src_frame = NULL; +- return ret; +- } + } else { + if (!vsca->src_frame) + return 0; + +- /* Disable streaming from the pipe */ +- ret = vimc_pipeline_s_stream(&vsca->sd.entity, 0); +- if (ret) +- return ret; +- + vfree(vsca->src_frame); + vsca->src_frame = NULL; + } +@@ -345,26 +332,19 @@ static void vimc_sca_fill_src_frame(cons + vimc_sca_scale_pix(vsca, i, j, sink_frame); + } + +-static void vimc_sca_process_frame(struct vimc_ent_device *ved, +- struct media_pad *sink, +- const void *sink_frame) ++static void *vimc_sca_process_frame(struct vimc_ent_device *ved, ++ const void *sink_frame) + { + struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, + ved); +- unsigned int i; + + /* If the stream in this node is not active, just return */ + if (!vsca->src_frame) +- return; ++ return ERR_PTR(-EINVAL); + + vimc_sca_fill_src_frame(vsca, sink_frame); + +- /* Propagate the frame through all source pads */ +- for (i = 1; i < vsca->sd.entity.num_pads; i++) { +- struct media_pad *pad = &vsca->sd.entity.pads[i]; +- +- vimc_propagate_frame(pad, vsca->src_frame); +- } ++ return vsca->src_frame; + }; + + static void vimc_sca_comp_unbind(struct device *comp, struct device *master, +--- a/drivers/media/platform/vimc/vimc-sensor.c ++++ b/drivers/media/platform/vimc/vimc-sensor.c +@@ -16,8 +16,6 @@ + */ + + #include +-#include +-#include + #include + #include + #include +@@ -197,38 +195,27 @@ static const struct v4l2_subdev_pad_ops + .set_fmt = vimc_sen_set_fmt, + }; + +-static int vimc_sen_tpg_thread(void *data) ++static void *vimc_sen_process_frame(struct vimc_ent_device *ved, ++ const void *sink_frame) + { +- struct vimc_sen_device *vsen = data; +- unsigned int i; +- +- set_freezable(); +- set_current_state(TASK_UNINTERRUPTIBLE); +- +- for (;;) { +- try_to_freeze(); +- if (kthread_should_stop()) +- break; +- +- tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); +- +- /* Send the frame to all source pads */ +- for (i = 0; i < vsen->sd.entity.num_pads; i++) +- vimc_propagate_frame(&vsen->sd.entity.pads[i], +- vsen->frame); ++ struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, ++ ved); ++ const struct vimc_pix_map *vpix; ++ unsigned int frame_size; + +- /* 60 frames per second */ +- schedule_timeout(HZ/60); +- } ++ /* Calculate the frame size */ ++ vpix = vimc_pix_map_by_code(vsen->mbus_format.code); ++ frame_size = vsen->mbus_format.width * vpix->bpp * ++ vsen->mbus_format.height; + +- return 0; ++ tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); ++ return vsen->frame; + } + + static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) + { + struct vimc_sen_device *vsen = + container_of(sd, struct vimc_sen_device, sd); +- int ret; + + if (enable) { + const struct vimc_pix_map *vpix; +@@ -254,26 +241,8 @@ static int vimc_sen_s_stream(struct v4l2 + /* configure the test pattern generator */ + vimc_sen_tpg_s_format(vsen); + +- /* Initialize the image generator thread */ +- vsen->kthread_sen = kthread_run(vimc_sen_tpg_thread, vsen, +- "%s-sen", vsen->sd.v4l2_dev->name); +- if (IS_ERR(vsen->kthread_sen)) { +- dev_err(vsen->dev, "%s: kernel_thread() failed\n", +- vsen->sd.name); +- vfree(vsen->frame); +- vsen->frame = NULL; +- return PTR_ERR(vsen->kthread_sen); +- } + } else { +- if (!vsen->kthread_sen) +- return 0; +- +- /* Stop image generator */ +- ret = kthread_stop(vsen->kthread_sen); +- if (ret) +- return ret; + +- vsen->kthread_sen = NULL; + vfree(vsen->frame); + vsen->frame = NULL; + return 0; +@@ -325,6 +294,7 @@ static int vimc_sen_comp_bind(struct dev + if (ret) + goto err_free_vsen; + ++ vsen->ved.process_frame = vimc_sen_process_frame; + dev_set_drvdata(comp, &vsen->ved); + vsen->dev = comp; + +--- /dev/null ++++ b/drivers/media/platform/vimc/vimc-streamer.c +@@ -0,0 +1,188 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++/* ++ * vimc-streamer.c Virtual Media Controller Driver ++ * ++ * Copyright (C) 2018 Lucas A. M. Magalhães ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "vimc-streamer.h" ++ ++/** ++ * vimc_get_source_entity - get the entity connected with the first sink pad ++ * ++ * @ent: reference media_entity ++ * ++ * Helper function that returns the media entity containing the source pad ++ * linked with the first sink pad from the given media entity pad list. ++ */ ++static struct media_entity *vimc_get_source_entity(struct media_entity *ent) ++{ ++ struct media_pad *pad; ++ int i; ++ ++ for (i = 0; i < ent->num_pads; i++) { ++ if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE) ++ continue; ++ pad = media_entity_remote_pad(&ent->pads[i]); ++ return pad ? pad->entity : NULL; ++ } ++ return NULL; ++} ++ ++/* ++ * vimc_streamer_pipeline_terminate - Disable stream in all ved in stream ++ * ++ * @stream: the pointer to the stream structure with the pipeline to be ++ * disabled. ++ * ++ * Calls s_stream to disable the stream in each entity of the pipeline ++ * ++ */ ++static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) ++{ ++ struct media_entity *entity; ++ struct v4l2_subdev *sd; ++ ++ while (stream->pipe_size) { ++ stream->pipe_size--; ++ entity = stream->ved_pipeline[stream->pipe_size]->ent; ++ entity = vimc_get_source_entity(entity); ++ stream->ved_pipeline[stream->pipe_size] = NULL; ++ ++ if (!is_media_entity_v4l2_subdev(entity)) ++ continue; ++ ++ sd = media_entity_to_v4l2_subdev(entity); ++ v4l2_subdev_call(sd, video, s_stream, 0); ++ } ++} ++ ++/* ++ * vimc_streamer_pipeline_init - initializes the stream structure ++ * ++ * @stream: the pointer to the stream structure to be initialized ++ * @ved: the pointer to the vimc entity initializing the stream ++ * ++ * Initializes the stream structure. Walks through the entity graph to ++ * construct the pipeline used later on the streamer thread. ++ * Calls s_stream to enable stream in all entities of the pipeline. ++ */ ++static int vimc_streamer_pipeline_init(struct vimc_stream *stream, ++ struct vimc_ent_device *ved) ++{ ++ struct media_entity *entity; ++ struct video_device *vdev; ++ struct v4l2_subdev *sd; ++ int ret = 0; ++ ++ stream->pipe_size = 0; ++ while (stream->pipe_size < VIMC_STREAMER_PIPELINE_MAX_SIZE) { ++ if (!ved) { ++ vimc_streamer_pipeline_terminate(stream); ++ return -EINVAL; ++ } ++ stream->ved_pipeline[stream->pipe_size++] = ved; ++ ++ entity = vimc_get_source_entity(ved->ent); ++ /* Check if the end of the pipeline was reached*/ ++ if (!entity) ++ return 0; ++ ++ if (is_media_entity_v4l2_subdev(entity)) { ++ sd = media_entity_to_v4l2_subdev(entity); ++ ret = v4l2_subdev_call(sd, video, s_stream, 1); ++ if (ret && ret != -ENOIOCTLCMD) { ++ vimc_streamer_pipeline_terminate(stream); ++ return ret; ++ } ++ ved = v4l2_get_subdevdata(sd); ++ } else { ++ vdev = container_of(entity, ++ struct video_device, ++ entity); ++ ved = video_get_drvdata(vdev); ++ } ++ } ++ ++ vimc_streamer_pipeline_terminate(stream); ++ return -EINVAL; ++} ++ ++static int vimc_streamer_thread(void *data) ++{ ++ struct vimc_stream *stream = data; ++ int i; ++ ++ set_freezable(); ++ set_current_state(TASK_UNINTERRUPTIBLE); ++ ++ for (;;) { ++ try_to_freeze(); ++ if (kthread_should_stop()) ++ break; ++ ++ for (i = stream->pipe_size - 1; i >= 0; i--) { ++ stream->frame = stream->ved_pipeline[i]->process_frame( ++ stream->ved_pipeline[i], ++ stream->frame); ++ if (!stream->frame) ++ break; ++ if (IS_ERR(stream->frame)) ++ break; ++ } ++ //wait for 60hz ++ schedule_timeout(HZ / 60); ++ } ++ ++ return 0; ++} ++ ++int vimc_streamer_s_stream(struct vimc_stream *stream, ++ struct vimc_ent_device *ved, ++ int enable) ++{ ++ int ret; ++ ++ if (!stream || !ved) ++ return -EINVAL; ++ ++ if (enable) { ++ if (stream->kthread) ++ return 0; ++ ++ ret = vimc_streamer_pipeline_init(stream, ved); ++ if (ret) ++ return ret; ++ ++ stream->kthread = kthread_run(vimc_streamer_thread, stream, ++ "vimc-streamer thread"); ++ ++ if (IS_ERR(stream->kthread)) ++ return PTR_ERR(stream->kthread); ++ ++ } else { ++ if (!stream->kthread) ++ return 0; ++ ++ ret = kthread_stop(stream->kthread); ++ if (ret) ++ return ret; ++ ++ stream->kthread = NULL; ++ ++ vimc_streamer_pipeline_terminate(stream); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(vimc_streamer_s_stream); ++ ++MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Streamer"); ++MODULE_AUTHOR("Lucas A. M. Magalhães "); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/media/platform/vimc/vimc-streamer.h +@@ -0,0 +1,38 @@ ++/* SPDX-License-Identifier: GPL-2.0+ */ ++/* ++ * vimc-streamer.h Virtual Media Controller Driver ++ * ++ * Copyright (C) 2018 Lucas A. M. Magalhães ++ * ++ */ ++ ++#ifndef _VIMC_STREAMER_H_ ++#define _VIMC_STREAMER_H_ ++ ++#include ++ ++#include "vimc-common.h" ++ ++#define VIMC_STREAMER_PIPELINE_MAX_SIZE 16 ++ ++struct vimc_stream { ++ struct media_pipeline pipe; ++ struct vimc_ent_device *ved_pipeline[VIMC_STREAMER_PIPELINE_MAX_SIZE]; ++ unsigned int pipe_size; ++ u8 *frame; ++ struct task_struct *kthread; ++}; ++ ++/** ++ * vimc_streamer_s_streamer - start/stop the stream ++ * ++ * @stream: the pointer to the stream to start or stop ++ * @ved: The last entity of the streamer pipeline ++ * @enable: any non-zero number start the stream, zero stop ++ * ++ */ ++int vimc_streamer_s_stream(struct vimc_stream *stream, ++ struct vimc_ent_device *ved, ++ int enable); ++ ++#endif //_VIMC_STREAMER_H_ diff --git a/queue-4.14/series b/queue-4.14/series index 4b451fd66f9..ae220d6ddcc 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -168,3 +168,15 @@ md-fix-failed-allocation-of-md_register_thread.patch tpm-tpm_crb-avoid-unaligned-reads-in-crb_recv.patch tpm-unify-the-send-callback-behaviour.patch rcu-do-rcu-gp-kthread-self-wakeup-from-softirq-and-interrupt.patch +media-imx-prpencvf-stop-upstream-before-disabling-idma-channel.patch +media-uvcvideo-avoid-null-pointer-dereference-at-the-end-of-streaming.patch +media-vimc-add-vimc-streamer-for-stream-control.patch +media-imx-csi-disable-csi-immediately-after-last-eof.patch +media-imx-csi-stop-upstream-before-disabling-idma-channel.patch +drm-radeon-evergreen_cs-fix-missing-break-in-switch-statement.patch +kvm-call-kvm_arch_memslots_updated-before-updating-memslots.patch +kvm-x86-mmu-detect-mmio-generation-wrap-in-any-address-space.patch +kvm-x86-mmu-do-not-cache-mmio-accesses-while-memslots-are-in-flux.patch +kvm-nvmx-sign-extend-displacements-of-vmx-instr-s-mem-operands.patch +kvm-nvmx-apply-addr-size-mask-to-effective-address-for-vmx-instructions.patch +kvm-nvmx-ignore-limit-checks-on-vmx-instructions-using-flat-segments.patch