mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 22:14:04 +02:00
Merge 1c273e10bc ("Merge tag 'zonefs-5.12-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs") into android-mainline
Steps on the way to 5.12-rc4 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I9c26fb4f4faf613469a5d342b768eea8ede3de6f
This commit is contained in:
commit
c36e49e512
|
|
@ -33,7 +33,7 @@ Contact: xfs@oss.sgi.com
|
|||
Description:
|
||||
The current state of the log write grant head. It
|
||||
represents the total log reservation of all currently
|
||||
oustanding transactions, including regrants due to
|
||||
outstanding transactions, including regrants due to
|
||||
rolling transactions. The grant head is exported in
|
||||
"cycle:bytes" format.
|
||||
Users: xfstests
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@ properties:
|
|||
- fsl,vf610-spdif
|
||||
- fsl,imx6sx-spdif
|
||||
- fsl,imx8qm-spdif
|
||||
- fsl,imx8qxp-spdif
|
||||
- fsl,imx8mq-spdif
|
||||
- fsl,imx8mm-spdif
|
||||
- fsl,imx8mn-spdif
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -1495,7 +1495,8 @@ Fails if any VCPU has already been created.
|
|||
|
||||
Define which vcpu is the Bootstrap Processor (BSP). Values are the same
|
||||
as the vcpu id in KVM_CREATE_VCPU. If this ioctl is not called, the default
|
||||
is vcpu 0.
|
||||
is vcpu 0. This ioctl has to be called before vcpu creation,
|
||||
otherwise it will return EBUSY error.
|
||||
|
||||
|
||||
4.42 KVM_GET_XSAVE
|
||||
|
|
@ -4806,8 +4807,10 @@ If an MSR access is not permitted through the filtering, it generates a
|
|||
allows user space to deflect and potentially handle various MSR accesses
|
||||
into user space.
|
||||
|
||||
If a vCPU is in running state while this ioctl is invoked, the vCPU may
|
||||
experience inconsistent filtering behavior on MSR accesses.
|
||||
Note, invoking this ioctl with a vCPU is running is inherently racy. However,
|
||||
KVM does guarantee that vCPUs will see either the previous filter or the new
|
||||
filter, e.g. MSRs with identical settings in both the old and new filter will
|
||||
have deterministic behavior.
|
||||
|
||||
4.127 KVM_XEN_HVM_SET_ATTR
|
||||
--------------------------
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ extern unsigned int s390_pci_no_rid;
|
|||
----------------------------------------------------------------------------- */
|
||||
/* Base stuff */
|
||||
int zpci_create_device(u32 fid, u32 fh, enum zpci_state state);
|
||||
void zpci_remove_device(struct zpci_dev *zdev);
|
||||
void zpci_remove_device(struct zpci_dev *zdev, bool set_error);
|
||||
int zpci_enable_device(struct zpci_dev *);
|
||||
int zpci_disable_device(struct zpci_dev *);
|
||||
int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
|
||||
|
|
|
|||
|
|
@ -968,7 +968,7 @@ static int cf_diag_all_start(void)
|
|||
*/
|
||||
static size_t cf_diag_needspace(unsigned int sets)
|
||||
{
|
||||
struct cpu_cf_events *cpuhw = this_cpu_ptr(&cpu_cf_events);
|
||||
struct cpu_cf_events *cpuhw = get_cpu_ptr(&cpu_cf_events);
|
||||
size_t bytes = 0;
|
||||
int i;
|
||||
|
||||
|
|
@ -984,6 +984,7 @@ static size_t cf_diag_needspace(unsigned int sets)
|
|||
sizeof(((struct s390_ctrset_cpudata *)0)->no_sets));
|
||||
debug_sprintf_event(cf_diag_dbg, 5, "%s bytes %ld\n", __func__,
|
||||
bytes);
|
||||
put_cpu_ptr(&cpu_cf_events);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -214,7 +214,7 @@ void vtime_flush(struct task_struct *tsk)
|
|||
avg_steal = S390_lowcore.avg_steal_timer / 2;
|
||||
if ((s64) steal > 0) {
|
||||
S390_lowcore.steal_timer = 0;
|
||||
account_steal_time(steal);
|
||||
account_steal_time(cputime_to_nsecs(steal));
|
||||
avg_steal += steal;
|
||||
}
|
||||
S390_lowcore.avg_steal_timer = avg_steal;
|
||||
|
|
|
|||
|
|
@ -682,16 +682,36 @@ int zpci_disable_device(struct zpci_dev *zdev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(zpci_disable_device);
|
||||
|
||||
void zpci_remove_device(struct zpci_dev *zdev)
|
||||
/* zpci_remove_device - Removes the given zdev from the PCI core
|
||||
* @zdev: the zdev to be removed from the PCI core
|
||||
* @set_error: if true the device's error state is set to permanent failure
|
||||
*
|
||||
* Sets a zPCI device to a configured but offline state; the zPCI
|
||||
* device is still accessible through its hotplug slot and the zPCI
|
||||
* API but is removed from the common code PCI bus, making it
|
||||
* no longer available to drivers.
|
||||
*/
|
||||
void zpci_remove_device(struct zpci_dev *zdev, bool set_error)
|
||||
{
|
||||
struct zpci_bus *zbus = zdev->zbus;
|
||||
struct pci_dev *pdev;
|
||||
|
||||
if (!zdev->zbus->bus)
|
||||
return;
|
||||
|
||||
pdev = pci_get_slot(zbus->bus, zdev->devfn);
|
||||
if (pdev) {
|
||||
if (pdev->is_virtfn)
|
||||
return zpci_iov_remove_virtfn(pdev, zdev->vfn);
|
||||
if (set_error)
|
||||
pdev->error_state = pci_channel_io_perm_failure;
|
||||
if (pdev->is_virtfn) {
|
||||
zpci_iov_remove_virtfn(pdev, zdev->vfn);
|
||||
/* balance pci_get_slot */
|
||||
pci_dev_put(pdev);
|
||||
return;
|
||||
}
|
||||
pci_stop_and_remove_bus_device_locked(pdev);
|
||||
/* balance pci_get_slot */
|
||||
pci_dev_put(pdev);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -765,7 +785,7 @@ void zpci_release_device(struct kref *kref)
|
|||
struct zpci_dev *zdev = container_of(kref, struct zpci_dev, kref);
|
||||
|
||||
if (zdev->zbus->bus)
|
||||
zpci_remove_device(zdev);
|
||||
zpci_remove_device(zdev, false);
|
||||
|
||||
switch (zdev->state) {
|
||||
case ZPCI_FN_STATE_ONLINE:
|
||||
|
|
|
|||
|
|
@ -76,13 +76,10 @@ void zpci_event_error(void *data)
|
|||
static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
||||
{
|
||||
struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
|
||||
struct pci_dev *pdev = NULL;
|
||||
enum zpci_state state;
|
||||
struct pci_dev *pdev;
|
||||
int ret;
|
||||
|
||||
if (zdev && zdev->zbus->bus)
|
||||
pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
|
||||
|
||||
zpci_err("avail CCDF:\n");
|
||||
zpci_err_hex(ccdf, sizeof(*ccdf));
|
||||
|
||||
|
|
@ -124,8 +121,7 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
|||
case 0x0303: /* Deconfiguration requested */
|
||||
if (!zdev)
|
||||
break;
|
||||
if (pdev)
|
||||
zpci_remove_device(zdev);
|
||||
zpci_remove_device(zdev, false);
|
||||
|
||||
ret = zpci_disable_device(zdev);
|
||||
if (ret)
|
||||
|
|
@ -140,12 +136,10 @@ static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
|
|||
case 0x0304: /* Configured -> Standby|Reserved */
|
||||
if (!zdev)
|
||||
break;
|
||||
if (pdev) {
|
||||
/* Give the driver a hint that the function is
|
||||
* already unusable. */
|
||||
pdev->error_state = pci_channel_io_perm_failure;
|
||||
zpci_remove_device(zdev);
|
||||
}
|
||||
/* Give the driver a hint that the function is
|
||||
* already unusable.
|
||||
*/
|
||||
zpci_remove_device(zdev, true);
|
||||
|
||||
zdev->fh = ccdf->fh;
|
||||
zpci_disable_device(zdev);
|
||||
|
|
|
|||
|
|
@ -884,12 +884,29 @@ struct kvm_hv_syndbg {
|
|||
u64 options;
|
||||
};
|
||||
|
||||
/* Current state of Hyper-V TSC page clocksource */
|
||||
enum hv_tsc_page_status {
|
||||
/* TSC page was not set up or disabled */
|
||||
HV_TSC_PAGE_UNSET = 0,
|
||||
/* TSC page MSR was written by the guest, update pending */
|
||||
HV_TSC_PAGE_GUEST_CHANGED,
|
||||
/* TSC page MSR was written by KVM userspace, update pending */
|
||||
HV_TSC_PAGE_HOST_CHANGED,
|
||||
/* TSC page was properly set up and is currently active */
|
||||
HV_TSC_PAGE_SET,
|
||||
/* TSC page is currently being updated and therefore is inactive */
|
||||
HV_TSC_PAGE_UPDATING,
|
||||
/* TSC page was set up with an inaccessible GPA */
|
||||
HV_TSC_PAGE_BROKEN,
|
||||
};
|
||||
|
||||
/* Hyper-V emulation context */
|
||||
struct kvm_hv {
|
||||
struct mutex hv_lock;
|
||||
u64 hv_guest_os_id;
|
||||
u64 hv_hypercall;
|
||||
u64 hv_tsc_page;
|
||||
enum hv_tsc_page_status hv_tsc_page_status;
|
||||
|
||||
/* Hyper-v based guest crash (NT kernel bugcheck) parameters */
|
||||
u64 hv_crash_param[HV_X64_MSR_CRASH_PARAMS];
|
||||
|
|
@ -931,6 +948,12 @@ enum kvm_irqchip_mode {
|
|||
KVM_IRQCHIP_SPLIT, /* created with KVM_CAP_SPLIT_IRQCHIP */
|
||||
};
|
||||
|
||||
struct kvm_x86_msr_filter {
|
||||
u8 count;
|
||||
bool default_allow:1;
|
||||
struct msr_bitmap_range ranges[16];
|
||||
};
|
||||
|
||||
#define APICV_INHIBIT_REASON_DISABLE 0
|
||||
#define APICV_INHIBIT_REASON_HYPERV 1
|
||||
#define APICV_INHIBIT_REASON_NESTED 2
|
||||
|
|
@ -1025,16 +1048,11 @@ struct kvm_arch {
|
|||
bool guest_can_read_msr_platform_info;
|
||||
bool exception_payload_enabled;
|
||||
|
||||
bool bus_lock_detection_enabled;
|
||||
|
||||
/* Deflect RDMSR and WRMSR to user space when they trigger a #GP */
|
||||
u32 user_space_msr_mask;
|
||||
|
||||
struct {
|
||||
u8 count;
|
||||
bool default_allow:1;
|
||||
struct msr_bitmap_range ranges[16];
|
||||
} msr_filter;
|
||||
|
||||
bool bus_lock_detection_enabled;
|
||||
struct kvm_x86_msr_filter __rcu *msr_filter;
|
||||
|
||||
struct kvm_pmu_event_filter __rcu *pmu_event_filter;
|
||||
struct task_struct *nx_lpage_recovery_thread;
|
||||
|
|
|
|||
|
|
@ -836,28 +836,25 @@ static void kvm_kick_cpu(int cpu)
|
|||
|
||||
static void kvm_wait(u8 *ptr, u8 val)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (in_nmi())
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (READ_ONCE(*ptr) != val)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* halt until it's our turn and kicked. Note that we do safe halt
|
||||
* for irq enabled case to avoid hang when lock info is overwritten
|
||||
* in irq spinlock slowpath and no spurious interrupt occur to save us.
|
||||
*/
|
||||
if (arch_irqs_disabled_flags(flags))
|
||||
halt();
|
||||
else
|
||||
safe_halt();
|
||||
if (irqs_disabled()) {
|
||||
if (READ_ONCE(*ptr) == val)
|
||||
halt();
|
||||
} else {
|
||||
local_irq_disable();
|
||||
|
||||
out:
|
||||
local_irq_restore(flags);
|
||||
if (READ_ONCE(*ptr) == val)
|
||||
safe_halt();
|
||||
|
||||
local_irq_enable();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
|
|
|
|||
|
|
@ -520,10 +520,10 @@ static u64 get_time_ref_counter(struct kvm *kvm)
|
|||
u64 tsc;
|
||||
|
||||
/*
|
||||
* The guest has not set up the TSC page or the clock isn't
|
||||
* stable, fall back to get_kvmclock_ns.
|
||||
* Fall back to get_kvmclock_ns() when TSC page hasn't been set up,
|
||||
* is broken, disabled or being updated.
|
||||
*/
|
||||
if (!hv->tsc_ref.tsc_sequence)
|
||||
if (hv->hv_tsc_page_status != HV_TSC_PAGE_SET)
|
||||
return div_u64(get_kvmclock_ns(kvm), 100);
|
||||
|
||||
vcpu = kvm_get_vcpu(kvm, 0);
|
||||
|
|
@ -1077,6 +1077,21 @@ static bool compute_tsc_page_parameters(struct pvclock_vcpu_time_info *hv_clock,
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't touch TSC page values if the guest has opted for TSC emulation after
|
||||
* migration. KVM doesn't fully support reenlightenment notifications and TSC
|
||||
* access emulation and Hyper-V is known to expect the values in TSC page to
|
||||
* stay constant before TSC access emulation is disabled from guest side
|
||||
* (HV_X64_MSR_TSC_EMULATION_STATUS). KVM userspace is expected to preserve TSC
|
||||
* frequency and guest visible TSC value across migration (and prevent it when
|
||||
* TSC scaling is unsupported).
|
||||
*/
|
||||
static inline bool tsc_page_update_unsafe(struct kvm_hv *hv)
|
||||
{
|
||||
return (hv->hv_tsc_page_status != HV_TSC_PAGE_GUEST_CHANGED) &&
|
||||
hv->hv_tsc_emulation_control;
|
||||
}
|
||||
|
||||
void kvm_hv_setup_tsc_page(struct kvm *kvm,
|
||||
struct pvclock_vcpu_time_info *hv_clock)
|
||||
{
|
||||
|
|
@ -1087,7 +1102,8 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
|
|||
BUILD_BUG_ON(sizeof(tsc_seq) != sizeof(hv->tsc_ref.tsc_sequence));
|
||||
BUILD_BUG_ON(offsetof(struct ms_hyperv_tsc_page, tsc_sequence) != 0);
|
||||
|
||||
if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))
|
||||
if (hv->hv_tsc_page_status == HV_TSC_PAGE_BROKEN ||
|
||||
hv->hv_tsc_page_status == HV_TSC_PAGE_UNSET)
|
||||
return;
|
||||
|
||||
mutex_lock(&hv->hv_lock);
|
||||
|
|
@ -1101,7 +1117,15 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
|
|||
*/
|
||||
if (unlikely(kvm_read_guest(kvm, gfn_to_gpa(gfn),
|
||||
&tsc_seq, sizeof(tsc_seq))))
|
||||
goto out_err;
|
||||
|
||||
if (tsc_seq && tsc_page_update_unsafe(hv)) {
|
||||
if (kvm_read_guest(kvm, gfn_to_gpa(gfn), &hv->tsc_ref, sizeof(hv->tsc_ref)))
|
||||
goto out_err;
|
||||
|
||||
hv->hv_tsc_page_status = HV_TSC_PAGE_SET;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
/*
|
||||
* While we're computing and writing the parameters, force the
|
||||
|
|
@ -1110,15 +1134,15 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
|
|||
hv->tsc_ref.tsc_sequence = 0;
|
||||
if (kvm_write_guest(kvm, gfn_to_gpa(gfn),
|
||||
&hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence)))
|
||||
goto out_unlock;
|
||||
goto out_err;
|
||||
|
||||
if (!compute_tsc_page_parameters(hv_clock, &hv->tsc_ref))
|
||||
goto out_unlock;
|
||||
goto out_err;
|
||||
|
||||
/* Ensure sequence is zero before writing the rest of the struct. */
|
||||
smp_wmb();
|
||||
if (kvm_write_guest(kvm, gfn_to_gpa(gfn), &hv->tsc_ref, sizeof(hv->tsc_ref)))
|
||||
goto out_unlock;
|
||||
goto out_err;
|
||||
|
||||
/*
|
||||
* Now switch to the TSC page mechanism by writing the sequence.
|
||||
|
|
@ -1131,8 +1155,45 @@ void kvm_hv_setup_tsc_page(struct kvm *kvm,
|
|||
smp_wmb();
|
||||
|
||||
hv->tsc_ref.tsc_sequence = tsc_seq;
|
||||
kvm_write_guest(kvm, gfn_to_gpa(gfn),
|
||||
&hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence));
|
||||
if (kvm_write_guest(kvm, gfn_to_gpa(gfn),
|
||||
&hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence)))
|
||||
goto out_err;
|
||||
|
||||
hv->hv_tsc_page_status = HV_TSC_PAGE_SET;
|
||||
goto out_unlock;
|
||||
|
||||
out_err:
|
||||
hv->hv_tsc_page_status = HV_TSC_PAGE_BROKEN;
|
||||
out_unlock:
|
||||
mutex_unlock(&hv->hv_lock);
|
||||
}
|
||||
|
||||
void kvm_hv_invalidate_tsc_page(struct kvm *kvm)
|
||||
{
|
||||
struct kvm_hv *hv = to_kvm_hv(kvm);
|
||||
u64 gfn;
|
||||
|
||||
if (hv->hv_tsc_page_status == HV_TSC_PAGE_BROKEN ||
|
||||
hv->hv_tsc_page_status == HV_TSC_PAGE_UNSET ||
|
||||
tsc_page_update_unsafe(hv))
|
||||
return;
|
||||
|
||||
mutex_lock(&hv->hv_lock);
|
||||
|
||||
if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))
|
||||
goto out_unlock;
|
||||
|
||||
/* Preserve HV_TSC_PAGE_GUEST_CHANGED/HV_TSC_PAGE_HOST_CHANGED states */
|
||||
if (hv->hv_tsc_page_status == HV_TSC_PAGE_SET)
|
||||
hv->hv_tsc_page_status = HV_TSC_PAGE_UPDATING;
|
||||
|
||||
gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT;
|
||||
|
||||
hv->tsc_ref.tsc_sequence = 0;
|
||||
if (kvm_write_guest(kvm, gfn_to_gpa(gfn),
|
||||
&hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence)))
|
||||
hv->hv_tsc_page_status = HV_TSC_PAGE_BROKEN;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&hv->hv_lock);
|
||||
}
|
||||
|
|
@ -1193,8 +1254,15 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
|
|||
}
|
||||
case HV_X64_MSR_REFERENCE_TSC:
|
||||
hv->hv_tsc_page = data;
|
||||
if (hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE)
|
||||
if (hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE) {
|
||||
if (!host)
|
||||
hv->hv_tsc_page_status = HV_TSC_PAGE_GUEST_CHANGED;
|
||||
else
|
||||
hv->hv_tsc_page_status = HV_TSC_PAGE_HOST_CHANGED;
|
||||
kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu);
|
||||
} else {
|
||||
hv->hv_tsc_page_status = HV_TSC_PAGE_UNSET;
|
||||
}
|
||||
break;
|
||||
case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
|
||||
return kvm_hv_msr_set_crash_data(kvm,
|
||||
|
|
@ -1229,6 +1297,9 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
|
|||
hv->hv_tsc_emulation_control = data;
|
||||
break;
|
||||
case HV_X64_MSR_TSC_EMULATION_STATUS:
|
||||
if (data && !host)
|
||||
return 1;
|
||||
|
||||
hv->hv_tsc_emulation_status = data;
|
||||
break;
|
||||
case HV_X64_MSR_TIME_REF_COUNT:
|
||||
|
|
|
|||
|
|
@ -133,6 +133,7 @@ void kvm_hv_process_stimers(struct kvm_vcpu *vcpu);
|
|||
|
||||
void kvm_hv_setup_tsc_page(struct kvm *kvm,
|
||||
struct pvclock_vcpu_time_info *hv_clock);
|
||||
void kvm_hv_invalidate_tsc_page(struct kvm *kvm);
|
||||
|
||||
void kvm_hv_init_vm(struct kvm *kvm);
|
||||
void kvm_hv_destroy_vm(struct kvm *kvm);
|
||||
|
|
|
|||
|
|
@ -78,6 +78,11 @@ static inline struct kvm_mmu_page *sptep_to_sp(u64 *sptep)
|
|||
return to_shadow_page(__pa(sptep));
|
||||
}
|
||||
|
||||
static inline int kvm_mmu_page_as_id(struct kvm_mmu_page *sp)
|
||||
{
|
||||
return sp->role.smm ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline bool kvm_vcpu_ad_need_write_protect(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -20,6 +20,21 @@ static gfn_t round_gfn_for_level(gfn_t gfn, int level)
|
|||
return gfn & -KVM_PAGES_PER_HPAGE(level);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the TDP iterator to the root PT and allow it to continue its
|
||||
* traversal over the paging structure from there.
|
||||
*/
|
||||
void tdp_iter_restart(struct tdp_iter *iter)
|
||||
{
|
||||
iter->yielded_gfn = iter->next_last_level_gfn;
|
||||
iter->level = iter->root_level;
|
||||
|
||||
iter->gfn = round_gfn_for_level(iter->next_last_level_gfn, iter->level);
|
||||
tdp_iter_refresh_sptep(iter);
|
||||
|
||||
iter->valid = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets a TDP iterator to walk a pre-order traversal of the paging structure
|
||||
* rooted at root_pt, starting with the walk to translate next_last_level_gfn.
|
||||
|
|
@ -31,16 +46,12 @@ void tdp_iter_start(struct tdp_iter *iter, u64 *root_pt, int root_level,
|
|||
WARN_ON(root_level > PT64_ROOT_MAX_LEVEL);
|
||||
|
||||
iter->next_last_level_gfn = next_last_level_gfn;
|
||||
iter->yielded_gfn = iter->next_last_level_gfn;
|
||||
iter->root_level = root_level;
|
||||
iter->min_level = min_level;
|
||||
iter->level = root_level;
|
||||
iter->pt_path[iter->level - 1] = (tdp_ptep_t)root_pt;
|
||||
iter->pt_path[iter->root_level - 1] = (tdp_ptep_t)root_pt;
|
||||
iter->as_id = kvm_mmu_page_as_id(sptep_to_sp(root_pt));
|
||||
|
||||
iter->gfn = round_gfn_for_level(iter->next_last_level_gfn, iter->level);
|
||||
tdp_iter_refresh_sptep(iter);
|
||||
|
||||
iter->valid = true;
|
||||
tdp_iter_restart(iter);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -159,8 +170,3 @@ void tdp_iter_next(struct tdp_iter *iter)
|
|||
iter->valid = false;
|
||||
}
|
||||
|
||||
tdp_ptep_t tdp_iter_root_pt(struct tdp_iter *iter)
|
||||
{
|
||||
return iter->pt_path[iter->root_level - 1];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ struct tdp_iter {
|
|||
int min_level;
|
||||
/* The iterator's current level within the paging structure */
|
||||
int level;
|
||||
/* The address space ID, i.e. SMM vs. regular. */
|
||||
int as_id;
|
||||
/* A snapshot of the value at sptep */
|
||||
u64 old_spte;
|
||||
/*
|
||||
|
|
@ -62,6 +64,6 @@ tdp_ptep_t spte_to_child_pt(u64 pte, int level);
|
|||
void tdp_iter_start(struct tdp_iter *iter, u64 *root_pt, int root_level,
|
||||
int min_level, gfn_t next_last_level_gfn);
|
||||
void tdp_iter_next(struct tdp_iter *iter);
|
||||
tdp_ptep_t tdp_iter_root_pt(struct tdp_iter *iter);
|
||||
void tdp_iter_restart(struct tdp_iter *iter);
|
||||
|
||||
#endif /* __KVM_X86_MMU_TDP_ITER_H */
|
||||
|
|
|
|||
|
|
@ -203,11 +203,6 @@ static void handle_changed_spte(struct kvm *kvm, int as_id, gfn_t gfn,
|
|||
u64 old_spte, u64 new_spte, int level,
|
||||
bool shared);
|
||||
|
||||
static int kvm_mmu_page_as_id(struct kvm_mmu_page *sp)
|
||||
{
|
||||
return sp->role.smm ? 1 : 0;
|
||||
}
|
||||
|
||||
static void handle_changed_spte_acc_track(u64 old_spte, u64 new_spte, int level)
|
||||
{
|
||||
bool pfn_changed = spte_to_pfn(old_spte) != spte_to_pfn(new_spte);
|
||||
|
|
@ -301,11 +296,16 @@ static void tdp_mmu_unlink_page(struct kvm *kvm, struct kvm_mmu_page *sp,
|
|||
*
|
||||
* Given a page table that has been removed from the TDP paging structure,
|
||||
* iterates through the page table to clear SPTEs and free child page tables.
|
||||
*
|
||||
* Note that pt is passed in as a tdp_ptep_t, but it does not need RCU
|
||||
* protection. Since this thread removed it from the paging structure,
|
||||
* this thread will be responsible for ensuring the page is freed. Hence the
|
||||
* early rcu_dereferences in the function.
|
||||
*/
|
||||
static void handle_removed_tdp_mmu_page(struct kvm *kvm, u64 *pt,
|
||||
static void handle_removed_tdp_mmu_page(struct kvm *kvm, tdp_ptep_t pt,
|
||||
bool shared)
|
||||
{
|
||||
struct kvm_mmu_page *sp = sptep_to_sp(pt);
|
||||
struct kvm_mmu_page *sp = sptep_to_sp(rcu_dereference(pt));
|
||||
int level = sp->role.level;
|
||||
gfn_t base_gfn = sp->gfn;
|
||||
u64 old_child_spte;
|
||||
|
|
@ -318,7 +318,7 @@ static void handle_removed_tdp_mmu_page(struct kvm *kvm, u64 *pt,
|
|||
tdp_mmu_unlink_page(kvm, sp, shared);
|
||||
|
||||
for (i = 0; i < PT64_ENT_PER_PAGE; i++) {
|
||||
sptep = pt + i;
|
||||
sptep = rcu_dereference(pt) + i;
|
||||
gfn = base_gfn + (i * KVM_PAGES_PER_HPAGE(level - 1));
|
||||
|
||||
if (shared) {
|
||||
|
|
@ -492,10 +492,6 @@ static inline bool tdp_mmu_set_spte_atomic(struct kvm *kvm,
|
|||
struct tdp_iter *iter,
|
||||
u64 new_spte)
|
||||
{
|
||||
u64 *root_pt = tdp_iter_root_pt(iter);
|
||||
struct kvm_mmu_page *root = sptep_to_sp(root_pt);
|
||||
int as_id = kvm_mmu_page_as_id(root);
|
||||
|
||||
lockdep_assert_held_read(&kvm->mmu_lock);
|
||||
|
||||
/*
|
||||
|
|
@ -509,8 +505,8 @@ static inline bool tdp_mmu_set_spte_atomic(struct kvm *kvm,
|
|||
new_spte) != iter->old_spte)
|
||||
return false;
|
||||
|
||||
handle_changed_spte(kvm, as_id, iter->gfn, iter->old_spte, new_spte,
|
||||
iter->level, true);
|
||||
handle_changed_spte(kvm, iter->as_id, iter->gfn, iter->old_spte,
|
||||
new_spte, iter->level, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -538,7 +534,7 @@ static inline bool tdp_mmu_zap_spte_atomic(struct kvm *kvm,
|
|||
* here since the SPTE is going from non-present
|
||||
* to non-present.
|
||||
*/
|
||||
WRITE_ONCE(*iter->sptep, 0);
|
||||
WRITE_ONCE(*rcu_dereference(iter->sptep), 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -564,10 +560,6 @@ static inline void __tdp_mmu_set_spte(struct kvm *kvm, struct tdp_iter *iter,
|
|||
u64 new_spte, bool record_acc_track,
|
||||
bool record_dirty_log)
|
||||
{
|
||||
tdp_ptep_t root_pt = tdp_iter_root_pt(iter);
|
||||
struct kvm_mmu_page *root = sptep_to_sp(root_pt);
|
||||
int as_id = kvm_mmu_page_as_id(root);
|
||||
|
||||
lockdep_assert_held_write(&kvm->mmu_lock);
|
||||
|
||||
/*
|
||||
|
|
@ -581,13 +573,13 @@ static inline void __tdp_mmu_set_spte(struct kvm *kvm, struct tdp_iter *iter,
|
|||
|
||||
WRITE_ONCE(*rcu_dereference(iter->sptep), new_spte);
|
||||
|
||||
__handle_changed_spte(kvm, as_id, iter->gfn, iter->old_spte, new_spte,
|
||||
iter->level, false);
|
||||
__handle_changed_spte(kvm, iter->as_id, iter->gfn, iter->old_spte,
|
||||
new_spte, iter->level, false);
|
||||
if (record_acc_track)
|
||||
handle_changed_spte_acc_track(iter->old_spte, new_spte,
|
||||
iter->level);
|
||||
if (record_dirty_log)
|
||||
handle_changed_spte_dirty_log(kvm, as_id, iter->gfn,
|
||||
handle_changed_spte_dirty_log(kvm, iter->as_id, iter->gfn,
|
||||
iter->old_spte, new_spte,
|
||||
iter->level);
|
||||
}
|
||||
|
|
@ -659,9 +651,7 @@ static inline bool tdp_mmu_iter_cond_resched(struct kvm *kvm,
|
|||
|
||||
WARN_ON(iter->gfn > iter->next_last_level_gfn);
|
||||
|
||||
tdp_iter_start(iter, iter->pt_path[iter->root_level - 1],
|
||||
iter->root_level, iter->min_level,
|
||||
iter->next_last_level_gfn);
|
||||
tdp_iter_restart(iter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1526,35 +1526,44 @@ EXPORT_SYMBOL_GPL(kvm_enable_efer_bits);
|
|||
|
||||
bool kvm_msr_allowed(struct kvm_vcpu *vcpu, u32 index, u32 type)
|
||||
{
|
||||
struct kvm_x86_msr_filter *msr_filter;
|
||||
struct msr_bitmap_range *ranges;
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
struct msr_bitmap_range *ranges = kvm->arch.msr_filter.ranges;
|
||||
u32 count = kvm->arch.msr_filter.count;
|
||||
u32 i;
|
||||
bool r = kvm->arch.msr_filter.default_allow;
|
||||
bool allowed;
|
||||
int idx;
|
||||
u32 i;
|
||||
|
||||
/* MSR filtering not set up or x2APIC enabled, allow everything */
|
||||
if (!count || (index >= 0x800 && index <= 0x8ff))
|
||||
/* x2APIC MSRs do not support filtering. */
|
||||
if (index >= 0x800 && index <= 0x8ff)
|
||||
return true;
|
||||
|
||||
/* Prevent collision with set_msr_filter */
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
msr_filter = srcu_dereference(kvm->arch.msr_filter, &kvm->srcu);
|
||||
if (!msr_filter) {
|
||||
allowed = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
allowed = msr_filter->default_allow;
|
||||
ranges = msr_filter->ranges;
|
||||
|
||||
for (i = 0; i < msr_filter->count; i++) {
|
||||
u32 start = ranges[i].base;
|
||||
u32 end = start + ranges[i].nmsrs;
|
||||
u32 flags = ranges[i].flags;
|
||||
unsigned long *bitmap = ranges[i].bitmap;
|
||||
|
||||
if ((index >= start) && (index < end) && (flags & type)) {
|
||||
r = !!test_bit(index - start, bitmap);
|
||||
allowed = !!test_bit(index - start, bitmap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
srcu_read_unlock(&kvm->srcu, idx);
|
||||
|
||||
return r;
|
||||
return allowed;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kvm_msr_allowed);
|
||||
|
||||
|
|
@ -2551,6 +2560,8 @@ static void kvm_gen_update_masterclock(struct kvm *kvm)
|
|||
struct kvm_vcpu *vcpu;
|
||||
struct kvm_arch *ka = &kvm->arch;
|
||||
|
||||
kvm_hv_invalidate_tsc_page(kvm);
|
||||
|
||||
spin_lock(&ka->pvclock_gtod_sync_lock);
|
||||
kvm_make_mclock_inprogress_request(kvm);
|
||||
/* no guest entries from this point */
|
||||
|
|
@ -5352,25 +5363,34 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
|
|||
return r;
|
||||
}
|
||||
|
||||
static void kvm_clear_msr_filter(struct kvm *kvm)
|
||||
static struct kvm_x86_msr_filter *kvm_alloc_msr_filter(bool default_allow)
|
||||
{
|
||||
u32 i;
|
||||
u32 count = kvm->arch.msr_filter.count;
|
||||
struct msr_bitmap_range ranges[16];
|
||||
struct kvm_x86_msr_filter *msr_filter;
|
||||
|
||||
mutex_lock(&kvm->lock);
|
||||
kvm->arch.msr_filter.count = 0;
|
||||
memcpy(ranges, kvm->arch.msr_filter.ranges, count * sizeof(ranges[0]));
|
||||
mutex_unlock(&kvm->lock);
|
||||
synchronize_srcu(&kvm->srcu);
|
||||
msr_filter = kzalloc(sizeof(*msr_filter), GFP_KERNEL_ACCOUNT);
|
||||
if (!msr_filter)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
kfree(ranges[i].bitmap);
|
||||
msr_filter->default_allow = default_allow;
|
||||
return msr_filter;
|
||||
}
|
||||
|
||||
static int kvm_add_msr_filter(struct kvm *kvm, struct kvm_msr_filter_range *user_range)
|
||||
static void kvm_free_msr_filter(struct kvm_x86_msr_filter *msr_filter)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
if (!msr_filter)
|
||||
return;
|
||||
|
||||
for (i = 0; i < msr_filter->count; i++)
|
||||
kfree(msr_filter->ranges[i].bitmap);
|
||||
|
||||
kfree(msr_filter);
|
||||
}
|
||||
|
||||
static int kvm_add_msr_filter(struct kvm_x86_msr_filter *msr_filter,
|
||||
struct kvm_msr_filter_range *user_range)
|
||||
{
|
||||
struct msr_bitmap_range *ranges = kvm->arch.msr_filter.ranges;
|
||||
struct msr_bitmap_range range;
|
||||
unsigned long *bitmap = NULL;
|
||||
size_t bitmap_size;
|
||||
|
|
@ -5404,11 +5424,9 @@ static int kvm_add_msr_filter(struct kvm *kvm, struct kvm_msr_filter_range *user
|
|||
goto err;
|
||||
}
|
||||
|
||||
/* Everything ok, add this range identifier to our global pool */
|
||||
ranges[kvm->arch.msr_filter.count] = range;
|
||||
/* Make sure we filled the array before we tell anyone to walk it */
|
||||
smp_wmb();
|
||||
kvm->arch.msr_filter.count++;
|
||||
/* Everything ok, add this range identifier. */
|
||||
msr_filter->ranges[msr_filter->count] = range;
|
||||
msr_filter->count++;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
|
|
@ -5419,10 +5437,11 @@ static int kvm_add_msr_filter(struct kvm *kvm, struct kvm_msr_filter_range *user
|
|||
static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
|
||||
{
|
||||
struct kvm_msr_filter __user *user_msr_filter = argp;
|
||||
struct kvm_x86_msr_filter *new_filter, *old_filter;
|
||||
struct kvm_msr_filter filter;
|
||||
bool default_allow;
|
||||
int r = 0;
|
||||
bool empty = true;
|
||||
int r = 0;
|
||||
u32 i;
|
||||
|
||||
if (copy_from_user(&filter, user_msr_filter, sizeof(filter)))
|
||||
|
|
@ -5435,25 +5454,32 @@ static int kvm_vm_ioctl_set_msr_filter(struct kvm *kvm, void __user *argp)
|
|||
if (empty && !default_allow)
|
||||
return -EINVAL;
|
||||
|
||||
kvm_clear_msr_filter(kvm);
|
||||
new_filter = kvm_alloc_msr_filter(default_allow);
|
||||
if (!new_filter)
|
||||
return -ENOMEM;
|
||||
|
||||
kvm->arch.msr_filter.default_allow = default_allow;
|
||||
|
||||
/*
|
||||
* Protect from concurrent calls to this function that could trigger
|
||||
* a TOCTOU violation on kvm->arch.msr_filter.count.
|
||||
*/
|
||||
mutex_lock(&kvm->lock);
|
||||
for (i = 0; i < ARRAY_SIZE(filter.ranges); i++) {
|
||||
r = kvm_add_msr_filter(kvm, &filter.ranges[i]);
|
||||
if (r)
|
||||
break;
|
||||
r = kvm_add_msr_filter(new_filter, &filter.ranges[i]);
|
||||
if (r) {
|
||||
kvm_free_msr_filter(new_filter);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&kvm->lock);
|
||||
|
||||
/* The per-VM filter is protected by kvm->lock... */
|
||||
old_filter = srcu_dereference_check(kvm->arch.msr_filter, &kvm->srcu, 1);
|
||||
|
||||
rcu_assign_pointer(kvm->arch.msr_filter, new_filter);
|
||||
synchronize_srcu(&kvm->srcu);
|
||||
|
||||
kvm_free_msr_filter(old_filter);
|
||||
|
||||
kvm_make_all_cpus_request(kvm, KVM_REQ_MSR_FILTER_CHANGED);
|
||||
mutex_unlock(&kvm->lock);
|
||||
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long kvm_arch_vm_ioctl(struct file *filp,
|
||||
|
|
@ -6603,7 +6629,7 @@ static int kvm_emulate_wbinvd_noskip(struct kvm_vcpu *vcpu)
|
|||
int cpu = get_cpu();
|
||||
|
||||
cpumask_set_cpu(cpu, vcpu->arch.wbinvd_dirty_mask);
|
||||
smp_call_function_many(vcpu->arch.wbinvd_dirty_mask,
|
||||
on_each_cpu_mask(vcpu->arch.wbinvd_dirty_mask,
|
||||
wbinvd_ipi, NULL, 1);
|
||||
put_cpu();
|
||||
cpumask_clear(vcpu->arch.wbinvd_dirty_mask);
|
||||
|
|
@ -10634,8 +10660,6 @@ void kvm_arch_pre_destroy_vm(struct kvm *kvm)
|
|||
|
||||
void kvm_arch_destroy_vm(struct kvm *kvm)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
if (current->mm == kvm->mm) {
|
||||
/*
|
||||
* Free memory regions allocated on behalf of userspace,
|
||||
|
|
@ -10651,8 +10675,7 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
|
|||
mutex_unlock(&kvm->slots_lock);
|
||||
}
|
||||
static_call_cond(kvm_x86_vm_destroy)(kvm);
|
||||
for (i = 0; i < kvm->arch.msr_filter.count; i++)
|
||||
kfree(kvm->arch.msr_filter.ranges[i].bitmap);
|
||||
kvm_free_msr_filter(srcu_dereference_check(kvm->arch.msr_filter, &kvm->srcu, 1));
|
||||
kvm_pic_destroy(kvm);
|
||||
kvm_ioapic_destroy(kvm);
|
||||
kvm_free_vcpus(kvm);
|
||||
|
|
|
|||
|
|
@ -325,22 +325,22 @@ static void rpm_put_suppliers(struct device *dev)
|
|||
static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
|
||||
__releases(&dev->power.lock) __acquires(&dev->power.lock)
|
||||
{
|
||||
bool use_links = dev->power.links_count > 0;
|
||||
bool get = false;
|
||||
int retval, idx;
|
||||
bool put;
|
||||
bool use_links = dev->power.links_count > 0;
|
||||
|
||||
if (dev->power.irq_safe) {
|
||||
spin_unlock(&dev->power.lock);
|
||||
} else if (!use_links) {
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
} else {
|
||||
get = dev->power.runtime_status == RPM_RESUMING;
|
||||
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
|
||||
/* Resume suppliers if necessary. */
|
||||
if (get) {
|
||||
/*
|
||||
* Resume suppliers if necessary.
|
||||
*
|
||||
* The device's runtime PM status cannot change until this
|
||||
* routine returns, so it is safe to read the status outside of
|
||||
* the lock.
|
||||
*/
|
||||
if (use_links && dev->power.runtime_status == RPM_RESUMING) {
|
||||
idx = device_links_read_lock();
|
||||
|
||||
retval = rpm_get_suppliers(dev);
|
||||
|
|
@ -355,36 +355,24 @@ static int __rpm_callback(int (*cb)(struct device *), struct device *dev)
|
|||
|
||||
if (dev->power.irq_safe) {
|
||||
spin_lock(&dev->power.lock);
|
||||
return retval;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* If the device is suspending and the callback has returned
|
||||
* success, drop the usage counters of the suppliers that have
|
||||
* been reference counted on its resume.
|
||||
*
|
||||
* Do that if resume fails too.
|
||||
*/
|
||||
if (use_links
|
||||
&& ((dev->power.runtime_status == RPM_SUSPENDING && !retval)
|
||||
|| (dev->power.runtime_status == RPM_RESUMING && retval))) {
|
||||
idx = device_links_read_lock();
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
fail:
|
||||
rpm_put_suppliers(dev);
|
||||
|
||||
if (!use_links)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* If the device is suspending and the callback has returned success,
|
||||
* drop the usage counters of the suppliers that have been reference
|
||||
* counted on its resume.
|
||||
*
|
||||
* Do that if the resume fails too.
|
||||
*/
|
||||
put = dev->power.runtime_status == RPM_SUSPENDING && !retval;
|
||||
if (put)
|
||||
__update_runtime_status(dev, RPM_SUSPENDED);
|
||||
else
|
||||
put = get && retval;
|
||||
|
||||
if (put) {
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
|
||||
idx = device_links_read_lock();
|
||||
|
||||
fail:
|
||||
rpm_put_suppliers(dev);
|
||||
|
||||
device_links_read_unlock(idx);
|
||||
device_links_read_unlock(idx);
|
||||
}
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -571,6 +571,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
struct lock_class_key *lock_key,
|
||||
struct lock_class_key *request_key)
|
||||
{
|
||||
struct fwnode_handle *fwnode = gc->parent ? dev_fwnode(gc->parent) : NULL;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
unsigned i;
|
||||
|
|
@ -594,6 +595,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
|||
|
||||
of_gpio_dev_init(gc, gdev);
|
||||
|
||||
/*
|
||||
* Assign fwnode depending on the result of the previous calls,
|
||||
* if none of them succeed, assign it to the parent's one.
|
||||
*/
|
||||
gdev->dev.fwnode = dev_fwnode(&gdev->dev) ?: fwnode;
|
||||
|
||||
gdev->id = ida_alloc(&gpio_ida, GFP_KERNEL);
|
||||
if (gdev->id < 0) {
|
||||
ret = gdev->id;
|
||||
|
|
@ -4256,7 +4263,8 @@ static int __init gpiolib_dev_init(void)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (driver_register(&gpio_stub_drv) < 0) {
|
||||
ret = driver_register(&gpio_stub_drv);
|
||||
if (ret < 0) {
|
||||
pr_err("gpiolib: could not register GPIO stub driver\n");
|
||||
bus_unregister(&gpio_bus_type);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -1507,38 +1507,8 @@ static void dcn20_update_dchubp_dpp(
|
|||
if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed
|
||||
|| pipe_ctx->stream->update_flags.bits.gamut_remap
|
||||
|| pipe_ctx->stream->update_flags.bits.out_csc) {
|
||||
struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
|
||||
|
||||
if (mpc->funcs->set_gamut_remap) {
|
||||
int i;
|
||||
int mpcc_id = hubp->inst;
|
||||
struct mpc_grph_gamut_adjustment adjust;
|
||||
bool enable_remap_dpp = false;
|
||||
|
||||
memset(&adjust, 0, sizeof(adjust));
|
||||
adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS;
|
||||
|
||||
/* save the enablement of gamut remap for dpp */
|
||||
enable_remap_dpp = pipe_ctx->stream->gamut_remap_matrix.enable_remap;
|
||||
|
||||
/* force bypass gamut remap for dpp/cm */
|
||||
pipe_ctx->stream->gamut_remap_matrix.enable_remap = false;
|
||||
dc->hwss.program_gamut_remap(pipe_ctx);
|
||||
|
||||
/* restore gamut remap flag and use this remap into mpc */
|
||||
pipe_ctx->stream->gamut_remap_matrix.enable_remap = enable_remap_dpp;
|
||||
|
||||
/* build remap matrix for top plane if enabled */
|
||||
if (enable_remap_dpp && pipe_ctx->top_pipe == NULL) {
|
||||
adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW;
|
||||
for (i = 0; i < CSC_TEMPERATURE_MATRIX_SIZE; i++)
|
||||
adjust.temperature_matrix[i] =
|
||||
pipe_ctx->stream->gamut_remap_matrix.matrix[i];
|
||||
}
|
||||
mpc->funcs->set_gamut_remap(mpc, mpcc_id, &adjust);
|
||||
} else
|
||||
/* dpp/cm gamut remap*/
|
||||
dc->hwss.program_gamut_remap(pipe_ctx);
|
||||
/* dpp/cm gamut remap*/
|
||||
dc->hwss.program_gamut_remap(pipe_ctx);
|
||||
|
||||
/*call the dcn2 method which uses mpc csc*/
|
||||
dc->hwss.program_output_csc(dc,
|
||||
|
|
|
|||
|
|
@ -1595,6 +1595,11 @@ static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_param
|
|||
dcn2_1_soc.num_chans = bw_params->num_channels;
|
||||
|
||||
ASSERT(clk_table->num_entries);
|
||||
/* Copy dcn2_1_soc.clock_limits to clock_limits to avoid copying over null states later */
|
||||
for (i = 0; i < dcn2_1_soc.num_states + 1; i++) {
|
||||
clock_limits[i] = dcn2_1_soc.clock_limits[i];
|
||||
}
|
||||
|
||||
for (i = 0; i < clk_table->num_entries; i++) {
|
||||
/* loop backwards*/
|
||||
for (closest_clk_lvl = 0, j = dcn2_1_soc.num_states - 1; j >= 0; j--) {
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ bool cm3_helper_translate_curve_to_hw_format(
|
|||
struct pwl_result_data *rgb_resulted;
|
||||
struct pwl_result_data *rgb;
|
||||
struct pwl_result_data *rgb_plus_1;
|
||||
struct pwl_result_data *rgb_minus_1;
|
||||
struct fixed31_32 end_value;
|
||||
|
||||
int32_t region_start, region_end;
|
||||
|
|
@ -140,7 +141,7 @@ bool cm3_helper_translate_curve_to_hw_format(
|
|||
region_start = -MAX_LOW_POINT;
|
||||
region_end = NUMBER_REGIONS - MAX_LOW_POINT;
|
||||
} else {
|
||||
/* 10 segments
|
||||
/* 11 segments
|
||||
* segment is from 2^-10 to 2^0
|
||||
* There are less than 256 points, for optimization
|
||||
*/
|
||||
|
|
@ -154,9 +155,10 @@ bool cm3_helper_translate_curve_to_hw_format(
|
|||
seg_distr[7] = 4;
|
||||
seg_distr[8] = 4;
|
||||
seg_distr[9] = 4;
|
||||
seg_distr[10] = 1;
|
||||
|
||||
region_start = -10;
|
||||
region_end = 0;
|
||||
region_end = 1;
|
||||
}
|
||||
|
||||
for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++)
|
||||
|
|
@ -189,6 +191,10 @@ bool cm3_helper_translate_curve_to_hw_format(
|
|||
rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index];
|
||||
rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index];
|
||||
|
||||
rgb_resulted[hw_points].red = rgb_resulted[hw_points - 1].red;
|
||||
rgb_resulted[hw_points].green = rgb_resulted[hw_points - 1].green;
|
||||
rgb_resulted[hw_points].blue = rgb_resulted[hw_points - 1].blue;
|
||||
|
||||
// All 3 color channels have same x
|
||||
corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2),
|
||||
dc_fixpt_from_int(region_start));
|
||||
|
|
@ -259,15 +265,18 @@ bool cm3_helper_translate_curve_to_hw_format(
|
|||
|
||||
rgb = rgb_resulted;
|
||||
rgb_plus_1 = rgb_resulted + 1;
|
||||
rgb_minus_1 = rgb;
|
||||
|
||||
i = 1;
|
||||
while (i != hw_points + 1) {
|
||||
if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
|
||||
rgb_plus_1->red = rgb->red;
|
||||
if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
|
||||
rgb_plus_1->green = rgb->green;
|
||||
if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
|
||||
rgb_plus_1->blue = rgb->blue;
|
||||
if (i >= hw_points - 1) {
|
||||
if (dc_fixpt_lt(rgb_plus_1->red, rgb->red))
|
||||
rgb_plus_1->red = dc_fixpt_add(rgb->red, rgb_minus_1->delta_red);
|
||||
if (dc_fixpt_lt(rgb_plus_1->green, rgb->green))
|
||||
rgb_plus_1->green = dc_fixpt_add(rgb->green, rgb_minus_1->delta_green);
|
||||
if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue))
|
||||
rgb_plus_1->blue = dc_fixpt_add(rgb->blue, rgb_minus_1->delta_blue);
|
||||
}
|
||||
|
||||
rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red);
|
||||
rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green);
|
||||
|
|
@ -283,6 +292,7 @@ bool cm3_helper_translate_curve_to_hw_format(
|
|||
}
|
||||
|
||||
++rgb_plus_1;
|
||||
rgb_minus_1 = rgb;
|
||||
++rgb;
|
||||
++i;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -603,7 +603,6 @@ static int append_oa_sample(struct i915_perf_stream *stream,
|
|||
{
|
||||
int report_size = stream->oa_buffer.format_size;
|
||||
struct drm_i915_perf_record_header header;
|
||||
u32 sample_flags = stream->sample_flags;
|
||||
|
||||
header.type = DRM_I915_PERF_RECORD_SAMPLE;
|
||||
header.pad = 0;
|
||||
|
|
@ -617,10 +616,8 @@ static int append_oa_sample(struct i915_perf_stream *stream,
|
|||
return -EFAULT;
|
||||
buf += sizeof(header);
|
||||
|
||||
if (sample_flags & SAMPLE_OA_REPORT) {
|
||||
if (copy_to_user(buf, report, report_size))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (copy_to_user(buf, report, report_size))
|
||||
return -EFAULT;
|
||||
|
||||
(*offset) += header.size;
|
||||
|
||||
|
|
@ -2682,7 +2679,7 @@ static void i915_oa_stream_enable(struct i915_perf_stream *stream)
|
|||
|
||||
stream->perf->ops.oa_enable(stream);
|
||||
|
||||
if (stream->periodic)
|
||||
if (stream->sample_flags & SAMPLE_OA_REPORT)
|
||||
hrtimer_start(&stream->poll_check_timer,
|
||||
ns_to_ktime(stream->poll_oa_period),
|
||||
HRTIMER_MODE_REL_PINNED);
|
||||
|
|
@ -2745,7 +2742,7 @@ static void i915_oa_stream_disable(struct i915_perf_stream *stream)
|
|||
{
|
||||
stream->perf->ops.oa_disable(stream);
|
||||
|
||||
if (stream->periodic)
|
||||
if (stream->sample_flags & SAMPLE_OA_REPORT)
|
||||
hrtimer_cancel(&stream->poll_check_timer);
|
||||
}
|
||||
|
||||
|
|
@ -3028,7 +3025,7 @@ static ssize_t i915_perf_read(struct file *file,
|
|||
* disabled stream as an error. In particular it might otherwise lead
|
||||
* to a deadlock for blocking file descriptors...
|
||||
*/
|
||||
if (!stream->enabled)
|
||||
if (!stream->enabled || !(stream->sample_flags & SAMPLE_OA_REPORT))
|
||||
return -EIO;
|
||||
|
||||
if (!(file->f_flags & O_NONBLOCK)) {
|
||||
|
|
|
|||
|
|
@ -3316,7 +3316,18 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
|
|||
|
||||
#define ILK_DISPLAY_CHICKEN1 _MMIO(0x42000)
|
||||
#define ILK_FBCQ_DIS (1 << 22)
|
||||
#define ILK_PABSTRETCH_DIS (1 << 21)
|
||||
#define ILK_PABSTRETCH_DIS REG_BIT(21)
|
||||
#define ILK_SABSTRETCH_DIS REG_BIT(20)
|
||||
#define IVB_PRI_STRETCH_MAX_MASK REG_GENMASK(21, 20)
|
||||
#define IVB_PRI_STRETCH_MAX_X8 REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 0)
|
||||
#define IVB_PRI_STRETCH_MAX_X4 REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 1)
|
||||
#define IVB_PRI_STRETCH_MAX_X2 REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 2)
|
||||
#define IVB_PRI_STRETCH_MAX_X1 REG_FIELD_PREP(IVB_PRI_STRETCH_MAX_MASK, 3)
|
||||
#define IVB_SPR_STRETCH_MAX_MASK REG_GENMASK(19, 18)
|
||||
#define IVB_SPR_STRETCH_MAX_X8 REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 0)
|
||||
#define IVB_SPR_STRETCH_MAX_X4 REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 1)
|
||||
#define IVB_SPR_STRETCH_MAX_X2 REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 2)
|
||||
#define IVB_SPR_STRETCH_MAX_X1 REG_FIELD_PREP(IVB_SPR_STRETCH_MAX_MASK, 3)
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -8039,6 +8050,16 @@ enum {
|
|||
|
||||
#define _CHICKEN_PIPESL_1_A 0x420b0
|
||||
#define _CHICKEN_PIPESL_1_B 0x420b4
|
||||
#define HSW_PRI_STRETCH_MAX_MASK REG_GENMASK(28, 27)
|
||||
#define HSW_PRI_STRETCH_MAX_X8 REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 0)
|
||||
#define HSW_PRI_STRETCH_MAX_X4 REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 1)
|
||||
#define HSW_PRI_STRETCH_MAX_X2 REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 2)
|
||||
#define HSW_PRI_STRETCH_MAX_X1 REG_FIELD_PREP(HSW_PRI_STRETCH_MAX_MASK, 3)
|
||||
#define HSW_SPR_STRETCH_MAX_MASK REG_GENMASK(26, 25)
|
||||
#define HSW_SPR_STRETCH_MAX_X8 REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 0)
|
||||
#define HSW_SPR_STRETCH_MAX_X4 REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 1)
|
||||
#define HSW_SPR_STRETCH_MAX_X2 REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 2)
|
||||
#define HSW_SPR_STRETCH_MAX_X1 REG_FIELD_PREP(HSW_SPR_STRETCH_MAX_MASK, 3)
|
||||
#define HSW_FBCQ_DIS (1 << 22)
|
||||
#define BDW_DPRS_MASK_VBLANK_SRD (1 << 0)
|
||||
#define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)
|
||||
|
|
|
|||
|
|
@ -7245,11 +7245,16 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv)
|
|||
intel_uncore_write(&dev_priv->uncore, CHICKEN_PAR1_1,
|
||||
intel_uncore_read(&dev_priv->uncore, CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD);
|
||||
|
||||
/* WaPsrDPRSUnmaskVBlankInSRD:bdw */
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
/* WaPsrDPRSUnmaskVBlankInSRD:bdw */
|
||||
intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe),
|
||||
intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe)) |
|
||||
BDW_DPRS_MASK_VBLANK_SRD);
|
||||
|
||||
/* Undocumented but fixes async flip + VT-d corruption */
|
||||
if (intel_vtd_active())
|
||||
intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe),
|
||||
HSW_PRI_STRETCH_MAX_MASK, HSW_PRI_STRETCH_MAX_X1);
|
||||
}
|
||||
|
||||
/* WaVSRefCountFullforceMissDisable:bdw */
|
||||
|
|
@ -7285,11 +7290,20 @@ static void bdw_init_clock_gating(struct drm_i915_private *dev_priv)
|
|||
|
||||
static void hsw_init_clock_gating(struct drm_i915_private *dev_priv)
|
||||
{
|
||||
enum pipe pipe;
|
||||
|
||||
/* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
|
||||
intel_uncore_write(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A),
|
||||
intel_uncore_read(&dev_priv->uncore, CHICKEN_PIPESL_1(PIPE_A)) |
|
||||
HSW_FBCQ_DIS);
|
||||
|
||||
for_each_pipe(dev_priv, pipe) {
|
||||
/* Undocumented but fixes async flip + VT-d corruption */
|
||||
if (intel_vtd_active())
|
||||
intel_uncore_rmw(&dev_priv->uncore, CHICKEN_PIPESL_1(pipe),
|
||||
HSW_PRI_STRETCH_MAX_MASK, HSW_PRI_STRETCH_MAX_X1);
|
||||
}
|
||||
|
||||
/* This is required by WaCatErrorRejectionIssue:hsw */
|
||||
intel_uncore_write(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
|
||||
intel_uncore_read(&dev_priv->uncore, GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
|
||||
|
|
|
|||
|
|
@ -551,6 +551,10 @@ nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
|
|||
|
||||
if (!ttm_dma)
|
||||
return;
|
||||
if (!ttm_dma->pages) {
|
||||
NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't waste time looping if the object is coherent */
|
||||
if (nvbo->force_coherent)
|
||||
|
|
@ -583,6 +587,10 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
|
|||
|
||||
if (!ttm_dma)
|
||||
return;
|
||||
if (!ttm_dma->pages) {
|
||||
NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't waste time looping if the object is coherent */
|
||||
if (nvbo->force_coherent)
|
||||
|
|
|
|||
|
|
@ -2149,11 +2149,12 @@ static int dsi_vc_send_short(struct dsi_data *dsi, int vc,
|
|||
const struct mipi_dsi_msg *msg)
|
||||
{
|
||||
struct mipi_dsi_packet pkt;
|
||||
int ret;
|
||||
u32 r;
|
||||
|
||||
r = mipi_dsi_create_packet(&pkt, msg);
|
||||
if (r < 0)
|
||||
return r;
|
||||
ret = mipi_dsi_create_packet(&pkt, msg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
WARN_ON(!dsi_bus_is_locked(dsi));
|
||||
|
||||
|
|
|
|||
|
|
@ -2714,7 +2714,6 @@ static int __init early_amd_iommu_init(void)
|
|||
struct acpi_table_header *ivrs_base;
|
||||
int i, remap_cache_sz, ret;
|
||||
acpi_status status;
|
||||
u32 pci_id;
|
||||
|
||||
if (!amd_iommu_detected)
|
||||
return -ENODEV;
|
||||
|
|
@ -2804,16 +2803,6 @@ static int __init early_amd_iommu_init(void)
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Disable IOMMU if there's Stoney Ridge graphics */
|
||||
for (i = 0; i < 32; i++) {
|
||||
pci_id = read_pci_config(0, i, 0, 0);
|
||||
if ((pci_id & 0xffff) == 0x1002 && (pci_id >> 16) == 0x98e4) {
|
||||
pr_info("Disable IOMMU on Stoney Ridge\n");
|
||||
amd_iommu_disabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable any previously enabled IOMMUs */
|
||||
if (!is_kdump_kernel() || amd_iommu_disabled)
|
||||
disable_iommus();
|
||||
|
|
@ -2880,6 +2869,7 @@ static bool detect_ivrs(void)
|
|||
{
|
||||
struct acpi_table_header *ivrs_base;
|
||||
acpi_status status;
|
||||
int i;
|
||||
|
||||
status = acpi_get_table("IVRS", 0, &ivrs_base);
|
||||
if (status == AE_NOT_FOUND)
|
||||
|
|
@ -2892,6 +2882,17 @@ static bool detect_ivrs(void)
|
|||
|
||||
acpi_put_table(ivrs_base);
|
||||
|
||||
/* Don't use IOMMU if there is Stoney Ridge graphics */
|
||||
for (i = 0; i < 32; i++) {
|
||||
u32 pci_id;
|
||||
|
||||
pci_id = read_pci_config(0, i, 0, 0);
|
||||
if ((pci_id & 0xffff) == 0x1002 && (pci_id >> 16) == 0x98e4) {
|
||||
pr_info("Disable IOMMU on Stoney Ridge\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure ACS will be enabled during PCI probe */
|
||||
pci_request_acs();
|
||||
|
||||
|
|
@ -2918,12 +2919,12 @@ static int __init state_next(void)
|
|||
}
|
||||
break;
|
||||
case IOMMU_IVRS_DETECTED:
|
||||
ret = early_amd_iommu_init();
|
||||
init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED;
|
||||
if (init_state == IOMMU_ACPI_FINISHED && amd_iommu_disabled) {
|
||||
pr_info("AMD IOMMU disabled\n");
|
||||
if (amd_iommu_disabled) {
|
||||
init_state = IOMMU_CMDLINE_DISABLED;
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
ret = early_amd_iommu_init();
|
||||
init_state = ret ? IOMMU_INIT_ERROR : IOMMU_ACPI_FINISHED;
|
||||
}
|
||||
break;
|
||||
case IOMMU_ACPI_FINISHED:
|
||||
|
|
@ -3001,8 +3002,11 @@ int __init amd_iommu_prepare(void)
|
|||
amd_iommu_irq_remap = true;
|
||||
|
||||
ret = iommu_go_to_state(IOMMU_ACPI_FINISHED);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
amd_iommu_irq_remap = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return amd_iommu_irq_remap ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -849,12 +849,11 @@ static struct iommu_device *tegra_smmu_probe_device(struct device *dev)
|
|||
smmu = tegra_smmu_find(args.np);
|
||||
if (smmu) {
|
||||
err = tegra_smmu_configure(smmu, dev, &args);
|
||||
of_node_put(args.np);
|
||||
|
||||
if (err < 0)
|
||||
if (err < 0) {
|
||||
of_node_put(args.np);
|
||||
return ERR_PTR(err);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
of_node_put(args.np);
|
||||
|
|
|
|||
|
|
@ -1226,28 +1226,12 @@ static void nvme_keep_alive_end_io(struct request *rq, blk_status_t status)
|
|||
queue_delayed_work(nvme_wq, &ctrl->ka_work, ctrl->kato * HZ);
|
||||
}
|
||||
|
||||
static int nvme_keep_alive(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
struct request *rq;
|
||||
|
||||
rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd,
|
||||
BLK_MQ_REQ_RESERVED);
|
||||
if (IS_ERR(rq))
|
||||
return PTR_ERR(rq);
|
||||
|
||||
rq->timeout = ctrl->kato * HZ;
|
||||
rq->end_io_data = ctrl;
|
||||
|
||||
blk_execute_rq_nowait(NULL, rq, 0, nvme_keep_alive_end_io);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nvme_keep_alive_work(struct work_struct *work)
|
||||
{
|
||||
struct nvme_ctrl *ctrl = container_of(to_delayed_work(work),
|
||||
struct nvme_ctrl, ka_work);
|
||||
bool comp_seen = ctrl->comp_seen;
|
||||
struct request *rq;
|
||||
|
||||
if ((ctrl->ctratt & NVME_CTRL_ATTR_TBKAS) && comp_seen) {
|
||||
dev_dbg(ctrl->device,
|
||||
|
|
@ -1257,12 +1241,18 @@ static void nvme_keep_alive_work(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
if (nvme_keep_alive(ctrl)) {
|
||||
rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd,
|
||||
BLK_MQ_REQ_RESERVED | BLK_MQ_REQ_NOWAIT);
|
||||
if (IS_ERR(rq)) {
|
||||
/* allocation failure, reset the controller */
|
||||
dev_err(ctrl->device, "keep-alive failed\n");
|
||||
dev_err(ctrl->device, "keep-alive failed: %ld\n", PTR_ERR(rq));
|
||||
nvme_reset_ctrl(ctrl);
|
||||
return;
|
||||
}
|
||||
|
||||
rq->timeout = ctrl->kato * HZ;
|
||||
rq->end_io_data = ctrl;
|
||||
blk_execute_rq_nowait(NULL, rq, 0, nvme_keep_alive_end_io);
|
||||
}
|
||||
|
||||
static void nvme_start_keep_alive(struct nvme_ctrl *ctrl)
|
||||
|
|
@ -1964,30 +1954,18 @@ static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns)
|
|||
blk_queue_max_write_zeroes_sectors(queue, UINT_MAX);
|
||||
}
|
||||
|
||||
static void nvme_config_write_zeroes(struct gendisk *disk, struct nvme_ns *ns)
|
||||
/*
|
||||
* Even though NVMe spec explicitly states that MDTS is not applicable to the
|
||||
* write-zeroes, we are cautious and limit the size to the controllers
|
||||
* max_hw_sectors value, which is based on the MDTS field and possibly other
|
||||
* limiting factors.
|
||||
*/
|
||||
static void nvme_config_write_zeroes(struct request_queue *q,
|
||||
struct nvme_ctrl *ctrl)
|
||||
{
|
||||
u64 max_blocks;
|
||||
|
||||
if (!(ns->ctrl->oncs & NVME_CTRL_ONCS_WRITE_ZEROES) ||
|
||||
(ns->ctrl->quirks & NVME_QUIRK_DISABLE_WRITE_ZEROES))
|
||||
return;
|
||||
/*
|
||||
* Even though NVMe spec explicitly states that MDTS is not
|
||||
* applicable to the write-zeroes:- "The restriction does not apply to
|
||||
* commands that do not transfer data between the host and the
|
||||
* controller (e.g., Write Uncorrectable ro Write Zeroes command).".
|
||||
* In order to be more cautious use controller's max_hw_sectors value
|
||||
* to configure the maximum sectors for the write-zeroes which is
|
||||
* configured based on the controller's MDTS field in the
|
||||
* nvme_init_identify() if available.
|
||||
*/
|
||||
if (ns->ctrl->max_hw_sectors == UINT_MAX)
|
||||
max_blocks = (u64)USHRT_MAX + 1;
|
||||
else
|
||||
max_blocks = ns->ctrl->max_hw_sectors + 1;
|
||||
|
||||
blk_queue_max_write_zeroes_sectors(disk->queue,
|
||||
nvme_lba_to_sect(ns, max_blocks));
|
||||
if ((ctrl->oncs & NVME_CTRL_ONCS_WRITE_ZEROES) &&
|
||||
!(ctrl->quirks & NVME_QUIRK_DISABLE_WRITE_ZEROES))
|
||||
blk_queue_max_write_zeroes_sectors(q, ctrl->max_hw_sectors);
|
||||
}
|
||||
|
||||
static bool nvme_ns_ids_valid(struct nvme_ns_ids *ids)
|
||||
|
|
@ -2159,7 +2137,7 @@ static void nvme_update_disk_info(struct gendisk *disk,
|
|||
set_capacity_and_notify(disk, capacity);
|
||||
|
||||
nvme_config_discard(disk, ns);
|
||||
nvme_config_write_zeroes(disk, ns);
|
||||
nvme_config_write_zeroes(disk->queue, ns->ctrl);
|
||||
|
||||
set_disk_ro(disk, (id->nsattr & NVME_NS_ATTR_RO) ||
|
||||
test_bit(NVME_NS_FORCE_RO, &ns->flags));
|
||||
|
|
|
|||
|
|
@ -18,6 +18,13 @@
|
|||
/* default is -1: the fail fast mechanism is disabled */
|
||||
#define NVMF_DEF_FAIL_FAST_TMO -1
|
||||
|
||||
/*
|
||||
* Reserved one command for internal usage. This command is used for sending
|
||||
* the connect command, as well as for the keep alive command on the admin
|
||||
* queue once live.
|
||||
*/
|
||||
#define NVMF_RESERVED_TAGS 1
|
||||
|
||||
/*
|
||||
* Define a host as seen by the target. We allocate one at boot, but also
|
||||
* allow the override it when creating controllers. This is both to provide
|
||||
|
|
|
|||
|
|
@ -2863,7 +2863,7 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl)
|
|||
memset(&ctrl->tag_set, 0, sizeof(ctrl->tag_set));
|
||||
ctrl->tag_set.ops = &nvme_fc_mq_ops;
|
||||
ctrl->tag_set.queue_depth = ctrl->ctrl.opts->queue_size;
|
||||
ctrl->tag_set.reserved_tags = 1; /* fabric connect */
|
||||
ctrl->tag_set.reserved_tags = NVMF_RESERVED_TAGS;
|
||||
ctrl->tag_set.numa_node = ctrl->ctrl.numa_node;
|
||||
ctrl->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
|
||||
ctrl->tag_set.cmd_size =
|
||||
|
|
@ -3485,7 +3485,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
|
|||
memset(&ctrl->admin_tag_set, 0, sizeof(ctrl->admin_tag_set));
|
||||
ctrl->admin_tag_set.ops = &nvme_fc_admin_mq_ops;
|
||||
ctrl->admin_tag_set.queue_depth = NVME_AQ_MQ_TAG_DEPTH;
|
||||
ctrl->admin_tag_set.reserved_tags = 2; /* fabric connect + Keep-Alive */
|
||||
ctrl->admin_tag_set.reserved_tags = NVMF_RESERVED_TAGS;
|
||||
ctrl->admin_tag_set.numa_node = ctrl->ctrl.numa_node;
|
||||
ctrl->admin_tag_set.cmd_size =
|
||||
struct_size((struct nvme_fcp_op_w_sgl *)NULL, priv,
|
||||
|
|
|
|||
|
|
@ -736,8 +736,11 @@ static int nvme_rdma_alloc_io_queues(struct nvme_rdma_ctrl *ctrl)
|
|||
return ret;
|
||||
|
||||
ctrl->ctrl.queue_count = nr_io_queues + 1;
|
||||
if (ctrl->ctrl.queue_count < 2)
|
||||
return 0;
|
||||
if (ctrl->ctrl.queue_count < 2) {
|
||||
dev_err(ctrl->ctrl.device,
|
||||
"unable to set any I/O queues\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_info(ctrl->ctrl.device,
|
||||
"creating %d I/O queues.\n", nr_io_queues);
|
||||
|
|
@ -798,7 +801,7 @@ static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl,
|
|||
memset(set, 0, sizeof(*set));
|
||||
set->ops = &nvme_rdma_admin_mq_ops;
|
||||
set->queue_depth = NVME_AQ_MQ_TAG_DEPTH;
|
||||
set->reserved_tags = 2; /* connect + keep-alive */
|
||||
set->reserved_tags = NVMF_RESERVED_TAGS;
|
||||
set->numa_node = nctrl->numa_node;
|
||||
set->cmd_size = sizeof(struct nvme_rdma_request) +
|
||||
NVME_RDMA_DATA_SGL_SIZE;
|
||||
|
|
@ -811,7 +814,7 @@ static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl,
|
|||
memset(set, 0, sizeof(*set));
|
||||
set->ops = &nvme_rdma_mq_ops;
|
||||
set->queue_depth = nctrl->sqsize + 1;
|
||||
set->reserved_tags = 1; /* fabric connect */
|
||||
set->reserved_tags = NVMF_RESERVED_TAGS;
|
||||
set->numa_node = nctrl->numa_node;
|
||||
set->flags = BLK_MQ_F_SHOULD_MERGE;
|
||||
set->cmd_size = sizeof(struct nvme_rdma_request) +
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,
|
|||
* directly, otherwise queue io_work. Also, only do that if we
|
||||
* are on the same cpu, so we don't introduce contention.
|
||||
*/
|
||||
if (queue->io_cpu == __smp_processor_id() &&
|
||||
if (queue->io_cpu == raw_smp_processor_id() &&
|
||||
sync && empty && mutex_trylock(&queue->send_mutex)) {
|
||||
queue->more_requests = !last;
|
||||
nvme_tcp_send_all(queue);
|
||||
|
|
@ -568,6 +568,13 @@ static int nvme_tcp_setup_h2c_data_pdu(struct nvme_tcp_request *req,
|
|||
req->pdu_len = le32_to_cpu(pdu->r2t_length);
|
||||
req->pdu_sent = 0;
|
||||
|
||||
if (unlikely(!req->pdu_len)) {
|
||||
dev_err(queue->ctrl->ctrl.device,
|
||||
"req %d r2t len is %u, probably a bug...\n",
|
||||
rq->tag, req->pdu_len);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
if (unlikely(req->data_sent + req->pdu_len > req->data_len)) {
|
||||
dev_err(queue->ctrl->ctrl.device,
|
||||
"req %d r2t len %u exceeded data len %u (%zu sent)\n",
|
||||
|
|
@ -1575,7 +1582,7 @@ static struct blk_mq_tag_set *nvme_tcp_alloc_tagset(struct nvme_ctrl *nctrl,
|
|||
memset(set, 0, sizeof(*set));
|
||||
set->ops = &nvme_tcp_admin_mq_ops;
|
||||
set->queue_depth = NVME_AQ_MQ_TAG_DEPTH;
|
||||
set->reserved_tags = 2; /* connect + keep-alive */
|
||||
set->reserved_tags = NVMF_RESERVED_TAGS;
|
||||
set->numa_node = nctrl->numa_node;
|
||||
set->flags = BLK_MQ_F_BLOCKING;
|
||||
set->cmd_size = sizeof(struct nvme_tcp_request);
|
||||
|
|
@ -1587,7 +1594,7 @@ static struct blk_mq_tag_set *nvme_tcp_alloc_tagset(struct nvme_ctrl *nctrl,
|
|||
memset(set, 0, sizeof(*set));
|
||||
set->ops = &nvme_tcp_mq_ops;
|
||||
set->queue_depth = nctrl->sqsize + 1;
|
||||
set->reserved_tags = 1; /* fabric connect */
|
||||
set->reserved_tags = NVMF_RESERVED_TAGS;
|
||||
set->numa_node = nctrl->numa_node;
|
||||
set->flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_BLOCKING;
|
||||
set->cmd_size = sizeof(struct nvme_tcp_request);
|
||||
|
|
@ -1745,8 +1752,11 @@ static int nvme_tcp_alloc_io_queues(struct nvme_ctrl *ctrl)
|
|||
return ret;
|
||||
|
||||
ctrl->queue_count = nr_io_queues + 1;
|
||||
if (ctrl->queue_count < 2)
|
||||
return 0;
|
||||
if (ctrl->queue_count < 2) {
|
||||
dev_err(ctrl->device,
|
||||
"unable to set any I/O queues\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_info(ctrl->device,
|
||||
"creating %d I/O queues.\n", nr_io_queues);
|
||||
|
|
|
|||
|
|
@ -1118,9 +1118,20 @@ static void nvmet_start_ctrl(struct nvmet_ctrl *ctrl)
|
|||
{
|
||||
lockdep_assert_held(&ctrl->lock);
|
||||
|
||||
if (nvmet_cc_iosqes(ctrl->cc) != NVME_NVM_IOSQES ||
|
||||
nvmet_cc_iocqes(ctrl->cc) != NVME_NVM_IOCQES ||
|
||||
nvmet_cc_mps(ctrl->cc) != 0 ||
|
||||
/*
|
||||
* Only I/O controllers should verify iosqes,iocqes.
|
||||
* Strictly speaking, the spec says a discovery controller
|
||||
* should verify iosqes,iocqes are zeroed, however that
|
||||
* would break backwards compatibility, so don't enforce it.
|
||||
*/
|
||||
if (ctrl->subsys->type != NVME_NQN_DISC &&
|
||||
(nvmet_cc_iosqes(ctrl->cc) != NVME_NVM_IOSQES ||
|
||||
nvmet_cc_iocqes(ctrl->cc) != NVME_NVM_IOCQES)) {
|
||||
ctrl->csts = NVME_CSTS_CFS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (nvmet_cc_mps(ctrl->cc) != 0 ||
|
||||
nvmet_cc_ams(ctrl->cc) != 0 ||
|
||||
nvmet_cc_css(ctrl->cc) != 0) {
|
||||
ctrl->csts = NVME_CSTS_CFS;
|
||||
|
|
|
|||
|
|
@ -349,7 +349,7 @@ static int nvme_loop_configure_admin_queue(struct nvme_loop_ctrl *ctrl)
|
|||
memset(&ctrl->admin_tag_set, 0, sizeof(ctrl->admin_tag_set));
|
||||
ctrl->admin_tag_set.ops = &nvme_loop_admin_mq_ops;
|
||||
ctrl->admin_tag_set.queue_depth = NVME_AQ_MQ_TAG_DEPTH;
|
||||
ctrl->admin_tag_set.reserved_tags = 2; /* connect + keep-alive */
|
||||
ctrl->admin_tag_set.reserved_tags = NVMF_RESERVED_TAGS;
|
||||
ctrl->admin_tag_set.numa_node = ctrl->ctrl.numa_node;
|
||||
ctrl->admin_tag_set.cmd_size = sizeof(struct nvme_loop_iod) +
|
||||
NVME_INLINE_SG_CNT * sizeof(struct scatterlist);
|
||||
|
|
@ -520,7 +520,7 @@ static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl)
|
|||
memset(&ctrl->tag_set, 0, sizeof(ctrl->tag_set));
|
||||
ctrl->tag_set.ops = &nvme_loop_mq_ops;
|
||||
ctrl->tag_set.queue_depth = ctrl->ctrl.opts->queue_size;
|
||||
ctrl->tag_set.reserved_tags = 1; /* fabric connect */
|
||||
ctrl->tag_set.reserved_tags = NVMF_RESERVED_TAGS;
|
||||
ctrl->tag_set.numa_node = ctrl->ctrl.numa_node;
|
||||
ctrl->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
|
||||
ctrl->tag_set.cmd_size = sizeof(struct nvme_loop_iod) +
|
||||
|
|
|
|||
|
|
@ -1098,11 +1098,11 @@ static int nvmet_tcp_try_recv_data(struct nvmet_tcp_queue *queue)
|
|||
cmd->rbytes_done += ret;
|
||||
}
|
||||
|
||||
nvmet_tcp_unmap_pdu_iovec(cmd);
|
||||
if (queue->data_digest) {
|
||||
nvmet_tcp_prep_recv_ddgst(cmd);
|
||||
return 0;
|
||||
}
|
||||
nvmet_tcp_unmap_pdu_iovec(cmd);
|
||||
|
||||
if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED) &&
|
||||
cmd->rbytes_done == cmd->req.transfer_len) {
|
||||
|
|
|
|||
|
|
@ -93,8 +93,9 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
|
|||
pci_dev_put(pdev);
|
||||
return -EBUSY;
|
||||
}
|
||||
pci_dev_put(pdev);
|
||||
|
||||
zpci_remove_device(zdev);
|
||||
zpci_remove_device(zdev, false);
|
||||
|
||||
rc = zpci_disable_device(zdev);
|
||||
if (rc)
|
||||
|
|
|
|||
|
|
@ -1433,6 +1433,7 @@ static int cqspi_probe(struct platform_device *pdev)
|
|||
cqspi = spi_master_get_devdata(master);
|
||||
|
||||
cqspi->pdev = pdev;
|
||||
platform_set_drvdata(pdev, cqspi);
|
||||
|
||||
/* Obtain configuration from OF. */
|
||||
ret = cqspi_of_get_pdata(cqspi);
|
||||
|
|
|
|||
|
|
@ -431,8 +431,7 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
}
|
||||
|
||||
adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa,
|
||||
dev, &ifc_vdpa_ops,
|
||||
IFCVF_MAX_QUEUE_PAIRS * 2, NULL);
|
||||
dev, &ifc_vdpa_ops, NULL);
|
||||
if (adapter == NULL) {
|
||||
IFCVF_ERR(pdev, "Failed to allocate vDPA structure");
|
||||
return -ENOMEM;
|
||||
|
|
@ -456,7 +455,7 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
for (i = 0; i < IFCVF_MAX_QUEUE_PAIRS * 2; i++)
|
||||
vf->vring[i].irq = -EINVAL;
|
||||
|
||||
ret = vdpa_register_device(&adapter->vdpa);
|
||||
ret = vdpa_register_device(&adapter->vdpa, IFCVF_MAX_QUEUE_PAIRS * 2);
|
||||
if (ret) {
|
||||
IFCVF_ERR(pdev, "Failed to register ifcvf to vdpa bus");
|
||||
goto err;
|
||||
|
|
|
|||
|
|
@ -1982,7 +1982,7 @@ static int mlx5v_probe(struct auxiliary_device *adev,
|
|||
max_vqs = min_t(u32, max_vqs, MLX5_MAX_SUPPORTED_VQS);
|
||||
|
||||
ndev = vdpa_alloc_device(struct mlx5_vdpa_net, mvdev.vdev, mdev->device, &mlx5_vdpa_ops,
|
||||
2 * mlx5_vdpa_max_qps(max_vqs), NULL);
|
||||
NULL);
|
||||
if (IS_ERR(ndev))
|
||||
return PTR_ERR(ndev);
|
||||
|
||||
|
|
@ -2009,7 +2009,7 @@ static int mlx5v_probe(struct auxiliary_device *adev,
|
|||
if (err)
|
||||
goto err_res;
|
||||
|
||||
err = vdpa_register_device(&mvdev->vdev);
|
||||
err = vdpa_register_device(&mvdev->vdev, 2 * mlx5_vdpa_max_qps(max_vqs));
|
||||
if (err)
|
||||
goto err_reg;
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ static void vdpa_release_dev(struct device *d)
|
|||
* initialized but before registered.
|
||||
* @parent: the parent device
|
||||
* @config: the bus operations that is supported by this device
|
||||
* @nvqs: number of virtqueues supported by this device
|
||||
* @size: size of the parent structure that contains private data
|
||||
* @name: name of the vdpa device; optional.
|
||||
*
|
||||
|
|
@ -81,7 +80,7 @@ static void vdpa_release_dev(struct device *d)
|
|||
*/
|
||||
struct vdpa_device *__vdpa_alloc_device(struct device *parent,
|
||||
const struct vdpa_config_ops *config,
|
||||
int nvqs, size_t size, const char *name)
|
||||
size_t size, const char *name)
|
||||
{
|
||||
struct vdpa_device *vdev;
|
||||
int err = -EINVAL;
|
||||
|
|
@ -107,7 +106,6 @@ struct vdpa_device *__vdpa_alloc_device(struct device *parent,
|
|||
vdev->index = err;
|
||||
vdev->config = config;
|
||||
vdev->features_valid = false;
|
||||
vdev->nvqs = nvqs;
|
||||
|
||||
if (name)
|
||||
err = dev_set_name(&vdev->dev, "%s", name);
|
||||
|
|
@ -136,10 +134,12 @@ static int vdpa_name_match(struct device *dev, const void *data)
|
|||
return (strcmp(dev_name(&vdev->dev), data) == 0);
|
||||
}
|
||||
|
||||
static int __vdpa_register_device(struct vdpa_device *vdev)
|
||||
static int __vdpa_register_device(struct vdpa_device *vdev, int nvqs)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
vdev->nvqs = nvqs;
|
||||
|
||||
lockdep_assert_held(&vdpa_dev_mutex);
|
||||
dev = bus_find_device(&vdpa_bus, NULL, dev_name(&vdev->dev), vdpa_name_match);
|
||||
if (dev) {
|
||||
|
|
@ -155,15 +155,16 @@ static int __vdpa_register_device(struct vdpa_device *vdev)
|
|||
* Caller must invoke this routine in the management device dev_add()
|
||||
* callback after setting up valid mgmtdev for this vdpa device.
|
||||
* @vdev: the vdpa device to be registered to vDPA bus
|
||||
* @nvqs: number of virtqueues supported by this device
|
||||
*
|
||||
* Returns an error when fail to add device to vDPA bus
|
||||
*/
|
||||
int _vdpa_register_device(struct vdpa_device *vdev)
|
||||
int _vdpa_register_device(struct vdpa_device *vdev, int nvqs)
|
||||
{
|
||||
if (!vdev->mdev)
|
||||
return -EINVAL;
|
||||
|
||||
return __vdpa_register_device(vdev);
|
||||
return __vdpa_register_device(vdev, nvqs);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(_vdpa_register_device);
|
||||
|
||||
|
|
@ -171,15 +172,16 @@ EXPORT_SYMBOL_GPL(_vdpa_register_device);
|
|||
* vdpa_register_device - register a vDPA device
|
||||
* Callers must have a succeed call of vdpa_alloc_device() before.
|
||||
* @vdev: the vdpa device to be registered to vDPA bus
|
||||
* @nvqs: number of virtqueues supported by this device
|
||||
*
|
||||
* Returns an error when fail to add to vDPA bus
|
||||
*/
|
||||
int vdpa_register_device(struct vdpa_device *vdev)
|
||||
int vdpa_register_device(struct vdpa_device *vdev, int nvqs)
|
||||
{
|
||||
int err;
|
||||
|
||||
mutex_lock(&vdpa_dev_mutex);
|
||||
err = __vdpa_register_device(vdev);
|
||||
err = __vdpa_register_device(vdev, nvqs);
|
||||
mutex_unlock(&vdpa_dev_mutex);
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr)
|
|||
ops = &vdpasim_config_ops;
|
||||
|
||||
vdpasim = vdpa_alloc_device(struct vdpasim, vdpa, NULL, ops,
|
||||
dev_attr->nvqs, dev_attr->name);
|
||||
dev_attr->name);
|
||||
if (!vdpasim)
|
||||
goto err_alloc;
|
||||
|
||||
|
|
|
|||
|
|
@ -110,8 +110,7 @@ static void vdpasim_net_work(struct work_struct *work)
|
|||
|
||||
static void vdpasim_net_get_config(struct vdpasim *vdpasim, void *config)
|
||||
{
|
||||
struct virtio_net_config *net_config =
|
||||
(struct virtio_net_config *)config;
|
||||
struct virtio_net_config *net_config = config;
|
||||
|
||||
net_config->mtu = cpu_to_vdpasim16(vdpasim, 1500);
|
||||
net_config->status = cpu_to_vdpasim16(vdpasim, VIRTIO_NET_S_LINK_UP);
|
||||
|
|
@ -147,7 +146,7 @@ static int vdpasim_net_dev_add(struct vdpa_mgmt_dev *mdev, const char *name)
|
|||
if (IS_ERR(simdev))
|
||||
return PTR_ERR(simdev);
|
||||
|
||||
ret = _vdpa_register_device(&simdev->vdpa);
|
||||
ret = _vdpa_register_device(&simdev->vdpa, VDPASIM_NET_VQ_NUM);
|
||||
if (ret)
|
||||
goto reg_err;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ config VFIO_VIRQFD
|
|||
|
||||
menuconfig VFIO
|
||||
tristate "VFIO Non-Privileged userspace driver framework"
|
||||
depends on IOMMU_API
|
||||
select VFIO_IOMMU_TYPE1 if (X86 || S390 || ARM || ARM64)
|
||||
select IOMMU_API
|
||||
select VFIO_IOMMU_TYPE1 if MMU && (X86 || S390 || ARM || ARM64)
|
||||
help
|
||||
VFIO provides a framework for secure userspace device drivers.
|
||||
See Documentation/driver-api/vfio.rst for more details.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config VFIO_PLATFORM
|
||||
tristate "VFIO support for platform devices"
|
||||
depends on VFIO && EVENTFD && (ARM || ARM64)
|
||||
depends on VFIO && EVENTFD && (ARM || ARM64 || COMPILE_TEST)
|
||||
select VFIO_VIRQFD
|
||||
help
|
||||
Support for platform devices with VFIO. This is required to make
|
||||
|
|
@ -12,7 +12,7 @@ config VFIO_PLATFORM
|
|||
|
||||
config VFIO_AMBA
|
||||
tristate "VFIO support for AMBA devices"
|
||||
depends on VFIO_PLATFORM && ARM_AMBA
|
||||
depends on VFIO_PLATFORM && (ARM_AMBA || COMPILE_TEST)
|
||||
help
|
||||
Support for ARM AMBA devices with VFIO. This is required to make
|
||||
use of ARM AMBA devices present on the system using the VFIO
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ static struct vfio_dma *vfio_find_dma(struct vfio_iommu *iommu,
|
|||
}
|
||||
|
||||
static struct rb_node *vfio_find_dma_first_node(struct vfio_iommu *iommu,
|
||||
dma_addr_t start, size_t size)
|
||||
dma_addr_t start, u64 size)
|
||||
{
|
||||
struct rb_node *res = NULL;
|
||||
struct rb_node *node = iommu->dma_list.rb_node;
|
||||
|
|
@ -785,7 +785,12 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
|
|||
return -ENODEV;
|
||||
|
||||
ret = vaddr_get_pfns(mm, vaddr, 1, dma->prot, pfn_base, pages);
|
||||
if (ret == 1 && do_accounting && !is_invalid_reserved_pfn(*pfn_base)) {
|
||||
if (ret != 1)
|
||||
goto out;
|
||||
|
||||
ret = 0;
|
||||
|
||||
if (do_accounting && !is_invalid_reserved_pfn(*pfn_base)) {
|
||||
ret = vfio_lock_acct(dma, 1, true);
|
||||
if (ret) {
|
||||
put_pfn(*pfn_base, dma->prot);
|
||||
|
|
@ -797,6 +802,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
|
|||
}
|
||||
}
|
||||
|
||||
out:
|
||||
mmput(mm);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1288,7 +1294,7 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
|
|||
int ret = -EINVAL, retries = 0;
|
||||
unsigned long pgshift;
|
||||
dma_addr_t iova = unmap->iova;
|
||||
unsigned long size = unmap->size;
|
||||
u64 size = unmap->size;
|
||||
bool unmap_all = unmap->flags & VFIO_DMA_UNMAP_FLAG_ALL;
|
||||
bool invalidate_vaddr = unmap->flags & VFIO_DMA_UNMAP_FLAG_VADDR;
|
||||
struct rb_node *n, *first_n;
|
||||
|
|
@ -1304,14 +1310,12 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
|
|||
if (unmap_all) {
|
||||
if (iova || size)
|
||||
goto unlock;
|
||||
size = SIZE_MAX;
|
||||
} else if (!size || size & (pgsize - 1)) {
|
||||
size = U64_MAX;
|
||||
} else if (!size || size & (pgsize - 1) ||
|
||||
iova + size - 1 < iova || size > SIZE_MAX) {
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (iova + size - 1 < iova || size > SIZE_MAX)
|
||||
goto unlock;
|
||||
|
||||
/* When dirty tracking is enabled, allow only min supported pgsize */
|
||||
if ((unmap->flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) &&
|
||||
(!iommu->dirty_page_tracking || (bitmap->pgsize != pgsize))) {
|
||||
|
|
|
|||
|
|
@ -308,8 +308,10 @@ static long vhost_vdpa_get_vring_num(struct vhost_vdpa *v, u16 __user *argp)
|
|||
|
||||
static void vhost_vdpa_config_put(struct vhost_vdpa *v)
|
||||
{
|
||||
if (v->config_ctx)
|
||||
if (v->config_ctx) {
|
||||
eventfd_ctx_put(v->config_ctx);
|
||||
v->config_ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)
|
||||
|
|
@ -329,8 +331,12 @@ static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)
|
|||
if (!IS_ERR_OR_NULL(ctx))
|
||||
eventfd_ctx_put(ctx);
|
||||
|
||||
if (IS_ERR(v->config_ctx))
|
||||
return PTR_ERR(v->config_ctx);
|
||||
if (IS_ERR(v->config_ctx)) {
|
||||
long ret = PTR_ERR(v->config_ctx);
|
||||
|
||||
v->config_ctx = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
v->vdpa->config->set_config_cb(v->vdpa, &cb);
|
||||
|
||||
|
|
@ -900,14 +906,10 @@ static int vhost_vdpa_open(struct inode *inode, struct file *filep)
|
|||
|
||||
static void vhost_vdpa_clean_irq(struct vhost_vdpa *v)
|
||||
{
|
||||
struct vhost_virtqueue *vq;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < v->nvqs; i++) {
|
||||
vq = &v->vqs[i];
|
||||
if (vq->call_ctx.producer.irq)
|
||||
irq_bypass_unregister_producer(&vq->call_ctx.producer);
|
||||
}
|
||||
for (i = 0; i < v->nvqs; i++)
|
||||
vhost_vdpa_unsetup_vq_irq(v, i);
|
||||
}
|
||||
|
||||
static int vhost_vdpa_release(struct inode *inode, struct file *filep)
|
||||
|
|
|
|||
|
|
@ -332,8 +332,8 @@ static void vhost_vq_reset(struct vhost_dev *dev,
|
|||
vq->error_ctx = NULL;
|
||||
vq->kick = NULL;
|
||||
vq->log_ctx = NULL;
|
||||
vhost_reset_is_le(vq);
|
||||
vhost_disable_cross_endian(vq);
|
||||
vhost_reset_is_le(vq);
|
||||
vq->busyloop_timeout = 0;
|
||||
vq->umem = NULL;
|
||||
vq->iotlb = NULL;
|
||||
|
|
|
|||
|
|
@ -141,15 +141,14 @@ void virtio_config_changed(struct virtio_device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(virtio_config_changed);
|
||||
|
||||
void virtio_config_disable(struct virtio_device *dev)
|
||||
static void virtio_config_disable(struct virtio_device *dev)
|
||||
{
|
||||
spin_lock_irq(&dev->config_lock);
|
||||
dev->config_enabled = false;
|
||||
spin_unlock_irq(&dev->config_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(virtio_config_disable);
|
||||
|
||||
void virtio_config_enable(struct virtio_device *dev)
|
||||
static void virtio_config_enable(struct virtio_device *dev)
|
||||
{
|
||||
spin_lock_irq(&dev->config_lock);
|
||||
dev->config_enabled = true;
|
||||
|
|
@ -158,7 +157,6 @@ void virtio_config_enable(struct virtio_device *dev)
|
|||
dev->config_change_pending = false;
|
||||
spin_unlock_irq(&dev->config_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(virtio_config_enable);
|
||||
|
||||
void virtio_add_status(struct virtio_device *dev, unsigned int status)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -548,8 +548,7 @@ static void virtio_mmio_release_dev(struct device *_d)
|
|||
{
|
||||
struct virtio_device *vdev =
|
||||
container_of(_d, struct virtio_device, dev);
|
||||
struct virtio_mmio_device *vm_dev =
|
||||
container_of(vdev, struct virtio_mmio_device, vdev);
|
||||
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
|
||||
struct platform_device *pdev = vm_dev->pdev;
|
||||
|
||||
devm_kfree(&pdev->dev, vm_dev);
|
||||
|
|
|
|||
|
|
@ -1365,7 +1365,9 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
|
|||
"failed to read tree block %llu from get_old_root",
|
||||
logical);
|
||||
} else {
|
||||
btrfs_tree_read_lock(old);
|
||||
eb = btrfs_clone_extent_buffer(old);
|
||||
btrfs_tree_read_unlock(old);
|
||||
free_extent_buffer(old);
|
||||
}
|
||||
} else if (old_root) {
|
||||
|
|
|
|||
|
|
@ -3323,6 +3323,7 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
|||
|
||||
if (last_ref && btrfs_header_generation(buf) == trans->transid) {
|
||||
struct btrfs_block_group *cache;
|
||||
bool must_pin = false;
|
||||
|
||||
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
|
||||
ret = check_ref_cleanup(trans, buf->start);
|
||||
|
|
@ -3340,7 +3341,27 @@ void btrfs_free_tree_block(struct btrfs_trans_handle *trans,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (btrfs_is_zoned(fs_info)) {
|
||||
/*
|
||||
* If this is a leaf and there are tree mod log users, we may
|
||||
* have recorded mod log operations that point to this leaf.
|
||||
* So we must make sure no one reuses this leaf's extent before
|
||||
* mod log operations are applied to a node, otherwise after
|
||||
* rewinding a node using the mod log operations we get an
|
||||
* inconsistent btree, as the leaf's extent may now be used as
|
||||
* a node or leaf for another different btree.
|
||||
* We are safe from races here because at this point no other
|
||||
* node or root points to this extent buffer, so if after this
|
||||
* check a new tree mod log user joins, it will not be able to
|
||||
* find a node pointing to this leaf and record operations that
|
||||
* point to this leaf.
|
||||
*/
|
||||
if (btrfs_header_level(buf) == 0) {
|
||||
read_lock(&fs_info->tree_mod_log_lock);
|
||||
must_pin = !list_empty(&fs_info->tree_mod_seq_list);
|
||||
read_unlock(&fs_info->tree_mod_log_lock);
|
||||
}
|
||||
|
||||
if (must_pin || btrfs_is_zoned(fs_info)) {
|
||||
btrfs_redirty_list_add(trans->transaction, buf);
|
||||
pin_down_extent(trans, cache, buf->start, buf->len, 1);
|
||||
btrfs_put_block_group(cache);
|
||||
|
|
|
|||
|
|
@ -2885,6 +2885,35 @@ static void end_page_read(struct page *page, bool uptodate, u64 start, u32 len)
|
|||
btrfs_subpage_end_reader(fs_info, page, start, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find extent buffer for a givne bytenr.
|
||||
*
|
||||
* This is for end_bio_extent_readpage(), thus we can't do any unsafe locking
|
||||
* in endio context.
|
||||
*/
|
||||
static struct extent_buffer *find_extent_buffer_readpage(
|
||||
struct btrfs_fs_info *fs_info, struct page *page, u64 bytenr)
|
||||
{
|
||||
struct extent_buffer *eb;
|
||||
|
||||
/*
|
||||
* For regular sectorsize, we can use page->private to grab extent
|
||||
* buffer
|
||||
*/
|
||||
if (fs_info->sectorsize == PAGE_SIZE) {
|
||||
ASSERT(PagePrivate(page) && page->private);
|
||||
return (struct extent_buffer *)page->private;
|
||||
}
|
||||
|
||||
/* For subpage case, we need to lookup buffer radix tree */
|
||||
rcu_read_lock();
|
||||
eb = radix_tree_lookup(&fs_info->buffer_radix,
|
||||
bytenr >> fs_info->sectorsize_bits);
|
||||
rcu_read_unlock();
|
||||
ASSERT(eb);
|
||||
return eb;
|
||||
}
|
||||
|
||||
/*
|
||||
* after a readpage IO is done, we need to:
|
||||
* clear the uptodate bits on error
|
||||
|
|
@ -2996,7 +3025,7 @@ static void end_bio_extent_readpage(struct bio *bio)
|
|||
} else {
|
||||
struct extent_buffer *eb;
|
||||
|
||||
eb = (struct extent_buffer *)page->private;
|
||||
eb = find_extent_buffer_readpage(fs_info, page, start);
|
||||
set_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags);
|
||||
eb->read_mirror = mirror;
|
||||
atomic_dec(&eb->io_pages);
|
||||
|
|
@ -3020,7 +3049,7 @@ static void end_bio_extent_readpage(struct bio *bio)
|
|||
*/
|
||||
if (page->index == end_index && i_size <= end) {
|
||||
u32 zero_start = max(offset_in_page(i_size),
|
||||
offset_in_page(end));
|
||||
offset_in_page(start));
|
||||
|
||||
zero_user_segment(page, zero_start,
|
||||
offset_in_page(end) + 1);
|
||||
|
|
|
|||
|
|
@ -9008,7 +9008,7 @@ int __init btrfs_init_cachep(void)
|
|||
|
||||
btrfs_free_space_bitmap_cachep = kmem_cache_create("btrfs_free_space_bitmap",
|
||||
PAGE_SIZE, PAGE_SIZE,
|
||||
SLAB_RED_ZONE, NULL);
|
||||
SLAB_MEM_SPREAD, NULL);
|
||||
if (!btrfs_free_space_bitmap_cachep)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -9877,6 +9877,7 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent(
|
|||
struct btrfs_path *path;
|
||||
u64 start = ins->objectid;
|
||||
u64 len = ins->offset;
|
||||
int qgroup_released;
|
||||
int ret;
|
||||
|
||||
memset(&stack_fi, 0, sizeof(stack_fi));
|
||||
|
|
@ -9889,16 +9890,16 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent(
|
|||
btrfs_set_stack_file_extent_compression(&stack_fi, BTRFS_COMPRESS_NONE);
|
||||
/* Encryption and other encoding is reserved and all 0 */
|
||||
|
||||
ret = btrfs_qgroup_release_data(inode, file_offset, len);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
qgroup_released = btrfs_qgroup_release_data(inode, file_offset, len);
|
||||
if (qgroup_released < 0)
|
||||
return ERR_PTR(qgroup_released);
|
||||
|
||||
if (trans) {
|
||||
ret = insert_reserved_file_extent(trans, inode,
|
||||
file_offset, &stack_fi,
|
||||
true, ret);
|
||||
true, qgroup_released);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
goto free_qgroup;
|
||||
return trans;
|
||||
}
|
||||
|
||||
|
|
@ -9909,21 +9910,35 @@ static struct btrfs_trans_handle *insert_prealloc_file_extent(
|
|||
extent_info.file_offset = file_offset;
|
||||
extent_info.extent_buf = (char *)&stack_fi;
|
||||
extent_info.is_new_extent = true;
|
||||
extent_info.qgroup_reserved = ret;
|
||||
extent_info.qgroup_reserved = qgroup_released;
|
||||
extent_info.insertions = 0;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!path) {
|
||||
ret = -ENOMEM;
|
||||
goto free_qgroup;
|
||||
}
|
||||
|
||||
ret = btrfs_replace_file_extents(&inode->vfs_inode, path, file_offset,
|
||||
file_offset + len - 1, &extent_info,
|
||||
&trans);
|
||||
btrfs_free_path(path);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
goto free_qgroup;
|
||||
return trans;
|
||||
|
||||
free_qgroup:
|
||||
/*
|
||||
* We have released qgroup data range at the beginning of the function,
|
||||
* and normally qgroup_released bytes will be freed when committing
|
||||
* transaction.
|
||||
* But if we error out early, we have to free what we have released
|
||||
* or we leak qgroup data reservation.
|
||||
*/
|
||||
btrfs_qgroup_free_refroot(inode->root->fs_info,
|
||||
inode->root->root_key.objectid, qgroup_released,
|
||||
BTRFS_QGROUP_RSV_DATA);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ int btree_readahead_hook(struct extent_buffer *eb, int err)
|
|||
/* find extent */
|
||||
spin_lock(&fs_info->reada_lock);
|
||||
re = radix_tree_lookup(&fs_info->reada_tree,
|
||||
eb->start >> PAGE_SHIFT);
|
||||
eb->start >> fs_info->sectorsize_bits);
|
||||
if (re)
|
||||
re->refcnt++;
|
||||
spin_unlock(&fs_info->reada_lock);
|
||||
|
|
@ -240,7 +240,7 @@ static struct reada_zone *reada_find_zone(struct btrfs_device *dev, u64 logical,
|
|||
zone = NULL;
|
||||
spin_lock(&fs_info->reada_lock);
|
||||
ret = radix_tree_gang_lookup(&dev->reada_zones, (void **)&zone,
|
||||
logical >> PAGE_SHIFT, 1);
|
||||
logical >> fs_info->sectorsize_bits, 1);
|
||||
if (ret == 1 && logical >= zone->start && logical <= zone->end) {
|
||||
kref_get(&zone->refcnt);
|
||||
spin_unlock(&fs_info->reada_lock);
|
||||
|
|
@ -283,13 +283,13 @@ static struct reada_zone *reada_find_zone(struct btrfs_device *dev, u64 logical,
|
|||
|
||||
spin_lock(&fs_info->reada_lock);
|
||||
ret = radix_tree_insert(&dev->reada_zones,
|
||||
(unsigned long)(zone->end >> PAGE_SHIFT),
|
||||
zone);
|
||||
(unsigned long)(zone->end >> fs_info->sectorsize_bits),
|
||||
zone);
|
||||
|
||||
if (ret == -EEXIST) {
|
||||
kfree(zone);
|
||||
ret = radix_tree_gang_lookup(&dev->reada_zones, (void **)&zone,
|
||||
logical >> PAGE_SHIFT, 1);
|
||||
logical >> fs_info->sectorsize_bits, 1);
|
||||
if (ret == 1 && logical >= zone->start && logical <= zone->end)
|
||||
kref_get(&zone->refcnt);
|
||||
else
|
||||
|
|
@ -315,7 +315,7 @@ static struct reada_extent *reada_find_extent(struct btrfs_fs_info *fs_info,
|
|||
u64 length;
|
||||
int real_stripes;
|
||||
int nzones = 0;
|
||||
unsigned long index = logical >> PAGE_SHIFT;
|
||||
unsigned long index = logical >> fs_info->sectorsize_bits;
|
||||
int dev_replace_is_ongoing;
|
||||
int have_zone = 0;
|
||||
|
||||
|
|
@ -497,7 +497,7 @@ static void reada_extent_put(struct btrfs_fs_info *fs_info,
|
|||
struct reada_extent *re)
|
||||
{
|
||||
int i;
|
||||
unsigned long index = re->logical >> PAGE_SHIFT;
|
||||
unsigned long index = re->logical >> fs_info->sectorsize_bits;
|
||||
|
||||
spin_lock(&fs_info->reada_lock);
|
||||
if (--re->refcnt) {
|
||||
|
|
@ -538,11 +538,12 @@ static void reada_extent_put(struct btrfs_fs_info *fs_info,
|
|||
static void reada_zone_release(struct kref *kref)
|
||||
{
|
||||
struct reada_zone *zone = container_of(kref, struct reada_zone, refcnt);
|
||||
struct btrfs_fs_info *fs_info = zone->device->fs_info;
|
||||
|
||||
lockdep_assert_held(&zone->device->fs_info->reada_lock);
|
||||
lockdep_assert_held(&fs_info->reada_lock);
|
||||
|
||||
radix_tree_delete(&zone->device->reada_zones,
|
||||
zone->end >> PAGE_SHIFT);
|
||||
zone->end >> fs_info->sectorsize_bits);
|
||||
|
||||
kfree(zone);
|
||||
}
|
||||
|
|
@ -593,7 +594,7 @@ static int reada_add_block(struct reada_control *rc, u64 logical,
|
|||
static void reada_peer_zones_set_lock(struct reada_zone *zone, int lock)
|
||||
{
|
||||
int i;
|
||||
unsigned long index = zone->end >> PAGE_SHIFT;
|
||||
unsigned long index = zone->end >> zone->device->fs_info->sectorsize_bits;
|
||||
|
||||
for (i = 0; i < zone->ndevs; ++i) {
|
||||
struct reada_zone *peer;
|
||||
|
|
@ -628,7 +629,7 @@ static int reada_pick_zone(struct btrfs_device *dev)
|
|||
(void **)&zone, index, 1);
|
||||
if (ret == 0)
|
||||
break;
|
||||
index = (zone->end >> PAGE_SHIFT) + 1;
|
||||
index = (zone->end >> dev->fs_info->sectorsize_bits) + 1;
|
||||
if (zone->locked) {
|
||||
if (zone->elems > top_locked_elems) {
|
||||
top_locked_elems = zone->elems;
|
||||
|
|
@ -709,7 +710,7 @@ static int reada_start_machine_dev(struct btrfs_device *dev)
|
|||
* plugging to speed things up
|
||||
*/
|
||||
ret = radix_tree_gang_lookup(&dev->reada_extents, (void **)&re,
|
||||
dev->reada_next >> PAGE_SHIFT, 1);
|
||||
dev->reada_next >> fs_info->sectorsize_bits, 1);
|
||||
if (ret == 0 || re->logical > dev->reada_curr_zone->end) {
|
||||
ret = reada_pick_zone(dev);
|
||||
if (!ret) {
|
||||
|
|
@ -718,7 +719,7 @@ static int reada_start_machine_dev(struct btrfs_device *dev)
|
|||
}
|
||||
re = NULL;
|
||||
ret = radix_tree_gang_lookup(&dev->reada_extents, (void **)&re,
|
||||
dev->reada_next >> PAGE_SHIFT, 1);
|
||||
dev->reada_next >> fs_info->sectorsize_bits, 1);
|
||||
}
|
||||
if (ret == 0) {
|
||||
spin_unlock(&fs_info->reada_lock);
|
||||
|
|
@ -885,7 +886,7 @@ static void dump_devs(struct btrfs_fs_info *fs_info, int all)
|
|||
pr_cont(" curr off %llu",
|
||||
device->reada_next - zone->start);
|
||||
pr_cont("\n");
|
||||
index = (zone->end >> PAGE_SHIFT) + 1;
|
||||
index = (zone->end >> fs_info->sectorsize_bits) + 1;
|
||||
}
|
||||
cnt = 0;
|
||||
index = 0;
|
||||
|
|
@ -910,7 +911,7 @@ static void dump_devs(struct btrfs_fs_info *fs_info, int all)
|
|||
}
|
||||
}
|
||||
pr_cont("\n");
|
||||
index = (re->logical >> PAGE_SHIFT) + 1;
|
||||
index = (re->logical >> fs_info->sectorsize_bits) + 1;
|
||||
if (++cnt > 15)
|
||||
break;
|
||||
}
|
||||
|
|
@ -926,7 +927,7 @@ static void dump_devs(struct btrfs_fs_info *fs_info, int all)
|
|||
if (ret == 0)
|
||||
break;
|
||||
if (!re->scheduled) {
|
||||
index = (re->logical >> PAGE_SHIFT) + 1;
|
||||
index = (re->logical >> fs_info->sectorsize_bits) + 1;
|
||||
continue;
|
||||
}
|
||||
pr_debug("re: logical %llu size %u list empty %d scheduled %d",
|
||||
|
|
@ -942,7 +943,7 @@ static void dump_devs(struct btrfs_fs_info *fs_info, int all)
|
|||
}
|
||||
}
|
||||
pr_cont("\n");
|
||||
index = (re->logical >> PAGE_SHIFT) + 1;
|
||||
index = (re->logical >> fs_info->sectorsize_bits) + 1;
|
||||
}
|
||||
spin_unlock(&fs_info->reada_lock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3169,10 +3169,6 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
|||
|
||||
mutex_lock(&log_root_tree->log_mutex);
|
||||
|
||||
index2 = log_root_tree->log_transid % 2;
|
||||
list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]);
|
||||
root_log_ctx.log_transid = log_root_tree->log_transid;
|
||||
|
||||
if (btrfs_is_zoned(fs_info)) {
|
||||
if (!log_root_tree->node) {
|
||||
ret = btrfs_alloc_log_tree_node(trans, log_root_tree);
|
||||
|
|
@ -3183,6 +3179,10 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
|
|||
}
|
||||
}
|
||||
|
||||
index2 = log_root_tree->log_transid % 2;
|
||||
list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]);
|
||||
root_log_ctx.log_transid = log_root_tree->log_transid;
|
||||
|
||||
/*
|
||||
* Now we are safe to update the log_root_tree because we're under the
|
||||
* log_mutex, and we're a current writer so we're holding the commit
|
||||
|
|
|
|||
|
|
@ -488,6 +488,8 @@ static int io_wqe_worker(void *data)
|
|||
set_task_comm(current, buf);
|
||||
|
||||
while (!test_bit(IO_WQ_BIT_EXIT, &wq->state)) {
|
||||
long ret;
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
loop:
|
||||
raw_spin_lock_irq(&wqe->lock);
|
||||
|
|
@ -498,7 +500,8 @@ static int io_wqe_worker(void *data)
|
|||
__io_worker_idle(wqe, worker);
|
||||
raw_spin_unlock_irq(&wqe->lock);
|
||||
io_flush_signals();
|
||||
if (schedule_timeout(WORKER_IDLE_TIMEOUT))
|
||||
ret = schedule_timeout(WORKER_IDLE_TIMEOUT);
|
||||
if (try_to_freeze() || ret)
|
||||
continue;
|
||||
if (fatal_signal_pending(current))
|
||||
break;
|
||||
|
|
@ -709,6 +712,7 @@ static int io_wq_manager(void *data)
|
|||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
io_wq_check_workers(wq);
|
||||
schedule_timeout(HZ);
|
||||
try_to_freeze();
|
||||
if (fatal_signal_pending(current))
|
||||
set_bit(IO_WQ_BIT_EXIT, &wq->state);
|
||||
} while (!test_bit(IO_WQ_BIT_EXIT, &wq->state));
|
||||
|
|
|
|||
10
fs/io-wq.h
10
fs/io-wq.h
|
|
@ -2,7 +2,6 @@
|
|||
#define INTERNAL_IO_WQ_H
|
||||
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/io_uring.h>
|
||||
|
||||
struct io_wq;
|
||||
|
||||
|
|
@ -21,6 +20,15 @@ enum io_wq_cancel {
|
|||
IO_WQ_CANCEL_NOTFOUND, /* work not found */
|
||||
};
|
||||
|
||||
struct io_wq_work_node {
|
||||
struct io_wq_work_node *next;
|
||||
};
|
||||
|
||||
struct io_wq_work_list {
|
||||
struct io_wq_work_node *first;
|
||||
struct io_wq_work_node *last;
|
||||
};
|
||||
|
||||
static inline void wq_list_add_after(struct io_wq_work_node *node,
|
||||
struct io_wq_work_node *pos,
|
||||
struct io_wq_work_list *list)
|
||||
|
|
|
|||
228
fs/io_uring.c
228
fs/io_uring.c
|
|
@ -258,7 +258,8 @@ enum {
|
|||
|
||||
struct io_sq_data {
|
||||
refcount_t refs;
|
||||
struct rw_semaphore rw_lock;
|
||||
atomic_t park_pending;
|
||||
struct mutex lock;
|
||||
|
||||
/* ctx's that are using this sqd */
|
||||
struct list_head ctx_list;
|
||||
|
|
@ -273,6 +274,7 @@ struct io_sq_data {
|
|||
|
||||
unsigned long state;
|
||||
struct completion exited;
|
||||
struct callback_head *park_task_work;
|
||||
};
|
||||
|
||||
#define IO_IOPOLL_BATCH 8
|
||||
|
|
@ -402,7 +404,7 @@ struct io_ring_ctx {
|
|||
struct socket *ring_sock;
|
||||
#endif
|
||||
|
||||
struct idr io_buffer_idr;
|
||||
struct xarray io_buffers;
|
||||
|
||||
struct xarray personalities;
|
||||
u32 pers_next;
|
||||
|
|
@ -454,6 +456,22 @@ struct io_ring_ctx {
|
|||
struct list_head tctx_list;
|
||||
};
|
||||
|
||||
struct io_uring_task {
|
||||
/* submission side */
|
||||
struct xarray xa;
|
||||
struct wait_queue_head wait;
|
||||
const struct io_ring_ctx *last;
|
||||
struct io_wq *io_wq;
|
||||
struct percpu_counter inflight;
|
||||
atomic_t in_idle;
|
||||
bool sqpoll;
|
||||
|
||||
spinlock_t task_lock;
|
||||
struct io_wq_work_list task_list;
|
||||
unsigned long task_state;
|
||||
struct callback_head task_work;
|
||||
};
|
||||
|
||||
/*
|
||||
* First field must be the file pointer in all the
|
||||
* iocb unions! See also 'struct kiocb' in <linux/fs.h>
|
||||
|
|
@ -1135,7 +1153,7 @@ static struct io_ring_ctx *io_ring_ctx_alloc(struct io_uring_params *p)
|
|||
init_waitqueue_head(&ctx->cq_wait);
|
||||
INIT_LIST_HEAD(&ctx->cq_overflow_list);
|
||||
init_completion(&ctx->ref_comp);
|
||||
idr_init(&ctx->io_buffer_idr);
|
||||
xa_init_flags(&ctx->io_buffers, XA_FLAGS_ALLOC1);
|
||||
xa_init_flags(&ctx->personalities, XA_FLAGS_ALLOC1);
|
||||
mutex_init(&ctx->uring_lock);
|
||||
init_waitqueue_head(&ctx->wait);
|
||||
|
|
@ -1550,14 +1568,17 @@ static void io_req_complete_post(struct io_kiocb *req, long res,
|
|||
io_put_task(req->task, 1);
|
||||
list_add(&req->compl.list, &cs->locked_free_list);
|
||||
cs->locked_free_nr++;
|
||||
} else
|
||||
req = NULL;
|
||||
} else {
|
||||
if (!percpu_ref_tryget(&ctx->refs))
|
||||
req = NULL;
|
||||
}
|
||||
io_commit_cqring(ctx);
|
||||
spin_unlock_irqrestore(&ctx->completion_lock, flags);
|
||||
io_cqring_ev_posted(ctx);
|
||||
|
||||
if (req)
|
||||
if (req) {
|
||||
io_cqring_ev_posted(ctx);
|
||||
percpu_ref_put(&ctx->refs);
|
||||
}
|
||||
}
|
||||
|
||||
static void io_req_complete_state(struct io_kiocb *req, long res,
|
||||
|
|
@ -1925,17 +1946,44 @@ static int io_req_task_work_add(struct io_kiocb *req)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool io_run_task_work_head(struct callback_head **work_head)
|
||||
{
|
||||
struct callback_head *work, *next;
|
||||
bool executed = false;
|
||||
|
||||
do {
|
||||
work = xchg(work_head, NULL);
|
||||
if (!work)
|
||||
break;
|
||||
|
||||
do {
|
||||
next = work->next;
|
||||
work->func(work);
|
||||
work = next;
|
||||
cond_resched();
|
||||
} while (work);
|
||||
executed = true;
|
||||
} while (1);
|
||||
|
||||
return executed;
|
||||
}
|
||||
|
||||
static void io_task_work_add_head(struct callback_head **work_head,
|
||||
struct callback_head *task_work)
|
||||
{
|
||||
struct callback_head *head;
|
||||
|
||||
do {
|
||||
head = READ_ONCE(*work_head);
|
||||
task_work->next = head;
|
||||
} while (cmpxchg(work_head, head, task_work) != head);
|
||||
}
|
||||
|
||||
static void io_req_task_work_add_fallback(struct io_kiocb *req,
|
||||
task_work_func_t cb)
|
||||
{
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
struct callback_head *head;
|
||||
|
||||
init_task_work(&req->task_work, cb);
|
||||
do {
|
||||
head = READ_ONCE(ctx->exit_task_work);
|
||||
req->task_work.next = head;
|
||||
} while (cmpxchg(&ctx->exit_task_work, head, &req->task_work) != head);
|
||||
io_task_work_add_head(&req->ctx->exit_task_work, &req->task_work);
|
||||
}
|
||||
|
||||
static void __io_req_task_cancel(struct io_kiocb *req, int error)
|
||||
|
|
@ -2843,7 +2891,7 @@ static struct io_buffer *io_buffer_select(struct io_kiocb *req, size_t *len,
|
|||
|
||||
lockdep_assert_held(&req->ctx->uring_lock);
|
||||
|
||||
head = idr_find(&req->ctx->io_buffer_idr, bgid);
|
||||
head = xa_load(&req->ctx->io_buffers, bgid);
|
||||
if (head) {
|
||||
if (!list_empty(&head->list)) {
|
||||
kbuf = list_last_entry(&head->list, struct io_buffer,
|
||||
|
|
@ -2851,7 +2899,7 @@ static struct io_buffer *io_buffer_select(struct io_kiocb *req, size_t *len,
|
|||
list_del(&kbuf->list);
|
||||
} else {
|
||||
kbuf = head;
|
||||
idr_remove(&req->ctx->io_buffer_idr, bgid);
|
||||
xa_erase(&req->ctx->io_buffers, bgid);
|
||||
}
|
||||
if (*len > kbuf->len)
|
||||
*len = kbuf->len;
|
||||
|
|
@ -3892,7 +3940,7 @@ static int __io_remove_buffers(struct io_ring_ctx *ctx, struct io_buffer *buf,
|
|||
}
|
||||
i++;
|
||||
kfree(buf);
|
||||
idr_remove(&ctx->io_buffer_idr, bgid);
|
||||
xa_erase(&ctx->io_buffers, bgid);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
|
@ -3910,7 +3958,7 @@ static int io_remove_buffers(struct io_kiocb *req, unsigned int issue_flags)
|
|||
lockdep_assert_held(&ctx->uring_lock);
|
||||
|
||||
ret = -ENOENT;
|
||||
head = idr_find(&ctx->io_buffer_idr, p->bgid);
|
||||
head = xa_load(&ctx->io_buffers, p->bgid);
|
||||
if (head)
|
||||
ret = __io_remove_buffers(ctx, head, p->bgid, p->nbufs);
|
||||
if (ret < 0)
|
||||
|
|
@ -3993,21 +4041,14 @@ static int io_provide_buffers(struct io_kiocb *req, unsigned int issue_flags)
|
|||
|
||||
lockdep_assert_held(&ctx->uring_lock);
|
||||
|
||||
list = head = idr_find(&ctx->io_buffer_idr, p->bgid);
|
||||
list = head = xa_load(&ctx->io_buffers, p->bgid);
|
||||
|
||||
ret = io_add_buffers(p, &head);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (!list) {
|
||||
ret = idr_alloc(&ctx->io_buffer_idr, head, p->bgid, p->bgid + 1,
|
||||
GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
if (ret >= 0 && !list) {
|
||||
ret = xa_insert(&ctx->io_buffers, p->bgid, head, GFP_KERNEL);
|
||||
if (ret < 0)
|
||||
__io_remove_buffers(ctx, head, p->bgid, -1U);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (ret < 0)
|
||||
req_set_fail_links(req);
|
||||
|
||||
|
|
@ -4359,7 +4400,7 @@ static int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
|
|||
kmsg = &iomsg;
|
||||
}
|
||||
|
||||
flags = req->sr_msg.msg_flags;
|
||||
flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
|
||||
if (flags & MSG_DONTWAIT)
|
||||
req->flags |= REQ_F_NOWAIT;
|
||||
else if (issue_flags & IO_URING_F_NONBLOCK)
|
||||
|
|
@ -4403,7 +4444,7 @@ static int io_send(struct io_kiocb *req, unsigned int issue_flags)
|
|||
msg.msg_controllen = 0;
|
||||
msg.msg_namelen = 0;
|
||||
|
||||
flags = req->sr_msg.msg_flags;
|
||||
flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
|
||||
if (flags & MSG_DONTWAIT)
|
||||
req->flags |= REQ_F_NOWAIT;
|
||||
else if (issue_flags & IO_URING_F_NONBLOCK)
|
||||
|
|
@ -4593,7 +4634,7 @@ static int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
|
|||
1, req->sr_msg.len);
|
||||
}
|
||||
|
||||
flags = req->sr_msg.msg_flags;
|
||||
flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
|
||||
if (flags & MSG_DONTWAIT)
|
||||
req->flags |= REQ_F_NOWAIT;
|
||||
else if (force_nonblock)
|
||||
|
|
@ -4652,7 +4693,7 @@ static int io_recv(struct io_kiocb *req, unsigned int issue_flags)
|
|||
msg.msg_iocb = NULL;
|
||||
msg.msg_flags = 0;
|
||||
|
||||
flags = req->sr_msg.msg_flags;
|
||||
flags = req->sr_msg.msg_flags | MSG_NOSIGNAL;
|
||||
if (flags & MSG_DONTWAIT)
|
||||
req->flags |= REQ_F_NOWAIT;
|
||||
else if (force_nonblock)
|
||||
|
|
@ -6204,7 +6245,6 @@ static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer)
|
|||
spin_unlock_irqrestore(&ctx->completion_lock, flags);
|
||||
|
||||
if (prev) {
|
||||
req_set_fail_links(prev);
|
||||
io_async_find_and_cancel(ctx, req, prev->user_data, -ETIME);
|
||||
io_put_req_deferred(prev, 1);
|
||||
} else {
|
||||
|
|
@ -6694,17 +6734,17 @@ static int io_sq_thread(void *data)
|
|||
set_cpus_allowed_ptr(current, cpu_online_mask);
|
||||
current->flags |= PF_NO_SETAFFINITY;
|
||||
|
||||
down_read(&sqd->rw_lock);
|
||||
|
||||
mutex_lock(&sqd->lock);
|
||||
while (!test_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state)) {
|
||||
int ret;
|
||||
bool cap_entries, sqt_spin, needs_sched;
|
||||
|
||||
if (test_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state)) {
|
||||
up_read(&sqd->rw_lock);
|
||||
mutex_unlock(&sqd->lock);
|
||||
cond_resched();
|
||||
down_read(&sqd->rw_lock);
|
||||
mutex_lock(&sqd->lock);
|
||||
io_run_task_work();
|
||||
io_run_task_work_head(&sqd->park_task_work);
|
||||
timeout = jiffies + sqd->sq_thread_idle;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -6750,32 +6790,28 @@ static int io_sq_thread(void *data)
|
|||
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
|
||||
io_ring_set_wakeup_flag(ctx);
|
||||
|
||||
up_read(&sqd->rw_lock);
|
||||
mutex_unlock(&sqd->lock);
|
||||
schedule();
|
||||
down_read(&sqd->rw_lock);
|
||||
try_to_freeze();
|
||||
mutex_lock(&sqd->lock);
|
||||
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
|
||||
io_ring_clear_wakeup_flag(ctx);
|
||||
}
|
||||
|
||||
finish_wait(&sqd->wait, &wait);
|
||||
io_run_task_work_head(&sqd->park_task_work);
|
||||
timeout = jiffies + sqd->sq_thread_idle;
|
||||
}
|
||||
up_read(&sqd->rw_lock);
|
||||
down_write(&sqd->rw_lock);
|
||||
/*
|
||||
* someone may have parked and added a cancellation task_work, run
|
||||
* it first because we don't want it in io_uring_cancel_sqpoll()
|
||||
*/
|
||||
io_run_task_work();
|
||||
|
||||
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
|
||||
io_uring_cancel_sqpoll(ctx);
|
||||
sqd->thread = NULL;
|
||||
list_for_each_entry(ctx, &sqd->ctx_list, sqd_list)
|
||||
io_ring_set_wakeup_flag(ctx);
|
||||
up_write(&sqd->rw_lock);
|
||||
mutex_unlock(&sqd->lock);
|
||||
|
||||
io_run_task_work();
|
||||
io_run_task_work_head(&sqd->park_task_work);
|
||||
complete(&sqd->exited);
|
||||
do_exit(0);
|
||||
}
|
||||
|
|
@ -7075,23 +7111,28 @@ static int io_sqe_files_unregister(struct io_ring_ctx *ctx)
|
|||
}
|
||||
|
||||
static void io_sq_thread_unpark(struct io_sq_data *sqd)
|
||||
__releases(&sqd->rw_lock)
|
||||
__releases(&sqd->lock)
|
||||
{
|
||||
WARN_ON_ONCE(sqd->thread == current);
|
||||
|
||||
/*
|
||||
* Do the dance but not conditional clear_bit() because it'd race with
|
||||
* other threads incrementing park_pending and setting the bit.
|
||||
*/
|
||||
clear_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
|
||||
up_write(&sqd->rw_lock);
|
||||
if (atomic_dec_return(&sqd->park_pending))
|
||||
set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
|
||||
mutex_unlock(&sqd->lock);
|
||||
}
|
||||
|
||||
static void io_sq_thread_park(struct io_sq_data *sqd)
|
||||
__acquires(&sqd->rw_lock)
|
||||
__acquires(&sqd->lock)
|
||||
{
|
||||
WARN_ON_ONCE(sqd->thread == current);
|
||||
|
||||
atomic_inc(&sqd->park_pending);
|
||||
set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
|
||||
down_write(&sqd->rw_lock);
|
||||
/* set again for consistency, in case concurrent parks are happening */
|
||||
set_bit(IO_SQ_THREAD_SHOULD_PARK, &sqd->state);
|
||||
mutex_lock(&sqd->lock);
|
||||
if (sqd->thread)
|
||||
wake_up_process(sqd->thread);
|
||||
}
|
||||
|
|
@ -7100,17 +7141,19 @@ static void io_sq_thread_stop(struct io_sq_data *sqd)
|
|||
{
|
||||
WARN_ON_ONCE(sqd->thread == current);
|
||||
|
||||
down_write(&sqd->rw_lock);
|
||||
mutex_lock(&sqd->lock);
|
||||
set_bit(IO_SQ_THREAD_SHOULD_STOP, &sqd->state);
|
||||
if (sqd->thread)
|
||||
wake_up_process(sqd->thread);
|
||||
up_write(&sqd->rw_lock);
|
||||
mutex_unlock(&sqd->lock);
|
||||
wait_for_completion(&sqd->exited);
|
||||
}
|
||||
|
||||
static void io_put_sq_data(struct io_sq_data *sqd)
|
||||
{
|
||||
if (refcount_dec_and_test(&sqd->refs)) {
|
||||
WARN_ON_ONCE(atomic_read(&sqd->park_pending));
|
||||
|
||||
io_sq_thread_stop(sqd);
|
||||
kfree(sqd);
|
||||
}
|
||||
|
|
@ -7184,9 +7227,10 @@ static struct io_sq_data *io_get_sq_data(struct io_uring_params *p,
|
|||
if (!sqd)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
atomic_set(&sqd->park_pending, 0);
|
||||
refcount_set(&sqd->refs, 1);
|
||||
INIT_LIST_HEAD(&sqd->ctx_list);
|
||||
init_rwsem(&sqd->rw_lock);
|
||||
mutex_init(&sqd->lock);
|
||||
init_waitqueue_head(&sqd->wait);
|
||||
init_completion(&sqd->exited);
|
||||
return sqd;
|
||||
|
|
@ -7866,22 +7910,17 @@ static int io_sq_offload_create(struct io_ring_ctx *ctx,
|
|||
|
||||
ret = 0;
|
||||
io_sq_thread_park(sqd);
|
||||
list_add(&ctx->sqd_list, &sqd->ctx_list);
|
||||
io_sqd_update_thread_idle(sqd);
|
||||
/* don't attach to a dying SQPOLL thread, would be racy */
|
||||
if (attached && !sqd->thread) {
|
||||
if (attached && !sqd->thread)
|
||||
ret = -ENXIO;
|
||||
} else {
|
||||
list_add(&ctx->sqd_list, &sqd->ctx_list);
|
||||
io_sqd_update_thread_idle(sqd);
|
||||
}
|
||||
io_sq_thread_unpark(sqd);
|
||||
|
||||
if (ret < 0) {
|
||||
io_put_sq_data(sqd);
|
||||
ctx->sq_data = NULL;
|
||||
return ret;
|
||||
} else if (attached) {
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
if (attached)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (p->flags & IORING_SETUP_SQ_AFF) {
|
||||
int cpu = p->sq_thread_cpu;
|
||||
|
|
@ -8332,19 +8371,13 @@ static int io_eventfd_unregister(struct io_ring_ctx *ctx)
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
static int __io_destroy_buffers(int id, void *p, void *data)
|
||||
{
|
||||
struct io_ring_ctx *ctx = data;
|
||||
struct io_buffer *buf = p;
|
||||
|
||||
__io_remove_buffers(ctx, buf, id, -1U);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void io_destroy_buffers(struct io_ring_ctx *ctx)
|
||||
{
|
||||
idr_for_each(&ctx->io_buffer_idr, __io_destroy_buffers, ctx);
|
||||
idr_destroy(&ctx->io_buffer_idr);
|
||||
struct io_buffer *buf;
|
||||
unsigned long index;
|
||||
|
||||
xa_for_each(&ctx->io_buffers, index, buf)
|
||||
__io_remove_buffers(ctx, buf, index, -1U);
|
||||
}
|
||||
|
||||
static void io_req_cache_free(struct list_head *list, struct task_struct *tsk)
|
||||
|
|
@ -8386,11 +8419,13 @@ static void io_ring_ctx_free(struct io_ring_ctx *ctx)
|
|||
{
|
||||
/*
|
||||
* Some may use context even when all refs and requests have been put,
|
||||
* and they are free to do so while still holding uring_lock, see
|
||||
* __io_req_task_submit(). Wait for them to finish.
|
||||
* and they are free to do so while still holding uring_lock or
|
||||
* completion_lock, see __io_req_task_submit(). Wait for them to finish.
|
||||
*/
|
||||
mutex_lock(&ctx->uring_lock);
|
||||
mutex_unlock(&ctx->uring_lock);
|
||||
spin_lock_irq(&ctx->completion_lock);
|
||||
spin_unlock_irq(&ctx->completion_lock);
|
||||
|
||||
io_sq_thread_finish(ctx);
|
||||
io_sqe_buffers_unregister(ctx);
|
||||
|
|
@ -8478,26 +8513,9 @@ static int io_unregister_personality(struct io_ring_ctx *ctx, unsigned id)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static bool io_run_ctx_fallback(struct io_ring_ctx *ctx)
|
||||
static inline bool io_run_ctx_fallback(struct io_ring_ctx *ctx)
|
||||
{
|
||||
struct callback_head *work, *next;
|
||||
bool executed = false;
|
||||
|
||||
do {
|
||||
work = xchg(&ctx->exit_task_work, NULL);
|
||||
if (!work)
|
||||
break;
|
||||
|
||||
do {
|
||||
next = work->next;
|
||||
work->func(work);
|
||||
work = next;
|
||||
cond_resched();
|
||||
} while (work);
|
||||
executed = true;
|
||||
} while (1);
|
||||
|
||||
return executed;
|
||||
return io_run_task_work_head(&ctx->exit_task_work);
|
||||
}
|
||||
|
||||
struct io_tctx_exit {
|
||||
|
|
@ -8580,6 +8598,14 @@ static void io_ring_ctx_wait_and_kill(struct io_ring_ctx *ctx)
|
|||
io_unregister_personality(ctx, index);
|
||||
mutex_unlock(&ctx->uring_lock);
|
||||
|
||||
/* prevent SQPOLL from submitting new requests */
|
||||
if (ctx->sq_data) {
|
||||
io_sq_thread_park(ctx->sq_data);
|
||||
list_del_init(&ctx->sqd_list);
|
||||
io_sqd_update_thread_idle(ctx->sq_data);
|
||||
io_sq_thread_unpark(ctx->sq_data);
|
||||
}
|
||||
|
||||
io_kill_timeouts(ctx, NULL, NULL);
|
||||
io_poll_remove_all(ctx, NULL, NULL);
|
||||
|
||||
|
|
@ -8879,7 +8905,7 @@ static void io_sqpoll_cancel_sync(struct io_ring_ctx *ctx)
|
|||
if (task) {
|
||||
init_completion(&work.completion);
|
||||
init_task_work(&work.task_work, io_sqpoll_cancel_cb);
|
||||
WARN_ON_ONCE(task_work_add(task, &work.task_work, TWA_SIGNAL));
|
||||
io_task_work_add_head(&sqd->park_task_work, &work.task_work);
|
||||
wake_up_process(task);
|
||||
}
|
||||
io_sq_thread_unpark(sqd);
|
||||
|
|
|
|||
|
|
@ -170,6 +170,16 @@ int iomap_swapfile_activate(struct swap_info_struct *sis,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this swapfile doesn't contain even a single page-aligned
|
||||
* contiguous range of blocks, reject this useless swapfile to
|
||||
* prevent confusion later on.
|
||||
*/
|
||||
if (isi.nr_pages == 0) {
|
||||
pr_warn("swapon: Cannot find a single usable page in file.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*pagespan = 1 + isi.highest_ppage - isi.lowest_ppage;
|
||||
sis->max = isi.nr_pages;
|
||||
sis->pages = isi.nr_pages - 1;
|
||||
|
|
|
|||
|
|
@ -1007,9 +1007,10 @@ xfs_create(
|
|||
/*
|
||||
* Make sure that we have allocated dquot(s) on disk.
|
||||
*/
|
||||
error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
|
||||
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
|
||||
&udqp, &gdqp, &pdqp);
|
||||
error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns),
|
||||
fsgid_into_mnt(mnt_userns), prid,
|
||||
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
|
||||
&udqp, &gdqp, &pdqp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
@ -1157,9 +1158,10 @@ xfs_create_tmpfile(
|
|||
/*
|
||||
* Make sure that we have allocated dquot(s) on disk.
|
||||
*/
|
||||
error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
|
||||
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
|
||||
&udqp, &gdqp, &pdqp);
|
||||
error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns),
|
||||
fsgid_into_mnt(mnt_userns), prid,
|
||||
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
|
||||
&udqp, &gdqp, &pdqp);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
|
|||
|
|
@ -168,6 +168,12 @@ xfs_bulkstat_one(
|
|||
};
|
||||
int error;
|
||||
|
||||
if (breq->mnt_userns != &init_user_ns) {
|
||||
xfs_warn_ratelimited(breq->mp,
|
||||
"bulkstat not supported inside of idmapped mounts.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ASSERT(breq->icount == 1);
|
||||
|
||||
bc.buf = kmem_zalloc(sizeof(struct xfs_bulkstat),
|
||||
|
|
|
|||
|
|
@ -634,6 +634,47 @@ xfs_check_summary_counts(
|
|||
return xfs_initialize_perag_data(mp, mp->m_sb.sb_agcount);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush and reclaim dirty inodes in preparation for unmount. Inodes and
|
||||
* internal inode structures can be sitting in the CIL and AIL at this point,
|
||||
* so we need to unpin them, write them back and/or reclaim them before unmount
|
||||
* can proceed.
|
||||
*
|
||||
* An inode cluster that has been freed can have its buffer still pinned in
|
||||
* memory because the transaction is still sitting in a iclog. The stale inodes
|
||||
* on that buffer will be pinned to the buffer until the transaction hits the
|
||||
* disk and the callbacks run. Pushing the AIL will skip the stale inodes and
|
||||
* may never see the pinned buffer, so nothing will push out the iclog and
|
||||
* unpin the buffer.
|
||||
*
|
||||
* Hence we need to force the log to unpin everything first. However, log
|
||||
* forces don't wait for the discards they issue to complete, so we have to
|
||||
* explicitly wait for them to complete here as well.
|
||||
*
|
||||
* Then we can tell the world we are unmounting so that error handling knows
|
||||
* that the filesystem is going away and we should error out anything that we
|
||||
* have been retrying in the background. This will prevent never-ending
|
||||
* retries in AIL pushing from hanging the unmount.
|
||||
*
|
||||
* Finally, we can push the AIL to clean all the remaining dirty objects, then
|
||||
* reclaim the remaining inodes that are still in memory at this point in time.
|
||||
*/
|
||||
static void
|
||||
xfs_unmount_flush_inodes(
|
||||
struct xfs_mount *mp)
|
||||
{
|
||||
xfs_log_force(mp, XFS_LOG_SYNC);
|
||||
xfs_extent_busy_wait_all(mp);
|
||||
flush_workqueue(xfs_discard_wq);
|
||||
|
||||
mp->m_flags |= XFS_MOUNT_UNMOUNTING;
|
||||
|
||||
xfs_ail_push_all_sync(mp->m_ail);
|
||||
cancel_delayed_work_sync(&mp->m_reclaim_work);
|
||||
xfs_reclaim_inodes(mp);
|
||||
xfs_health_unmount(mp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does the following on an initial mount of a file system:
|
||||
* - reads the superblock from disk and init the mount struct
|
||||
|
|
@ -1008,7 +1049,7 @@ xfs_mountfs(
|
|||
/* Clean out dquots that might be in memory after quotacheck. */
|
||||
xfs_qm_unmount(mp);
|
||||
/*
|
||||
* Cancel all delayed reclaim work and reclaim the inodes directly.
|
||||
* Flush all inode reclamation work and flush the log.
|
||||
* We have to do this /after/ rtunmount and qm_unmount because those
|
||||
* two will have scheduled delayed reclaim for the rt/quota inodes.
|
||||
*
|
||||
|
|
@ -1018,11 +1059,8 @@ xfs_mountfs(
|
|||
* qm_unmount_quotas and therefore rely on qm_unmount to release the
|
||||
* quota inodes.
|
||||
*/
|
||||
cancel_delayed_work_sync(&mp->m_reclaim_work);
|
||||
xfs_reclaim_inodes(mp);
|
||||
xfs_health_unmount(mp);
|
||||
xfs_unmount_flush_inodes(mp);
|
||||
out_log_dealloc:
|
||||
mp->m_flags |= XFS_MOUNT_UNMOUNTING;
|
||||
xfs_log_mount_cancel(mp);
|
||||
out_fail_wait:
|
||||
if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp)
|
||||
|
|
@ -1063,47 +1101,7 @@ xfs_unmountfs(
|
|||
xfs_rtunmount_inodes(mp);
|
||||
xfs_irele(mp->m_rootip);
|
||||
|
||||
/*
|
||||
* We can potentially deadlock here if we have an inode cluster
|
||||
* that has been freed has its buffer still pinned in memory because
|
||||
* the transaction is still sitting in a iclog. The stale inodes
|
||||
* on that buffer will be pinned to the buffer until the
|
||||
* transaction hits the disk and the callbacks run. Pushing the AIL will
|
||||
* skip the stale inodes and may never see the pinned buffer, so
|
||||
* nothing will push out the iclog and unpin the buffer. Hence we
|
||||
* need to force the log here to ensure all items are flushed into the
|
||||
* AIL before we go any further.
|
||||
*/
|
||||
xfs_log_force(mp, XFS_LOG_SYNC);
|
||||
|
||||
/*
|
||||
* Wait for all busy extents to be freed, including completion of
|
||||
* any discard operation.
|
||||
*/
|
||||
xfs_extent_busy_wait_all(mp);
|
||||
flush_workqueue(xfs_discard_wq);
|
||||
|
||||
/*
|
||||
* We now need to tell the world we are unmounting. This will allow
|
||||
* us to detect that the filesystem is going away and we should error
|
||||
* out anything that we have been retrying in the background. This will
|
||||
* prevent neverending retries in AIL pushing from hanging the unmount.
|
||||
*/
|
||||
mp->m_flags |= XFS_MOUNT_UNMOUNTING;
|
||||
|
||||
/*
|
||||
* Flush all pending changes from the AIL.
|
||||
*/
|
||||
xfs_ail_push_all_sync(mp->m_ail);
|
||||
|
||||
/*
|
||||
* Reclaim all inodes. At this point there should be no dirty inodes and
|
||||
* none should be pinned or locked. Stop background inode reclaim here
|
||||
* if it is still running.
|
||||
*/
|
||||
cancel_delayed_work_sync(&mp->m_reclaim_work);
|
||||
xfs_reclaim_inodes(mp);
|
||||
xfs_health_unmount(mp);
|
||||
xfs_unmount_flush_inodes(mp);
|
||||
|
||||
xfs_qm_unmount(mp);
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,8 @@ xfs_symlink(
|
|||
/*
|
||||
* Make sure that we have allocated dquot(s) on disk.
|
||||
*/
|
||||
error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
|
||||
error = xfs_qm_vop_dqalloc(dp, fsuid_into_mnt(mnt_userns),
|
||||
fsgid_into_mnt(mnt_userns), prid,
|
||||
XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
|
||||
&udqp, &gdqp, &pdqp);
|
||||
if (error)
|
||||
|
|
|
|||
|
|
@ -165,6 +165,21 @@ static int zonefs_writepages(struct address_space *mapping,
|
|||
return iomap_writepages(mapping, wbc, &wpc, &zonefs_writeback_ops);
|
||||
}
|
||||
|
||||
static int zonefs_swap_activate(struct swap_info_struct *sis,
|
||||
struct file *swap_file, sector_t *span)
|
||||
{
|
||||
struct inode *inode = file_inode(swap_file);
|
||||
struct zonefs_inode_info *zi = ZONEFS_I(inode);
|
||||
|
||||
if (zi->i_ztype != ZONEFS_ZTYPE_CNV) {
|
||||
zonefs_err(inode->i_sb,
|
||||
"swap file: not a conventional zone file\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return iomap_swapfile_activate(sis, swap_file, span, &zonefs_iomap_ops);
|
||||
}
|
||||
|
||||
static const struct address_space_operations zonefs_file_aops = {
|
||||
.readpage = zonefs_readpage,
|
||||
.readahead = zonefs_readahead,
|
||||
|
|
@ -177,6 +192,7 @@ static const struct address_space_operations zonefs_file_aops = {
|
|||
.is_partially_uptodate = iomap_is_partially_uptodate,
|
||||
.error_remove_page = generic_error_remove_page,
|
||||
.direct_IO = noop_direct_IO,
|
||||
.swap_activate = zonefs_swap_activate,
|
||||
};
|
||||
|
||||
static void zonefs_update_stats(struct inode *inode, loff_t new_isize)
|
||||
|
|
@ -727,6 +743,68 @@ static ssize_t zonefs_file_dio_append(struct kiocb *iocb, struct iov_iter *from)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not exceed the LFS limits nor the file zone size. If pos is under the
|
||||
* limit it becomes a short access. If it exceeds the limit, return -EFBIG.
|
||||
*/
|
||||
static loff_t zonefs_write_check_limits(struct file *file, loff_t pos,
|
||||
loff_t count)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
struct zonefs_inode_info *zi = ZONEFS_I(inode);
|
||||
loff_t limit = rlimit(RLIMIT_FSIZE);
|
||||
loff_t max_size = zi->i_max_size;
|
||||
|
||||
if (limit != RLIM_INFINITY) {
|
||||
if (pos >= limit) {
|
||||
send_sig(SIGXFSZ, current, 0);
|
||||
return -EFBIG;
|
||||
}
|
||||
count = min(count, limit - pos);
|
||||
}
|
||||
|
||||
if (!(file->f_flags & O_LARGEFILE))
|
||||
max_size = min_t(loff_t, MAX_NON_LFS, max_size);
|
||||
|
||||
if (unlikely(pos >= max_size))
|
||||
return -EFBIG;
|
||||
|
||||
return min(count, max_size - pos);
|
||||
}
|
||||
|
||||
static ssize_t zonefs_write_checks(struct kiocb *iocb, struct iov_iter *from)
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct zonefs_inode_info *zi = ZONEFS_I(inode);
|
||||
loff_t count;
|
||||
|
||||
if (IS_SWAPFILE(inode))
|
||||
return -ETXTBSY;
|
||||
|
||||
if (!iov_iter_count(from))
|
||||
return 0;
|
||||
|
||||
if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
|
||||
return -EINVAL;
|
||||
|
||||
if (iocb->ki_flags & IOCB_APPEND) {
|
||||
if (zi->i_ztype != ZONEFS_ZTYPE_SEQ)
|
||||
return -EINVAL;
|
||||
mutex_lock(&zi->i_truncate_mutex);
|
||||
iocb->ki_pos = zi->i_wpoffset;
|
||||
mutex_unlock(&zi->i_truncate_mutex);
|
||||
}
|
||||
|
||||
count = zonefs_write_check_limits(file, iocb->ki_pos,
|
||||
iov_iter_count(from));
|
||||
if (count < 0)
|
||||
return count;
|
||||
|
||||
iov_iter_truncate(from, count);
|
||||
return iov_iter_count(from);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle direct writes. For sequential zone files, this is the only possible
|
||||
* write path. For these files, check that the user is issuing writes
|
||||
|
|
@ -744,8 +822,7 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
|
|||
struct super_block *sb = inode->i_sb;
|
||||
bool sync = is_sync_kiocb(iocb);
|
||||
bool append = false;
|
||||
size_t count;
|
||||
ssize_t ret;
|
||||
ssize_t ret, count;
|
||||
|
||||
/*
|
||||
* For async direct IOs to sequential zone files, refuse IOCB_NOWAIT
|
||||
|
|
@ -763,12 +840,11 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
|
|||
inode_lock(inode);
|
||||
}
|
||||
|
||||
ret = generic_write_checks(iocb, from);
|
||||
if (ret <= 0)
|
||||
count = zonefs_write_checks(iocb, from);
|
||||
if (count <= 0) {
|
||||
ret = count;
|
||||
goto inode_unlock;
|
||||
|
||||
iov_iter_truncate(from, zi->i_max_size - iocb->ki_pos);
|
||||
count = iov_iter_count(from);
|
||||
}
|
||||
|
||||
if ((iocb->ki_pos | count) & (sb->s_blocksize - 1)) {
|
||||
ret = -EINVAL;
|
||||
|
|
@ -828,12 +904,10 @@ static ssize_t zonefs_file_buffered_write(struct kiocb *iocb,
|
|||
inode_lock(inode);
|
||||
}
|
||||
|
||||
ret = generic_write_checks(iocb, from);
|
||||
ret = zonefs_write_checks(iocb, from);
|
||||
if (ret <= 0)
|
||||
goto inode_unlock;
|
||||
|
||||
iov_iter_truncate(from, zi->i_max_size - iocb->ki_pos);
|
||||
|
||||
ret = iomap_file_buffered_write(iocb, from, &zonefs_iomap_ops);
|
||||
if (ret > 0)
|
||||
iocb->ki_pos += ret;
|
||||
|
|
@ -966,9 +1040,7 @@ static int zonefs_open_zone(struct inode *inode)
|
|||
|
||||
mutex_lock(&zi->i_truncate_mutex);
|
||||
|
||||
zi->i_wr_refcnt++;
|
||||
if (zi->i_wr_refcnt == 1) {
|
||||
|
||||
if (!zi->i_wr_refcnt) {
|
||||
if (atomic_inc_return(&sbi->s_open_zones) > sbi->s_max_open_zones) {
|
||||
atomic_dec(&sbi->s_open_zones);
|
||||
ret = -EBUSY;
|
||||
|
|
@ -978,7 +1050,6 @@ static int zonefs_open_zone(struct inode *inode)
|
|||
if (i_size_read(inode) < zi->i_max_size) {
|
||||
ret = zonefs_zone_mgmt(inode, REQ_OP_ZONE_OPEN);
|
||||
if (ret) {
|
||||
zi->i_wr_refcnt--;
|
||||
atomic_dec(&sbi->s_open_zones);
|
||||
goto unlock;
|
||||
}
|
||||
|
|
@ -986,6 +1057,8 @@ static int zonefs_open_zone(struct inode *inode)
|
|||
}
|
||||
}
|
||||
|
||||
zi->i_wr_refcnt++;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&zi->i_truncate_mutex);
|
||||
|
||||
|
|
|
|||
|
|
@ -612,9 +612,11 @@ static inline void ttm_bo_pin(struct ttm_buffer_object *bo)
|
|||
static inline void ttm_bo_unpin(struct ttm_buffer_object *bo)
|
||||
{
|
||||
dma_resv_assert_held(bo->base.resv);
|
||||
WARN_ON_ONCE(!bo->pin_count);
|
||||
WARN_ON_ONCE(!kref_read(&bo->kref));
|
||||
--bo->pin_count;
|
||||
if (bo->pin_count)
|
||||
--bo->pin_count;
|
||||
else
|
||||
WARN_ON_ONCE(true);
|
||||
}
|
||||
|
||||
int ttm_mem_evict_first(struct ttm_bo_device *bdev,
|
||||
|
|
|
|||
|
|
@ -105,8 +105,19 @@ extern struct bus_type amba_bustype;
|
|||
#define amba_get_drvdata(d) dev_get_drvdata(&d->dev)
|
||||
#define amba_set_drvdata(d,p) dev_set_drvdata(&d->dev, p)
|
||||
|
||||
#ifdef CONFIG_ARM_AMBA
|
||||
int amba_driver_register(struct amba_driver *);
|
||||
void amba_driver_unregister(struct amba_driver *);
|
||||
#else
|
||||
static inline int amba_driver_register(struct amba_driver *drv)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
static inline void amba_driver_unregister(struct amba_driver *drv)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
struct amba_device *amba_device_alloc(const char *, resource_size_t, size_t);
|
||||
void amba_device_put(struct amba_device *);
|
||||
int amba_device_add(struct amba_device *, struct resource *);
|
||||
|
|
|
|||
|
|
@ -5,31 +5,6 @@
|
|||
#include <linux/sched.h>
|
||||
#include <linux/xarray.h>
|
||||
|
||||
struct io_wq_work_node {
|
||||
struct io_wq_work_node *next;
|
||||
};
|
||||
|
||||
struct io_wq_work_list {
|
||||
struct io_wq_work_node *first;
|
||||
struct io_wq_work_node *last;
|
||||
};
|
||||
|
||||
struct io_uring_task {
|
||||
/* submission side */
|
||||
struct xarray xa;
|
||||
struct wait_queue_head wait;
|
||||
void *last;
|
||||
void *io_wq;
|
||||
struct percpu_counter inflight;
|
||||
atomic_t in_idle;
|
||||
bool sqpoll;
|
||||
|
||||
spinlock_t task_lock;
|
||||
struct io_wq_work_list task_list;
|
||||
unsigned long task_state;
|
||||
struct callback_head task_work;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_IO_URING)
|
||||
struct sock *io_uring_get_socket(struct file *file);
|
||||
void __io_uring_task_cancel(void);
|
||||
|
|
|
|||
|
|
@ -250,20 +250,20 @@ struct vdpa_config_ops {
|
|||
|
||||
struct vdpa_device *__vdpa_alloc_device(struct device *parent,
|
||||
const struct vdpa_config_ops *config,
|
||||
int nvqs, size_t size, const char *name);
|
||||
size_t size, const char *name);
|
||||
|
||||
#define vdpa_alloc_device(dev_struct, member, parent, config, nvqs, name) \
|
||||
#define vdpa_alloc_device(dev_struct, member, parent, config, name) \
|
||||
container_of(__vdpa_alloc_device( \
|
||||
parent, config, nvqs, \
|
||||
parent, config, \
|
||||
sizeof(dev_struct) + \
|
||||
BUILD_BUG_ON_ZERO(offsetof( \
|
||||
dev_struct, member)), name), \
|
||||
dev_struct, member)
|
||||
|
||||
int vdpa_register_device(struct vdpa_device *vdev);
|
||||
int vdpa_register_device(struct vdpa_device *vdev, int nvqs);
|
||||
void vdpa_unregister_device(struct vdpa_device *vdev);
|
||||
|
||||
int _vdpa_register_device(struct vdpa_device *vdev);
|
||||
int _vdpa_register_device(struct vdpa_device *vdev, int nvqs);
|
||||
void _vdpa_unregister_device(struct vdpa_device *vdev);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -132,8 +132,6 @@ bool is_virtio_device(struct device *dev);
|
|||
void virtio_break_device(struct virtio_device *dev);
|
||||
|
||||
void virtio_config_changed(struct virtio_device *dev);
|
||||
void virtio_config_disable(struct virtio_device *dev);
|
||||
void virtio_config_enable(struct virtio_device *dev);
|
||||
int virtio_finalize_features(struct virtio_device *dev);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
int virtio_device_freeze(struct virtio_device *dev);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ TRACE_EVENT(workqueue_queue_work,
|
|||
TP_STRUCT__entry(
|
||||
__field( void *, work )
|
||||
__field( void *, function)
|
||||
__field( const char *, workqueue)
|
||||
__string( workqueue, pwq->wq->name)
|
||||
__field( unsigned int, req_cpu )
|
||||
__field( unsigned int, cpu )
|
||||
),
|
||||
|
|
@ -38,13 +38,13 @@ TRACE_EVENT(workqueue_queue_work,
|
|||
TP_fast_assign(
|
||||
__entry->work = work;
|
||||
__entry->function = work->func;
|
||||
__entry->workqueue = pwq->wq->name;
|
||||
__assign_str(workqueue, pwq->wq->name);
|
||||
__entry->req_cpu = req_cpu;
|
||||
__entry->cpu = pwq->pool->cpu;
|
||||
),
|
||||
|
||||
TP_printk("work struct=%p function=%ps workqueue=%s req_cpu=%u cpu=%u",
|
||||
__entry->work, __entry->function, __entry->workqueue,
|
||||
__entry->work, __entry->function, __get_str(workqueue),
|
||||
__entry->req_cpu, __entry->cpu)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -2449,7 +2449,6 @@ struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node)
|
|||
if (!IS_ERR(tsk)) {
|
||||
sigfillset(&tsk->blocked);
|
||||
sigdelsetmask(&tsk->blocked, sigmask(SIGKILL));
|
||||
tsk->flags |= PF_NOFREEZE;
|
||||
}
|
||||
return tsk;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ bool freeze_task(struct task_struct *p)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!(p->flags & PF_KTHREAD))
|
||||
if (!(p->flags & (PF_KTHREAD | PF_IO_WORKER)))
|
||||
fake_signal_wake_up(p);
|
||||
else
|
||||
wake_up_state(p, TASK_INTERRUPTIBLE);
|
||||
|
|
|
|||
|
|
@ -246,8 +246,6 @@ void migrate_to_reboot_cpu(void)
|
|||
void kernel_restart(char *cmd)
|
||||
{
|
||||
kernel_restart_prepare(cmd);
|
||||
if (pm_power_off_prepare)
|
||||
pm_power_off_prepare();
|
||||
migrate_to_reboot_cpu();
|
||||
syscore_shutdown();
|
||||
if (!cmd)
|
||||
|
|
|
|||
|
|
@ -493,11 +493,10 @@ void snd_dice_stream_stop_duplex(struct snd_dice *dice)
|
|||
struct reg_params tx_params, rx_params;
|
||||
|
||||
if (dice->substreams_counter == 0) {
|
||||
if (get_register_params(dice, &tx_params, &rx_params) >= 0) {
|
||||
amdtp_domain_stop(&dice->domain);
|
||||
if (get_register_params(dice, &tx_params, &rx_params) >= 0)
|
||||
finish_session(dice, &tx_params, &rx_params);
|
||||
}
|
||||
|
||||
amdtp_domain_stop(&dice->domain);
|
||||
release_resources(dice);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4065,7 +4065,7 @@ static int add_micmute_led_hook(struct hda_codec *codec)
|
|||
|
||||
spec->micmute_led.led_mode = MICMUTE_LED_FOLLOW_MUTE;
|
||||
spec->micmute_led.capture = 0;
|
||||
spec->micmute_led.led_value = 0;
|
||||
spec->micmute_led.led_value = -1;
|
||||
spec->micmute_led.old_hook = spec->cap_sync_hook;
|
||||
spec->cap_sync_hook = update_micmute_led;
|
||||
if (!snd_hda_gen_add_kctl(spec, NULL, &micmute_led_mode_ctl))
|
||||
|
|
|
|||
|
|
@ -4225,6 +4225,12 @@ static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
|
|||
}
|
||||
}
|
||||
|
||||
static void alc236_fixup_hp_gpio_led(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
alc_fixup_hp_gpio_led(codec, action, 0x02, 0x01);
|
||||
}
|
||||
|
||||
static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
|
||||
const struct hda_fixup *fix, int action)
|
||||
{
|
||||
|
|
@ -6381,6 +6387,7 @@ enum {
|
|||
ALC294_FIXUP_ASUS_GX502_VERBS,
|
||||
ALC285_FIXUP_HP_GPIO_LED,
|
||||
ALC285_FIXUP_HP_MUTE_LED,
|
||||
ALC236_FIXUP_HP_GPIO_LED,
|
||||
ALC236_FIXUP_HP_MUTE_LED,
|
||||
ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
|
||||
ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
|
||||
|
|
@ -7616,6 +7623,10 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc285_fixup_hp_mute_led,
|
||||
},
|
||||
[ALC236_FIXUP_HP_GPIO_LED] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc236_fixup_hp_gpio_led,
|
||||
},
|
||||
[ALC236_FIXUP_HP_MUTE_LED] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc236_fixup_hp_mute_led,
|
||||
|
|
@ -8045,9 +8056,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8783, "HP ZBook Fury 15 G7 Mobile Workstation",
|
||||
ALC285_FIXUP_HP_GPIO_AMP_INIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP),
|
||||
SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
|
||||
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
|
||||
|
|
@ -8242,7 +8256,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101),
|
||||
SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
|
||||
SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802),
|
||||
SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X),
|
||||
|
|
|
|||
|
|
@ -186,7 +186,6 @@ config SND_SOC_ALL_CODECS
|
|||
imply SND_SOC_SI476X
|
||||
imply SND_SOC_SIMPLE_AMPLIFIER
|
||||
imply SND_SOC_SIMPLE_MUX
|
||||
imply SND_SOC_SIRF_AUDIO_CODEC
|
||||
imply SND_SOC_SPDIF
|
||||
imply SND_SOC_SSM2305
|
||||
imply SND_SOC_SSM2518
|
||||
|
|
@ -1279,10 +1278,6 @@ config SND_SOC_SIMPLE_MUX
|
|||
tristate "Simple Audio Mux"
|
||||
select GPIOLIB
|
||||
|
||||
config SND_SOC_SIRF_AUDIO_CODEC
|
||||
tristate "SiRF SoC internal audio codec"
|
||||
select REGMAP_MMIO
|
||||
|
||||
config SND_SOC_SPDIF
|
||||
tristate "S/PDIF CODEC"
|
||||
|
||||
|
|
|
|||
|
|
@ -812,6 +812,7 @@ static const struct of_device_id ak4458_of_match[] = {
|
|||
{ .compatible = "asahi-kasei,ak4497", .data = &ak4497_drvdata},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ak4458_of_match);
|
||||
|
||||
static struct i2c_driver ak4458_i2c_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -419,6 +419,7 @@ static const struct of_device_id ak5558_i2c_dt_ids[] __maybe_unused = {
|
|||
{ .compatible = "asahi-kasei,ak5558"},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ak5558_i2c_dt_ids);
|
||||
|
||||
static struct i2c_driver ak5558_i2c_driver = {
|
||||
.driver = {
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ static const struct regmap_config cs42l42_regmap = {
|
|||
};
|
||||
|
||||
static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false);
|
||||
static DECLARE_TLV_DB_SCALE(mixer_tlv, -6200, 100, false);
|
||||
static DECLARE_TLV_DB_SCALE(mixer_tlv, -6300, 100, true);
|
||||
|
||||
static const char * const cs42l42_hpf_freq_text[] = {
|
||||
"1.86Hz", "120Hz", "235Hz", "466Hz"
|
||||
|
|
@ -458,7 +458,7 @@ static const struct snd_kcontrol_new cs42l42_snd_controls[] = {
|
|||
CS42L42_DAC_HPF_EN_SHIFT, true, false),
|
||||
SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL,
|
||||
CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT,
|
||||
0x3e, 1, mixer_tlv)
|
||||
0x3f, 1, mixer_tlv)
|
||||
};
|
||||
|
||||
static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w,
|
||||
|
|
@ -511,43 +511,6 @@ static const struct snd_soc_dapm_route cs42l42_audio_map[] = {
|
|||
{"HP", NULL, "HPDRV"}
|
||||
};
|
||||
|
||||
static int cs42l42_set_bias_level(struct snd_soc_component *component,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
|
||||
regcache_cache_only(cs42l42->regmap, false);
|
||||
regcache_sync(cs42l42->regmap);
|
||||
ret = regulator_bulk_enable(
|
||||
ARRAY_SIZE(cs42l42->supplies),
|
||||
cs42l42->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(component->dev,
|
||||
"Failed to enable regulators: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
|
||||
regcache_cache_only(cs42l42->regmap, true);
|
||||
regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies),
|
||||
cs42l42->supplies);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs42l42_component_probe(struct snd_soc_component *component)
|
||||
{
|
||||
struct cs42l42_private *cs42l42 =
|
||||
|
|
@ -560,7 +523,6 @@ static int cs42l42_component_probe(struct snd_soc_component *component)
|
|||
|
||||
static const struct snd_soc_component_driver soc_component_dev_cs42l42 = {
|
||||
.probe = cs42l42_component_probe,
|
||||
.set_bias_level = cs42l42_set_bias_level,
|
||||
.dapm_widgets = cs42l42_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets),
|
||||
.dapm_routes = cs42l42_audio_map,
|
||||
|
|
@ -691,24 +653,6 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
|
|||
CS42L42_CLK_OASRC_SEL_MASK,
|
||||
CS42L42_CLK_OASRC_SEL_12 <<
|
||||
CS42L42_CLK_OASRC_SEL_SHIFT);
|
||||
/* channel 1 on low LRCLK, 32 bit */
|
||||
snd_soc_component_update_bits(component,
|
||||
CS42L42_ASP_RX_DAI0_CH1_AP_RES,
|
||||
CS42L42_ASP_RX_CH_AP_MASK |
|
||||
CS42L42_ASP_RX_CH_RES_MASK,
|
||||
(CS42L42_ASP_RX_CH_AP_LOW <<
|
||||
CS42L42_ASP_RX_CH_AP_SHIFT) |
|
||||
(CS42L42_ASP_RX_CH_RES_32 <<
|
||||
CS42L42_ASP_RX_CH_RES_SHIFT));
|
||||
/* Channel 2 on high LRCLK, 32 bit */
|
||||
snd_soc_component_update_bits(component,
|
||||
CS42L42_ASP_RX_DAI0_CH2_AP_RES,
|
||||
CS42L42_ASP_RX_CH_AP_MASK |
|
||||
CS42L42_ASP_RX_CH_RES_MASK,
|
||||
(CS42L42_ASP_RX_CH_AP_HI <<
|
||||
CS42L42_ASP_RX_CH_AP_SHIFT) |
|
||||
(CS42L42_ASP_RX_CH_RES_32 <<
|
||||
CS42L42_ASP_RX_CH_RES_SHIFT));
|
||||
if (pll_ratio_table[i].mclk_src_sel == 0) {
|
||||
/* Pass the clock straight through */
|
||||
snd_soc_component_update_bits(component,
|
||||
|
|
@ -797,27 +741,23 @@ static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
|
|||
/* Bitclock/frame inversion */
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
asp_cfg_val |= CS42L42_ASP_SCPOL_NOR << CS42L42_ASP_SCPOL_SHIFT;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
asp_cfg_val |= CS42L42_ASP_POL_INV <<
|
||||
CS42L42_ASP_LCPOL_IN_SHIFT;
|
||||
asp_cfg_val |= CS42L42_ASP_SCPOL_NOR << CS42L42_ASP_SCPOL_SHIFT;
|
||||
asp_cfg_val |= CS42L42_ASP_LCPOL_INV << CS42L42_ASP_LCPOL_SHIFT;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
asp_cfg_val |= CS42L42_ASP_POL_INV <<
|
||||
CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
asp_cfg_val |= CS42L42_ASP_POL_INV <<
|
||||
CS42L42_ASP_LCPOL_IN_SHIFT;
|
||||
asp_cfg_val |= CS42L42_ASP_POL_INV <<
|
||||
CS42L42_ASP_SCPOL_IN_DAC_SHIFT;
|
||||
asp_cfg_val |= CS42L42_ASP_LCPOL_INV << CS42L42_ASP_LCPOL_SHIFT;
|
||||
break;
|
||||
}
|
||||
|
||||
snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG,
|
||||
CS42L42_ASP_MODE_MASK |
|
||||
CS42L42_ASP_SCPOL_IN_DAC_MASK |
|
||||
CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val);
|
||||
snd_soc_component_update_bits(component, CS42L42_ASP_CLK_CFG, CS42L42_ASP_MODE_MASK |
|
||||
CS42L42_ASP_SCPOL_MASK |
|
||||
CS42L42_ASP_LCPOL_MASK,
|
||||
asp_cfg_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -828,14 +768,29 @@ static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
{
|
||||
struct snd_soc_component *component = dai->component;
|
||||
struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
|
||||
int retval;
|
||||
unsigned int width = (params_width(params) / 8) - 1;
|
||||
unsigned int val = 0;
|
||||
|
||||
cs42l42->srate = params_rate(params);
|
||||
cs42l42->swidth = params_width(params);
|
||||
|
||||
retval = cs42l42_pll_config(component);
|
||||
switch(substream->stream) {
|
||||
case SNDRV_PCM_STREAM_PLAYBACK:
|
||||
val |= width << CS42L42_ASP_RX_CH_RES_SHIFT;
|
||||
/* channel 1 on low LRCLK */
|
||||
snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_CH1_AP_RES,
|
||||
CS42L42_ASP_RX_CH_AP_MASK |
|
||||
CS42L42_ASP_RX_CH_RES_MASK, val);
|
||||
/* Channel 2 on high LRCLK */
|
||||
val |= CS42L42_ASP_RX_CH_AP_HI << CS42L42_ASP_RX_CH_AP_SHIFT;
|
||||
snd_soc_component_update_bits(component, CS42L42_ASP_RX_DAI0_CH2_AP_RES,
|
||||
CS42L42_ASP_RX_CH_AP_MASK |
|
||||
CS42L42_ASP_RX_CH_RES_MASK, val);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
return cs42l42_pll_config(component);
|
||||
}
|
||||
|
||||
static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
|
||||
|
|
@ -900,9 +855,9 @@ static int cs42l42_mute(struct snd_soc_dai *dai, int mute, int direction)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE)
|
||||
#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE |\
|
||||
SNDRV_PCM_FMTBIT_S32_LE )
|
||||
|
||||
|
||||
static const struct snd_soc_dai_ops cs42l42_ops = {
|
||||
|
|
@ -1801,7 +1756,7 @@ static int cs42l42_i2c_probe(struct i2c_client *i2c_client,
|
|||
dev_dbg(&i2c_client->dev, "Found reset GPIO\n");
|
||||
gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
|
||||
}
|
||||
mdelay(3);
|
||||
usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
|
||||
|
||||
/* Request IRQ */
|
||||
ret = devm_request_threaded_irq(&i2c_client->dev,
|
||||
|
|
@ -1926,6 +1881,7 @@ static int cs42l42_runtime_resume(struct device *dev)
|
|||
}
|
||||
|
||||
gpiod_set_value_cansleep(cs42l42->reset_gpio, 1);
|
||||
usleep_range(CS42L42_BOOT_TIME_US, CS42L42_BOOT_TIME_US * 2);
|
||||
|
||||
regcache_cache_only(cs42l42->regmap, false);
|
||||
regcache_sync(cs42l42->regmap);
|
||||
|
|
|
|||
|
|
@ -258,11 +258,12 @@
|
|||
#define CS42L42_ASP_SLAVE_MODE 0x00
|
||||
#define CS42L42_ASP_MODE_SHIFT 4
|
||||
#define CS42L42_ASP_MODE_MASK (1 << CS42L42_ASP_MODE_SHIFT)
|
||||
#define CS42L42_ASP_SCPOL_IN_DAC_SHIFT 2
|
||||
#define CS42L42_ASP_SCPOL_IN_DAC_MASK (1 << CS42L42_ASP_SCPOL_IN_DAC_SHIFT)
|
||||
#define CS42L42_ASP_LCPOL_IN_SHIFT 0
|
||||
#define CS42L42_ASP_LCPOL_IN_MASK (1 << CS42L42_ASP_LCPOL_IN_SHIFT)
|
||||
#define CS42L42_ASP_POL_INV 1
|
||||
#define CS42L42_ASP_SCPOL_SHIFT 2
|
||||
#define CS42L42_ASP_SCPOL_MASK (3 << CS42L42_ASP_SCPOL_SHIFT)
|
||||
#define CS42L42_ASP_SCPOL_NOR 3
|
||||
#define CS42L42_ASP_LCPOL_SHIFT 0
|
||||
#define CS42L42_ASP_LCPOL_MASK (3 << CS42L42_ASP_LCPOL_SHIFT)
|
||||
#define CS42L42_ASP_LCPOL_INV 3
|
||||
|
||||
#define CS42L42_ASP_FRM_CFG (CS42L42_PAGE_12 + 0x08)
|
||||
#define CS42L42_ASP_STP_SHIFT 4
|
||||
|
|
@ -739,6 +740,7 @@
|
|||
#define CS42L42_FRAC2_VAL(val) (((val) & 0xff0000) >> 16)
|
||||
|
||||
#define CS42L42_NUM_SUPPLIES 5
|
||||
#define CS42L42_BOOT_TIME_US 3000
|
||||
|
||||
static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = {
|
||||
"VA",
|
||||
|
|
@ -756,7 +758,6 @@ struct cs42l42_private {
|
|||
struct completion pdn_done;
|
||||
u32 sclk;
|
||||
u32 srate;
|
||||
u32 swidth;
|
||||
u8 plug_state;
|
||||
u8 hs_type;
|
||||
u8 ts_inv;
|
||||
|
|
|
|||
|
|
@ -63,13 +63,8 @@ static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(adc_pga_gain_tlv,
|
|||
1, 1, TLV_DB_SCALE_ITEM(0, 0, 0),
|
||||
2, 2, TLV_DB_SCALE_ITEM(250, 0, 0),
|
||||
3, 3, TLV_DB_SCALE_ITEM(450, 0, 0),
|
||||
4, 4, TLV_DB_SCALE_ITEM(700, 0, 0),
|
||||
5, 5, TLV_DB_SCALE_ITEM(1000, 0, 0),
|
||||
6, 6, TLV_DB_SCALE_ITEM(1300, 0, 0),
|
||||
7, 7, TLV_DB_SCALE_ITEM(1600, 0, 0),
|
||||
8, 8, TLV_DB_SCALE_ITEM(1800, 0, 0),
|
||||
9, 9, TLV_DB_SCALE_ITEM(2100, 0, 0),
|
||||
10, 10, TLV_DB_SCALE_ITEM(2400, 0, 0),
|
||||
4, 7, TLV_DB_SCALE_ITEM(700, 300, 0),
|
||||
8, 10, TLV_DB_SCALE_ITEM(1800, 300, 0),
|
||||
);
|
||||
|
||||
static const SNDRV_CTL_TLVD_DECLARE_DB_RANGE(hpout_vol_tlv,
|
||||
|
|
|
|||
|
|
@ -2895,7 +2895,7 @@ static int rx_macro_enable_echo(struct snd_soc_dapm_widget *w,
|
|||
{
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
u16 val, ec_hq_reg;
|
||||
int ec_tx;
|
||||
int ec_tx = -1;
|
||||
|
||||
val = snd_soc_component_read(component,
|
||||
CDC_RX_INP_MUX_RX_MIX_CFG4);
|
||||
|
|
|
|||
|
|
@ -189,7 +189,6 @@ struct va_macro {
|
|||
struct device *dev;
|
||||
unsigned long active_ch_mask[VA_MACRO_MAX_DAIS];
|
||||
unsigned long active_ch_cnt[VA_MACRO_MAX_DAIS];
|
||||
unsigned long active_decimator[VA_MACRO_MAX_DAIS];
|
||||
u16 dmic_clk_div;
|
||||
|
||||
int dec_mode[VA_MACRO_NUM_DECIMATORS];
|
||||
|
|
@ -549,11 +548,9 @@ static int va_macro_tx_mixer_put(struct snd_kcontrol *kcontrol,
|
|||
if (enable) {
|
||||
set_bit(dec_id, &va->active_ch_mask[dai_id]);
|
||||
va->active_ch_cnt[dai_id]++;
|
||||
va->active_decimator[dai_id] = dec_id;
|
||||
} else {
|
||||
clear_bit(dec_id, &va->active_ch_mask[dai_id]);
|
||||
va->active_ch_cnt[dai_id]--;
|
||||
va->active_decimator[dai_id] = -1;
|
||||
}
|
||||
|
||||
snd_soc_dapm_mixer_update_power(widget->dapm, kcontrol, enable, update);
|
||||
|
|
@ -880,18 +877,19 @@ static int va_macro_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
|
|||
struct va_macro *va = snd_soc_component_get_drvdata(component);
|
||||
u16 tx_vol_ctl_reg, decimator;
|
||||
|
||||
decimator = va->active_decimator[dai->id];
|
||||
|
||||
tx_vol_ctl_reg = CDC_VA_TX0_TX_PATH_CTL +
|
||||
VA_MACRO_TX_PATH_OFFSET * decimator;
|
||||
if (mute)
|
||||
snd_soc_component_update_bits(component, tx_vol_ctl_reg,
|
||||
CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
|
||||
CDC_VA_TX_PATH_PGA_MUTE_EN);
|
||||
else
|
||||
snd_soc_component_update_bits(component, tx_vol_ctl_reg,
|
||||
CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
|
||||
CDC_VA_TX_PATH_PGA_MUTE_DISABLE);
|
||||
for_each_set_bit(decimator, &va->active_ch_mask[dai->id],
|
||||
VA_MACRO_DEC_MAX) {
|
||||
tx_vol_ctl_reg = CDC_VA_TX0_TX_PATH_CTL +
|
||||
VA_MACRO_TX_PATH_OFFSET * decimator;
|
||||
if (mute)
|
||||
snd_soc_component_update_bits(component, tx_vol_ctl_reg,
|
||||
CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
|
||||
CDC_VA_TX_PATH_PGA_MUTE_EN);
|
||||
else
|
||||
snd_soc_component_update_bits(component, tx_vol_ctl_reg,
|
||||
CDC_VA_TX_PATH_PGA_MUTE_EN_MASK,
|
||||
CDC_VA_TX_PATH_PGA_MUTE_DISABLE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1211,14 +1211,16 @@ static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
|
|||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
|
||||
u16 gain_reg;
|
||||
u16 path_reg, gain_reg;
|
||||
int val;
|
||||
|
||||
switch (w->reg) {
|
||||
case CDC_WSA_RX0_RX_PATH_MIX_CTL:
|
||||
switch (w->shift) {
|
||||
case WSA_MACRO_RX_MIX0:
|
||||
path_reg = CDC_WSA_RX0_RX_PATH_MIX_CTL;
|
||||
gain_reg = CDC_WSA_RX0_RX_VOL_MIX_CTL;
|
||||
break;
|
||||
case CDC_WSA_RX1_RX_PATH_MIX_CTL:
|
||||
case WSA_MACRO_RX_MIX1:
|
||||
path_reg = CDC_WSA_RX1_RX_PATH_MIX_CTL;
|
||||
gain_reg = CDC_WSA_RX1_RX_VOL_MIX_CTL;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -1231,7 +1233,7 @@ static int wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w,
|
|||
snd_soc_component_write(component, gain_reg, val);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
snd_soc_component_update_bits(component, w->reg,
|
||||
snd_soc_component_update_bits(component, path_reg,
|
||||
CDC_WSA_RX_PATH_MIX_CLK_EN_MASK,
|
||||
CDC_WSA_RX_PATH_MIX_CLK_DISABLE);
|
||||
break;
|
||||
|
|
@ -2068,14 +2070,14 @@ static const struct snd_soc_dapm_widget wsa_macro_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_MUX("WSA_RX0 INP0", SND_SOC_NOPM, 0, 0, &rx0_prim_inp0_mux),
|
||||
SND_SOC_DAPM_MUX("WSA_RX0 INP1", SND_SOC_NOPM, 0, 0, &rx0_prim_inp1_mux),
|
||||
SND_SOC_DAPM_MUX("WSA_RX0 INP2", SND_SOC_NOPM, 0, 0, &rx0_prim_inp2_mux),
|
||||
SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", CDC_WSA_RX0_RX_PATH_MIX_CTL,
|
||||
0, 0, &rx0_mix_mux, wsa_macro_enable_mix_path,
|
||||
SND_SOC_DAPM_MUX_E("WSA_RX0 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX0,
|
||||
0, &rx0_mix_mux, wsa_macro_enable_mix_path,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
SND_SOC_DAPM_MUX("WSA_RX1 INP0", SND_SOC_NOPM, 0, 0, &rx1_prim_inp0_mux),
|
||||
SND_SOC_DAPM_MUX("WSA_RX1 INP1", SND_SOC_NOPM, 0, 0, &rx1_prim_inp1_mux),
|
||||
SND_SOC_DAPM_MUX("WSA_RX1 INP2", SND_SOC_NOPM, 0, 0, &rx1_prim_inp2_mux),
|
||||
SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", CDC_WSA_RX1_RX_PATH_MIX_CTL,
|
||||
0, 0, &rx1_mix_mux, wsa_macro_enable_mix_path,
|
||||
SND_SOC_DAPM_MUX_E("WSA_RX1 MIX INP", SND_SOC_NOPM, WSA_MACRO_RX_MIX1,
|
||||
0, &rx1_mix_mux, wsa_macro_enable_mix_path,
|
||||
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
SND_SOC_DAPM_MIXER_E("WSA_RX INT0 MIX", SND_SOC_NOPM, 0, 0, NULL, 0,
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ static bool rt1015_volatile_register(struct device *dev, unsigned int reg)
|
|||
case RT1015_VENDOR_ID:
|
||||
case RT1015_DEVICE_ID:
|
||||
case RT1015_PRO_ALT:
|
||||
case RT1015_MAN_I2C:
|
||||
case RT1015_DAC3:
|
||||
case RT1015_VBAT_TEST_OUT1:
|
||||
case RT1015_VBAT_TEST_OUT2:
|
||||
|
|
@ -513,6 +514,7 @@ static void rt1015_calibrate(struct rt1015_priv *rt1015)
|
|||
msleep(300);
|
||||
regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x0008);
|
||||
regmap_write(regmap, RT1015_SYS_RST1, 0x05F5);
|
||||
regmap_write(regmap, RT1015_CLK_DET, 0x8000);
|
||||
|
||||
regcache_cache_bypass(regmap, false);
|
||||
regcache_mark_dirty(regmap);
|
||||
|
|
|
|||
|
|
@ -339,9 +339,9 @@ static bool rt5640_readable_register(struct device *dev, unsigned int reg)
|
|||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
|
||||
static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -6562, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
|
||||
static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -1762, 3000);
|
||||
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
|
||||
|
||||
/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
|
||||
|
|
|
|||
|
|
@ -285,9 +285,9 @@ static bool rt5651_readable_register(struct device *dev, unsigned int reg)
|
|||
}
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
|
||||
static const DECLARE_TLV_DB_MINMAX(dac_vol_tlv, -6562, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
|
||||
static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
|
||||
static const DECLARE_TLV_DB_MINMAX(adc_vol_tlv, -1762, 3000);
|
||||
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
|
||||
|
||||
/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */
|
||||
|
|
|
|||
|
|
@ -3426,12 +3426,17 @@ static int rt5659_set_component_sysclk(struct snd_soc_component *component, int
|
|||
{
|
||||
struct rt5659_priv *rt5659 = snd_soc_component_get_drvdata(component);
|
||||
unsigned int reg_val = 0;
|
||||
int ret;
|
||||
|
||||
if (freq == rt5659->sysclk && clk_id == rt5659->sysclk_src)
|
||||
return 0;
|
||||
|
||||
switch (clk_id) {
|
||||
case RT5659_SCLK_S_MCLK:
|
||||
ret = clk_set_rate(rt5659->mclk, freq);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg_val |= RT5659_SCLK_SRC_MCLK;
|
||||
break;
|
||||
case RT5659_SCLK_S_PLL1:
|
||||
|
|
|
|||
|
|
@ -629,21 +629,69 @@ static SOC_ENUM_SINGLE_DECL(rt5670_if2_dac_enum, RT5670_DIG_INF1_DATA,
|
|||
static SOC_ENUM_SINGLE_DECL(rt5670_if2_adc_enum, RT5670_DIG_INF1_DATA,
|
||||
RT5670_IF2_ADC_SEL_SFT, rt5670_data_select);
|
||||
|
||||
/*
|
||||
* For reliable output-mute LED control we need a "DAC1 Playback Switch" control.
|
||||
* We emulate this by only clearing the RT5670_M_DAC1_L/_R AD_DA_MIXER register
|
||||
* bits when both our emulated DAC1 Playback Switch control and the DAC1 MIXL/R
|
||||
* DAPM-mixer DAC1 input are enabled.
|
||||
*/
|
||||
static void rt5670_update_ad_da_mixer_dac1_m_bits(struct rt5670_priv *rt5670)
|
||||
{
|
||||
int val = RT5670_M_DAC1_L | RT5670_M_DAC1_R;
|
||||
|
||||
if (rt5670->dac1_mixl_dac1_switch && rt5670->dac1_playback_switch_l)
|
||||
val &= ~RT5670_M_DAC1_L;
|
||||
|
||||
if (rt5670->dac1_mixr_dac1_switch && rt5670->dac1_playback_switch_r)
|
||||
val &= ~RT5670_M_DAC1_R;
|
||||
|
||||
regmap_update_bits(rt5670->regmap, RT5670_AD_DA_MIXER,
|
||||
RT5670_M_DAC1_L | RT5670_M_DAC1_R, val);
|
||||
}
|
||||
|
||||
static int rt5670_dac1_playback_switch_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
ucontrol->value.integer.value[0] = rt5670->dac1_playback_switch_l;
|
||||
ucontrol->value.integer.value[1] = rt5670->dac1_playback_switch_r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rt5670_dac1_playback_switch_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
|
||||
struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (rt5670->dac1_playback_switch_l == ucontrol->value.integer.value[0] &&
|
||||
rt5670->dac1_playback_switch_r == ucontrol->value.integer.value[1])
|
||||
return 0;
|
||||
|
||||
rt5670->dac1_playback_switch_l = ucontrol->value.integer.value[0];
|
||||
rt5670->dac1_playback_switch_r = ucontrol->value.integer.value[1];
|
||||
|
||||
rt5670_update_ad_da_mixer_dac1_m_bits(rt5670);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new rt5670_snd_controls[] = {
|
||||
/* Headphone Output Volume */
|
||||
SOC_DOUBLE("HP Playback Switch", RT5670_HP_VOL,
|
||||
RT5670_L_MUTE_SFT, RT5670_R_MUTE_SFT, 1, 1),
|
||||
SOC_DOUBLE_TLV("HP Playback Volume", RT5670_HP_VOL,
|
||||
RT5670_L_VOL_SFT, RT5670_R_VOL_SFT,
|
||||
39, 1, out_vol_tlv),
|
||||
/* OUTPUT Control */
|
||||
SOC_DOUBLE("OUT Channel Switch", RT5670_LOUT1,
|
||||
RT5670_VOL_L_SFT, RT5670_VOL_R_SFT, 1, 1),
|
||||
SOC_DOUBLE_TLV("OUT Playback Volume", RT5670_LOUT1,
|
||||
RT5670_L_VOL_SFT, RT5670_R_VOL_SFT, 39, 1, out_vol_tlv),
|
||||
/* DAC Digital Volume */
|
||||
SOC_DOUBLE("DAC2 Playback Switch", RT5670_DAC_CTRL,
|
||||
RT5670_M_DAC_L2_VOL_SFT, RT5670_M_DAC_R2_VOL_SFT, 1, 1),
|
||||
SOC_DOUBLE_EXT("DAC1 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0,
|
||||
rt5670_dac1_playback_switch_get, rt5670_dac1_playback_switch_put),
|
||||
SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5670_DAC1_DIG_VOL,
|
||||
RT5670_L_VOL_SFT, RT5670_R_VOL_SFT,
|
||||
175, 0, dac_vol_tlv),
|
||||
|
|
@ -913,18 +961,44 @@ static const struct snd_kcontrol_new rt5670_mono_adc_r_mix[] = {
|
|||
RT5670_M_MONO_ADC_R2_SFT, 1, 1),
|
||||
};
|
||||
|
||||
/* See comment above rt5670_update_ad_da_mixer_dac1_m_bits() */
|
||||
static int rt5670_put_dac1_mix_dac1_switch(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
|
||||
struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
|
||||
struct rt5670_priv *rt5670 = snd_soc_component_get_drvdata(component);
|
||||
int ret;
|
||||
|
||||
if (mc->shift == 0)
|
||||
rt5670->dac1_mixl_dac1_switch = ucontrol->value.integer.value[0];
|
||||
else
|
||||
rt5670->dac1_mixr_dac1_switch = ucontrol->value.integer.value[0];
|
||||
|
||||
/* Apply the update (if any) */
|
||||
ret = snd_soc_dapm_put_volsw(kcontrol, ucontrol);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
rt5670_update_ad_da_mixer_dac1_m_bits(rt5670);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define SOC_DAPM_SINGLE_RT5670_DAC1_SW(name, shift) \
|
||||
SOC_SINGLE_EXT(name, SND_SOC_NOPM, shift, 1, 0, \
|
||||
snd_soc_dapm_get_volsw, rt5670_put_dac1_mix_dac1_switch)
|
||||
|
||||
static const struct snd_kcontrol_new rt5670_dac_l_mix[] = {
|
||||
SOC_DAPM_SINGLE("Stereo ADC Switch", RT5670_AD_DA_MIXER,
|
||||
RT5670_M_ADCMIX_L_SFT, 1, 1),
|
||||
SOC_DAPM_SINGLE("DAC1 Switch", RT5670_AD_DA_MIXER,
|
||||
RT5670_M_DAC1_L_SFT, 1, 1),
|
||||
SOC_DAPM_SINGLE_RT5670_DAC1_SW("DAC1 Switch", 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new rt5670_dac_r_mix[] = {
|
||||
SOC_DAPM_SINGLE("Stereo ADC Switch", RT5670_AD_DA_MIXER,
|
||||
RT5670_M_ADCMIX_R_SFT, 1, 1),
|
||||
SOC_DAPM_SINGLE("DAC1 Switch", RT5670_AD_DA_MIXER,
|
||||
RT5670_M_DAC1_R_SFT, 1, 1),
|
||||
SOC_DAPM_SINGLE_RT5670_DAC1_SW("DAC1 Switch", 1),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new rt5670_sto_dac_l_mix[] = {
|
||||
|
|
@ -1656,12 +1730,10 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
|
|||
RT5670_PWR_ADC_S1F_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5670_PWR_DIG2,
|
||||
RT5670_PWR_ADC_S2F_BIT, 0, NULL, 0),
|
||||
SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", RT5670_STO1_ADC_DIG_VOL,
|
||||
RT5670_L_MUTE_SFT, 1, rt5670_sto1_adc_l_mix,
|
||||
ARRAY_SIZE(rt5670_sto1_adc_l_mix)),
|
||||
SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", RT5670_STO1_ADC_DIG_VOL,
|
||||
RT5670_R_MUTE_SFT, 1, rt5670_sto1_adc_r_mix,
|
||||
ARRAY_SIZE(rt5670_sto1_adc_r_mix)),
|
||||
SND_SOC_DAPM_MIXER("Sto1 ADC MIXL", SND_SOC_NOPM, 0, 0,
|
||||
rt5670_sto1_adc_l_mix, ARRAY_SIZE(rt5670_sto1_adc_l_mix)),
|
||||
SND_SOC_DAPM_MIXER("Sto1 ADC MIXR", SND_SOC_NOPM, 0, 0,
|
||||
rt5670_sto1_adc_r_mix, ARRAY_SIZE(rt5670_sto1_adc_r_mix)),
|
||||
SND_SOC_DAPM_MIXER("Sto2 ADC MIXL", SND_SOC_NOPM, 0, 0,
|
||||
rt5670_sto2_adc_l_mix,
|
||||
ARRAY_SIZE(rt5670_sto2_adc_l_mix)),
|
||||
|
|
@ -2999,6 +3071,16 @@ static int rt5670_i2c_probe(struct i2c_client *i2c,
|
|||
dev_info(&i2c->dev, "quirk JD mode 3\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the emulated "DAC1 Playback Switch" by default to avoid
|
||||
* muting the output with older UCM profiles.
|
||||
*/
|
||||
rt5670->dac1_playback_switch_l = true;
|
||||
rt5670->dac1_playback_switch_r = true;
|
||||
/* The Power-On-Reset values for the DAC1 mixer have the DAC1 input enabled. */
|
||||
rt5670->dac1_mixl_dac1_switch = true;
|
||||
rt5670->dac1_mixr_dac1_switch = true;
|
||||
|
||||
rt5670->regmap = devm_regmap_init_i2c(i2c, &rt5670_regmap);
|
||||
if (IS_ERR(rt5670->regmap)) {
|
||||
ret = PTR_ERR(rt5670->regmap);
|
||||
|
|
|
|||
|
|
@ -212,12 +212,8 @@
|
|||
/* global definition */
|
||||
#define RT5670_L_MUTE (0x1 << 15)
|
||||
#define RT5670_L_MUTE_SFT 15
|
||||
#define RT5670_VOL_L_MUTE (0x1 << 14)
|
||||
#define RT5670_VOL_L_SFT 14
|
||||
#define RT5670_R_MUTE (0x1 << 7)
|
||||
#define RT5670_R_MUTE_SFT 7
|
||||
#define RT5670_VOL_R_MUTE (0x1 << 6)
|
||||
#define RT5670_VOL_R_SFT 6
|
||||
#define RT5670_L_VOL_MASK (0x3f << 8)
|
||||
#define RT5670_L_VOL_SFT 8
|
||||
#define RT5670_R_VOL_MASK (0x3f)
|
||||
|
|
@ -2017,6 +2013,11 @@ struct rt5670_priv {
|
|||
int dsp_rate;
|
||||
int jack_type;
|
||||
int jack_type_saved;
|
||||
|
||||
bool dac1_mixl_dac1_switch;
|
||||
bool dac1_mixr_dac1_switch;
|
||||
bool dac1_playback_switch_l;
|
||||
bool dac1_playback_switch_r;
|
||||
};
|
||||
|
||||
void rt5670_jack_suspend(struct snd_soc_component *component);
|
||||
|
|
|
|||
|
|
@ -895,6 +895,13 @@ static int rt711_probe(struct snd_soc_component *component)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void rt711_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
regcache_cache_only(rt711->regmap, true);
|
||||
}
|
||||
|
||||
static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
|
||||
.probe = rt711_probe,
|
||||
.set_bias_level = rt711_set_bias_level,
|
||||
|
|
@ -905,6 +912,7 @@ static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
|
|||
.dapm_routes = rt711_audio_map,
|
||||
.num_dapm_routes = ARRAY_SIZE(rt711_audio_map),
|
||||
.set_jack = rt711_set_jack_detect,
|
||||
.remove = rt711_remove,
|
||||
};
|
||||
|
||||
static int rt711_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ static const struct reg_default sgtl5000_reg_defaults[] = {
|
|||
{ SGTL5000_DAP_EQ_BASS_BAND4, 0x002f },
|
||||
{ SGTL5000_DAP_MAIN_CHAN, 0x8000 },
|
||||
{ SGTL5000_DAP_MIX_CHAN, 0x0000 },
|
||||
{ SGTL5000_DAP_AVC_CTRL, 0x0510 },
|
||||
{ SGTL5000_DAP_AVC_CTRL, 0x5100 },
|
||||
{ SGTL5000_DAP_AVC_THRESHOLD, 0x1473 },
|
||||
{ SGTL5000_DAP_AVC_ATTACK, 0x0028 },
|
||||
{ SGTL5000_DAP_AVC_DECAY, 0x0050 },
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* SiRF inner codec controllers define
|
||||
*
|
||||
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
|
||||
*/
|
||||
|
||||
#ifndef _SIRF_AUDIO_CODEC_H
|
||||
#define _SIRF_AUDIO_CODEC_H
|
||||
|
||||
|
||||
#define AUDIO_IC_CODEC_PWR (0x00E0)
|
||||
#define AUDIO_IC_CODEC_CTRL0 (0x00E4)
|
||||
#define AUDIO_IC_CODEC_CTRL1 (0x00E8)
|
||||
#define AUDIO_IC_CODEC_CTRL2 (0x00EC)
|
||||
#define AUDIO_IC_CODEC_CTRL3 (0x00F0)
|
||||
|
||||
#define MICBIASEN (1 << 3)
|
||||
|
||||
#define IC_RDACEN (1 << 0)
|
||||
#define IC_LDACEN (1 << 1)
|
||||
#define IC_HSREN (1 << 2)
|
||||
#define IC_HSLEN (1 << 3)
|
||||
#define IC_SPEN (1 << 4)
|
||||
#define IC_CPEN (1 << 5)
|
||||
|
||||
#define IC_HPRSELR (1 << 6)
|
||||
#define IC_HPLSELR (1 << 7)
|
||||
#define IC_HPRSELL (1 << 8)
|
||||
#define IC_HPLSELL (1 << 9)
|
||||
#define IC_SPSELR (1 << 10)
|
||||
#define IC_SPSELL (1 << 11)
|
||||
|
||||
#define IC_MONOR (1 << 12)
|
||||
#define IC_MONOL (1 << 13)
|
||||
|
||||
#define IC_RXOSRSEL (1 << 28)
|
||||
#define IC_CPFREQ (1 << 29)
|
||||
#define IC_HSINVEN (1 << 30)
|
||||
|
||||
#define IC_MICINREN (1 << 0)
|
||||
#define IC_MICINLEN (1 << 1)
|
||||
#define IC_MICIN1SEL (1 << 2)
|
||||
#define IC_MICIN2SEL (1 << 3)
|
||||
#define IC_MICDIFSEL (1 << 4)
|
||||
#define IC_LINEIN1SEL (1 << 5)
|
||||
#define IC_LINEIN2SEL (1 << 6)
|
||||
#define IC_RADCEN (1 << 7)
|
||||
#define IC_LADCEN (1 << 8)
|
||||
#define IC_ALM (1 << 9)
|
||||
|
||||
#define IC_DIGMICEN (1 << 22)
|
||||
#define IC_DIGMICFREQ (1 << 23)
|
||||
#define IC_ADC14B_12 (1 << 24)
|
||||
#define IC_FIRDAC_HSL_EN (1 << 25)
|
||||
#define IC_FIRDAC_HSR_EN (1 << 26)
|
||||
#define IC_FIRDAC_LOUT_EN (1 << 27)
|
||||
#define IC_POR (1 << 28)
|
||||
#define IC_CODEC_CLK_EN (1 << 29)
|
||||
#define IC_HP_3DB_BOOST (1 << 30)
|
||||
|
||||
#define IC_ADC_LEFT_GAIN_SHIFT 16
|
||||
#define IC_ADC_RIGHT_GAIN_SHIFT 10
|
||||
#define IC_ADC_GAIN_MASK 0x3F
|
||||
#define IC_MIC_MAX_GAIN 0x39
|
||||
|
||||
#define IC_RXPGAR_MASK 0x3F
|
||||
#define IC_RXPGAR_SHIFT 14
|
||||
#define IC_RXPGAL_MASK 0x3F
|
||||
#define IC_RXPGAL_SHIFT 21
|
||||
#define IC_RXPGAR 0x7B
|
||||
#define IC_RXPGAL 0x7B
|
||||
|
||||
#define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK 0x3F
|
||||
#define AUDIO_PORT_TX_FIFO_SC_OFFSET 0
|
||||
#define AUDIO_PORT_TX_FIFO_LC_OFFSET 10
|
||||
#define AUDIO_PORT_TX_FIFO_HC_OFFSET 20
|
||||
|
||||
#define TX_FIFO_SC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
|
||||
<< AUDIO_PORT_TX_FIFO_SC_OFFSET)
|
||||
#define TX_FIFO_LC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
|
||||
<< AUDIO_PORT_TX_FIFO_LC_OFFSET)
|
||||
#define TX_FIFO_HC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \
|
||||
<< AUDIO_PORT_TX_FIFO_HC_OFFSET)
|
||||
|
||||
#define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK 0x0F
|
||||
#define AUDIO_PORT_RX_FIFO_SC_OFFSET 0
|
||||
#define AUDIO_PORT_RX_FIFO_LC_OFFSET 10
|
||||
#define AUDIO_PORT_RX_FIFO_HC_OFFSET 20
|
||||
|
||||
#define RX_FIFO_SC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
|
||||
<< AUDIO_PORT_RX_FIFO_SC_OFFSET)
|
||||
#define RX_FIFO_LC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
|
||||
<< AUDIO_PORT_RX_FIFO_LC_OFFSET)
|
||||
#define RX_FIFO_HC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \
|
||||
<< AUDIO_PORT_RX_FIFO_HC_OFFSET)
|
||||
#define AUDIO_PORT_IC_CODEC_TX_CTRL (0x00F4)
|
||||
#define AUDIO_PORT_IC_CODEC_RX_CTRL (0x00F8)
|
||||
|
||||
#define AUDIO_PORT_IC_TXFIFO_OP (0x00FC)
|
||||
#define AUDIO_PORT_IC_TXFIFO_LEV_CHK (0x0100)
|
||||
#define AUDIO_PORT_IC_TXFIFO_STS (0x0104)
|
||||
#define AUDIO_PORT_IC_TXFIFO_INT (0x0108)
|
||||
#define AUDIO_PORT_IC_TXFIFO_INT_MSK (0x010C)
|
||||
|
||||
#define AUDIO_PORT_IC_RXFIFO_OP (0x0110)
|
||||
#define AUDIO_PORT_IC_RXFIFO_LEV_CHK (0x0114)
|
||||
#define AUDIO_PORT_IC_RXFIFO_STS (0x0118)
|
||||
#define AUDIO_PORT_IC_RXFIFO_INT (0x011C)
|
||||
#define AUDIO_PORT_IC_RXFIFO_INT_MSK (0x0120)
|
||||
|
||||
#define AUDIO_FIFO_START (1 << 0)
|
||||
#define AUDIO_FIFO_RESET (1 << 1)
|
||||
|
||||
#define AUDIO_FIFO_FULL (1 << 0)
|
||||
#define AUDIO_FIFO_EMPTY (1 << 1)
|
||||
#define AUDIO_FIFO_OFLOW (1 << 2)
|
||||
#define AUDIO_FIFO_UFLOW (1 << 3)
|
||||
|
||||
#define IC_TX_ENABLE (0x03)
|
||||
#define IC_RX_ENABLE_MONO (0x01)
|
||||
#define IC_RX_ENABLE_STEREO (0x03)
|
||||
|
||||
#endif /*__SIRF_AUDIO_CODEC_H*/
|
||||
|
|
@ -878,6 +878,7 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream,
|
|||
static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt)
|
||||
{
|
||||
u32 strcr = 0, scr = 0, stcr, srcr, mask;
|
||||
unsigned int slots;
|
||||
|
||||
ssi->dai_fmt = fmt;
|
||||
|
||||
|
|
@ -909,10 +910,11 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
slots = ssi->slots ? : 2;
|
||||
regmap_update_bits(ssi->regs, REG_SSI_STCCR,
|
||||
SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2));
|
||||
SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots));
|
||||
regmap_update_bits(ssi->regs, REG_SSI_SRCCR,
|
||||
SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(2));
|
||||
SSI_SxCCR_DC_MASK, SSI_SxCCR_DC(slots));
|
||||
|
||||
/* Data on rising edge of bclk, frame low, 1clk before data */
|
||||
strcr |= SSI_STCR_TFSI | SSI_STCR_TSCKP | SSI_STCR_TEFS;
|
||||
|
|
|
|||
|
|
@ -172,15 +172,16 @@ int asoc_simple_parse_clk(struct device *dev,
|
|||
* or device's module clock.
|
||||
*/
|
||||
clk = devm_get_clk_from_child(dev, node, NULL);
|
||||
if (IS_ERR(clk))
|
||||
clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
|
||||
|
||||
if (!IS_ERR(clk)) {
|
||||
simple_dai->clk = clk;
|
||||
simple_dai->sysclk = clk_get_rate(clk);
|
||||
} else if (!of_property_read_u32(node, "system-clock-frequency",
|
||||
&val)) {
|
||||
|
||||
simple_dai->clk = clk;
|
||||
} else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
|
||||
simple_dai->sysclk = val;
|
||||
} else {
|
||||
clk = devm_get_clk_from_child(dev, dlc->of_node, NULL);
|
||||
if (!IS_ERR(clk))
|
||||
simple_dai->sysclk = clk_get_rate(clk);
|
||||
}
|
||||
|
||||
if (of_property_read_bool(node, "system-clock-direction-out"))
|
||||
|
|
|
|||
|
|
@ -581,7 +581,7 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = {
|
|||
},
|
||||
.driver_data = (void *)(BYT_RT5640_DMIC1_MAP |
|
||||
BYT_RT5640_JD_SRC_JD1_IN4P |
|
||||
BYT_RT5640_OVCD_TH_1500UA |
|
||||
BYT_RT5640_OVCD_TH_2000UA |
|
||||
BYT_RT5640_OVCD_SF_0P75 |
|
||||
BYT_RT5640_MCLK_EN),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -555,7 +555,9 @@ static int mtk_dai_tdm_hw_params(struct snd_pcm_substream *substream,
|
|||
|
||||
/* set tdm */
|
||||
if (tdm_priv->bck_invert)
|
||||
tdm_con |= 1 << BCK_INVERSE_SFT;
|
||||
regmap_update_bits(afe->regmap, AUDIO_TOP_CON3,
|
||||
BCK_INVERSE_MASK_SFT,
|
||||
0x1 << BCK_INVERSE_SFT);
|
||||
|
||||
if (tdm_priv->lck_invert)
|
||||
tdm_con |= 1 << LRCK_INVERSE_SFT;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user