diff options
66 files changed, 2012 insertions, 1048 deletions
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index aed52b0fc16e..1a2b5210cdbf 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -3856,49 +3856,20 @@ base 2 of the page size in the bottom 6 bits. -EFAULT if struct kvm_reinject_control cannot be read, -EINVAL if the supplied shift or flags are invalid, -ENOMEM if unable to allocate the new HPT, - -ENOSPC if there was a hash collision - -:: - - struct kvm_ppc_rmmu_info { - struct kvm_ppc_radix_geom { - __u8 page_shift; - __u8 level_bits[4]; - __u8 pad[3]; - } geometries[8]; - __u32 ap_encodings[8]; - }; - -The geometries[] field gives up to 8 supported geometries for the -radix page table, in terms of the log base 2 of the smallest page -size, and the number of bits indexed at each level of the tree, from -the PTE level up to the PGD level in that order. Any unused entries -will have 0 in the page_shift field. - -The ap_encodings gives the supported page sizes and their AP field -encodings, encoded with the AP value in the top 3 bits and the log -base 2 of the page size in the bottom 6 bits. - -4.102 KVM_PPC_RESIZE_HPT_PREPARE --------------------------------- - -:Capability: KVM_CAP_SPAPR_RESIZE_HPT -:Architectures: powerpc -:Type: vm ioctl -:Parameters: struct kvm_ppc_resize_hpt (in) -:Returns: 0 on successful completion, - >0 if a new HPT is being prepared, the value is an estimated - number of milliseconds until preparation is complete, - -EFAULT if struct kvm_reinject_control cannot be read, - -EINVAL if the supplied shift or flags are invalid,when moving existing - HPT entries to the new HPT, - -EIO on other error conditions Used to implement the PAPR extension for runtime resizing of a guest's Hashed Page Table (HPT). Specifically this starts, stops or monitors the preparation of a new potential HPT for the guest, essentially implementing the H_RESIZE_HPT_PREPARE hypercall. +:: + + struct kvm_ppc_resize_hpt { + __u64 flags; + __u32 shift; + __u32 pad; + }; + If called with shift > 0 when there is no pending HPT for the guest, this begins preparation of a new pending HPT of size 2^(shift) bytes. It then returns a positive integer with the estimated number of @@ -3926,14 +3897,6 @@ Normally this will be called repeatedly with the same parameters until it returns <= 0. The first call will initiate preparation, subsequent ones will monitor preparation until it completes or fails. -:: - - struct kvm_ppc_resize_hpt { - __u64 flags; - __u32 shift; - __u32 pad; - }; - 4.103 KVM_PPC_RESIZE_HPT_COMMIT ------------------------------- @@ -3956,6 +3919,14 @@ Hashed Page Table (HPT). Specifically this requests that the guest be transferred to working with the new HPT, essentially implementing the H_RESIZE_HPT_COMMIT hypercall. +:: + + struct kvm_ppc_resize_hpt { + __u64 flags; + __u32 shift; + __u32 pad; + }; + This should only be called after KVM_PPC_RESIZE_HPT_PREPARE has returned 0 with the same parameters. In other cases KVM_PPC_RESIZE_HPT_COMMIT will return an error (usually -ENXIO or @@ -3971,14 +3942,6 @@ HPT and the previous HPT will be discarded. On failure, the guest will still be operating on its previous HPT. -:: - - struct kvm_ppc_resize_hpt { - __u64 flags; - __u32 shift; - __u32 pad; - }; - 4.104 KVM_X86_GET_MCE_CAP_SUPPORTED ----------------------------------- @@ -4915,6 +4878,14 @@ see KVM_XEN_HVM_SET_ATTR above. union { __u64 gpa; __u64 pad[4]; + struct { + __u64 state; + __u64 state_entry_time; + __u64 time_running; + __u64 time_runnable; + __u64 time_blocked; + __u64 time_offline; + } runstate; } u; }; @@ -4927,6 +4898,31 @@ KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO Sets the guest physical address of an additional pvclock structure for a given vCPU. This is typically used for guest vsyscall support. +KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR + Sets the guest physical address of the vcpu_runstate_info for a given + vCPU. This is how a Xen guest tracks CPU state such as steal time. + +KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT + Sets the runstate (RUNSTATE_running/_runnable/_blocked/_offline) of + the given vCPU from the .u.runstate.state member of the structure. + KVM automatically accounts running and runnable time but blocked + and offline states are only entered explicitly. + +KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA + Sets all fields of the vCPU runstate data from the .u.runstate member + of the structure, including the current runstate. The state_entry_time + must equal the sum of the other four times. + +KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST + This *adds* the contents of the .u.runstate members of the structure + to the corresponding members of the given vCPU's runstate data, thus + permitting atomic adjustments to the runstate times. The adjustment + to the state_entry_time must equal the sum of the adjustments to the + other four times. The state field must be set to -1, or to a valid + runstate value (RUNSTATE_running, RUNSTATE_runnable, RUNSTATE_blocked + or RUNSTATE_offline) to set the current accounted state as of the + adjusted state_entry_time. + 4.130 KVM_XEN_VCPU_GET_ATTR --------------------------- @@ -4939,6 +4935,9 @@ KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO Allows Xen vCPU attributes to be read. For the structure and types, see KVM_XEN_VCPU_SET_ATTR above. +The KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST type may not be used +with the KVM_XEN_VCPU_GET_ATTR ioctl. + 5. The kvm_run structure ======================== @@ -5000,7 +4999,8 @@ local APIC is not used. __u16 flags; More architecture-specific flags detailing state of the VCPU that may -affect the device's behavior. Current defined flags: +affect the device's behavior. Current defined flags:: + /* x86, set if the VCPU is in system management mode */ #define KVM_RUN_X86_SMM (1 << 0) /* x86, set if bus lock detected in VM */ @@ -6217,7 +6217,7 @@ the bus lock vm exit can be preempted by a higher priority VM exit, the exit notifications to userspace can be KVM_EXIT_BUS_LOCK or other reasons. KVM_RUN_BUS_LOCK flag is used to distinguish between them. -7.22 KVM_CAP_PPC_DAWR1 +7.23 KVM_CAP_PPC_DAWR1 ---------------------- :Architectures: ppc @@ -6702,6 +6702,7 @@ PVHVM guests. Valid flags are:: #define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR (1 << 0) #define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL (1 << 1) #define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2) + #define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 2) The KVM_XEN_HVM_CONFIG_HYPERCALL_MSR flag indicates that the KVM_XEN_HVM_CONFIG ioctl is available, for the guest to set its hypercall page. @@ -6716,3 +6717,7 @@ KVM_XEN_HVM_SET_ATTR, KVM_XEN_HVM_GET_ATTR, KVM_XEN_VCPU_SET_ATTR and KVM_XEN_VCPU_GET_ATTR ioctls, as well as the delivery of exception vectors for event channel upcalls when the evtchn_upcall_pending field of a vcpu's vcpu_info is set. + +The KVM_XEN_HVM_CONFIG_RUNSTATE flag indicates that the runstate-related +features KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR/_CURRENT/_DATA/_ADJUST are +supported by the KVM_XEN_VCPU_SET_ATTR/KVM_XEN_VCPU_GET_ATTR ioctls. diff --git a/arch/arm/xen/p2m.c b/arch/arm/xen/p2m.c index fd6e3aafe272..acb464547a54 100644 --- a/arch/arm/xen/p2m.c +++ b/arch/arm/xen/p2m.c @@ -93,12 +93,39 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, int i; for (i = 0; i < count; i++) { + struct gnttab_unmap_grant_ref unmap; + int rc; + if (map_ops[i].status) continue; - if (unlikely(!set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT, - map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT))) { - return -ENOMEM; - } + if (likely(set_phys_to_machine(map_ops[i].host_addr >> XEN_PAGE_SHIFT, + map_ops[i].dev_bus_addr >> XEN_PAGE_SHIFT))) + continue; + + /* + * Signal an error for this slot. This in turn requires + * immediate unmapping. + */ + map_ops[i].status = GNTST_general_error; + unmap.host_addr = map_ops[i].host_addr, + unmap.handle = map_ops[i].handle; + map_ops[i].handle = ~0; + if (map_ops[i].flags & GNTMAP_device_map) + unmap.dev_bus_addr = map_ops[i].dev_bus_addr; + else + unmap.dev_bus_addr = 0; + + /* + * Pre-populate the status field, to be recognizable in + * the log message below. + */ + unmap.status = 1; + + rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, + &unmap, 1); + if (rc || unmap.status != GNTST_okay) + pr_err_once("gnttab unmap failed: rc=%d st=%d\n", + rc, unmap.status); } return 0; diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 0cf71ff2b2e5..877a4025d8da 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -535,10 +535,16 @@ struct kvm_vcpu_hv { /* Xen HVM per vcpu emulation context */ struct kvm_vcpu_xen { u64 hypercall_rip; + u32 current_runstate; bool vcpu_info_set; bool vcpu_time_info_set; + bool runstate_set; struct gfn_to_hva_cache vcpu_info_cache; struct gfn_to_hva_cache vcpu_time_info_cache; + struct gfn_to_hva_cache runstate_cache; + u64 last_steal; + u64 runstate_entry_time; + u64 runstate_times[4]; }; struct kvm_vcpu_arch { @@ -939,9 +945,6 @@ struct kvm_arch { unsigned int indirect_shadow_pages; u8 mmu_valid_gen; struct hlist_head mmu_page_hash[KVM_NUM_MMU_PAGES]; - /* - * Hash table of struct kvm_mmu_page. - */ struct list_head active_mmu_pages; struct list_head zapped_obsolete_pages; struct list_head lpage_disallowed_mmu_pages; diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index 1a162e559753..7068e4bb057d 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -87,6 +87,18 @@ clear_foreign_p2m_mapping(struct gnttab_unmap_grant_ref *unmap_ops, #endif /* + * The maximum amount of extra memory compared to the base size. The + * main scaling factor is the size of struct page. At extreme ratios + * of base:extra, all the base memory can be filled with page + * structures for the extra memory, leaving no space for anything + * else. + * + * 10x seems like a reasonable balance between scaling flexibility and + * leaving a practically usable system. + */ +#define XEN_EXTRA_MEM_RATIO (10) + +/* * Helper functions to write or read unsigned long values to/from * memory, when the access may fault. */ diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index 7ac592664c52..a788d5120d4d 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -103,6 +103,15 @@ config KVM_AMD_SEV Provides support for launching Encrypted VMs (SEV) and Encrypted VMs with Encrypted State (SEV-ES) on AMD processors. +config KVM_XEN + bool "Support for Xen hypercall interface" + depends on KVM + help + Provides KVM support for the hosting Xen HVM guests and + passing Xen hypercalls to userspace. + + If in doubt, say "N". + config KVM_MMU_AUDIT bool "Audit KVM MMU" depends on KVM && TRACEPOINTS diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index aeab168c5711..1b4766fe1de2 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -14,11 +14,12 @@ kvm-y += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o \ $(KVM)/dirty_ring.o kvm-$(CONFIG_KVM_ASYNC_PF) += $(KVM)/async_pf.o -kvm-y += x86.o emulate.o i8259.o irq.o lapic.o xen.o \ +kvm-y += x86.o emulate.o i8259.o irq.o lapic.o \ i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \ hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \ mmu/spte.o kvm-$(CONFIG_X86_64) += mmu/tdp_iter.o mmu/tdp_mmu.o +kvm-$(CONFIG_KVM_XEN) += xen.o kvm-intel-y += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \ vmx/evmcs.o vmx/nested.o vmx/posted_intr.o diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index 7d2dae92d638..58fa8c029867 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -159,7 +159,7 @@ static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vpidx) struct kvm_vcpu_hv_synic *synic; vcpu = get_vcpu_by_vpidx(kvm, vpidx); - if (!vcpu) + if (!vcpu || !to_hv_vcpu(vcpu)) return NULL; synic = to_hv_synic(vcpu); return (synic->active) ? synic : NULL; diff --git a/arch/x86/kvm/mmu/mmu_internal.h b/arch/x86/kvm/mmu/mmu_internal.h index 72b0928f2b2d..ec4fc28b325a 100644 --- a/arch/x86/kvm/mmu/mmu_internal.h +++ b/arch/x86/kvm/mmu/mmu_internal.h @@ -81,15 +81,15 @@ static inline struct kvm_mmu_page *sptep_to_sp(u64 *sptep) static inline bool kvm_vcpu_ad_need_write_protect(struct kvm_vcpu *vcpu) { /* - * When using the EPT page-modification log, the GPAs in the log - * would come from L2 rather than L1. Therefore, we need to rely - * on write protection to record dirty pages. This also bypasses - * PML, since writes now result in a vmexit. Note, this helper will - * tag SPTEs as needing write-protection even if PML is disabled or - * unsupported, but that's ok because the tag is consumed if and only - * if PML is enabled. Omit the PML check to save a few uops. + * When using the EPT page-modification log, the GPAs in the CPU dirty + * log would come from L2 rather than L1. Therefore, we need to rely + * on write protection to record dirty pages, which bypasses PML, since + * writes now result in a vmexit. Note, the check on CPU dirty logging + * being enabled is mandatory as the bits used to denote WP-only SPTEs + * are reserved for NPT w/ PAE (32-bit KVM). */ - return vcpu->arch.mmu == &vcpu->arch.guest_mmu; + return vcpu->arch.mmu == &vcpu->arch.guest_mmu && + kvm_x86_ops.cpu_dirty_log_size; } bool is_nx_huge_page_enabled(void); diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index c636021b066b..baee91c1e936 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -1200,6 +1200,7 @@ static void init_vmcb(struct vcpu_svm *svm) init_sys_seg(&save->ldtr, SEG_TYPE_LDT); init_sys_seg(&save->tr, SEG_TYPE_BUSY_TSS16); + svm_set_cr4(&svm->vcpu, 0); svm_set_efer(&svm->vcpu, 0); save->dr6 = 0xffff0ff0; kvm_set_rflags(&svm->vcpu, X86_EFLAGS_FIXED); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3712bb5245eb..2a20ce60152e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2957,6 +2957,11 @@ static void record_steal_time(struct kvm_vcpu *vcpu) struct kvm_host_map map; struct kvm_steal_time *st; + if (kvm_xen_msr_enabled(vcpu->kvm)) { + kvm_xen_runstate_set_running(vcpu); + return; + } + if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED)) return; @@ -3756,11 +3761,15 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ENFORCE_PV_FEATURE_CPUID: r = 1; break; +#ifdef CONFIG_KVM_XEN case KVM_CAP_XEN_HVM: r = KVM_XEN_HVM_CONFIG_HYPERCALL_MSR | KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL | KVM_XEN_HVM_CONFIG_SHARED_INFO; + if (sched_info_on()) + r |= KVM_XEN_HVM_CONFIG_RUNSTATE; break; +#endif case KVM_CAP_SYNC_REGS: r = KVM_SYNC_X86_VALID_FIELDS; break; @@ -4038,7 +4047,11 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) if (vcpu->preempted && !vcpu->arch.guest_state_protected) vcpu->arch.preempted_in_kernel = !static_call(kvm_x86_get_cpl)(vcpu); - kvm_steal_time_set_preempted(vcpu); + if (kvm_xen_msr_enabled(vcpu->kvm)) + kvm_xen_runstate_set_preempted(vcpu); + else + kvm_steal_time_set_preempted(vcpu); + static_call(kvm_x86_vcpu_put)(vcpu); vcpu->arch.last_host_tsc = rdtsc(); /* @@ -5013,6 +5026,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, case KVM_GET_SUPPORTED_HV_CPUID: r = kvm_ioctl_get_supported_hv_cpuid(vcpu, argp); break; +#ifdef CONFIG_KVM_XEN case KVM_XEN_VCPU_GET_ATTR: { struct kvm_xen_vcpu_attr xva; @@ -5033,6 +5047,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, r = kvm_xen_vcpu_set_attr(vcpu, &xva); break; } +#endif default: r = -EINVAL; } @@ -5654,6 +5669,7 @@ set_pit2_out: kvm->arch.bsp_vcpu_id = arg; mutex_unlock(&kvm->lock); break; +#ifdef CONFIG_KVM_XEN case KVM_XEN_HVM_CONFIG: { struct kvm_xen_hvm_config xhc; r = -EFAULT; @@ -5682,6 +5698,7 @@ set_pit2_out: r = kvm_xen_hvm_set_attr(kvm, &xha); break; } +#endif case KVM_SET_CLOCK: { struct kvm_clock_data user_ns; u64 now_ns; @@ -8040,7 +8057,10 @@ void kvm_arch_exit(void) kvm_mmu_module_exit(); free_percpu(user_return_msrs); kmem_cache_destroy(x86_fpu_cache); +#ifdef CONFIG_KVM_XEN + static_key_deferred_flush(&kvm_xen_enabled); WARN_ON(static_branch_unlikely(&kvm_xen_enabled.key)); +#endif } static int __kvm_vcpu_halt(struct kvm_vcpu *vcpu, int state, int reason) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index af8f6562fce4..ae17250e1efe 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -11,9 +11,11 @@ #include "hyperv.h" #include <linux/kvm_host.h> +#include <linux/sched/stat.h> #include <trace/events/kvm.h> #include <xen/interface/xen.h> +#include <xen/interface/vcpu.h> #include "trace.h" @@ -61,6 +63,132 @@ out: return ret; } +static void kvm_xen_update_runstate(struct kvm_vcpu *v, int state) +{ + struct kvm_vcpu_xen *vx = &v->arch.xen; + u64 now = get_kvmclock_ns(v->kvm); + u64 delta_ns = now - vx->runstate_entry_time; + u64 run_delay = current->sched_info.run_delay; + + if (unlikely(!vx->runstate_entry_time)) + vx->current_runstate = RUNSTATE_offline; + + /* + * Time waiting for the scheduler isn't "stolen" if the + * vCPU wasn't running anyway. + */ + if (vx->current_runstate == RUNSTATE_running) { + u64 steal_ns = run_delay - vx->last_steal; + + delta_ns -= steal_ns; + + vx->runstate_times[RUNSTATE_runnable] += steal_ns; + } + vx->last_steal = run_delay; + + vx->runstate_times[vx->current_runstate] += delta_ns; + vx->current_runstate = state; + vx->runstate_entry_time = now; +} + +void kvm_xen_update_runstate_guest(struct kvm_vcpu *v, int state) +{ + struct kvm_vcpu_xen *vx = &v->arch.xen; + uint64_t state_entry_time; + unsigned int offset; + + kvm_xen_update_runstate(v, state); + + if (!vx->runstate_set) + return; + + BUILD_BUG_ON(sizeof(struct compat_vcpu_runstate_info) != 0x2c); + + offset = offsetof(struct compat_vcpu_runstate_info, state_entry_time); +#ifdef CONFIG_X86_64 + /* + * The only difference is alignment of uint64_t in 32-bit. + * So the first field 'state' is accessed directly using + * offsetof() (where its offset happens to be zero), while the + * remaining fields which are all uint64_t, start at 'offset' + * which we tweak here by adding 4. + */ + BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state_entry_time) != + offsetof(struct compat_vcpu_runstate_info, state_entry_time) + 4); + BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, time) != + offsetof(struct compat_vcpu_runstate_info, time) + 4); + + if (v->kvm->arch.xen.long_mode) + offset = offsetof(struct vcpu_runstate_info, state_entry_time); +#endif + /* + * First write the updated state_entry_time at the appropriate + * location determined by 'offset'. + */ + state_entry_time = vx->runstate_entry_time; + state_entry_time |= XEN_RUNSTATE_UPDATE; + + BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->state_entry_time) != + sizeof(state_entry_time)); + BUILD_BUG_ON(sizeof(((struct compat_vcpu_runstate_info *)0)->state_entry_time) != + sizeof(state_entry_time)); + + if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache, + &state_entry_time, offset, + sizeof(state_entry_time))) + return; + smp_wmb(); + + /* + * Next, write the new runstate. This is in the *same* place + * for 32-bit and 64-bit guests, asserted here for paranoia. + */ + BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state) != + offsetof(struct compat_vcpu_runstate_info, state)); + BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->state) != + sizeof(vx->current_runstate)); + BUILD_BUG_ON(sizeof(((struct compat_vcpu_runstate_info *)0)->state) != + sizeof(vx->current_runstate)); + + if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache, + &vx->current_runstate, + offsetof(struct vcpu_runstate_info, state), + sizeof(vx->current_runstate))) + return; + + /* + * Write the actual runstate times immediately after the + * runstate_entry_time. + */ + BUILD_BUG_ON(offsetof(struct vcpu_runstate_info, state_entry_time) != + offsetof(struct vcpu_runstate_info, time) - sizeof(u64)); + BUILD_BUG_ON(offsetof(struct compat_vcpu_runstate_info, state_entry_time) != + offsetof(struct compat_vcpu_runstate_info, time) - sizeof(u64)); + BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->time) != + sizeof(((struct compat_vcpu_runstate_info *)0)->time)); + BUILD_BUG_ON(sizeof(((struct vcpu_runstate_info *)0)->time) != + sizeof(vx->runstate_times)); + + if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache, + &vx->runstate_times[0], + offset + sizeof(u64), + sizeof(vx->runstate_times))) + return; + + smp_wmb(); + + /* + * Finally, clear the XEN_RUNSTATE_UPDATE bit in the guest's + * runstate_entry_time field. + */ + + state_entry_time &= ~XEN_RUNSTATE_UPDATE; + if (kvm_write_guest_offset_cached(v->kvm, &v->arch.xen.runstate_cache, + &state_entry_time, offset, + sizeof(state_entry_time))) + return; +} + int __kvm_xen_has_interrupt(struct kvm_vcpu *v) { u8 rc = 0; @@ -187,9 +315,12 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data) /* No compat necessary here. */ BUILD_BUG_ON(sizeof(struct vcpu_info) != sizeof(struct compat_vcpu_info)); + BUILD_BUG_ON(offsetof(struct vcpu_info, time) != + offsetof(struct compat_vcpu_info, time)); if (data->u.gpa == GPA_INVALID) { vcpu->arch.xen.vcpu_info_set = false; + r = 0; break; } @@ -206,6 +337,7 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data) case KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO: if (data->u.gpa == GPA_INVALID) { vcpu->arch.xen.vcpu_time_info_set = false; + r = 0; break; } @@ -219,6 +351,121 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data) } break; + case KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR: + if (!sched_info_on()) { + r = -EOPNOTSUPP; + break; + } + if (data->u.gpa == GPA_INVALID) { + vcpu->arch.xen.runstate_set = false; + r = 0; + break; + } + + r = kvm_gfn_to_hva_cache_init(vcpu->kvm, + &vcpu->arch.xen.runstate_cache, + data->u.gpa, + sizeof(struct vcpu_runstate_info)); + if (!r) { + vcpu->arch.xen.runstate_set = true; + } + break; + + case KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT: + if (!sched_info_on()) { + r = -EOPNOTSUPP; + break; + } + if (data->u.runstate.state > RUNSTATE_offline) { + r = -EINVAL; + break; + } + + kvm_xen_update_runstate(vcpu, data->u.runstate.state); + r = 0; + break; + + case KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA: + if (!sched_info_on()) { + r = -EOPNOTSUPP; + break; + } + if (data->u.runstate.state > RUNSTATE_offline) { + r = -EINVAL; + break; + } + if (data->u.runstate.state_entry_time != + (data->u.runstate.time_running + + data->u.runstate.time_runnable + + data->u.runstate.time_blocked + + data->u.runstate.time_offline)) { + r = -EINVAL; + break; + } + if (get_kvmclock_ns(vcpu->kvm) < + data->u.runstate.state_entry_time) { + r = -EINVAL; + break; + } + + vcpu->arch.xen.current_runstate = data->u.runstate.state; + vcpu->arch.xen.runstate_entry_time = + data->u.runstate.state_entry_time; + vcpu->arch.xen.runstate_times[RUNSTATE_running] = + data->u.runstate.time_running; + vcpu->arch.xen.runstate_times[RUNSTATE_runnable] = + data->u.runstate.time_runnable; + vcpu->arch.xen.runstate_times[RUNSTATE_blocked] = + data->u.runstate.time_blocked; + vcpu->arch.xen.runstate_times[RUNSTATE_offline] = + data->u.runstate.time_offline; + vcpu->arch.xen.last_steal = current->sched_info.run_delay; + r = 0; + break; + + case KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST: + if (!sched_info_on()) { + r = -EOPNOTSUPP; + break; + } + if (data->u.runstate.state > RUNSTATE_offline && + data->u.runstate.state != (u64)-1) { + r = -EINVAL; + break; + } + /* The adjustment must add up */ + if (data->u.runstate.state_entry_time != + (data->u.runstate.time_running + + data->u.runstate.time_runnable + + data->u.runstate.time_blocked + + data->u.runstate.time_offline)) { + r = -EINVAL; + break; + } + + if (get_kvmclock_ns(vcpu->kvm) < + (vcpu->arch.xen.runstate_entry_time + + data->u.runstate.state_entry_time)) { + r = -EINVAL; + break; + } + + vcpu->arch.xen.runstate_entry_time += + data->u.runstate.state_entry_time; + vcpu->arch.xen.runstate_times[RUNSTATE_running] += + data->u.runstate.time_running; + vcpu->arch.xen.runstate_times[RUNSTATE_runnable] += + data->u.runstate.time_runnable; + vcpu->arch.xen.runstate_times[RUNSTATE_blocked] += + data->u.runstate.time_blocked; + vcpu->arch.xen.runstate_times[RUNSTATE_offline] += + data->u.runstate.time_offline; + + if (data->u.runstate.state <= RUNSTATE_offline) + kvm_xen_update_runstate(vcpu, data->u.runstate.state); + r = 0; + break; + default: break; } @@ -251,6 +498,49 @@ int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data) r = 0; break; + case KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR: + if (!sched_info_on()) { + r = -EOPNOTSUPP; + break; + } + if (vcpu->arch.xen.runstate_set) { + data->u.gpa = vcpu->arch.xen.runstate_cache.gpa; + r = 0; + } + break; + + case KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT: + if (!sched_info_on()) { + r = -EOPNOTSUPP; + break; + } + data->u.runstate.state = vcpu->arch.xen.current_runstate; + r = 0; + break; + + case KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA: + if (!sched_info_on()) { + r = -EOPNOTSUPP; + break; + } + data->u.runstate.state = vcpu->arch.xen.current_runstate; + data->u.runstate.state_entry_time = + vcpu->arch.xen.runstate_entry_time; + data->u.runstate.time_running = + vcpu->arch.xen.runstate_times[RUNSTATE_running]; + data->u.runstate.time_runnable = + vcpu->arch.xen.runstate_times[RUNSTATE_runnable]; + data->u.runstate.time_blocked = + vcpu->arch.xen.runstate_times[RUNSTATE_blocked]; + data->u.runstate.time_offline = + vcpu->arch.xen.runstate_times[RUNSTATE_offline]; + r = 0; + break; + + case KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST: + r = -EINVAL; + break; + default: break; } diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h index b66a921776f4..463a7844a8ca 100644 --- a/arch/x86/kvm/xen.h +++ b/arch/x86/kvm/xen.h @@ -9,6 +9,7 @@ #ifndef __ARCH_X86_KVM_XEN_H__ #define __ARCH_X86_KVM_XEN_H__ +#ifdef CONFIG_KVM_XEN #include <linux/jump_label_ratelimit.h> extern struct static_key_false_deferred kvm_xen_enabled; @@ -18,11 +19,16 @@ int kvm_xen_vcpu_set_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data) int kvm_xen_vcpu_get_attr(struct kvm_vcpu *vcpu, struct kvm_xen_vcpu_attr *data); int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data); int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data); -int kvm_xen_hypercall(struct kvm_vcpu *vcpu); int kvm_xen_write_hypercall_page(struct kvm_vcpu *vcpu, u64 data); int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc); void kvm_xen_destroy_vm(struct kvm *kvm); +static inline bool kvm_xen_msr_enabled(struct kvm *kvm) +{ + return static_branch_unlikely(&kvm_xen_enabled.key) && + kvm->arch.xen_hvm_config.msr; +} + static inline bool kvm_xen_hypercall_enabled(struct kvm *kvm) { return static_branch_unlikely(&kvm_xen_enabled.key) && @@ -38,11 +44,59 @@ static inline int kvm_xen_has_interrupt(struct kvm_vcpu *vcpu) return 0; } +#else +static inline int kvm_xen_write_hypercall_page(struct kvm_vcpu *vcpu, u64 data) +{ + return 1; +} + +static inline void kvm_xen_destroy_vm(struct kvm *kvm) +{ +} + +static inline bool kvm_xen_msr_enabled(struct kvm *kvm) +{ + return false; +} + +static inline bool kvm_xen_hypercall_enabled(struct kvm *kvm) +{ + return false; +} + +static inline int kvm_xen_has_interrupt(struct kvm_vcpu *vcpu) +{ + return 0; +} +#endif + +int kvm_xen_hypercall(struct kvm_vcpu *vcpu); -/* 32-bit compatibility definitions, also used natively in 32-bit build */ #include <asm/pvclock-abi.h> #include <asm/xen/interface.h> +#include <xen/interface/vcpu.h> + +void kvm_xen_update_runstate_guest(struct kvm_vcpu *vcpu, int state); +static inline void kvm_xen_runstate_set_running(struct kvm_vcpu *vcpu) +{ + kvm_xen_update_runstate_guest(vcpu, RUNSTATE_running); +} + +static inline void kvm_xen_runstate_set_preempted(struct kvm_vcpu *vcpu) +{ + /* + * If the vCPU wasn't preempted but took a normal exit for + * some reason (hypercalls, I/O, etc.), that is accounted as + * still RUNSTATE_running, as the VMM is still operating on + * behalf of the vCPU. Only if the VMM does actually block + * does it need to enter RUNSTATE_blocked. + */ + if (vcpu->preempted) + kvm_xen_update_runstate_guest(vcpu, RUNSTATE_runnable); +} + +/* 32-bit compatibility definitions, also used natively in 32-bit build */ struct compat_arch_vcpu_info { unsigned int cr2; unsigned int pad[5]; @@ -75,4 +129,10 @@ struct compat_shared_info { struct compat_arch_shared_info arch; }; +struct compat_vcpu_runstate_info { + int state; + uint64_t state_entry_time; + uint64_t time[4]; +} __attribute__((packed)); + #endif /* __ARCH_X86_KVM_XEN_H__ */ diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index b5949e5a83ec..a3cc33091f46 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -416,6 +416,9 @@ void __init xen_vmalloc_p2m_tree(void) xen_p2m_last_pfn = xen_max_p2m_pfn; p2m_limit = (phys_addr_t)P2M_LIMIT * 1024 * 1024 * 1024 / PAGE_SIZE; + if (!p2m_limit && IS_ENABLED(CONFIG_XEN_UNPOPULATED_ALLOC)) + p2m_limit = xen_start_info->nr_pages * XEN_EXTRA_MEM_RATIO; + vm.flags = VM_ALLOC; vm.size = ALIGN(sizeof(unsigned long) * max(xen_max_p2m_pfn, p2m_limit), PMD_SIZE * PMDS_PER_MID_PAGE); @@ -652,10 +655,9 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn) pte_t *ptep; unsigned int level; - if (unlikely(pfn >= xen_p2m_size)) { - BUG_ON(mfn != INVALID_P2M_ENTRY); - return true; - } + /* Only invalid entries allowed above the highest p2m covered frame. */ + if (unlikely(pfn >= xen_p2m_size)) + return mfn == INVALID_P2M_ENTRY; /* * The interface requires atomic updates on p2m elements. @@ -710,6 +712,8 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, for (i = 0; i < count; i++) { unsigned long mfn, pfn; + struct gnttab_unmap_grant_ref unmap[2]; + int rc; /* Do not add to override if the map failed. */ if (map_ops[i].status != GNTST_okay || @@ -727,10 +731,46 @@ int set_foreign_p2m_mapping(struct gnttab_map_grant_ref *map_ops, WARN(pfn_to_mfn(pfn) != INVALID_P2M_ENTRY, "page must be ballooned"); - if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) { - ret = -ENOMEM; - goto out; + if (likely(set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) + continue; + + /* + * Signal an error for this slot. This in turn requires + * immediate unmapping. + */ + map_ops[i].status = GNTST_general_error; + unmap[0].host_addr = map_ops[i].host_addr, + unmap[0].handle = map_ops[i].handle; + map_ops[i].handle = ~0; + if (map_ops[i].flags & GNTMAP_device_map) + unmap[0].dev_bus_addr = map_ops[i].dev_bus_addr; + else + unmap[0].dev_bus_addr = 0; + + if (kmap_ops) { + kmap_ops[i].status = GNTST_general_error; + unmap[1].host_addr = kmap_ops[i].host_addr, + unmap[1].handle = kmap_ops[i].handle; + kmap_ops[i].handle = ~0; + if (kmap_ops[i].flags & GNTMAP_device_map) + unmap[1].dev_bus_addr = kmap_ops[i].dev_bus_addr; + else + unmap[1].dev_bus_addr = 0; } + + /* + * Pre-populate both status fields, to be recognizable in + * the log message below. + */ + unmap[0].status = 1; + unmap[1].status = 1; + + rc = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, + unmap, 1 + !!kmap_ops); + if (rc || unmap[0].status != GNTST_okay || + unmap[1].status != GNTST_okay) + pr_err_once("gnttab unmap failed: rc=%d st0=%d st1=%d\n", + rc, unmap[0].status, unmap[1].status); } out: diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 7eab14d56369..1a3b75652fa4 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -59,18 +59,6 @@ static struct { } xen_remap_buf __initdata __aligned(PAGE_SIZE); static unsigned long xen_remap_mfn __initdata = INVALID_P2M_ENTRY; -/* - * The maximum amount of extra memory compared to the base size. The - * main scaling factor is the size of struct page. At extreme ratios - * of base:extra, all the base memory can be filled with page - * structures for the extra memory, leaving no space for anything - * else. - * - * 10x seems like a reasonable balance between scaling flexibility and - * leaving a practically usable system. - */ -#define EXTRA_MEM_RATIO (10) - static bool xen_512gb_limit __initdata = IS_ENABLED(CONFIG_XEN_512GB); static void __init xen_parse_512gb(void) @@ -790,20 +778,13 @@ char * __init xen_memory_setup(void) extra_pages += max_pages - max_pfn; /* - * Clamp the amount of extra memory to a EXTRA_MEM_RATIO - * factor the base size. On non-highmem systems, the base - * size is the full initial memory allocation; on highmem it - * is limited to the max size of lowmem, so that it doesn't - * get completely filled. + * Clamp the amount of extra memory to a XEN_EXTRA_MEM_RATIO + * factor the base size. * * Make sure we have no memory above max_pages, as this area * isn't handled by the p2m management. - * - * In principle there could be a problem in lowmem systems if - * the initial memory is also very large with respect to - * lowmem, but we won't try to deal with that here. */ - extra_pages = min3(EXTRA_MEM_RATIO * min(max_pfn, PFN_DOWN(MAXMEM)), + extra_pages = min3(XEN_EXTRA_MEM_RATIO * min(max_pfn, PFN_DOWN(MAXMEM)), extra_pages, max_pages - max_pfn); i = 0; addr = xen_e820_table.entries[0].addr; diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 19e23fcc6bc8..ddaeceb7e109 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -278,8 +278,6 @@ static void tpm_devs_release(struct device *dev) { struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs); - dump_stack(); - /* release the master device reference */ put_device(&chip->dev); } diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 431919d5f48a..a2e0395cbe61 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -707,12 +707,22 @@ static int tpm_tis_gen_interrupt(struct tpm_chip *chip) const char *desc = "attempting to generate an interrupt"; u32 cap2; cap_t cap; + int ret; + /* TPM 2.0 */ if (chip->flags & TPM_CHIP_FLAG_TPM2) return tpm2_get_tpm_pt(chip, 0x100, &cap2, desc); - else - return tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, - 0); + + /* TPM 1.2 */ + ret = request_locality(chip, 0); + if (ret < 0) + return ret; + + ret = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, 0); + + release_locality(chip, 0); + + return ret; } /* Register the IRQ and issue a command that will cause an interrupt. If an @@ -1019,11 +1029,21 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, init_waitqueue_head(&priv->read_queue); init_waitqueue_head(&priv->int_queue); if (irq != -1) { - /* Before doing irq testing issue a command to the TPM in polling mode + /* + * Before doing irq testing issue a command to the TPM in polling mode * to make sure it works. May as well use that command to set the * proper timeouts for the driver. */ - if (tpm_get_timeouts(chip)) { + + rc = request_locality(chip, 0); + if (rc < 0) + goto out_err; + + rc = tpm_get_timeouts(chip); + + release_locality(chip, 0); + + if (rc) { dev_err(dev, "Could not get TPM timeouts and durations\n"); rc = -ENODEV; goto out_err; diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index e5c73f819662..6afb5ca999c2 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1343,11 +1343,21 @@ int xenvif_tx_action(struct xenvif_queue *queue, int budget) return 0; gnttab_batch_copy(queue->tx_copy_ops, nr_cops); - if (nr_mops != 0) + if (nr_mops != 0) { ret = gnttab_map_refs(queue->tx_map_ops, NULL, queue->pages_to_map, nr_mops); + if (ret) { + unsigned int i; + + netdev_err(queue->vif->dev, "Map fail: nr %u ret %d\n", + nr_mops, ret); + for (i = 0; i < nr_mops; ++i) + WARN_ON_ONCE(queue->tx_map_ops[i].status == + GNTST_okay); + } + } work_done = xenvif_tx_submit(queue); diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 7ad11e42306d..04633e5157e9 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -3430,125 +3430,125 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, switch(param) { case ISCSI_PARAM_FAST_ABORT: - len = sprintf(buf, "%d\n", session->fast_abort); + len = sysfs_emit(buf, "%d\n", session->fast_abort); break; case ISCSI_PARAM_ABORT_TMO: - len = sprintf(buf, "%d\n", session->abort_timeout); + len = sysfs_emit(buf, "%d\n", session->abort_timeout); break; case ISCSI_PARAM_LU_RESET_TMO: - len = sprintf(buf, "%d\n", session->lu_reset_timeout); + len = sysfs_emit(buf, "%d\n", session->lu_reset_timeout); break; case ISCSI_PARAM_TGT_RESET_TMO: - len = sprintf(buf, "%d\n", session->tgt_reset_timeout); + len = sysfs_emit(buf, "%d\n", session->tgt_reset_timeout); break; case ISCSI_PARAM_INITIAL_R2T_EN: - len = sprintf(buf, "%d\n", session->initial_r2t_en); + len = sysfs_emit(buf, "%d\n", session->initial_r2t_en); break; case ISCSI_PARAM_MAX_R2T: - len = sprintf(buf, "%hu\n", session->max_r2t); + len = sysfs_emit(buf, "%hu\n", session->max_r2t); break; case ISCSI_PARAM_IMM_DATA_EN: - len = sprintf(buf, "%d\n", session->imm_data_en); + len = sysfs_emit(buf, "%d\n", session->imm_data_en); break; case ISCSI_PARAM_FIRST_BURST: - len = sprintf(buf, "%u\n", session->first_burst); + len = sysfs_emit(buf, "%u\n", session->first_burst); break; case ISCSI_PARAM_MAX_BURST: - len = sprintf(buf, "%u\n", session->max_burst); + len = sysfs_emit(buf, "%u\n", session->max_burst); break; case ISCSI_PARAM_PDU_INORDER_EN: - len = sprintf(buf, "%d\n", session->pdu_inorder_en); + len = sysfs_emit(buf, "%d\n", session->pdu_inorder_en); break; case ISCSI_PARAM_DATASEQ_INORDER_EN: - len = sprintf(buf, "%d\n", session->dataseq_inorder_en); + len = sysfs_emit(buf, "%d\n", session->dataseq_inorder_en); break; case ISCSI_PARAM_DEF_TASKMGMT_TMO: - len = sprintf(buf, "%d\n", session->def_taskmgmt_tmo); + len = sysfs_emit(buf, "%d\n", session->def_taskmgmt_tmo); break; case ISCSI_PARAM_ERL: - len = sprintf(buf, "%d\n", session->erl); + len = sysfs_emit(buf, "%d\n", session->erl); break; case ISCSI_PARAM_TARGET_NAME: - len = sprintf(buf, "%s\n", session->targetname); + len = sysfs_emit(buf, "%s\n", session->targetname); break; case ISCSI_PARAM_TARGET_ALIAS: - len = sprintf(buf, "%s\n", session->targetalias); + len = sysfs_emit(buf, "%s\n", session->targetalias); break; case ISCSI_PARAM_TPGT: - len = sprintf(buf, "%d\n", session->tpgt); + len = sysfs_emit(buf, "%d\n", session->tpgt); break; case ISCSI_PARAM_USERNAME: - len = sprintf(buf, "%s\n", session->username); + len = sysfs_emit(buf, "%s\n", session->username); break; case ISCSI_PARAM_USERNAME_IN: - len = sprintf(buf, "%s\n", session->username_in); + len = sysfs_emit(buf, "%s\n", session->username_in); break; case ISCSI_PARAM_PASSWORD: - len = sprintf(buf, "%s\n", session->password); + len = sysfs_emit(buf, "%s\n", session->password); break; case ISCSI_PARAM_PASSWORD_IN: - len = sprintf(buf, "%s\n", session->password_in); + len = sysfs_emit(buf, "%s\n", session->password_in); break; case ISCSI_PARAM_IFACE_NAME: - len = sprintf(buf, "%s\n", session->ifacename); + len = sysfs_emit(buf, "%s\n", session->ifacename); break; case ISCSI_PARAM_INITIATOR_NAME: - len = sprintf(buf, "%s\n", session->initiatorname); + len = sysfs_emit(buf, "%s\n", session->initiatorname); break; case ISCSI_PARAM_BOOT_ROOT: - len = sprintf(buf, "%s\n", session->boot_root); + len = sysfs_emit(buf, "%s\n", session->boot_root); break; case ISCSI_PARAM_BOOT_NIC: - len = sprintf(buf, "%s\n", session->boot_nic); + len = sysfs_emit(buf, "%s\n", session->boot_nic); break; case ISCSI_PARAM_BOOT_TARGET: - len = sprintf(buf, "%s\n", session->boot_target); + len = sysfs_emit(buf, "%s\n", session->boot_target); break; case ISCSI_PARAM_AUTO_SND_TGT_DISABLE: - len = sprintf(buf, "%u\n", session->auto_snd_tgt_disable); + len = sysfs_emit(buf, "%u\n", session->auto_snd_tgt_disable); break; case ISCSI_PARAM_DISCOVERY_SESS: - len = sprintf(buf, "%u\n", session->discovery_sess); + len = sysfs_emit(buf, "%u\n", session->discovery_sess); break; case ISCSI_PARAM_PORTAL_TYPE: - len = sprintf(buf, "%s\n", session->portal_type); + len = sysfs_emit(buf, "%s\n", session->portal_type); break; case ISCSI_PARAM_CHAP_AUTH_EN: - len = sprintf(buf, "%u\n", session->chap_auth_en); + len = sysfs_emit(buf, "%u\n", session->chap_auth_en); break; case ISCSI_PARAM_DISCOVERY_LOGOUT_EN: - len = sprintf(buf, "%u\n", session->discovery_logout_en); + len = sysfs_emit(buf, "%u\n", session->discovery_logout_en); break; case ISCSI_PARAM_BIDI_CHAP_EN: - len = sprintf(buf, "%u\n", session->bidi_chap_en); + len = sysfs_emit(buf, "%u\n", session->bidi_chap_en); break; case ISCSI_PARAM_DISCOVERY_AUTH_OPTIONAL: - len = sprintf(buf, "%u\n", session->discovery_auth_optional); + len = sysfs_emit(buf, "%u\n", session->discovery_auth_optional); break; case ISCSI_PARAM_DEF_TIME2WAIT: - len = sprintf(buf, "%d\n", session->time2wait); + len = sysfs_emit(buf, "%d\n", session->time2wait); break; case ISCSI_PARAM_DEF_TIME2RETAIN: - len = sprintf(buf, "%d\n", session->time2retain); + len = sysfs_emit(buf, "%d\n", session->time2retain); break; case ISCSI_PARAM_TSID: - len = sprintf(buf, "%u\n", session->tsid); + len = sysfs_emit(buf, "%u\n", session->tsid); break; case ISCSI_PARAM_ISID: - len = sprintf(buf, "%02x%02x%02x%02x%02x%02x\n", + len = sysfs_emit(buf, "%02x%02x%02x%02x%02x%02x\n", session->isid[0], session->isid[1], session->isid[2], session->isid[3], session->isid[4], session->isid[5]); break; case ISCSI_PARAM_DISCOVERY_PARENT_IDX: - len = sprintf(buf, "%u\n", session->discovery_parent_idx); + len = sysfs_emit(buf, "%u\n", session->discovery_parent_idx); break; case ISCSI_PARAM_DISCOVERY_PARENT_TYPE: if (session->discovery_parent_type) - len = sprintf(buf, "%s\n", + len = sysfs_emit(buf, "%s\n", session->discovery_parent_type); else - len = sprintf(buf, "\n"); + len = sysfs_emit(buf, "\n"); break; default: return -ENOSYS; @@ -3580,16 +3580,16 @@ int iscsi_conn_get_addr_param(struct sockaddr_storage *addr, case ISCSI_PARAM_CONN_ADDRESS: case ISCSI_HOST_PARAM_IPADDRESS: if (sin) - len = sprintf(buf, "%pI4\n", &sin->sin_addr.s_addr); + len = sysfs_emit(buf, "%pI4\n", &sin->sin_addr.s_addr); else - len = sprintf(buf, "%pI6\n", &sin6->sin6_addr); + len = sysfs_emit(buf, "%pI6\n", &sin6->sin6_addr); break; case ISCSI_PARAM_CONN_PORT: case ISCSI_PARAM_LOCAL_PORT: if (sin) - len = sprintf(buf, "%hu\n", be16_to_cpu(sin->sin_port)); + len = sysfs_emit(buf, "%hu\n", be16_to_cpu(sin->sin_port)); else - len = sprintf(buf, "%hu\n", + len = sysfs_emit(buf, "%hu\n", be16_to_cpu(sin6->sin6_port)); break; default: @@ -3608,88 +3608,88 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, switch(param) { case ISCSI_PARAM_PING_TMO: - len = sprintf(buf, "%u\n", conn->ping_timeout); + len = sysfs_emit(buf, "%u\n", conn->ping_timeout); break; case ISCSI_PARAM_RECV_TMO: - len = sprintf(buf, "%u\n", conn->recv_timeout); + len = sysfs_emit(buf, "%u\n", conn->recv_timeout); break; case ISCSI_PARAM_MAX_RECV_DLENGTH: - len = sprintf(buf, "%u\n", conn->max_recv_dlength); + len = sysfs_emit(buf, "%u\n", conn->max_recv_dlength); break; case ISCSI_PARAM_MAX_XMIT_DLENGTH: - len = sprintf(buf, "%u\n", conn->max_xmit_dlength); + len = sysfs_emit(buf, "%u\n", conn->max_xmit_dlength); break; case ISCSI_PARAM_HDRDGST_EN: - len = sprintf(buf, "%d\n", conn->hdrdgst_en); + len = sysfs_emit(buf, "%d\n", conn->hdrdgst_en); break; case ISCSI_PARAM_DATADGST_EN: - len = sprintf(buf, "%d\n", conn->datadgst_en); + len = sysfs_emit(buf, "%d\n", conn->datadgst_en); break; case ISCSI_PARAM_IFMARKER_EN: - len = sprintf(buf, "%d\n", conn->ifmarker_en); + len = sysfs_emit(buf, "%d\n", conn->ifmarker_en); break; case ISCSI_PARAM_OFMARKER_EN: - len = sprintf(buf, "%d\n", conn->ofmarker_en); + len = sysfs_emit(buf, "%d\n", conn->ofmarker_en); break; case ISCSI_PARAM_EXP_STATSN: - len = sprintf(buf, "%u\n", conn->exp_statsn); + len = sysfs_emit(buf, "%u\n", conn->exp_statsn); break; case ISCSI_PARAM_PERSISTENT_PORT: - len = sprintf(buf, "%d\n", conn->persistent_port); + len = sysfs_emit(buf, "%d\n", conn->persistent_port); break; case ISCSI_PARAM_PERSISTENT_ADDRESS: - len = sprintf(buf, "%s\n", conn->persistent_address); + len = sysfs_emit(buf, "%s\n", conn->persistent_address); break; case ISCSI_PARAM_STATSN: - len = sprintf(buf, "%u\n", conn->statsn); + len = sysfs_emit(buf, "%u\n", conn->statsn); break; case ISCSI_PARAM_MAX_SEGMENT_SIZE: - len = sprintf(buf, "%u\n", conn->max_segment_size); + len = sysfs_emit(buf, "%u\n", conn->max_segment_size); break; case ISCSI_PARAM_KEEPALIVE_TMO: - len = sprintf(buf, "%u\n", conn->keepalive_tmo); + len = sysfs_emit(buf, "%u\n", conn->keepalive_tmo); break; case ISCSI_PARAM_LOCAL_PORT: - len = sprintf(buf, "%u\n", conn->local_port); + len = sysfs_emit(buf, "%u\n", conn->local_port); break; case ISCSI_PARAM_TCP_TIMESTAMP_STAT: - len = sprintf(buf, "%u\n", conn->tcp_timestamp_stat); + len = sysfs_emit(buf, "%u\n", conn->tcp_timestamp_stat); break; case ISCSI_PARAM_TCP_NAGLE_DISABLE: - len = sprintf(buf, "%u\n", conn->tcp_nagle_disable); + len = sysfs_emit(buf, "%u\n", conn->tcp_nagle_disable); break; case ISCSI_PARAM_TCP_WSF_DISABLE: - len = sprintf(buf, "%u\n", conn->tcp_wsf_disable); + len = sysfs_emit(buf, "%u\n", conn->tcp_wsf_disable); break; case ISCSI_PARAM_TCP_TIMER_SCALE: - len = sprintf(buf, "%u\n", conn->tcp_timer_scale); + len = sysfs_emit(buf, "%u\n", conn->tcp_timer_scale); break; case ISCSI_PARAM_TCP_TIMESTAMP_EN: - len = sprintf(buf, "%u\n", conn->tcp_timestamp_en); + len = sysfs_emit(buf, "%u\n", conn->tcp_timestamp_en); break; case ISCSI_PARAM_IP_FRAGMENT_DISABLE: - len = sprintf(buf, "%u\n", conn->fragment_disable); + len = sysfs_emit(buf, "%u\n", conn->fragment_disable); break; case ISCSI_PARAM_IPV4_TOS: - len = sprintf(buf, "%u\n", conn->ipv4_tos); + len = sysfs_emit(buf, "%u\n", conn->ipv4_tos); break; case ISCSI_PARAM_IPV6_TC: - len = sprintf(buf, "%u\n", conn->ipv6_traffic_class); + len = sysfs_emit(buf, "%u\n", conn->ipv6_traffic_class); break; case ISCSI_PARAM_IPV6_FLOW_LABEL: - len = sprintf(buf, "%u\n", conn->ipv6_flow_label); + len = sysfs_emit(buf, "%u\n", conn->ipv6_flow_label); break; case ISCSI_PARAM_IS_FW_ASSIGNED_IPV6: - len = sprintf(buf, "%u\n", conn->is_fw_assigned_ipv6); + len = sysfs_emit(buf, "%u\n", conn->is_fw_assigned_ipv6); break; case ISCSI_PARAM_TCP_XMIT_WSF: - len = sprintf(buf, "%u\n", conn->tcp_xmit_wsf); + len = sysfs_emit(buf, "%u\n", conn->tcp_xmit_wsf); break; case ISCSI_PARAM_TCP_RECV_WSF: - len = sprintf(buf, "%u\n", conn->tcp_recv_wsf); + len = sysfs_emit(buf, "%u\n", conn->tcp_recv_wsf); break; case ISCSI_PARAM_LOCAL_IPADDR: - len = sprintf(buf, "%s\n", conn->local_ipaddr); + len = sysfs_emit(buf, "%s\n", conn->local_ipaddr); break; default: return -ENOSYS; @@ -3707,13 +3707,13 @@ int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, switch (param) { case ISCSI_HOST_PARAM_NETDEV_NAME: - len = sprintf(buf, "%s\n", ihost->netdev); + len = sysfs_emit(buf, "%s\n", ihost->netdev); break; case ISCSI_HOST_PARAM_HWADDRESS: - len = sprintf(buf, "%s\n", ihost->hwaddress); + len = sysfs_emit(buf, "%s\n", ihost->hwaddress); break; case ISCSI_HOST_PARAM_INITIATOR_NAME: - len = sprintf(buf, "%s\n", ihost->initiatorname); + len = sysfs_emit(buf, "%s\n", ihost->initiatorname); break; default: return -ENOSYS; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 969d24d580e2..91074fd97f64 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -132,7 +132,11 @@ show_transport_handle(struct device *dev, struct device_attribute *attr, char *buf) { struct iscsi_internal *priv = dev_to_iscsi_internal(dev); - return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport)); + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return sysfs_emit(buf, "%llu\n", + (unsigned long long)iscsi_handle(priv->iscsi_transport)); } static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL); @@ -142,7 +146,7 @@ show_transport_##name(struct device *dev, \ struct device_attribute *attr,char *buf) \ { \ struct iscsi_internal *priv = dev_to_iscsi_internal(dev); \ - return sprintf(buf, format"\n", priv->iscsi_transport->name); \ + return sysfs_emit(buf, format"\n", priv->iscsi_transport->name);\ } \ static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL); @@ -183,7 +187,7 @@ static ssize_t show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf) { struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); - return sprintf(buf, "%llu\n", (unsigned long long) ep->id); + return sysfs_emit(buf, "%llu\n", (unsigned long long) ep->id); } static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL); @@ -2880,6 +2884,9 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) struct iscsi_cls_session *session; int err = 0, value = 0; + if (ev->u.set_param.len > PAGE_SIZE) + return -EINVAL; + session = iscsi_session_lookup(ev->u.set_param.sid); conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); if (!conn || !session) @@ -3027,6 +3034,9 @@ iscsi_set_host_param(struct iscsi_transport *transport, if (!transport->set_host_param) return -ENOSYS; + if (ev->u.set_host_param.len > PAGE_SIZE) + return -EINVAL; + shost = scsi_host_lookup(ev->u.set_host_param.host_no); if (!shost) { printk(KERN_ERR "set_host_param could not find host no %u\n", @@ -3614,6 +3624,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) { int err = 0; u32 portid; + u32 pdu_len; struct iscsi_uevent *ev = nlmsg_data(nlh); struct iscsi_transport *transport = NULL; struct iscsi_internal *priv; @@ -3621,6 +3632,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) struct iscsi_cls_conn *conn; struct iscsi_endpoint *ep = NULL; + if (!netlink_capable(skb, CAP_SYS_ADMIN)) + return -EPERM; + if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE) *group = ISCSI_NL_GRP_UIP; else @@ -3753,6 +3767,14 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) err = -EINVAL; break; case ISCSI_UEVENT_SEND_PDU: + pdu_len = nlh->nlmsg_len - sizeof(*nlh) - sizeof(*ev); + + if ((ev->u.send_pdu.hdr_size > pdu_len) || + (ev->u.send_pdu.data_size > (pdu_len - ev->u.send_pdu.hdr_size))) { + err = -EINVAL; + break; + } + conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid); if (conn) { mutex_lock(&conn_mutex); @@ -3957,7 +3979,7 @@ static ssize_t show_conn_state(struct device *dev, conn->state < ARRAY_SIZE(connection_state_names)) state = connection_state_names[conn->state]; - return sprintf(buf, "%s\n", state); + return sysfs_emit(buf, "%s\n", state); } static ISCSI_CLASS_ATTR(conn, state, S_IRUGO, show_conn_state, NULL); @@ -4185,7 +4207,7 @@ show_priv_session_state(struct device *dev, struct device_attribute *attr, char *buf) { struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent); - return sprintf(buf, "%s\n", iscsi_session_state_name(session->state)); + return sysfs_emit(buf, "%s\n", iscsi_session_state_name(session->state)); } static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state, NULL); @@ -4194,7 +4216,7 @@ show_priv_session_creator(struct device *dev, struct device_attribute *attr, char *buf) { struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent); - return sprintf(buf, "%d\n", session->creator); + return sysfs_emit(buf, "%d\n", session->creator); } static ISCSI_CLASS_ATTR(priv_sess, creator, S_IRUGO, show_priv_session_creator, NULL); @@ -4203,7 +4225,7 @@ show_priv_session_target_id(struct device *dev, struct device_attribute *attr, char *buf) { struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent); - return sprintf(buf, "%d\n", session->target_id); + return sysfs_emit(buf, "%d\n", session->target_id); } static ISCSI_CLASS_ATTR(priv_sess, target_id, S_IRUGO, show_priv_session_target_id, NULL); @@ -4216,8 +4238,8 @@ show_priv_session_##field(struct device *dev, \ struct iscsi_cls_session *session = \ iscsi_dev_to_session(dev->parent); \ if (session->field == -1) \ - return sprintf(buf, "off\n"); \ - return sprintf(buf, format"\n", session->field); \ + return sysfs_emit(buf, "off\n"); \ + return sysfs_emit(buf, format"\n", session->field); \ } #define iscsi_priv_session_attr_store(field) \ diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index 76820d0b9deb..06bac8ba14e9 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -48,8 +48,6 @@ struct sdw_intel { #endif }; -#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1) - int intel_master_startup(struct platform_device *pdev); int intel_master_process_wakeen_event(struct platform_device *pdev); diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c index bc8520eb385e..05b726cdfebc 100644 --- a/drivers/soundwire/intel_init.c +++ b/drivers/soundwire/intel_init.c @@ -18,42 +18,12 @@ #include "cadence_master.h" #include "intel.h" -#define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */ -#define SDW_MAX_LINKS 4 #define SDW_SHIM_LCAP 0x0 #define SDW_SHIM_BASE 0x2C000 #define SDW_ALH_BASE 0x2C800 #define SDW_LINK_BASE 0x30000 #define SDW_LINK_SIZE 0x10000 -static int ctrl_link_mask; -module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444); -MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)"); - -static bool is_link_enabled(struct fwnode_handle *fw_node, int i) -{ - struct fwnode_handle *link; - char name[32]; - u32 quirk_mask = 0; - - /* Find master handle */ - snprintf(name, sizeof(name), - "mipi-sdw-link-%d-subproperties", i); - - link = fwnode_get_named_child_node(fw_node, name); - if (!link) - return false; - - fwnode_property_read_u32(link, - "intel-quirk-mask", - &quirk_mask); - - if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) - return false; - - return true; -} - static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx) { struct sdw_intel_link_res *link = ctx->links; @@ -81,74 +51,6 @@ static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx) return 0; } -static int -sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) -{ - struct acpi_device *adev; - int ret, i; - u8 count; - - if (acpi_bus_get_device(info->handle, &adev)) - return -EINVAL; - - /* Found controller, find links supported */ - count = 0; - ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev), - "mipi-sdw-master-count", &count, 1); - - /* - * In theory we could check the number of links supported in - * hardware, but in that step we cannot assume SoundWire IP is - * powered. - * - * In addition, if the BIOS doesn't even provide this - * 'master-count' property then all the inits based on link - * masks will fail as well. - * - * We will check the hardware capabilities in the startup() step - */ - - if (ret) { - dev_err(&adev->dev, - "Failed to read mipi-sdw-master-count: %d\n", ret); - return -EINVAL; - } - - /* Check count is within bounds */ - if (count > SDW_MAX_LINKS) { - dev_err(&adev->dev, "Link count %d exceeds max %d\n", - count, SDW_MAX_LINKS); - return -EINVAL; - } - - if (!count) { - dev_warn(&adev->dev, "No SoundWire links detected\n"); - return -EINVAL; - } - dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count); - - info->count = count; - info->link_mask = 0; - - for (i = 0; i < count; i++) { - if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) { - dev_dbg(&adev->dev, - "Link %d masked, will not be enabled\n", i); - continue; - } - - if (!is_link_enabled(acpi_fwnode_handle(adev), i)) { - dev_dbg(&adev->dev, - "Link %d not selected in firmware\n", i); - continue; - } - - info->link_mask |= BIT(i); - } - - return 0; -} - #define HDA_DSP_REG_ADSPIC2 (0x10) #define HDA_DSP_REG_ADSPIS2 (0x14) #define HDA_DSP_REG_ADSPIC2_SNDW BIT(5) @@ -357,66 +259,6 @@ sdw_intel_startup_controller(struct sdw_intel_ctx *ctx) return 0; } -static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, - void *cdata, void **return_value) -{ - struct sdw_intel_acpi_info *info = cdata; - struct acpi_device *adev; - acpi_status status; - u64 adr; - - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); - if (ACPI_FAILURE(status)) - return AE_OK; /* keep going */ - - if (acpi_bus_get_device(handle, &adev)) { - pr_err("%s: Couldn't find ACPI handle\n", __func__); - return AE_NOT_FOUND; - } - - info->handle = handle; - - /* - * On some Intel platforms, multiple children of the HDAS - * device can be found, but only one of them is the SoundWire - * controller. The SNDW device is always exposed with - * Name(_ADR, 0x40000000), with bits 31..28 representing the - * SoundWire link so filter accordingly - */ - if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE) - return AE_OK; /* keep going */ - - /* device found, stop namespace walk */ - return AE_CTRL_TERMINATE; -} - -/** - * sdw_intel_acpi_scan() - SoundWire Intel init routine - * @parent_handle: ACPI parent handle - * @info: description of what firmware/DSDT tables expose - * - * This scans the namespace and queries firmware to figure out which - * links to enable. A follow-up use of sdw_intel_probe() and - * sdw_intel_startup() is required for creation of devices and bus - * startup - */ -int sdw_intel_acpi_scan(acpi_handle *parent_handle, - struct sdw_intel_acpi_info *info) -{ - acpi_status status; - - info->handle = NULL; - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, - parent_handle, 1, - sdw_intel_acpi_cb, - NULL, info, NULL); - if (ACPI_FAILURE(status) || info->handle == NULL) - return -ENODEV; - - return sdw_intel_scan_controller(info); -} -EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SOUNDWIRE_INTEL_INIT); - /** * sdw_intel_probe() - SoundWire Intel probe routine * @res: resource data diff --git a/include/linux/soundwire/sdw_intel.h b/include/linux/soundwire/sdw_intel.h index 120ffddc03d2..3a5446ac014a 100644 --- a/include/linux/soundwire/sdw_intel.h +++ b/include/linux/soundwire/sdw_intel.h @@ -187,4 +187,6 @@ void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable); irqreturn_t sdw_intel_thread(int irq, void *dev_id); +#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1) + #endif diff --git a/include/sound/intel-nhlt.h b/include/sound/intel-nhlt.h index 743c2f442280..d0574805865f 100644 --- a/include/sound/intel-nhlt.h +++ b/include/sound/intel-nhlt.h @@ -113,6 +113,11 @@ struct nhlt_vendor_dmic_array_config { } __packed; enum { + NHLT_CONFIG_TYPE_GENERIC = 0, + NHLT_CONFIG_TYPE_MIC_ARRAY = 1 +}; + +enum { NHLT_MIC_ARRAY_2CH_SMALL = 0xa, NHLT_MIC_ARRAY_2CH_BIG = 0xb, NHLT_MIC_ARRAY_4CH_1ST_GEOM = 0xc, diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 9a43c44dcbbb..c45075024c30 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -174,7 +174,7 @@ struct snd_soc_acpi_codecs { static inline bool snd_soc_acpi_sof_parent(struct device *dev) { return dev->parent && dev->parent->driver && dev->parent->driver->name && - !strcmp(dev->parent->driver->name, "sof-audio-acpi"); + !strncmp(dev->parent->driver->name, "sof-audio-acpi", strlen("sof-audio-acpi")); } #endif diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 8b281f722e5b..f6afee209620 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1154,6 +1154,7 @@ struct kvm_x86_mce { #define KVM_XEN_HVM_CONFIG_HYPERCALL_MSR (1 << 0) #define KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL (1 << 1) #define KVM_XEN_HVM_CONFIG_SHARED_INFO (1 << 2) +#define KVM_XEN_HVM_CONFIG_RUNSTATE (1 << 3) struct kvm_xen_hvm_config { __u32 flags; @@ -1621,12 +1622,24 @@ struct kvm_xen_vcpu_attr { union { __u64 gpa; __u64 pad[8]; + struct { + __u64 state; + __u64 state_entry_time; + __u64 time_running; + __u64 time_runnable; + __u64 time_blocked; + __u64 time_offline; + } runstate; } u; }; /* Available with KVM_CAP_XEN_HVM / KVM_XEN_HVM_CONFIG_SHARED_INFO */ #define KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO 0x0 #define KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO 0x1 +#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR 0x2 +#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_CURRENT 0x3 +#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA 0x4 +#define KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST 0x5 /* Secure Encrypted Virtualization command */ enum sev_cmd_id { diff --git a/sound/hda/Kconfig b/sound/hda/Kconfig index 9ed5cfa3c18c..57595f1552c9 100644 --- a/sound/hda/Kconfig +++ b/sound/hda/Kconfig @@ -44,9 +44,13 @@ config SND_INTEL_NHLT config SND_INTEL_DSP_CONFIG tristate select SND_INTEL_NHLT if ACPI + select SND_INTEL_SOUNDWIRE_ACPI if ACPI # this config should be selected only for Intel DSP platforms. # A fallback is provided so that the code compiles in all cases. +config SND_INTEL_SOUNDWIRE_ACPI + tristate + config SND_INTEL_BYT_PREFER_SOF bool "Prefer SOF driver over SST on BY/CHT platforms" depends on SND_SST_ATOM_HIFI2_PLATFORM_ACPI && SND_SOC_SOF_BAYTRAIL diff --git a/sound/hda/Makefile b/sound/hda/Makefile index 601e617918b8..78f487a635f8 100644 --- a/sound/hda/Makefile +++ b/sound/hda/Makefile @@ -17,3 +17,6 @@ obj-$(CONFIG_SND_HDA_EXT_CORE) += ext/ snd-intel-dspcfg-objs := intel-dsp-config.o snd-intel-dspcfg-$(CONFIG_SND_INTEL_NHLT) += intel-nhlt.o obj-$(CONFIG_SND_INTEL_DSP_CONFIG) += snd-intel-dspcfg.o + +snd-intel-sdw-acpi-objs := intel-sdw-acpi.o +obj-$(CONFIG_SND_INTEL_SOUNDWIRE_ACPI) += snd-intel-sdw-acpi.o diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index a9bd39b93697..b2df7b4f9227 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -133,7 +133,7 @@ void snd_hdac_link_free_all(struct hdac_bus *bus) EXPORT_SYMBOL_GPL(snd_hdac_link_free_all); /** - * snd_hdac_ext_bus_get_link_index - get link based on codec name + * snd_hdac_ext_bus_get_link - get link based on codec name * @bus: the pointer to HDAC bus object * @codec_name: codec name */ diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index c4d54a838773..0c005d67fa89 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -133,7 +133,7 @@ void snd_hdac_ext_stream_decouple(struct hdac_bus *bus, EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_decouple); /** - * snd_hdac_ext_linkstream_start - start a stream + * snd_hdac_ext_link_stream_start - start a stream * @stream: HD-audio ext core stream to start */ void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *stream) diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c index d75f31eb9d78..fe3587547cfe 100644 --- a/sound/hda/hdac_regmap.c +++ b/sound/hda/hdac_regmap.c @@ -386,7 +386,7 @@ int snd_hdac_regmap_init(struct hdac_device *codec) EXPORT_SYMBOL_GPL(snd_hdac_regmap_init); /** - * snd_hdac_regmap_init - Release the regmap from HDA codec + * snd_hdac_regmap_exit - Release the regmap from HDA codec * @codec: the codec object */ void snd_hdac_regmap_exit(struct hdac_device *codec) diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index d1eb9d34993a..ab5ff7867eb9 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -557,4 +557,4 @@ EXPORT_SYMBOL_GPL(snd_intel_acpi_dsp_driver_probe); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel DSP config driver"); -MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT); +MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI); diff --git a/sound/hda/intel-nhlt.c b/sound/hda/intel-nhlt.c index 059aaf04f536..d053beccfaec 100644 --- a/sound/hda/intel-nhlt.c +++ b/sound/hda/intel-nhlt.c @@ -31,18 +31,44 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) struct nhlt_endpoint *epnt; struct nhlt_dmic_array_config *cfg; struct nhlt_vendor_dmic_array_config *cfg_vendor; + struct nhlt_fmt *fmt_configs; unsigned int dmic_geo = 0; - u8 j; + u16 max_ch = 0; + u8 i, j; if (!nhlt) return 0; - epnt = (struct nhlt_endpoint *)nhlt->desc; + for (j = 0, epnt = nhlt->desc; j < nhlt->endpoint_count; j++, + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length)) { - for (j = 0; j < nhlt->endpoint_count; j++) { - if (epnt->linktype == NHLT_LINK_DMIC) { - cfg = (struct nhlt_dmic_array_config *) - (epnt->config.caps); + if (epnt->linktype != NHLT_LINK_DMIC) + continue; + + cfg = (struct nhlt_dmic_array_config *)(epnt->config.caps); + fmt_configs = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size); + + /* find max number of channels based on format_configuration */ + if (fmt_configs->fmt_count) { + dev_dbg(dev, "%s: found %d format definitions\n", + __func__, fmt_configs->fmt_count); + + for (i = 0; i < fmt_configs->fmt_count; i++) { + struct wav_fmt_ext *fmt_ext; + + fmt_ext = &fmt_configs->fmt_config[i].fmt_ext; + + if (fmt_ext->fmt.channels > max_ch) + max_ch = fmt_ext->fmt.channels; + } + dev_dbg(dev, "%s: max channels found %d\n", __func__, max_ch); + } else { + dev_dbg(dev, "%s: No format information found\n", __func__); + } + + if (cfg->device_config.config_type != NHLT_CONFIG_TYPE_MIC_ARRAY) { + dmic_geo = max_ch; + } else { switch (cfg->array_type) { case NHLT_MIC_ARRAY_2CH_SMALL: case NHLT_MIC_ARRAY_2CH_BIG: @@ -59,13 +85,23 @@ int intel_nhlt_get_dmic_geo(struct device *dev, struct nhlt_acpi_table *nhlt) dmic_geo = cfg_vendor->nb_mics; break; default: - dev_warn(dev, "undefined DMIC array_type 0x%0x\n", - cfg->array_type); + dev_warn(dev, "%s: undefined DMIC array_type 0x%0x\n", + __func__, cfg->array_type); + } + + if (dmic_geo > 0) { + dev_dbg(dev, "%s: Array with %d dmics\n", __func__, dmic_geo); + } + if (max_ch > dmic_geo) { + dev_dbg(dev, "%s: max channels %d exceed dmic number %d\n", + __func__, max_ch, dmic_geo); } } - epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); } + dev_dbg(dev, "%s: dmic number %d max_ch %d\n", + __func__, dmic_geo, max_ch); + return dmic_geo; } EXPORT_SYMBOL_GPL(intel_nhlt_get_dmic_geo); diff --git a/sound/hda/intel-sdw-acpi.c b/sound/hda/intel-sdw-acpi.c new file mode 100644 index 000000000000..c0123bc31c0d --- /dev/null +++ b/sound/hda/intel-sdw-acpi.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2015-2021 Intel Corporation. + +/* + * SDW Intel ACPI scan helpers + */ + +#include <linux/acpi.h> +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/export.h> +#include <linux/fwnode.h> +#include <linux/module.h> +#include <linux/soundwire/sdw_intel.h> +#include <linux/string.h> + +#define SDW_LINK_TYPE 4 /* from Intel ACPI documentation */ +#define SDW_MAX_LINKS 4 + +static int ctrl_link_mask; +module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444); +MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)"); + +static bool is_link_enabled(struct fwnode_handle *fw_node, int i) +{ + struct fwnode_handle *link; + char name[32]; + u32 quirk_mask = 0; + + /* Find master handle */ + snprintf(name, sizeof(name), + "mipi-sdw-link-%d-subproperties", i); + + link = fwnode_get_named_child_node(fw_node, name); + if (!link) + return false; + + fwnode_property_read_u32(link, + "intel-quirk-mask", + &quirk_mask); + + if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) + return false; + + return true; +} + +static int +sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) +{ + struct acpi_device *adev; + int ret, i; + u8 count; + + if (acpi_bus_get_device(info->handle, &adev)) + return -EINVAL; + + /* Found controller, find links supported */ + count = 0; + ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev), + "mipi-sdw-master-count", &count, 1); + + /* + * In theory we could check the number of links supported in + * hardware, but in that step we cannot assume SoundWire IP is + * powered. + * + * In addition, if the BIOS doesn't even provide this + * 'master-count' property then all the inits based on link + * masks will fail as well. + * + * We will check the hardware capabilities in the startup() step + */ + + if (ret) { + dev_err(&adev->dev, + "Failed to read mipi-sdw-master-count: %d\n", ret); + return -EINVAL; + } + + /* Check count is within bounds */ + if (count > SDW_MAX_LINKS) { + dev_err(&adev->dev, "Link count %d exceeds max %d\n", + count, SDW_MAX_LINKS); + return -EINVAL; + } + + if (!count) { + dev_warn(&adev->dev, "No SoundWire links detected\n"); + return -EINVAL; + } + dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count); + + info->count = count; + info->link_mask = 0; + + for (i = 0; i < count; i++) { + if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) { + dev_dbg(&adev->dev, + "Link %d masked, will not be enabled\n", i); + continue; + } + + if (!is_link_enabled(acpi_fwnode_handle(adev), i)) { + dev_dbg(&adev->dev, + "Link %d not selected in firmware\n", i); + continue; + } + + info->link_mask |= BIT(i); + } + + return 0; +} + +static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, + void *cdata, void **return_value) +{ + struct sdw_intel_acpi_info *info = cdata; + struct acpi_device *adev; + acpi_status status; + u64 adr; + + status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); + if (ACPI_FAILURE(status)) + return AE_OK; /* keep going */ + + if (acpi_bus_get_device(handle, &adev)) { + pr_err("%s: Couldn't find ACPI handle\n", __func__); + return AE_NOT_FOUND; + } + + info->handle = handle; + + /* + * On some Intel platforms, multiple children of the HDAS + * device can be found, but only one of them is the SoundWire + * controller. The SNDW device is always exposed with + * Name(_ADR, 0x40000000), with bits 31..28 representing the + * SoundWire link so filter accordingly + */ + if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE) + return AE_OK; /* keep going */ + + /* device found, stop namespace walk */ + return AE_CTRL_TERMINATE; +} + +/** + * sdw_intel_acpi_scan() - SoundWire Intel init routine + * @parent_handle: ACPI parent handle + * @info: description of what firmware/DSDT tables expose + * + * This scans the namespace and queries firmware to figure out which + * links to enable. A follow-up use of sdw_intel_probe() and + * sdw_intel_startup() is required for creation of devices and bus + * startup + */ +int sdw_intel_acpi_scan(acpi_handle *parent_handle, + struct sdw_intel_acpi_info *info) +{ + acpi_status status; + + info->handle = NULL; + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, + parent_handle, 1, + sdw_intel_acpi_cb, + NULL, info, NULL); + if (ACPI_FAILURE(status) || info->handle == NULL) + return -ENODEV; + + return sdw_intel_scan_controller(info); +} +EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SND_INTEL_SOUNDWIRE_ACPI); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Intel Soundwire ACPI helpers"); diff --git a/sound/mips/snd-n64.c b/sound/mips/snd-n64.c index ca6b4b99da98..e35e93157755 100644 --- a/sound/mips/snd-n64.c +++ b/sound/mips/snd-n64.c @@ -312,14 +312,14 @@ static int __init n64audio_probe(struct platform_device *pdev) } priv->mi_reg_base = devm_platform_ioremap_resource(pdev, 0); - if (!priv->mi_reg_base) { - err = -EINVAL; + if (IS_ERR(priv->mi_reg_base)) { + err = PTR_ERR(priv->mi_reg_base); goto fail_dma_alloc; } priv->ai_reg_base = devm_platform_ioremap_resource(pdev, 1); - if (!priv->ai_reg_base) { - err = -EINVAL; + if (IS_ERR(priv->ai_reg_base)) { + err = PTR_ERR(priv->ai_reg_base); goto fail_dma_alloc; } diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index a855fb8c58bd..55af8ef29838 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -991,7 +991,7 @@ static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf) if (idx < 4) { /* S/PDIF output */ - switch ((conf & 0x7)) { + switch ((conf & 0xf)) { case 1: set_field(&ctl->txctl[idx], ATXCTL_NUC, 0); break; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9b755062d841..2026f1ccaf5a 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3483,7 +3483,7 @@ EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power); */ /** - * snd_hda_input_mux_info_info - Info callback helper for the input-mux enum + * snd_hda_input_mux_info - Info callback helper for the input-mux enum * @imux: imux helper object * @uinfo: pointer to get/store the data */ @@ -3506,7 +3506,7 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, EXPORT_SYMBOL_GPL(snd_hda_input_mux_info); /** - * snd_hda_input_mux_info_put - Put callback helper for the input-mux enum + * snd_hda_input_mux_put - Put callback helper for the input-mux enum * @codec: the HDA codec * @imux: imux helper object * @ucontrol: pointer to get/store the data @@ -3941,7 +3941,7 @@ unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec, EXPORT_SYMBOL_GPL(snd_hda_correct_pin_ctl); /** - * _snd_hda_pin_ctl - Helper to set pin ctl value + * _snd_hda_set_pin_ctl - Helper to set pin ctl value * @codec: the HDA codec * @pin: referred pin NID * @val: pin control value to set diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 5e40944e7342..8b7c5508f368 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -3923,7 +3923,7 @@ static void vmaster_update_mute_led(void *private_data, int enabled) } /** - * snd_dha_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED + * snd_hda_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED * @codec: the HDA codec * @callback: the callback for LED classdev brightness_set_blocking */ @@ -4074,7 +4074,7 @@ static int add_micmute_led_hook(struct hda_codec *codec) } /** - * snd_dha_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED + * snd_hda_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED * @codec: the HDA codec * @callback: the callback for LED classdev brightness_set_blocking * diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index b8b568046592..ac00866d8032 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -213,7 +213,7 @@ static void jack_detect_update(struct hda_codec *codec, } /** - * snd_hda_set_dirty_all - Mark all the cached as dirty + * snd_hda_jack_set_dirty_all - Mark all the cached as dirty * @codec: the HDA codec * * This function sets the dirty flag to all entries of jack table. @@ -293,7 +293,7 @@ find_callback_from_list(struct hda_jack_tbl *jack, } /** - * snd_hda_jack_detect_enable_mst - enable the jack-detection + * snd_hda_jack_detect_enable_callback_mst - enable the jack-detection * @codec: the HDA codec * @nid: pin NID to enable * @func: callback function to register diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 7e62aed172a9..c966f49fa942 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2338,7 +2338,7 @@ static int dspio_send_scp_message(struct hda_codec *codec, } /** - * Prepare and send the SCP message to DSP + * dspio_scp - Prepare and send the SCP message to DSP * @codec: the HDA codec * @mod_id: ID of the DSP module to send the command * @src_id: ID of the source @@ -2865,7 +2865,7 @@ static int dsp_dma_stop(struct hda_codec *codec, } /** - * Allocate router ports + * dsp_allocate_router_ports - Allocate router ports * * @codec: the HDA codec * @num_chans: number of channels in the stream @@ -3178,8 +3178,7 @@ static int dspxfr_hci_write(struct hda_codec *codec, } /** - * Write a block of data into DSP code or data RAM using pre-allocated - * DMA engine. + * dspxfr_one_seg - Write a block of data into DSP code or data RAM using pre-allocated DMA engine. * * @codec: the HDA codec * @fls: pointer to a fast load image @@ -3376,7 +3375,7 @@ static int dspxfr_one_seg(struct hda_codec *codec, } /** - * Write the entire DSP image of a DSP code/data overlay to DSP memories + * dspxfr_image - Write the entire DSP image of a DSP code/data overlay to DSP memories * * @codec: the HDA codec * @fls_data: pointer to a fast load image diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index e405be7929e3..e6d0843ee9df 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -157,6 +157,7 @@ struct hdmi_spec { bool dyn_pin_out; bool dyn_pcm_assign; + bool dyn_pcm_no_legacy; bool intel_hsw_fixup; /* apply Intel platform-specific fixups */ /* * Non-generic VIA/NVIDIA specific @@ -1345,6 +1346,12 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec, { int i; + /* on the new machines, try to assign the pcm slot dynamically, + * not use the preferred fixed map (legacy way) anymore. + */ + if (spec->dyn_pcm_no_legacy) + goto last_try; + /* * generic_hdmi_build_pcms() may allocate extra PCMs on some * platforms (with maximum of 'num_nids + dev_num - 1') @@ -1374,6 +1381,7 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec, return i; } + last_try: /* the last try; check the empty slots in pins */ for (i = 0; i < spec->num_nids; i++) { if (!test_bit(i, &spec->pcm_bitmap)) @@ -2987,8 +2995,16 @@ static int patch_i915_tgl_hdmi(struct hda_codec *codec) * the index indicate the port number. */ static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; + int ret; - return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map)); + ret = intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map)); + if (!ret) { + struct hdmi_spec *spec = codec->spec; + + spec->dyn_pcm_no_legacy = true; + } + + return ret; } /* Intel Baytrail and Braswell; with eld notifier */ diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1927605f0f7e..b47504fa8dfd 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2532,6 +2532,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950), SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), + SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS), SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS), SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), @@ -6396,6 +6397,7 @@ enum { ALC269_FIXUP_LEMOTE_A1802, ALC269_FIXUP_LEMOTE_A190X, ALC256_FIXUP_INTEL_NUC8_RUGGED, + ALC256_FIXUP_INTEL_NUC10, ALC255_FIXUP_XIAOMI_HEADSET_MIC, ALC274_FIXUP_HP_MIC, ALC274_FIXUP_HP_HEADSET_MIC, @@ -6406,6 +6408,7 @@ enum { ALC236_FIXUP_DELL_AIO_HEADSET_MIC, ALC282_FIXUP_ACER_DISABLE_LINEOUT, ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST, + ALC256_FIXUP_ACER_HEADSET_MIC, }; static const struct hda_fixup alc269_fixups[] = { @@ -7782,6 +7785,15 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_HEADSET_MODE }, + [ALC256_FIXUP_INTEL_NUC10] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE + }, [ALC255_FIXUP_XIAOMI_HEADSET_MIC] = { .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { @@ -7853,6 +7865,16 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE, }, + [ALC256_FIXUP_ACER_HEADSET_MIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x02a1113c }, /* use as headset mic, without its own jack detect */ + { 0x1a, 0x90a1092f }, /* use as internal mic */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC + }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -7879,9 +7901,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x1246, "Acer Predator Helios 500", ALC299_FIXUP_PREDATOR_SPK), SND_PCI_QUIRK(0x1025, 0x1247, "Acer vCopperbox", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS), SND_PCI_QUIRK(0x1025, 0x1248, "Acer Veriton N4660G", ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1025, 0x1269, "Acer SWIFT SF314-54", ALC256_FIXUP_ACER_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x128f, "Acer Veriton Z6860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), + SND_PCI_QUIRK(0x1025, 0x129c, "Acer SWIFT SF314-55", ALC256_FIXUP_ACER_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC), SND_PCI_QUIRK(0x1025, 0x1330, "Acer TravelMate X514-51T", ALC255_FIXUP_ACER_HEADSET_MIC), @@ -8128,6 +8152,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1558, 0x8551, "System76 Gazelle (gaze14)", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8560, "System76 Gazelle (gaze14)", ALC269_FIXUP_HEADSET_MIC), SND_PCI_QUIRK(0x1558, 0x8561, "System76 Gazelle (gaze14)", ALC269_FIXUP_HEADSET_MIC), + SND_PCI_QUIRK(0x1558, 0x8562, "Clevo NH[5|7][0-9]RZ[Q]", ALC269_FIXUP_DMIC), SND_PCI_QUIRK(0x1558, 0x8668, "Clevo NP50B[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8680, "Clevo NJ50LU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE), @@ -8222,6 +8247,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802), SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X), SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED), + SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10), #if 0 /* Below is a quirk table taken from the old code. diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 3e8b6c035ce3..8dfc165c3690 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -9,29 +9,34 @@ config SND_SOC_SOF_TOPLEVEL if SND_SOC_SOF_TOPLEVEL +config SND_SOC_SOF_PCI_DEV + tristate + config SND_SOC_SOF_PCI tristate "SOF PCI enumeration support" depends on PCI - select SND_SOC_SOF - select SND_SOC_ACPI if ACPI help This adds support for PCI enumeration. This option is required to enable Intel Skylake+ devices. + For backwards-compatibility with previous configurations the selection will + be used as default for platform-specific drivers. Say Y if you need this option. If unsure select "N". config SND_SOC_SOF_ACPI tristate "SOF ACPI enumeration support" depends on ACPI || COMPILE_TEST - select SND_SOC_SOF - select SND_SOC_ACPI if ACPI - select IOSF_MBI if X86 && PCI help This adds support for ACPI enumeration. This option is required to enable Intel Broadwell/Baytrail/Cherrytrail devices. + For backwards-compatibility with previous configurations the selection will + be used as default for platform-specific drivers. Say Y if you need this option. If unsure select "N". +config SND_SOC_SOF_ACPI_DEV + tristate + config SND_SOC_SOF_OF tristate "SOF OF enumeration support" depends on OF || COMPILE_TEST diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 05718dfe6cd2..606d8137cd98 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -14,9 +14,9 @@ obj-$(CONFIG_SND_SOC_SOF) += snd-sof.o obj-$(CONFIG_SND_SOC_SOF_NOCODEC) += snd-sof-nocodec.o -obj-$(CONFIG_SND_SOC_SOF_ACPI) += snd-sof-acpi.o +obj-$(CONFIG_SND_SOC_SOF_ACPI_DEV) += snd-sof-acpi.o obj-$(CONFIG_SND_SOC_SOF_OF) += snd-sof-of.o -obj-$(CONFIG_SND_SOC_SOF_PCI) += snd-sof-pci.o +obj-$(CONFIG_SND_SOC_SOF_PCI_DEV) += snd-sof-pci.o obj-$(CONFIG_SND_SOC_SOF_INTEL_TOPLEVEL) += intel/ obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 4797a1cf8c80..da1c396f529d 100644 --- a/sound/soc/sof/intel/Kconfig +++ b/sound/soc/sof/intel/Kconfig @@ -9,31 +9,6 @@ config SND_SOC_SOF_INTEL_TOPLEVEL if SND_SOC_SOF_INTEL_TOPLEVEL -config SND_SOC_SOF_INTEL_ACPI - def_tristate SND_SOC_SOF_ACPI - select SND_SOC_SOF_BAYTRAIL if SND_SOC_SOF_BAYTRAIL_SUPPORT - select SND_SOC_SOF_BROADWELL if SND_SOC_SOF_BROADWELL_SUPPORT - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -config SND_SOC_SOF_INTEL_PCI - def_tristate SND_SOC_SOF_PCI - select SND_SOC_SOF_MERRIFIELD if SND_SOC_SOF_MERRIFIELD_SUPPORT - select SND_SOC_SOF_APOLLOLAKE if SND_SOC_SOF_APOLLOLAKE_SUPPORT - select SND_SOC_SOF_GEMINILAKE if SND_SOC_SOF_GEMINILAKE_SUPPORT - select SND_SOC_SOF_CANNONLAKE if SND_SOC_SOF_CANNONLAKE_SUPPORT - select SND_SOC_SOF_COFFEELAKE if SND_SOC_SOF_COFFEELAKE_SUPPORT - select SND_SOC_SOF_ICELAKE if SND_SOC_SOF_ICELAKE_SUPPORT - select SND_SOC_SOF_COMETLAKE if SND_SOC_SOF_COMETLAKE_SUPPORT - select SND_SOC_SOF_TIGERLAKE if SND_SOC_SOF_TIGERLAKE_SUPPORT - select SND_SOC_SOF_ELKHARTLAKE if SND_SOC_SOF_ELKHARTLAKE_SUPPORT - select SND_SOC_SOF_JASPERLAKE if SND_SOC_SOF_JASPERLAKE_SUPPORT - select SND_SOC_SOF_ALDERLAKE if SND_SOC_SOF_ALDERLAKE_SUPPORT - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - config SND_SOC_SOF_INTEL_HIFI_EP_IPC tristate help @@ -50,18 +25,25 @@ config SND_SOC_SOF_INTEL_ATOM_HIFI_EP config SND_SOC_SOF_INTEL_COMMON tristate + select SND_SOC_SOF select SND_SOC_ACPI_INTEL_MATCH select SND_SOC_SOF_XTENSA select SND_SOC_INTEL_MACH select SND_SOC_ACPI if ACPI + select SND_INTEL_DSP_CONFIG help This option is not user-selectable but automagically handled by 'select' statements at a higher level. -if SND_SOC_SOF_INTEL_ACPI +if SND_SOC_SOF_ACPI -config SND_SOC_SOF_BAYTRAIL_SUPPORT - bool "SOF support for Baytrail, Braswell and Cherrytrail" +config SND_SOC_SOF_BAYTRAIL + tristate "SOF support for Baytrail, Braswell and Cherrytrail" + default SND_SOC_SOF_ACPI + select SND_SOC_SOF_INTEL_COMMON + select SND_SOC_SOF_INTEL_ATOM_HIFI_EP + select SND_SOC_SOF_ACPI_DEV + select IOSF_MBI if X86 && PCI help This adds support for Sound Open Firmware for Intel(R) platforms using the Baytrail, Braswell or Cherrytrail processors. @@ -75,17 +57,12 @@ config SND_SOC_SOF_BAYTRAIL_SUPPORT Say Y if you want to enable SOF on Baytrail/Cherrytrail. If unsure select "N". -config SND_SOC_SOF_BAYTRAIL - tristate - select SND_SOC_SOF_INTEL_ATOM_HIFI_EP - select SND_INTEL_DSP_CONFIG - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -config SND_SOC_SOF_BROADWELL_SUPPORT - bool "SOF support for Broadwell" - select SND_INTEL_DSP_CONFIG +config SND_SOC_SOF_BROADWELL + tristate "SOF support for Broadwell" + default SND_SOC_SOF_ACPI + select SND_SOC_SOF_INTEL_COMMON + select SND_SOC_SOF_INTEL_HIFI_EP_IPC + select SND_SOC_SOF_ACPI_DEV help This adds support for Sound Open Firmware for Intel(R) platforms using the Broadwell processors. @@ -100,197 +77,143 @@ config SND_SOC_SOF_BROADWELL_SUPPORT Say Y if you want to enable SOF on Broadwell. If unsure select "N". -config SND_SOC_SOF_BROADWELL - tristate - select SND_SOC_SOF_INTEL_COMMON - select SND_SOC_SOF_INTEL_HIFI_EP_IPC - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -endif ## SND_SOC_SOF_INTEL_ACPI +endif ## SND_SOC_SOF_ACPI -if SND_SOC_SOF_INTEL_PCI +if SND_SOC_SOF_PCI -config SND_SOC_SOF_MERRIFIELD_SUPPORT - bool "SOF support for Tangier/Merrifield" +config SND_SOC_SOF_MERRIFIELD + tristate "SOF support for Tangier/Merrifield" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_ATOM_HIFI_EP help This adds support for Sound Open Firmware for Intel(R) platforms using the Tangier/Merrifield processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_MERRIFIELD +config SND_SOC_SOF_INTEL_APL tristate - select SND_SOC_SOF_INTEL_ATOM_HIFI_EP - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. + select SND_SOC_SOF_HDA_COMMON -config SND_SOC_SOF_APOLLOLAKE_SUPPORT - bool "SOF support for Apollolake" +config SND_SOC_SOF_APOLLOLAKE + tristate "SOF support for Apollolake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_APL help This adds support for Sound Open Firmware for Intel(R) platforms using the Apollolake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_APOLLOLAKE - tristate - select SND_SOC_SOF_HDA_COMMON - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -config SND_SOC_SOF_GEMINILAKE_SUPPORT - bool "SOF support for GeminiLake" +config SND_SOC_SOF_GEMINILAKE + tristate "SOF support for GeminiLake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_APL help This adds support for Sound Open Firmware for Intel(R) platforms using the Geminilake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_GEMINILAKE +config SND_SOC_SOF_INTEL_CNL tristate select SND_SOC_SOF_HDA_COMMON - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. + select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE -config SND_SOC_SOF_CANNONLAKE_SUPPORT - bool "SOF support for Cannonlake" +config SND_SOC_SOF_CANNONLAKE + tristate "SOF support for Cannonlake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_CNL help This adds support for Sound Open Firmware for Intel(R) platforms using the Cannonlake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_CANNONLAKE - tristate - select SND_SOC_SOF_HDA_COMMON - select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -config SND_SOC_SOF_COFFEELAKE_SUPPORT - bool "SOF support for CoffeeLake" +config SND_SOC_SOF_COFFEELAKE + tristate "SOF support for CoffeeLake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_CNL help This adds support for Sound Open Firmware for Intel(R) platforms using the Coffeelake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_COFFEELAKE - tristate - select SND_SOC_SOF_HDA_COMMON - select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -config SND_SOC_SOF_ICELAKE_SUPPORT - bool "SOF support for Icelake" +config SND_SOC_SOF_COMETLAKE + tristate "SOF support for CometLake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_CNL help This adds support for Sound Open Firmware for Intel(R) platforms - using the Icelake processors. - Say Y if you have such a device. + using the Cometlake processors. If unsure select "N". -config SND_SOC_SOF_ICELAKE - tristate - select SND_SOC_SOF_HDA_COMMON - select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -config SND_SOC_SOF_COMETLAKE +config SND_SOC_SOF_INTEL_ICL tristate select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -config SND_SOC_SOF_COMETLAKE_SUPPORT - bool -config SND_SOC_SOF_COMETLAKE_LP_SUPPORT - bool "SOF support for CometLake" - select SND_SOC_SOF_COMETLAKE_SUPPORT +config SND_SOC_SOF_ICELAKE + tristate "SOF support for Icelake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_ICL help This adds support for Sound Open Firmware for Intel(R) platforms - using the Cometlake processors. + using the Icelake processors. + Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_TIGERLAKE_SUPPORT - bool "SOF support for Tigerlake" +config SND_SOC_SOF_JASPERLAKE + tristate "SOF support for JasperLake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_ICL help This adds support for Sound Open Firmware for Intel(R) platforms - using the Tigerlake processors. + using the JasperLake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_TIGERLAKE +config SND_SOC_SOF_INTEL_TGL tristate select SND_SOC_SOF_HDA_COMMON select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. -config SND_SOC_SOF_ELKHARTLAKE_SUPPORT - bool "SOF support for ElkhartLake" +config SND_SOC_SOF_TIGERLAKE + tristate "SOF support for Tigerlake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_TGL help This adds support for Sound Open Firmware for Intel(R) platforms - using the ElkhartLake processors. + using the Tigerlake processors. Say Y if you have such a device. If unsure select "N". config SND_SOC_SOF_ELKHARTLAKE - tristate - select SND_SOC_SOF_HDA_COMMON - select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -config SND_SOC_SOF_JASPERLAKE_SUPPORT - bool "SOF support for JasperLake" + tristate "SOF support for ElkhartLake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_TGL help This adds support for Sound Open Firmware for Intel(R) platforms - using the JasperLake processors. + using the ElkhartLake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_JASPERLAKE - tristate - select SND_SOC_SOF_HDA_COMMON - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. - -config SND_SOC_SOF_ALDERLAKE_SUPPORT - bool "SOF support for Alderlake" +config SND_SOC_SOF_ALDERLAKE + tristate "SOF support for Alderlake" + default SND_SOC_SOF_PCI + select SND_SOC_SOF_INTEL_TGL help This adds support for Sound Open Firmware for Intel(R) platforms using the Alderlake processors. Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_ALDERLAKE - tristate - select SND_SOC_SOF_HDA_COMMON - select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level - config SND_SOC_SOF_HDA_COMMON tristate - select SND_INTEL_DSP_CONFIG select SND_SOC_SOF_INTEL_COMMON + select SND_SOC_SOF_PCI_DEV + select SND_INTEL_DSP_CONFIG select SND_SOC_SOF_HDA_LINK_BASELINE help This option is not user-selectable but automagically handled by @@ -353,29 +276,22 @@ config SND_SOC_SOF_HDA This option is not user-selectable but automagically handled by 'select' statements at a higher level. -config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK - bool "SOF support for SoundWire" - depends on ACPI - help - This adds support for SoundWire with Sound Open Firmware - for Intel(R) platforms. - Say Y if you want to enable SoundWire links with SOF. - If unsure select "N". - config SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE tristate - select SND_SOC_SOF_INTEL_SOUNDWIRE if SND_SOC_SOF_INTEL_SOUNDWIRE_LINK - help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. config SND_SOC_SOF_INTEL_SOUNDWIRE - tristate - select SOUNDWIRE + tristate "SOF support for SoundWire" + default SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + depends on SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE + depends on ACPI && SOUNDWIRE + depends on !(SOUNDWIRE=m && SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE=y) select SOUNDWIRE_INTEL + select SND_INTEL_SOUNDWIRE_ACPI help - This option is not user-selectable but automagically handled by - 'select' statements at a higher level. + This adds support for SoundWire with Sound Open Firmware + for Intel(R) platforms. + Say Y if you want to enable SoundWire links with SOF. + If unsure select "N". endif ## SND_SOC_SOF_INTEL_PCI diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index 2589111c2fae..f3d6f7070fb3 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -snd-sof-intel-byt-objs := byt.o -snd-sof-intel-bdw-objs := bdw.o +snd-sof-acpi-intel-byt-objs := byt.o +snd-sof-acpi-intel-bdw-objs := bdw.o snd-sof-intel-ipc-objs := intel-ipc.o @@ -13,8 +13,20 @@ snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-compress.o snd-sof-intel-hda-objs := hda-codec.o -obj-$(CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP) += snd-sof-intel-byt.o -obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-intel-bdw.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_ATOM_HIFI_EP) += snd-sof-acpi-intel-byt.o +obj-$(CONFIG_SND_SOC_SOF_BROADWELL) += snd-sof-acpi-intel-bdw.o obj-$(CONFIG_SND_SOC_SOF_INTEL_HIFI_EP_IPC) += snd-sof-intel-ipc.o obj-$(CONFIG_SND_SOC_SOF_HDA_COMMON) += snd-sof-intel-hda-common.o obj-$(CONFIG_SND_SOC_SOF_HDA) += snd-sof-intel-hda.o + +snd-sof-pci-intel-tng-objs := pci-tng.o +snd-sof-pci-intel-apl-objs := pci-apl.o +snd-sof-pci-intel-cnl-objs := pci-cnl.o +snd-sof-pci-intel-icl-objs := pci-icl.o +snd-sof-pci-intel-tgl-objs := pci-tgl.o + +obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_APL) += snd-sof-pci-intel-apl.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_CNL) += snd-sof-pci-intel-cnl.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o +obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index 50a4a73e6b9f..fd5ae628732d 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -15,8 +15,12 @@ #include <linux/module.h> #include <sound/sof.h> #include <sound/sof/xtensa.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include <sound/intel-dsp-config.h> #include "../ops.h" #include "shim.h" +#include "../sof-acpi-dev.h" #include "../sof-audio.h" /* BARs */ @@ -590,7 +594,7 @@ static struct snd_soc_dai_driver bdw_dai[] = { }; /* broadwell ops */ -const struct snd_sof_dsp_ops sof_bdw_ops = { +static const struct snd_sof_dsp_ops sof_bdw_ops = { /*Device init */ .probe = bdw_probe, @@ -651,14 +655,69 @@ const struct snd_sof_dsp_ops sof_bdw_ops = { .arch_ops = &sof_xtensa_arch_ops, }; -EXPORT_SYMBOL_NS(sof_bdw_ops, SND_SOC_SOF_BROADWELL); -const struct sof_intel_dsp_desc bdw_chip_info = { +static const struct sof_intel_dsp_desc bdw_chip_info = { .cores_num = 1, .host_managed_cores_mask = 1, }; -EXPORT_SYMBOL_NS(bdw_chip_info, SND_SOC_SOF_BROADWELL); + +static const struct sof_dev_desc sof_acpi_broadwell_desc = { + .machines = snd_soc_acpi_intel_broadwell_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = -1, + .irqindex_host_ipc = 0, + .chip_info = &bdw_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-bdw.ri", + .nocodec_tplg_filename = "sof-bdw-nocodec.tplg", + .ops = &sof_bdw_ops, +}; + +static const struct acpi_device_id sof_broadwell_match[] = { + { "INT3438", (unsigned long)&sof_acpi_broadwell_desc }, + { } +}; +MODULE_DEVICE_TABLE(acpi, sof_broadwell_match); + +static int sof_broadwell_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct acpi_device_id *id; + const struct sof_dev_desc *desc; + int ret; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return -ENODEV; + + ret = snd_intel_acpi_dsp_driver_probe(dev, id->id); + if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) { + dev_dbg(dev, "SOF ACPI driver not selected, aborting probe\n"); + return -ENODEV; + } + + desc = device_get_match_data(dev); + if (!desc) + return -ENODEV; + + return sof_acpi_probe(pdev, device_get_match_data(dev)); +} + +/* acpi_driver definition */ +static struct platform_driver snd_sof_acpi_intel_bdw_driver = { + .probe = sof_broadwell_probe, + .remove = sof_acpi_remove, + .driver = { + .name = "sof-audio-acpi-intel-bdw", + .pm = &sof_acpi_pm, + .acpi_match_table = sof_broadwell_match, + }, +}; +module_platform_driver(snd_sof_acpi_intel_bdw_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC); MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_IMPORT_NS(SND_SOC_SOF_ACPI_DEV); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index 19260dbecac5..2846fdec9d95 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -15,8 +15,12 @@ #include <linux/module.h> #include <sound/sof.h> #include <sound/sof/xtensa.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include <sound/intel-dsp-config.h> #include "../ops.h" #include "shim.h" +#include "../sof-acpi-dev.h" #include "../sof-audio.h" #include "../../intel/common/soc-intel-quirks.h" @@ -822,7 +826,7 @@ irq: } /* baytrail ops */ -const struct snd_sof_dsp_ops sof_byt_ops = { +static const struct snd_sof_dsp_ops sof_byt_ops = { /* device init */ .probe = byt_acpi_probe, .remove = byt_remove, @@ -892,16 +896,14 @@ const struct snd_sof_dsp_ops sof_byt_ops = { .arch_ops = &sof_xtensa_arch_ops, }; -EXPORT_SYMBOL_NS(sof_byt_ops, SND_SOC_SOF_BAYTRAIL); -const struct sof_intel_dsp_desc byt_chip_info = { +static const struct sof_intel_dsp_desc byt_chip_info = { .cores_num = 1, .host_managed_cores_mask = 1, }; -EXPORT_SYMBOL_NS(byt_chip_info, SND_SOC_SOF_BAYTRAIL); /* cherrytrail and braswell ops */ -const struct snd_sof_dsp_ops sof_cht_ops = { +static const struct snd_sof_dsp_ops sof_cht_ops = { /* device init */ .probe = byt_acpi_probe, .remove = byt_remove, @@ -972,16 +974,104 @@ const struct snd_sof_dsp_ops sof_cht_ops = { .arch_ops = &sof_xtensa_arch_ops, }; -EXPORT_SYMBOL_NS(sof_cht_ops, SND_SOC_SOF_BAYTRAIL); -const struct sof_intel_dsp_desc cht_chip_info = { +static const struct sof_intel_dsp_desc cht_chip_info = { .cores_num = 1, .host_managed_cores_mask = 1, }; -EXPORT_SYMBOL_NS(cht_chip_info, SND_SOC_SOF_BAYTRAIL); + +/* BYTCR uses different IRQ index */ +static const struct sof_dev_desc sof_acpi_baytrailcr_desc = { + .machines = snd_soc_acpi_intel_baytrail_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = 2, + .irqindex_host_ipc = 0, + .chip_info = &byt_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-byt.ri", + .nocodec_tplg_filename = "sof-byt-nocodec.tplg", + .ops = &sof_byt_ops, +}; + +static const struct sof_dev_desc sof_acpi_baytrail_desc = { + .machines = snd_soc_acpi_intel_baytrail_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = 2, + .irqindex_host_ipc = 5, + .chip_info = &byt_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-byt.ri", + .nocodec_tplg_filename = "sof-byt-nocodec.tplg", + .ops = &sof_byt_ops, +}; + +static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { + .machines = snd_soc_acpi_intel_cherrytrail_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = 1, + .resindex_imr_base = 2, + .irqindex_host_ipc = 5, + .chip_info = &cht_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-cht.ri", + .nocodec_tplg_filename = "sof-cht-nocodec.tplg", + .ops = &sof_cht_ops, +}; + +static const struct acpi_device_id sof_baytrail_match[] = { + { "80860F28", (unsigned long)&sof_acpi_baytrail_desc }, + { "808622A8", (unsigned long)&sof_acpi_cherrytrail_desc }, + { } +}; +MODULE_DEVICE_TABLE(acpi, sof_baytrail_match); + +static int sof_baytrail_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct sof_dev_desc *desc; + const struct acpi_device_id *id; + int ret; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return -ENODEV; + + ret = snd_intel_acpi_dsp_driver_probe(dev, id->id); + if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) { + dev_dbg(dev, "SOF ACPI driver not selected, aborting probe\n"); + return -ENODEV; + } + + desc = device_get_match_data(&pdev->dev); + if (!desc) + return -ENODEV; + + if (desc == &sof_acpi_baytrail_desc && soc_intel_is_byt_cr(pdev)) + desc = &sof_acpi_baytrailcr_desc; + + return sof_acpi_probe(pdev, desc); +} + +/* acpi_driver definition */ +static struct platform_driver snd_sof_acpi_intel_byt_driver = { + .probe = sof_baytrail_probe, + .remove = sof_acpi_remove, + .driver = { + .name = "sof-audio-acpi-intel-byt", + .pm = &sof_acpi_pm, + .acpi_match_table = sof_baytrail_match, + }, +}; +module_platform_driver(snd_sof_acpi_intel_byt_driver); #endif /* CONFIG_SND_SOC_SOF_BAYTRAIL */ MODULE_LICENSE("Dual BSD/GPL"); MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC); MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_IMPORT_NS(SND_SOC_SOF_ACPI_DEV); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 0dc3a8c0f5e3..1d29b1fd6a94 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -22,10 +22,12 @@ #include <linux/module.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_intel.h> +#include <sound/intel-dsp-config.h> #include <sound/intel-nhlt.h> #include <sound/sof.h> #include <sound/sof/xtensa.h> #include "../sof-audio.h" +#include "../sof-pci-dev.h" #include "../ops.h" #include "hda.h" @@ -1258,8 +1260,24 @@ void hda_machine_select(struct snd_sof_dev *sdev) dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n"); } +int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + int ret; + + ret = snd_intel_dsp_driver_probe(pci); + if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) { + dev_dbg(&pci->dev, "SOF PCI driver not selected, aborting probe\n"); + return -ENODEV; + } + + return sof_pci_probe(pci, pci_id); +} +EXPORT_SYMBOL_NS(hda_pci_intel_probe, SND_SOC_SOF_INTEL_HDA_COMMON); + MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC); MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC_I915); MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA); +MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI); MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index d1c38c37bc9d..7c7579daee7f 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -764,4 +764,7 @@ void hda_machine_select(struct snd_sof_dev *sdev); void hda_set_mach_params(const struct snd_soc_acpi_mach *mach, struct device *dev); +/* PCI driver selection and probe */ +int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id); + #endif diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c new file mode 100644 index 000000000000..f89e746c2570 --- /dev/null +++ b/sound/soc/sof/intel/pci-apl.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018-2021 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// + +#include <linux/module.h> +#include <linux/pci.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include <sound/sof.h> +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" + +static const struct sof_dev_desc bxt_desc = { + .machines = snd_soc_acpi_intel_bxt_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &apl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-apl.ri", + .nocodec_tplg_filename = "sof-apl-nocodec.tplg", + .ops = &sof_apl_ops, +}; + +static const struct sof_dev_desc glk_desc = { + .machines = snd_soc_acpi_intel_glk_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &apl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-glk.ri", + .nocodec_tplg_filename = "sof-glk-nocodec.tplg", + .ops = &sof_apl_ops, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE(0x8086, 0x5a98), /* BXT-P (ApolloLake) */ + .driver_data = (unsigned long)&bxt_desc}, + { PCI_DEVICE(0x8086, 0x1a98),/* BXT-T */ + .driver_data = (unsigned long)&bxt_desc}, + { PCI_DEVICE(0x8086, 0x3198), /* GeminiLake */ + .driver_data = (unsigned long)&glk_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_apl_driver = { + .name = "sof-audio-pci-intel-apl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_apl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c new file mode 100644 index 000000000000..f23257adf2ab --- /dev/null +++ b/sound/soc/sof/intel/pci-cnl.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// + +#include <linux/module.h> +#include <linux/pci.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include <sound/sof.h> +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" + +static const struct sof_dev_desc cnl_desc = { + .machines = snd_soc_acpi_intel_cnl_machines, + .alt_machines = snd_soc_acpi_intel_cnl_sdw_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &cnl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-cnl.ri", + .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", + .ops = &sof_cnl_ops, +}; + +static const struct sof_dev_desc cfl_desc = { + .machines = snd_soc_acpi_intel_cfl_machines, + .alt_machines = snd_soc_acpi_intel_cfl_sdw_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &cnl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-cfl.ri", + .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", + .ops = &sof_cnl_ops, +}; + +static const struct sof_dev_desc cml_desc = { + .machines = snd_soc_acpi_intel_cml_machines, + .alt_machines = snd_soc_acpi_intel_cml_sdw_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &cnl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-cml.ri", + .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", + .ops = &sof_cnl_ops, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE(0x8086, 0x9dc8), /* CNL-LP */ + .driver_data = (unsigned long)&cnl_desc}, + { PCI_DEVICE(0x8086, 0xa348), /* CNL-H */ + .driver_data = (unsigned long)&cfl_desc}, + { PCI_DEVICE(0x8086, 0x02c8), /* CML-LP */ + .driver_data = (unsigned long)&cml_desc}, + { PCI_DEVICE(0x8086, 0x06c8), /* CML-H */ + .driver_data = (unsigned long)&cml_desc}, + { PCI_DEVICE(0x8086, 0xa3f0), /* CML-S */ + .driver_data = (unsigned long)&cml_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_cnl_driver = { + .name = "sof-audio-pci-intel-cnl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_cnl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c new file mode 100644 index 000000000000..2f60c28ae81f --- /dev/null +++ b/sound/soc/sof/intel/pci-icl.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018-2021 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// + +#include <linux/module.h> +#include <linux/pci.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include <sound/sof.h> +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" + +static const struct sof_dev_desc icl_desc = { + .machines = snd_soc_acpi_intel_icl_machines, + .alt_machines = snd_soc_acpi_intel_icl_sdw_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &icl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-icl.ri", + .nocodec_tplg_filename = "sof-icl-nocodec.tplg", + .ops = &sof_icl_ops, +}; + +static const struct sof_dev_desc jsl_desc = { + .machines = snd_soc_acpi_intel_jsl_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &jsl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-jsl.ri", + .nocodec_tplg_filename = "sof-jsl-nocodec.tplg", + .ops = &sof_cnl_ops, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE(0x8086, 0x34C8), /* ICL-LP */ + .driver_data = (unsigned long)&icl_desc}, + { PCI_DEVICE(0x8086, 0x3dc8), /* ICL-H */ + .driver_data = (unsigned long)&icl_desc}, + { PCI_DEVICE(0x8086, 0x38c8), /* ICL-N */ + .driver_data = (unsigned long)&jsl_desc}, + { PCI_DEVICE(0x8086, 0x4dc8), /* JSL-N */ + .driver_data = (unsigned long)&jsl_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_icl_driver = { + .name = "sof-audio-pci-intel-icl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_icl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c new file mode 100644 index 000000000000..485607471181 --- /dev/null +++ b/sound/soc/sof/intel/pci-tgl.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018-2021 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// + +#include <linux/module.h> +#include <linux/pci.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include <sound/sof.h> +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "hda.h" + +static const struct sof_dev_desc tgl_desc = { + .machines = snd_soc_acpi_intel_tgl_machines, + .alt_machines = snd_soc_acpi_intel_tgl_sdw_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &tgl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-tgl.ri", + .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", + .ops = &sof_tgl_ops, +}; + +static const struct sof_dev_desc tglh_desc = { + .machines = snd_soc_acpi_intel_tgl_machines, + .alt_machines = snd_soc_acpi_intel_tgl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &tglh_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-tgl-h.ri", + .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", + .ops = &sof_tgl_ops, +}; + +static const struct sof_dev_desc ehl_desc = { + .machines = snd_soc_acpi_intel_ehl_machines, + .use_acpi_target_states = true, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &ehl_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-ehl.ri", + .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", + .ops = &sof_cnl_ops, +}; + +static const struct sof_dev_desc adls_desc = { + .machines = snd_soc_acpi_intel_adl_machines, + .alt_machines = snd_soc_acpi_intel_adl_sdw_machines, + .resindex_lpe_base = 0, + .resindex_pcicfg_base = -1, + .resindex_imr_base = -1, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &adls_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-adl-s.ri", + .nocodec_tplg_filename = "sof-adl-nocodec.tplg", + .ops = &sof_tgl_ops, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE(0x8086, 0xa0c8), /* TGL-LP */ + .driver_data = (unsigned long)&tgl_desc}, + { PCI_DEVICE(0x8086, 0x43c8), /* TGL-H */ + .driver_data = (unsigned long)&tglh_desc}, + { PCI_DEVICE(0x8086, 0x4b55), /* EHL */ + .driver_data = (unsigned long)&ehl_desc}, + { PCI_DEVICE(0x8086, 0x4b58), /* EHL */ + .driver_data = (unsigned long)&ehl_desc}, + { PCI_DEVICE(0x8086, 0x7ad0), /* ADL-S */ + .driver_data = (unsigned long)&adls_desc}, + { PCI_DEVICE(0x8086, 0x51c8), /* ADL-P */ + .driver_data = (unsigned long)&tgl_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_tgl_driver = { + .name = "sof-audio-pci-intel-tgl", + .id_table = sof_pci_ids, + .probe = hda_pci_intel_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_tgl_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); + diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c new file mode 100644 index 000000000000..94b9704c0117 --- /dev/null +++ b/sound/soc/sof/intel/pci-tng.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// This file is provided under a dual BSD/GPLv2 license. When using or +// redistributing this file, you may do so under either license. +// +// Copyright(c) 2018-2021 Intel Corporation. All rights reserved. +// +// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com> +// + +#include <linux/module.h> +#include <linux/pci.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include <sound/sof.h> +#include "../ops.h" +#include "../sof-pci-dev.h" + +/* platform specific devices */ +#include "shim.h" + +static struct snd_soc_acpi_mach sof_tng_machines[] = { + { + .id = "INT343A", + .drv_name = "edison", + .sof_fw_filename = "sof-byt.ri", + .sof_tplg_filename = "sof-byt.tplg", + }, + {} +}; + +static const struct sof_dev_desc tng_desc = { + .machines = sof_tng_machines, + .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */ + .resindex_pcicfg_base = -1, + .resindex_imr_base = 0, + .irqindex_host_ipc = -1, + .resindex_dma_base = -1, + .chip_info = &tng_chip_info, + .default_fw_path = "intel/sof", + .default_tplg_path = "intel/sof-tplg", + .default_fw_filename = "sof-byt.ri", + .nocodec_tplg_filename = "sof-byt.tplg", + .ops = &sof_tng_ops, +}; + +/* PCI IDs */ +static const struct pci_device_id sof_pci_ids[] = { + { PCI_DEVICE(0x8086, 0x119a), + .driver_data = (unsigned long)&tng_desc}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sof_pci_ids); + +/* pci_driver definition */ +static struct pci_driver snd_sof_pci_intel_tng_driver = { + .name = "sof-audio-pci-intel-tng", + .id_table = sof_pci_ids, + .probe = sof_pci_probe, + .remove = sof_pci_remove, + .shutdown = sof_pci_shutdown, + .driver = { + .pm = &sof_pci_pm, + }, +}; +module_pci_driver(snd_sof_pci_intel_tng_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(SND_SOC_SOF_MERRIFIELD); +MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV); diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 1e0afb5c8720..529f68d0ca47 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -167,13 +167,7 @@ struct sof_intel_dsp_desc { }; extern const struct snd_sof_dsp_ops sof_tng_ops; -extern const struct snd_sof_dsp_ops sof_byt_ops; -extern const struct snd_sof_dsp_ops sof_cht_ops; -extern const struct snd_sof_dsp_ops sof_bdw_ops; -extern const struct sof_intel_dsp_desc byt_chip_info; -extern const struct sof_intel_dsp_desc cht_chip_info; -extern const struct sof_intel_dsp_desc bdw_chip_info; extern const struct sof_intel_dsp_desc tng_chip_info; struct sof_intel_stream { diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index cc2e257087e4..1fec0420f662 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -12,12 +12,12 @@ #include <linux/firmware.h> #include <linux/module.h> #include <linux/pm_runtime.h> -#include <sound/intel-dsp-config.h> #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> #include <sound/sof.h> #include "../intel/common/soc-intel-quirks.h" #include "ops.h" +#include "sof-acpi-dev.h" /* platform specific devices */ #include "intel/shim.h" @@ -36,74 +36,12 @@ MODULE_PARM_DESC(sof_acpi_debug, "SOF ACPI debug options (0x0 all off)"); #define SOF_ACPI_DISABLE_PM_RUNTIME BIT(0) -#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) -static const struct sof_dev_desc sof_acpi_broadwell_desc = { - .machines = snd_soc_acpi_intel_broadwell_machines, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = 1, - .resindex_imr_base = -1, - .irqindex_host_ipc = 0, - .chip_info = &bdw_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-bdw.ri", - .nocodec_tplg_filename = "sof-bdw-nocodec.tplg", - .ops = &sof_bdw_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - -/* BYTCR uses different IRQ index */ -static const struct sof_dev_desc sof_acpi_baytrailcr_desc = { - .machines = snd_soc_acpi_intel_baytrail_machines, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = 1, - .resindex_imr_base = 2, - .irqindex_host_ipc = 0, - .chip_info = &byt_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-byt.ri", - .nocodec_tplg_filename = "sof-byt-nocodec.tplg", - .ops = &sof_byt_ops, -}; - -static const struct sof_dev_desc sof_acpi_baytrail_desc = { - .machines = snd_soc_acpi_intel_baytrail_machines, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = 1, - .resindex_imr_base = 2, - .irqindex_host_ipc = 5, - .chip_info = &byt_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-byt.ri", - .nocodec_tplg_filename = "sof-byt-nocodec.tplg", - .ops = &sof_byt_ops, -}; - -static const struct sof_dev_desc sof_acpi_cherrytrail_desc = { - .machines = snd_soc_acpi_intel_cherrytrail_machines, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = 1, - .resindex_imr_base = 2, - .irqindex_host_ipc = 5, - .chip_info = &cht_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-cht.ri", - .nocodec_tplg_filename = "sof-cht-nocodec.tplg", - .ops = &sof_cht_ops, -}; - -#endif - -static const struct dev_pm_ops sof_acpi_pm = { +const struct dev_pm_ops sof_acpi_pm = { SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, snd_sof_runtime_idle) }; +EXPORT_SYMBOL_NS(sof_acpi_pm, SND_SOC_SOF_ACPI_DEV); static void sof_acpi_probe_complete(struct device *dev) { @@ -118,41 +56,19 @@ static void sof_acpi_probe_complete(struct device *dev) pm_runtime_enable(dev); } -static int sof_acpi_probe(struct platform_device *pdev) +int sof_acpi_probe(struct platform_device *pdev, const struct sof_dev_desc *desc) { struct device *dev = &pdev->dev; - const struct acpi_device_id *id; - const struct sof_dev_desc *desc; struct snd_sof_pdata *sof_pdata; const struct snd_sof_dsp_ops *ops; int ret; - id = acpi_match_device(dev->driver->acpi_match_table, dev); - if (!id) - return -ENODEV; - - if (IS_REACHABLE(CONFIG_SND_INTEL_DSP_CONFIG)) { - ret = snd_intel_acpi_dsp_driver_probe(dev, id->id); - if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) { - dev_dbg(dev, "SOF ACPI driver not selected, aborting probe\n"); - return -ENODEV; - } - } dev_dbg(dev, "ACPI DSP detected"); sof_pdata = devm_kzalloc(dev, sizeof(*sof_pdata), GFP_KERNEL); if (!sof_pdata) return -ENOMEM; - desc = device_get_match_data(dev); - if (!desc) - return -ENODEV; - -#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - if (desc == &sof_acpi_baytrail_desc && soc_intel_is_byt_cr(pdev)) - desc = &sof_acpi_baytrailcr_desc; -#endif - /* get ops for platform */ ops = desc->ops; if (!ops) { @@ -194,44 +110,20 @@ static int sof_acpi_probe(struct platform_device *pdev) return ret; } +EXPORT_SYMBOL_NS(sof_acpi_probe, SND_SOC_SOF_ACPI_DEV); -static int sof_acpi_remove(struct platform_device *pdev) +int sof_acpi_remove(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + if (!(sof_acpi_debug & SOF_ACPI_DISABLE_PM_RUNTIME)) - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); /* call sof helper for DSP hardware remove */ - snd_sof_device_remove(&pdev->dev); + snd_sof_device_remove(dev); return 0; } - -#ifdef CONFIG_ACPI -static const struct acpi_device_id sof_acpi_match[] = { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BROADWELL) - { "INT3438", (unsigned long)&sof_acpi_broadwell_desc }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_BAYTRAIL) - { "80860F28", (unsigned long)&sof_acpi_baytrail_desc }, - { "808622A8", (unsigned long)&sof_acpi_cherrytrail_desc }, -#endif - { } -}; -MODULE_DEVICE_TABLE(acpi, sof_acpi_match); -#endif - -/* acpi_driver definition */ -static struct platform_driver snd_sof_acpi_driver = { - .probe = sof_acpi_probe, - .remove = sof_acpi_remove, - .driver = { - .name = "sof-audio-acpi", - .pm = &sof_acpi_pm, - .acpi_match_table = ACPI_PTR(sof_acpi_match), - }, -}; -module_platform_driver(snd_sof_acpi_driver); +EXPORT_SYMBOL_NS(sof_acpi_remove, SND_SOC_SOF_ACPI_DEV); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_IMPORT_NS(SND_SOC_SOF_BAYTRAIL); -MODULE_IMPORT_NS(SND_SOC_SOF_BROADWELL); diff --git a/sound/soc/sof/sof-acpi-dev.h b/sound/soc/sof/sof-acpi-dev.h new file mode 100644 index 000000000000..5c2b558d2ace --- /dev/null +++ b/sound/soc/sof/sof-acpi-dev.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Intel Corporation. All rights reserved. + */ + +#ifndef __SOUND_SOC_SOF_ACPI_H +#define __SOUND_SOC_SOF_ACPI_H + +extern const struct dev_pm_ops sof_acpi_pm; +int sof_acpi_probe(struct platform_device *pdev, const struct sof_dev_desc *desc); +int sof_acpi_remove(struct platform_device *pdev); + +#endif diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index fd1f0d8c2853..b842a414e1df 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -13,15 +13,11 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/pm_runtime.h> -#include <sound/intel-dsp-config.h> #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> #include <sound/sof.h> #include "ops.h" - -/* platform specific devices */ -#include "intel/shim.h" -#include "intel/hda.h" +#include "sof-pci-dev.h" static char *fw_path; module_param(fw_path, charp, 0444); @@ -81,243 +77,14 @@ static const struct dmi_system_id community_key_platforms[] = { {}, }; -#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) -static const struct sof_dev_desc bxt_desc = { - .machines = snd_soc_acpi_intel_bxt_machines, - .use_acpi_target_states = true, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &apl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-apl.ri", - .nocodec_tplg_filename = "sof-apl-nocodec.tplg", - .ops = &sof_apl_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) -static const struct sof_dev_desc glk_desc = { - .machines = snd_soc_acpi_intel_glk_machines, - .use_acpi_target_states = true, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &apl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-glk.ri", - .nocodec_tplg_filename = "sof-glk-nocodec.tplg", - .ops = &sof_apl_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) -static struct snd_soc_acpi_mach sof_tng_machines[] = { - { - .id = "INT343A", - .drv_name = "edison", - .sof_fw_filename = "sof-byt.ri", - .sof_tplg_filename = "sof-byt.tplg", - }, - {} -}; - -static const struct sof_dev_desc tng_desc = { - .machines = sof_tng_machines, - .resindex_lpe_base = 3, /* IRAM, but subtract IRAM offset */ - .resindex_pcicfg_base = -1, - .resindex_imr_base = 0, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &tng_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-byt.ri", - .nocodec_tplg_filename = "sof-byt.tplg", - .ops = &sof_tng_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) -static const struct sof_dev_desc cnl_desc = { - .machines = snd_soc_acpi_intel_cnl_machines, - .alt_machines = snd_soc_acpi_intel_cnl_sdw_machines, - .use_acpi_target_states = true, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &cnl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-cnl.ri", - .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", - .ops = &sof_cnl_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) -static const struct sof_dev_desc cfl_desc = { - .machines = snd_soc_acpi_intel_cfl_machines, - .alt_machines = snd_soc_acpi_intel_cfl_sdw_machines, - .use_acpi_target_states = true, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &cnl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-cfl.ri", - .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", - .ops = &sof_cnl_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE) -static const struct sof_dev_desc cml_desc = { - .machines = snd_soc_acpi_intel_cml_machines, - .alt_machines = snd_soc_acpi_intel_cml_sdw_machines, - .use_acpi_target_states = true, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &cnl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-cml.ri", - .nocodec_tplg_filename = "sof-cnl-nocodec.tplg", - .ops = &sof_cnl_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) -static const struct sof_dev_desc icl_desc = { - .machines = snd_soc_acpi_intel_icl_machines, - .alt_machines = snd_soc_acpi_intel_icl_sdw_machines, - .use_acpi_target_states = true, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &icl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-icl.ri", - .nocodec_tplg_filename = "sof-icl-nocodec.tplg", - .ops = &sof_icl_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) || IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) -static const struct sof_dev_desc tgl_desc = { - .machines = snd_soc_acpi_intel_tgl_machines, - .alt_machines = snd_soc_acpi_intel_tgl_sdw_machines, - .use_acpi_target_states = true, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &tgl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-tgl.ri", - .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", - .ops = &sof_tgl_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) -static const struct sof_dev_desc tglh_desc = { - .machines = snd_soc_acpi_intel_tgl_machines, - .alt_machines = snd_soc_acpi_intel_tgl_sdw_machines, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &tglh_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-tgl-h.ri", - .nocodec_tplg_filename = "sof-tgl-nocodec.tplg", - .ops = &sof_tgl_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) -static const struct sof_dev_desc ehl_desc = { - .machines = snd_soc_acpi_intel_ehl_machines, - .use_acpi_target_states = true, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &ehl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-ehl.ri", - .nocodec_tplg_filename = "sof-ehl-nocodec.tplg", - .ops = &sof_cnl_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) -static const struct sof_dev_desc jsl_desc = { - .machines = snd_soc_acpi_intel_jsl_machines, - .use_acpi_target_states = true, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &jsl_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-jsl.ri", - .nocodec_tplg_filename = "sof-jsl-nocodec.tplg", - .ops = &sof_cnl_ops, -}; -#endif - -#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) -static const struct sof_dev_desc adls_desc = { - .machines = snd_soc_acpi_intel_adl_machines, - .alt_machines = snd_soc_acpi_intel_adl_sdw_machines, - .resindex_lpe_base = 0, - .resindex_pcicfg_base = -1, - .resindex_imr_base = -1, - .irqindex_host_ipc = -1, - .resindex_dma_base = -1, - .chip_info = &adls_chip_info, - .default_fw_path = "intel/sof", - .default_tplg_path = "intel/sof-tplg", - .default_fw_filename = "sof-adl-s.ri", - .nocodec_tplg_filename = "sof-adl-nocodec.tplg", - .ops = &sof_tgl_ops, -}; -#endif - -static const struct dev_pm_ops sof_pci_pm = { +const struct dev_pm_ops sof_pci_pm = { .prepare = snd_sof_prepare, .complete = snd_sof_complete, SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, snd_sof_runtime_idle) }; +EXPORT_SYMBOL_NS(sof_pci_pm, SND_SOC_SOF_PCI_DEV); static void sof_pci_probe_complete(struct device *dev) { @@ -343,8 +110,7 @@ static void sof_pci_probe_complete(struct device *dev) pm_runtime_put_noidle(dev); } -static int sof_pci_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { struct device *dev = &pci->dev; const struct sof_dev_desc *desc = @@ -353,13 +119,6 @@ static int sof_pci_probe(struct pci_dev *pci, const struct snd_sof_dsp_ops *ops; int ret; - if (IS_REACHABLE(CONFIG_SND_INTEL_DSP_CONFIG)) { - ret = snd_intel_dsp_driver_probe(pci); - if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_SOF) { - dev_dbg(&pci->dev, "SOF PCI driver not selected, aborting probe\n"); - return -ENODEV; - } - } dev_dbg(&pci->dev, "PCI DSP detected"); /* get ops for platform */ @@ -447,8 +206,9 @@ release_regions: return ret; } +EXPORT_SYMBOL_NS(sof_pci_probe, SND_SOC_SOF_PCI_DEV); -static void sof_pci_remove(struct pci_dev *pci) +void sof_pci_remove(struct pci_dev *pci) { /* call sof helper for DSP hardware remove */ snd_sof_device_remove(&pci->dev); @@ -461,94 +221,12 @@ static void sof_pci_remove(struct pci_dev *pci) /* release pci regions and disable device */ pci_release_regions(pci); } +EXPORT_SYMBOL_NS(sof_pci_remove, SND_SOC_SOF_PCI_DEV); -static void sof_pci_shutdown(struct pci_dev *pci) +void sof_pci_shutdown(struct pci_dev *pci) { snd_sof_device_shutdown(&pci->dev); } - -/* PCI IDs */ -static const struct pci_device_id sof_pci_ids[] = { -#if IS_ENABLED(CONFIG_SND_SOC_SOF_MERRIFIELD) - { PCI_DEVICE(0x8086, 0x119a), - .driver_data = (unsigned long)&tng_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) - /* BXT-P & Apollolake */ - { PCI_DEVICE(0x8086, 0x5a98), - .driver_data = (unsigned long)&bxt_desc}, - { PCI_DEVICE(0x8086, 0x1a98), - .driver_data = (unsigned long)&bxt_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_GEMINILAKE) - { PCI_DEVICE(0x8086, 0x3198), - .driver_data = (unsigned long)&glk_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_CANNONLAKE) - { PCI_DEVICE(0x8086, 0x9dc8), - .driver_data = (unsigned long)&cnl_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_COFFEELAKE) - { PCI_DEVICE(0x8086, 0xa348), - .driver_data = (unsigned long)&cfl_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_ICELAKE) - { PCI_DEVICE(0x8086, 0x34C8), /* ICL-LP */ - .driver_data = (unsigned long)&icl_desc}, - { PCI_DEVICE(0x8086, 0x3dc8), /* ICL-H */ - .driver_data = (unsigned long)&icl_desc}, - -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_JASPERLAKE) - { PCI_DEVICE(0x8086, 0x38c8), - .driver_data = (unsigned long)&jsl_desc}, - { PCI_DEVICE(0x8086, 0x4dc8), - .driver_data = (unsigned long)&jsl_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_COMETLAKE) - { PCI_DEVICE(0x8086, 0x02c8), /* CML-LP */ - .driver_data = (unsigned long)&cml_desc}, - { PCI_DEVICE(0x8086, 0x06c8), /* CML-H */ - .driver_data = (unsigned long)&cml_desc}, - { PCI_DEVICE(0x8086, 0xa3f0), /* CML-S */ - .driver_data = (unsigned long)&cml_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_TIGERLAKE) - { PCI_DEVICE(0x8086, 0xa0c8), /* TGL-LP */ - .driver_data = (unsigned long)&tgl_desc}, - { PCI_DEVICE(0x8086, 0x43c8), /* TGL-H */ - .driver_data = (unsigned long)&tglh_desc}, - -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_ELKHARTLAKE) - { PCI_DEVICE(0x8086, 0x4b55), - .driver_data = (unsigned long)&ehl_desc}, - { PCI_DEVICE(0x8086, 0x4b58), - .driver_data = (unsigned long)&ehl_desc}, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_SOF_ALDERLAKE) - { PCI_DEVICE(0x8086, 0x7ad0), - .driver_data = (unsigned long)&adls_desc}, - { PCI_DEVICE(0x8086, 0x51c8), - .driver_data = (unsigned long)&tgl_desc}, -#endif - { 0, } -}; -MODULE_DEVICE_TABLE(pci, sof_pci_ids); - -/* pci_driver definition */ -static struct pci_driver snd_sof_pci_driver = { - .name = "sof-audio-pci", - .id_table = sof_pci_ids, - .probe = sof_pci_probe, - .remove = sof_pci_remove, - .shutdown = sof_pci_shutdown, - .driver = { - .pm = &sof_pci_pm, - }, -}; -module_pci_driver(snd_sof_pci_driver); +EXPORT_SYMBOL_NS(sof_pci_shutdown, SND_SOC_SOF_PCI_DEV); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_IMPORT_NS(SND_SOC_SOF_MERRIFIELD); -MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/sof-pci-dev.h b/sound/soc/sof/sof-pci-dev.h new file mode 100644 index 000000000000..81155a59e63a --- /dev/null +++ b/sound/soc/sof/sof-pci-dev.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2021 Intel Corporation. All rights reserved. + */ + +#ifndef __SOUND_SOC_SOF_PCI_H +#define __SOUND_SOC_SOF_PCI_H + +extern const struct dev_pm_ops sof_pci_pm; +int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id); +void sof_pci_remove(struct pci_dev *pci); +void sof_pci_shutdown(struct pci_dev *pci); + +#endif diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 8243652d5604..a746802d0ac3 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c @@ -652,10 +652,10 @@ static int set_sample_rate_v2v3(struct snd_usb_audio *chip, cur_rate = prev_rate; if (cur_rate != rate) { - usb_audio_warn(chip, - "%d:%d: freq mismatch (RO clock): req %d, clock runs @%d\n", - fmt->iface, fmt->altsetting, rate, cur_rate); - return -ENXIO; + usb_audio_dbg(chip, + "%d:%d: freq mismatch: req %d, clock runs @%d\n", + fmt->iface, fmt->altsetting, rate, cur_rate); + /* continue processing */ } validation: diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index b1c78db0d470..b004b2e63a5d 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1307,6 +1307,17 @@ no_res_check: /* totally crap, return an error */ return -EINVAL; } + } else { + /* if the max volume is too low, it's likely a bogus range; + * here we use -96dB as the threshold + */ + if (cval->dBmax <= -9600) { + usb_audio_info(cval->head.mixer->chip, + "%d:%d: bogus dB values (%d/%d), disabling dB reporting\n", + cval->head.id, mixer_ctrl_intf(cval->head.mixer), + cval->dBmin, cval->dBmax); + cval->dBmin = cval->dBmax = 0; + } } return 0; diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index a7212f16660e..646deb6244b1 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -537,6 +537,16 @@ static const struct usbmix_ctl_map usbmix_ctl_maps[] = { .map = bose_companion5_map, }, { + /* Corsair Virtuoso SE (wired mode) */ + .id = USB_ID(0x1b1c, 0x0a3d), + .map = corsair_virtuoso_map, + }, + { + /* Corsair Virtuoso SE (wireless mode) */ + .id = USB_ID(0x1b1c, 0x0a3e), + .map = corsair_virtuoso_map, + }, + { /* Corsair Virtuoso (wired mode) */ .id = USB_ID(0x1b1c, 0x0a41), .map = corsair_virtuoso_map, diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index bf5a0f3c1fad..e5311b6bb3f6 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -845,13 +845,19 @@ get_sync_ep_from_substream(struct snd_usb_substream *subs) list_for_each_entry(fp, &subs->fmt_list, list) { ep = snd_usb_get_endpoint(chip, fp->endpoint); - if (ep && ep->cur_rate) - return ep; + if (ep && ep->cur_audiofmt) { + /* if EP is already opened solely for this substream, + * we still allow us to change the parameter; otherwise + * this substream has to follow the existing parameter + */ + if (ep->cur_audiofmt != subs->cur_audiofmt || ep->opened > 1) + return ep; + } if (!fp->implicit_fb) continue; /* for the implicit fb, check the sync ep as well */ ep = snd_usb_get_endpoint(chip, fp->sync_ep); - if (ep && ep->cur_rate) + if (ep && ep->cur_audiofmt) return ep; } return NULL; diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 9ba4682ebc48..737b2729c0d3 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1482,7 +1482,7 @@ static int pioneer_djm_set_format_quirk(struct snd_usb_substream *subs, usb_set_interface(subs->dev, 0, 1); // we should derive windex from fmt-sync_ep but it's not set snd_usb_ctl_msg(subs->stream->chip->dev, - usb_rcvctrlpipe(subs->stream->chip->dev, 0), + usb_sndctrlpipe(subs->stream->chip->dev, 0), 0x01, 0x22, 0x0100, windex, &sr, 0x0003); return 0; } diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index d787cb802b4a..e5fbf16f725b 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -21,6 +21,8 @@ #define KVM_UTIL_PGS_PER_HUGEPG 512 #define KVM_UTIL_MIN_PFN 2 +static int vcpu_mmap_sz(void); + /* Aligns x up to the next multiple of size. Size must be a power of 2. */ static void *align(void *x, size_t size) { @@ -509,7 +511,7 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct vcpu *vcpu) vcpu->dirty_gfns = NULL; } - ret = munmap(vcpu->state, sizeof(*vcpu->state)); + ret = munmap(vcpu->state, vcpu_mmap_sz()); TEST_ASSERT(ret == 0, "munmap of VCPU fd failed, rc: %i " "errno: %i", ret, errno); close(vcpu->fd); @@ -978,7 +980,7 @@ void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->state), "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, 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); 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 9246ea310587..804ff5ff022d 100644 --- a/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c +++ b/tools/testing/selftests/kvm/x86_64/xen_shinfo_test.c @@ -13,19 +13,27 @@ #include <stdint.h> #include <time.h> +#include <sched.h> +#include <sys/syscall.h> #define VCPU_ID 5 +#define SHINFO_REGION_GVA 0xc0000000ULL #define SHINFO_REGION_GPA 0xc0000000ULL #define SHINFO_REGION_SLOT 10 #define PAGE_SIZE 4096 #define PVTIME_ADDR (SHINFO_REGION_GPA + PAGE_SIZE) +#define RUNSTATE_ADDR (SHINFO_REGION_GPA + PAGE_SIZE + 0x20) + +#define RUNSTATE_VADDR (SHINFO_REGION_GVA + PAGE_SIZE + 0x20) static struct kvm_vm *vm; #define XEN_HYPERCALL_MSR 0x40000000 +#define MIN_STEAL_TIME 50000 + struct pvclock_vcpu_time_info { u32 version; u32 pad0; @@ -43,11 +51,67 @@ struct pvclock_wall_clock { u32 nsec; } __attribute__((__packed__)); +struct vcpu_runstate_info { + uint32_t state; + uint64_t state_entry_time; + uint64_t time[4]; +}; + +#define RUNSTATE_running 0 +#define RUNSTATE_runnable 1 +#define RUNSTATE_blocked 2 +#define RUNSTATE_offline 3 + static void guest_code(void) { + struct vcpu_runstate_info *rs = (void *)RUNSTATE_VADDR; + + /* Test having the host set runstates manually */ + GUEST_SYNC(RUNSTATE_runnable); + GUEST_ASSERT(rs->time[RUNSTATE_runnable] != 0); + GUEST_ASSERT(rs->state == 0); + + GUEST_SYNC(RUNSTATE_blocked); + GUEST_ASSERT(rs->time[RUNSTATE_blocked] != 0); + GUEST_ASSERT(rs->state == 0); + + GUEST_SYNC(RUNSTATE_offline); + GUEST_ASSERT(rs->time[RUNSTATE_offline] != 0); + GUEST_ASSERT(rs->state == 0); + + /* Test runstate time adjust */ + GUEST_SYNC(4); + GUEST_ASSERT(rs->time[RUNSTATE_blocked] == 0x5a); + GUEST_ASSERT(rs->time[RUNSTATE_offline] == 0x6b6b); + + /* Test runstate time set */ + GUEST_SYNC(5); + GUEST_ASSERT(rs->state_entry_time >= 0x8000); + GUEST_ASSERT(rs->time[RUNSTATE_runnable] == 0); + GUEST_ASSERT(rs->time[RUNSTATE_blocked] == 0x6b6b); + GUEST_ASSERT(rs->time[RUNSTATE_offline] == 0x5a); + + /* sched_yield() should result in some 'runnable' time */ + GUEST_SYNC(6); + GUEST_ASSERT(rs->time[RUNSTATE_runnable] >= MIN_STEAL_TIME); + GUEST_DONE(); } +static long get_run_delay(void) +{ + char path[64]; + long val[2]; + FILE *fp; + + sprintf(path, "/proc/%ld/schedstat", syscall(SYS_gettid)); + fp = fopen(path, "r"); + fscanf(fp, "%ld %ld ", &val[0], &val[1]); + fclose(fp); + + return val[1]; +} + static int cmp_timespec(struct timespec *a, struct timespec *b) { if (a->tv_sec > b->tv_sec) @@ -66,12 +130,14 @@ int main(int argc, char *argv[]) { struct timespec min_ts, max_ts, vm_ts; - if (!(kvm_check_cap(KVM_CAP_XEN_HVM) & - KVM_XEN_HVM_CONFIG_SHARED_INFO) ) { + 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); } + bool do_runstate_tests = !!(xen_caps & KVM_XEN_HVM_CONFIG_RUNSTATE); + clock_gettime(CLOCK_REALTIME, &min_ts); vm = vm_create_default(VCPU_ID, 0, (void *) guest_code); @@ -80,6 +146,7 @@ int main(int argc, char *argv[]) /* Map a region for the shared_info page */ vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, SHINFO_REGION_GPA, SHINFO_REGION_SLOT, 2, 0); + virt_map(vm, SHINFO_REGION_GVA, SHINFO_REGION_GPA, 2, 0); struct kvm_xen_hvm_config hvmc = { .flags = KVM_XEN_HVM_CONFIG_INTERCEPT_HCALL, @@ -111,6 +178,17 @@ int main(int argc, char *argv[]) }; vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &pvclock); + if (do_runstate_tests) { + struct kvm_xen_vcpu_attr st = { + .type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR, + .u.gpa = RUNSTATE_ADDR, + }; + vcpu_ioctl(vm, VCPU_ID, KVM_XEN_VCPU_SET_ATTR, &st); + } + + struct vcpu_runstate_info *rs = addr_gpa2hva(vm, RUNSTATE_ADDR);; + rs->state = 0x5a; + for (;;) { volatile struct kvm_run *run = vcpu_state(vm, VCPU_ID); struct ucall uc; @@ -126,8 +204,56 @@ int main(int argc, char *argv[]) case UCALL_ABORT: TEST_FAIL("%s", (const char *)uc.args[0]); /* NOT REACHED */ - case UCALL_SYNC: + case UCALL_SYNC: { + struct kvm_xen_vcpu_attr rst; + long rundelay; + + /* If no runstate support, bail out early */ + if (!do_runstate_tests) + goto done; + + TEST_ASSERT(rs->state_entry_time == rs->time[0] + + rs->time[1] + rs->time[2] + rs->time[3], + "runstate times don't add up"); + + switch (uc.args[1]) { + case RUNSTATE_running...RUNSTATE_offline: + 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); + break; + case 4: + rst.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADJUST; + memset(&rst.u, 0, sizeof(rst.u)); + rst.u.runstate.state = (uint64_t)-1; + rst.u.runstate.time_blocked = + 0x5a - rs->time[RUNSTATE_blocked]; + rst.u.runstate.time_offline = + 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); + break; + + case 5: + rst.type = KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_DATA; + memset(&rst.u, 0, sizeof(rst.u)); + rst.u.runstate.state = RUNSTATE_running; + 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); + break; + case 6: + /* Yield until scheduler delay exceeds target */ + rundelay = get_run_delay() + MIN_STEAL_TIME; + do { + sched_yield(); + } while (get_run_delay() < rundelay); + break; + } break; + } case UCALL_DONE: goto done; default: @@ -162,6 +288,33 @@ int main(int argc, char *argv[]) TEST_ASSERT(ti2->version && !(ti2->version & 1), "Bad time_info version %x", ti->version); + if (do_runstate_tests) { + /* + * Fetch runstate and check sanity. Strictly speaking in the + * general case we might not expect the numbers to be identical + * but in this case we know we aren't running the vCPU any more. + */ + 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); + + TEST_ASSERT(rs->state == rst.u.runstate.state, "Runstate mismatch"); + TEST_ASSERT(rs->state_entry_time == rst.u.runstate.state_entry_time, + "State entry time mismatch"); + TEST_ASSERT(rs->time[RUNSTATE_running] == rst.u.runstate.time_running, + "Running time mismatch"); + TEST_ASSERT(rs->time[RUNSTATE_runnable] == rst.u.runstate.time_runnable, + "Runnable time mismatch"); + TEST_ASSERT(rs->time[RUNSTATE_blocked] == rst.u.runstate.time_blocked, + "Blocked time mismatch"); + TEST_ASSERT(rs->time[RUNSTATE_offline] == rst.u.runstate.time_offline, + "Offline time mismatch"); + + TEST_ASSERT(rs->state_entry_time == rs->time[0] + + rs->time[1] + rs->time[2] + rs->time[3], + "runstate times don't add up"); + } kvm_vm_free(vm); return 0; } |